2 * Copyright 1997-2000 Marcus Meissner
3 * Copyright 1998-2000 Lionel Ulmer
4 * Copyright 2000-2001 TransGaming Technologies Inc.
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2002-2003 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2011, 2013-2014 Stefan Dösinger for CodeWeavers
10 * Copyright 2007-2008 Henri Verbeet
11 * Copyright 2006-2008 Roderick Colenbrander
12 * Copyright 2009-2011 Henri Verbeet for CodeWeavers
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
30 #include "wine/port.h"
31 #include "wined3d_private.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(d3d
);
34 WINE_DECLARE_DEBUG_CHANNEL(d3d_perf
);
36 static const DWORD surface_simple_locations
= WINED3D_LOCATION_SYSMEM
37 | WINED3D_LOCATION_USER_MEMORY
| WINED3D_LOCATION_BUFFER
;
43 enum wined3d_gl_resource_type tex_type
;
44 struct wined3d_vec3 texcoords
[4];
55 static inline void cube_coords_float(const RECT
*r
, UINT w
, UINT h
, struct float_rect
*f
)
57 f
->l
= ((r
->left
* 2.0f
) / w
) - 1.0f
;
58 f
->t
= ((r
->top
* 2.0f
) / h
) - 1.0f
;
59 f
->r
= ((r
->right
* 2.0f
) / w
) - 1.0f
;
60 f
->b
= ((r
->bottom
* 2.0f
) / h
) - 1.0f
;
63 static void surface_get_blt_info(GLenum target
, const RECT
*rect
, GLsizei w
, GLsizei h
, struct blt_info
*info
)
65 struct wined3d_vec3
*coords
= info
->texcoords
;
71 FIXME("Unsupported texture target %#x.\n", target
);
72 /* Fall back to GL_TEXTURE_2D */
74 info
->binding
= GL_TEXTURE_BINDING_2D
;
75 info
->bind_target
= GL_TEXTURE_2D
;
76 info
->tex_type
= WINED3D_GL_RES_TYPE_TEX_2D
;
77 coords
[0].x
= (float)rect
->left
/ w
;
78 coords
[0].y
= (float)rect
->top
/ h
;
81 coords
[1].x
= (float)rect
->right
/ w
;
82 coords
[1].y
= (float)rect
->top
/ h
;
85 coords
[2].x
= (float)rect
->left
/ w
;
86 coords
[2].y
= (float)rect
->bottom
/ h
;
89 coords
[3].x
= (float)rect
->right
/ w
;
90 coords
[3].y
= (float)rect
->bottom
/ h
;
94 case GL_TEXTURE_RECTANGLE_ARB
:
95 info
->binding
= GL_TEXTURE_BINDING_RECTANGLE_ARB
;
96 info
->bind_target
= GL_TEXTURE_RECTANGLE_ARB
;
97 info
->tex_type
= WINED3D_GL_RES_TYPE_TEX_RECT
;
98 coords
[0].x
= rect
->left
; coords
[0].y
= rect
->top
; coords
[0].z
= 0.0f
;
99 coords
[1].x
= rect
->right
; coords
[1].y
= rect
->top
; coords
[1].z
= 0.0f
;
100 coords
[2].x
= rect
->left
; coords
[2].y
= rect
->bottom
; coords
[2].z
= 0.0f
;
101 coords
[3].x
= rect
->right
; coords
[3].y
= rect
->bottom
; coords
[3].z
= 0.0f
;
104 case GL_TEXTURE_CUBE_MAP_POSITIVE_X
:
105 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
106 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
107 info
->tex_type
= WINED3D_GL_RES_TYPE_TEX_CUBE
;
108 cube_coords_float(rect
, w
, h
, &f
);
110 coords
[0].x
= 1.0f
; coords
[0].y
= -f
.t
; coords
[0].z
= -f
.l
;
111 coords
[1].x
= 1.0f
; coords
[1].y
= -f
.t
; coords
[1].z
= -f
.r
;
112 coords
[2].x
= 1.0f
; coords
[2].y
= -f
.b
; coords
[2].z
= -f
.l
;
113 coords
[3].x
= 1.0f
; coords
[3].y
= -f
.b
; coords
[3].z
= -f
.r
;
116 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X
:
117 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
118 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
119 info
->tex_type
= WINED3D_GL_RES_TYPE_TEX_CUBE
;
120 cube_coords_float(rect
, w
, h
, &f
);
122 coords
[0].x
= -1.0f
; coords
[0].y
= -f
.t
; coords
[0].z
= f
.l
;
123 coords
[1].x
= -1.0f
; coords
[1].y
= -f
.t
; coords
[1].z
= f
.r
;
124 coords
[2].x
= -1.0f
; coords
[2].y
= -f
.b
; coords
[2].z
= f
.l
;
125 coords
[3].x
= -1.0f
; coords
[3].y
= -f
.b
; coords
[3].z
= f
.r
;
128 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y
:
129 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
130 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
131 info
->tex_type
= WINED3D_GL_RES_TYPE_TEX_CUBE
;
132 cube_coords_float(rect
, w
, h
, &f
);
134 coords
[0].x
= f
.l
; coords
[0].y
= 1.0f
; coords
[0].z
= f
.t
;
135 coords
[1].x
= f
.r
; coords
[1].y
= 1.0f
; coords
[1].z
= f
.t
;
136 coords
[2].x
= f
.l
; coords
[2].y
= 1.0f
; coords
[2].z
= f
.b
;
137 coords
[3].x
= f
.r
; coords
[3].y
= 1.0f
; coords
[3].z
= f
.b
;
140 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
:
141 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
142 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
143 info
->tex_type
= WINED3D_GL_RES_TYPE_TEX_CUBE
;
144 cube_coords_float(rect
, w
, h
, &f
);
146 coords
[0].x
= f
.l
; coords
[0].y
= -1.0f
; coords
[0].z
= -f
.t
;
147 coords
[1].x
= f
.r
; coords
[1].y
= -1.0f
; coords
[1].z
= -f
.t
;
148 coords
[2].x
= f
.l
; coords
[2].y
= -1.0f
; coords
[2].z
= -f
.b
;
149 coords
[3].x
= f
.r
; coords
[3].y
= -1.0f
; coords
[3].z
= -f
.b
;
152 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z
:
153 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
154 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
155 info
->tex_type
= WINED3D_GL_RES_TYPE_TEX_CUBE
;
156 cube_coords_float(rect
, w
, h
, &f
);
158 coords
[0].x
= f
.l
; coords
[0].y
= -f
.t
; coords
[0].z
= 1.0f
;
159 coords
[1].x
= f
.r
; coords
[1].y
= -f
.t
; coords
[1].z
= 1.0f
;
160 coords
[2].x
= f
.l
; coords
[2].y
= -f
.b
; coords
[2].z
= 1.0f
;
161 coords
[3].x
= f
.r
; coords
[3].y
= -f
.b
; coords
[3].z
= 1.0f
;
164 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
:
165 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
166 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
167 info
->tex_type
= WINED3D_GL_RES_TYPE_TEX_CUBE
;
168 cube_coords_float(rect
, w
, h
, &f
);
170 coords
[0].x
= -f
.l
; coords
[0].y
= -f
.t
; coords
[0].z
= -1.0f
;
171 coords
[1].x
= -f
.r
; coords
[1].y
= -f
.t
; coords
[1].z
= -1.0f
;
172 coords
[2].x
= -f
.l
; coords
[2].y
= -f
.b
; coords
[2].z
= -1.0f
;
173 coords
[3].x
= -f
.r
; coords
[3].y
= -f
.b
; coords
[3].z
= -1.0f
;
178 static void surface_get_rect(const struct wined3d_surface
*surface
, const RECT
*rect_in
, RECT
*rect_out
)
181 *rect_out
= *rect_in
;
184 const struct wined3d_texture
*texture
= surface
->container
;
186 SetRect(rect_out
, 0, 0, wined3d_texture_get_level_width(texture
, surface
->texture_level
),
187 wined3d_texture_get_level_height(texture
, surface
->texture_level
));
191 /* Context activation is done by the caller. */
192 void draw_textured_quad(const struct wined3d_surface
*src_surface
, struct wined3d_context
*context
,
193 const RECT
*src_rect
, const RECT
*dst_rect
, enum wined3d_texture_filter_type filter
)
195 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
196 struct wined3d_texture
*texture
= src_surface
->container
;
197 struct blt_info info
;
199 surface_get_blt_info(src_surface
->texture_target
, src_rect
,
200 wined3d_texture_get_level_pow2_width(texture
, src_surface
->texture_level
),
201 wined3d_texture_get_level_pow2_height(texture
, src_surface
->texture_level
), &info
);
203 gl_info
->gl_ops
.gl
.p_glEnable(info
.bind_target
);
204 checkGLcall("glEnable(bind_target)");
206 context_bind_texture(context
, info
.bind_target
, texture
->texture_rgb
.name
);
208 /* Filtering for StretchRect */
209 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_MAG_FILTER
, wined3d_gl_mag_filter(filter
));
210 checkGLcall("glTexParameteri");
211 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_MIN_FILTER
,
212 wined3d_gl_min_mip_filter(filter
, WINED3D_TEXF_NONE
));
213 checkGLcall("glTexParameteri");
214 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
215 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
216 if (context
->gl_info
->supported
[EXT_TEXTURE_SRGB_DECODE
])
217 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_SRGB_DECODE_EXT
, GL_SKIP_DECODE_EXT
);
218 gl_info
->gl_ops
.gl
.p_glTexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_REPLACE
);
219 checkGLcall("glTexEnvi");
222 gl_info
->gl_ops
.gl
.p_glBegin(GL_TRIANGLE_STRIP
);
223 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(&info
.texcoords
[0].x
);
224 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
->left
, dst_rect
->top
);
226 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(&info
.texcoords
[1].x
);
227 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
->right
, dst_rect
->top
);
229 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(&info
.texcoords
[2].x
);
230 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
->left
, dst_rect
->bottom
);
232 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(&info
.texcoords
[3].x
);
233 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
->right
, dst_rect
->bottom
);
234 gl_info
->gl_ops
.gl
.p_glEnd();
236 /* Unbind the texture */
237 context_bind_texture(context
, info
.bind_target
, 0);
239 /* We changed the filtering settings on the texture. Inform the
240 * container about this to get the filters reset properly next draw. */
241 texture
->texture_rgb
.sampler_desc
.mag_filter
= WINED3D_TEXF_POINT
;
242 texture
->texture_rgb
.sampler_desc
.min_filter
= WINED3D_TEXF_POINT
;
243 texture
->texture_rgb
.sampler_desc
.mip_filter
= WINED3D_TEXF_NONE
;
244 texture
->texture_rgb
.sampler_desc
.srgb_decode
= FALSE
;
247 /* Works correctly only for <= 4 bpp formats. */
248 static void get_color_masks(const struct wined3d_format
*format
, DWORD
*masks
)
250 masks
[0] = ((1u << format
->red_size
) - 1) << format
->red_offset
;
251 masks
[1] = ((1u << format
->green_size
) - 1) << format
->green_offset
;
252 masks
[2] = ((1u << format
->blue_size
) - 1) << format
->blue_offset
;
255 void wined3d_surface_destroy_dc(struct wined3d_surface
*surface
)
257 unsigned int sub_resource_idx
= surface_get_sub_resource_idx(surface
);
258 struct wined3d_texture
*texture
= surface
->container
;
259 struct wined3d_device
*device
= texture
->resource
.device
;
260 const struct wined3d_gl_info
*gl_info
= NULL
;
261 D3DKMT_DESTROYDCFROMMEMORY destroy_desc
;
262 struct wined3d_context
*context
= NULL
;
263 struct wined3d_bo_address data
;
268 ERR("Surface %p has no DC.\n", surface
);
272 TRACE("dc %p, bitmap %p.\n", surface
->dc
, surface
->bitmap
);
274 destroy_desc
.hDc
= surface
->dc
;
275 destroy_desc
.hBitmap
= surface
->bitmap
;
276 if ((status
= D3DKMTDestroyDCFromMemory(&destroy_desc
)))
277 ERR("Failed to destroy dc, status %#x.\n", status
);
279 surface
->bitmap
= NULL
;
281 if (device
->d3d_initialized
)
283 context
= context_acquire(device
, NULL
, 0);
284 gl_info
= context
->gl_info
;
287 wined3d_texture_get_memory(texture
, sub_resource_idx
, &data
, texture
->resource
.map_binding
);
288 wined3d_texture_unmap_bo_address(&data
, gl_info
, GL_PIXEL_UNPACK_BUFFER
);
291 context_release(context
);
294 HRESULT
wined3d_surface_create_dc(struct wined3d_surface
*surface
)
296 unsigned int sub_resource_idx
= surface_get_sub_resource_idx(surface
);
297 struct wined3d_texture
*texture
= surface
->container
;
298 const struct wined3d_format
*format
= texture
->resource
.format
;
299 struct wined3d_device
*device
= texture
->resource
.device
;
300 const struct wined3d_gl_info
*gl_info
= NULL
;
301 struct wined3d_context
*context
= NULL
;
302 unsigned int row_pitch
, slice_pitch
;
303 struct wined3d_bo_address data
;
304 D3DKMT_CREATEDCFROMMEMORY desc
;
307 TRACE("surface %p.\n", surface
);
309 if (!format
->ddi_format
)
311 WARN("Cannot create a DC for format %s.\n", debug_d3dformat(format
->id
));
312 return WINED3DERR_INVALIDCALL
;
315 wined3d_texture_get_pitch(texture
, surface
->texture_level
, &row_pitch
, &slice_pitch
);
317 if (device
->d3d_initialized
)
319 context
= context_acquire(device
, NULL
, 0);
320 gl_info
= context
->gl_info
;
323 wined3d_texture_get_memory(texture
, sub_resource_idx
, &data
, texture
->resource
.map_binding
);
324 desc
.pMemory
= wined3d_texture_map_bo_address(&data
, texture
->sub_resources
[sub_resource_idx
].size
,
325 gl_info
, GL_PIXEL_UNPACK_BUFFER
, 0);
328 context_release(context
);
330 desc
.Format
= format
->ddi_format
;
331 desc
.Width
= wined3d_texture_get_level_width(texture
, surface
->texture_level
);
332 desc
.Height
= wined3d_texture_get_level_height(texture
, surface
->texture_level
);
333 desc
.Pitch
= row_pitch
;
334 desc
.hDeviceDc
= CreateCompatibleDC(NULL
);
335 desc
.pColorTable
= NULL
;
337 status
= D3DKMTCreateDCFromMemory(&desc
);
338 DeleteDC(desc
.hDeviceDc
);
341 WARN("Failed to create DC, status %#x.\n", status
);
342 return WINED3DERR_INVALIDCALL
;
345 surface
->dc
= desc
.hDc
;
346 surface
->bitmap
= desc
.hBitmap
;
348 TRACE("Created DC %p, bitmap %p for surface %p.\n", surface
->dc
, surface
->bitmap
, surface
);
353 static BOOL
surface_is_full_rect(const struct wined3d_surface
*surface
, const RECT
*r
)
357 t
= wined3d_texture_get_level_width(surface
->container
, surface
->texture_level
);
358 if ((r
->left
&& r
->right
) || abs(r
->right
- r
->left
) != t
)
360 t
= wined3d_texture_get_level_height(surface
->container
, surface
->texture_level
);
361 if ((r
->top
&& r
->bottom
) || abs(r
->bottom
- r
->top
) != t
)
366 static void surface_depth_blt_fbo(const struct wined3d_device
*device
,
367 struct wined3d_surface
*src_surface
, DWORD src_location
, const RECT
*src_rect
,
368 struct wined3d_surface
*dst_surface
, DWORD dst_location
, const RECT
*dst_rect
)
370 unsigned int dst_sub_resource_idx
= surface_get_sub_resource_idx(dst_surface
);
371 unsigned int src_sub_resource_idx
= surface_get_sub_resource_idx(src_surface
);
372 struct wined3d_texture
*dst_texture
= dst_surface
->container
;
373 struct wined3d_texture
*src_texture
= src_surface
->container
;
374 const struct wined3d_gl_info
*gl_info
;
375 struct wined3d_context
*context
;
376 DWORD src_mask
, dst_mask
;
379 TRACE("device %p\n", device
);
380 TRACE("src_surface %p, src_location %s, src_rect %s,\n",
381 src_surface
, wined3d_debug_location(src_location
), wine_dbgstr_rect(src_rect
));
382 TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n",
383 dst_surface
, wined3d_debug_location(dst_location
), wine_dbgstr_rect(dst_rect
));
385 src_mask
= src_texture
->resource
.format_flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
386 dst_mask
= dst_texture
->resource
.format_flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
388 if (src_mask
!= dst_mask
)
390 ERR("Incompatible formats %s and %s.\n",
391 debug_d3dformat(src_texture
->resource
.format
->id
),
392 debug_d3dformat(dst_texture
->resource
.format
->id
));
398 ERR("Not a depth / stencil format: %s.\n",
399 debug_d3dformat(src_texture
->resource
.format
->id
));
404 if (src_mask
& WINED3DFMT_FLAG_DEPTH
)
405 gl_mask
|= GL_DEPTH_BUFFER_BIT
;
406 if (src_mask
& WINED3DFMT_FLAG_STENCIL
)
407 gl_mask
|= GL_STENCIL_BUFFER_BIT
;
409 context
= context_acquire(device
, NULL
, 0);
412 context_release(context
);
413 WARN("Invalid context, skipping blit.\n");
417 /* Make sure the locations are up-to-date. Loading the destination
418 * surface isn't required if the entire surface is overwritten. */
419 wined3d_texture_load_location(src_texture
, src_sub_resource_idx
, context
, src_location
);
420 if (!surface_is_full_rect(dst_surface
, dst_rect
))
421 wined3d_texture_load_location(dst_texture
, dst_sub_resource_idx
, context
, dst_location
);
423 wined3d_texture_prepare_location(dst_texture
, dst_sub_resource_idx
, context
, dst_location
);
425 gl_info
= context
->gl_info
;
427 context_apply_fbo_state_blit(context
, GL_READ_FRAMEBUFFER
, NULL
, src_surface
, src_location
);
428 context_check_fbo_status(context
, GL_READ_FRAMEBUFFER
);
430 context_apply_fbo_state_blit(context
, GL_DRAW_FRAMEBUFFER
, NULL
, dst_surface
, dst_location
);
431 context_set_draw_buffer(context
, GL_NONE
);
432 context_check_fbo_status(context
, GL_DRAW_FRAMEBUFFER
);
433 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
435 if (gl_mask
& GL_DEPTH_BUFFER_BIT
)
437 gl_info
->gl_ops
.gl
.p_glDepthMask(GL_TRUE
);
438 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_ZWRITEENABLE
));
440 if (gl_mask
& GL_STENCIL_BUFFER_BIT
)
442 if (context
->gl_info
->supported
[EXT_STENCIL_TWO_SIDE
])
444 gl_info
->gl_ops
.gl
.p_glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT
);
445 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_TWOSIDEDSTENCILMODE
));
447 gl_info
->gl_ops
.gl
.p_glStencilMask(~0U);
448 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_STENCILWRITEMASK
));
451 gl_info
->gl_ops
.gl
.p_glDisable(GL_SCISSOR_TEST
);
452 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE
));
454 gl_info
->fbo_ops
.glBlitFramebuffer(src_rect
->left
, src_rect
->top
, src_rect
->right
, src_rect
->bottom
,
455 dst_rect
->left
, dst_rect
->top
, dst_rect
->right
, dst_rect
->bottom
, gl_mask
, GL_NEAREST
);
456 checkGLcall("glBlitFramebuffer()");
458 if (wined3d_settings
.strict_draw_ordering
)
459 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
461 context_release(context
);
464 /* Blit between surface locations. Onscreen on different swapchains is not supported.
465 * Depth / stencil is not supported. Context activation is done by the caller. */
466 static void surface_blt_fbo(const struct wined3d_device
*device
,
467 struct wined3d_context
*old_ctx
, enum wined3d_texture_filter_type filter
,
468 struct wined3d_surface
*src_surface
, DWORD src_location
, const RECT
*src_rect_in
,
469 struct wined3d_surface
*dst_surface
, DWORD dst_location
, const RECT
*dst_rect_in
)
471 unsigned int dst_sub_resource_idx
= surface_get_sub_resource_idx(dst_surface
);
472 unsigned int src_sub_resource_idx
= surface_get_sub_resource_idx(src_surface
);
473 struct wined3d_texture
*dst_texture
= dst_surface
->container
;
474 struct wined3d_texture
*src_texture
= src_surface
->container
;
475 const struct wined3d_gl_info
*gl_info
;
476 struct wined3d_context
*context
= old_ctx
;
477 struct wined3d_surface
*required_rt
, *restore_rt
= NULL
;
478 RECT src_rect
, dst_rect
;
482 TRACE("device %p, filter %s,\n", device
, debug_d3dtexturefiltertype(filter
));
483 TRACE("src_surface %p, src_location %s, src_rect %s,\n",
484 src_surface
, wined3d_debug_location(src_location
), wine_dbgstr_rect(src_rect_in
));
485 TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n",
486 dst_surface
, wined3d_debug_location(dst_location
), wine_dbgstr_rect(dst_rect_in
));
488 src_rect
= *src_rect_in
;
489 dst_rect
= *dst_rect_in
;
493 case WINED3D_TEXF_LINEAR
:
494 gl_filter
= GL_LINEAR
;
498 FIXME("Unsupported filter mode %s (%#x).\n", debug_d3dtexturefiltertype(filter
), filter
);
499 case WINED3D_TEXF_NONE
:
500 case WINED3D_TEXF_POINT
:
501 gl_filter
= GL_NEAREST
;
505 /* Resolve the source surface first if needed. */
506 if (src_location
== WINED3D_LOCATION_RB_MULTISAMPLE
507 && (src_texture
->resource
.format
->id
!= dst_texture
->resource
.format
->id
508 || abs(src_rect
.bottom
- src_rect
.top
) != abs(dst_rect
.bottom
- dst_rect
.top
)
509 || abs(src_rect
.right
- src_rect
.left
) != abs(dst_rect
.right
- dst_rect
.left
)))
510 src_location
= WINED3D_LOCATION_RB_RESOLVED
;
512 /* Make sure the locations are up-to-date. Loading the destination
513 * surface isn't required if the entire surface is overwritten. (And is
514 * in fact harmful if we're being called by surface_load_location() with
515 * the purpose of loading the destination surface.) */
516 wined3d_texture_load_location(src_texture
, src_sub_resource_idx
, old_ctx
, src_location
);
517 if (!surface_is_full_rect(dst_surface
, &dst_rect
))
518 wined3d_texture_load_location(dst_texture
, dst_sub_resource_idx
, old_ctx
, dst_location
);
520 wined3d_texture_prepare_location(dst_texture
, dst_sub_resource_idx
, old_ctx
, dst_location
);
523 if (src_location
== WINED3D_LOCATION_DRAWABLE
) required_rt
= src_surface
;
524 else if (dst_location
== WINED3D_LOCATION_DRAWABLE
) required_rt
= dst_surface
;
525 else required_rt
= NULL
;
527 restore_rt
= context_get_rt_surface(old_ctx
);
528 if (restore_rt
!= required_rt
)
529 context
= context_acquire(device
, required_rt
? required_rt
->container
: NULL
,
530 required_rt
? surface_get_sub_resource_idx(required_rt
) : 0);
536 context_release(context
);
537 WARN("Invalid context, skipping blit.\n");
541 gl_info
= context
->gl_info
;
543 if (src_location
== WINED3D_LOCATION_DRAWABLE
)
545 TRACE("Source surface %p is onscreen.\n", src_surface
);
546 buffer
= wined3d_texture_get_gl_buffer(src_texture
);
547 surface_translate_drawable_coords(src_surface
, context
->win_handle
, &src_rect
);
551 TRACE("Source surface %p is offscreen.\n", src_surface
);
552 buffer
= GL_COLOR_ATTACHMENT0
;
555 context_apply_fbo_state_blit(context
, GL_READ_FRAMEBUFFER
, src_surface
, NULL
, src_location
);
556 gl_info
->gl_ops
.gl
.p_glReadBuffer(buffer
);
557 checkGLcall("glReadBuffer()");
558 context_check_fbo_status(context
, GL_READ_FRAMEBUFFER
);
560 if (dst_location
== WINED3D_LOCATION_DRAWABLE
)
562 TRACE("Destination surface %p is onscreen.\n", dst_surface
);
563 buffer
= wined3d_texture_get_gl_buffer(dst_texture
);
564 surface_translate_drawable_coords(dst_surface
, context
->win_handle
, &dst_rect
);
568 TRACE("Destination surface %p is offscreen.\n", dst_surface
);
569 buffer
= GL_COLOR_ATTACHMENT0
;
572 context_apply_fbo_state_blit(context
, GL_DRAW_FRAMEBUFFER
, dst_surface
, NULL
, dst_location
);
573 context_set_draw_buffer(context
, buffer
);
574 context_check_fbo_status(context
, GL_DRAW_FRAMEBUFFER
);
575 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
577 gl_info
->gl_ops
.gl
.p_glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
578 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE
));
579 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE1
));
580 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE2
));
581 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE3
));
583 gl_info
->gl_ops
.gl
.p_glDisable(GL_SCISSOR_TEST
);
584 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE
));
586 gl_info
->fbo_ops
.glBlitFramebuffer(src_rect
.left
, src_rect
.top
, src_rect
.right
, src_rect
.bottom
,
587 dst_rect
.left
, dst_rect
.top
, dst_rect
.right
, dst_rect
.bottom
, GL_COLOR_BUFFER_BIT
, gl_filter
);
588 checkGLcall("glBlitFramebuffer()");
590 if (wined3d_settings
.strict_draw_ordering
|| (dst_location
== WINED3D_LOCATION_DRAWABLE
591 && dst_texture
->swapchain
->front_buffer
== dst_texture
))
592 gl_info
->gl_ops
.gl
.p_glFlush();
595 context_restore(context
, restore_rt
);
598 static BOOL
fbo_blit_supported(const struct wined3d_gl_info
*gl_info
, enum wined3d_blit_op blit_op
,
599 const RECT
*src_rect
, DWORD src_usage
, enum wined3d_pool src_pool
, const struct wined3d_format
*src_format
,
600 const RECT
*dst_rect
, DWORD dst_usage
, enum wined3d_pool dst_pool
, const struct wined3d_format
*dst_format
)
602 if ((wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
) || !gl_info
->fbo_ops
.glBlitFramebuffer
)
605 /* Source and/or destination need to be on the GL side */
606 if (src_pool
== WINED3D_POOL_SYSTEM_MEM
|| dst_pool
== WINED3D_POOL_SYSTEM_MEM
)
611 case WINED3D_BLIT_OP_COLOR_BLIT
:
612 if (!((src_format
->flags
[WINED3D_GL_RES_TYPE_TEX_2D
] & WINED3DFMT_FLAG_FBO_ATTACHABLE
)
613 || (src_usage
& WINED3DUSAGE_RENDERTARGET
)))
615 if (!((dst_format
->flags
[WINED3D_GL_RES_TYPE_TEX_2D
] & WINED3DFMT_FLAG_FBO_ATTACHABLE
)
616 || (dst_usage
& WINED3DUSAGE_RENDERTARGET
)))
618 if (!(src_format
->id
== dst_format
->id
619 || (is_identity_fixup(src_format
->color_fixup
)
620 && is_identity_fixup(dst_format
->color_fixup
))))
624 case WINED3D_BLIT_OP_DEPTH_BLIT
:
625 if (!(src_format
->flags
[WINED3D_GL_RES_TYPE_TEX_2D
] & (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
)))
627 if (!(dst_format
->flags
[WINED3D_GL_RES_TYPE_TEX_2D
] & (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
)))
629 /* Accept pure swizzle fixups for depth formats. In general we
630 * ignore the stencil component (if present) at the moment and the
631 * swizzle is not relevant with just the depth component. */
632 if (is_complex_fixup(src_format
->color_fixup
) || is_complex_fixup(dst_format
->color_fixup
)
633 || is_scaling_fixup(src_format
->color_fixup
) || is_scaling_fixup(dst_format
->color_fixup
))
644 static HRESULT
wined3d_surface_depth_fill(struct wined3d_surface
*surface
, const RECT
*rect
, float depth
)
646 struct wined3d_resource
*resource
= &surface
->container
->resource
;
647 struct wined3d_device
*device
= resource
->device
;
648 struct wined3d_rendertarget_view
*view
;
649 struct wined3d_view_desc view_desc
;
650 const struct blit_shader
*blitter
;
653 if (!(blitter
= wined3d_select_blitter(&device
->adapter
->gl_info
, &device
->adapter
->d3d_info
,
654 WINED3D_BLIT_OP_DEPTH_FILL
, NULL
, 0, 0, NULL
, rect
, resource
->usage
, resource
->pool
, resource
->format
)))
656 FIXME("No blitter is capable of performing the requested depth fill operation.\n");
657 return WINED3DERR_INVALIDCALL
;
660 view_desc
.format_id
= resource
->format
->id
;
662 view_desc
.u
.texture
.level_idx
= surface
->texture_level
;
663 view_desc
.u
.texture
.level_count
= 1;
664 view_desc
.u
.texture
.layer_idx
= surface
->texture_layer
;
665 view_desc
.u
.texture
.layer_count
= 1;
666 if (FAILED(hr
= wined3d_rendertarget_view_create(&view_desc
,
667 resource
, NULL
, &wined3d_null_parent_ops
, &view
)))
669 ERR("Failed to create rendertarget view, hr %#x.\n", hr
);
673 hr
= blitter
->depth_fill(device
, view
, rect
, WINED3DCLEAR_ZBUFFER
, depth
, 0);
674 wined3d_rendertarget_view_decref(view
);
679 static HRESULT
wined3d_surface_depth_blt(struct wined3d_surface
*src_surface
, DWORD src_location
, const RECT
*src_rect
,
680 struct wined3d_surface
*dst_surface
, DWORD dst_location
, const RECT
*dst_rect
)
682 struct wined3d_texture
*src_texture
= src_surface
->container
;
683 struct wined3d_texture
*dst_texture
= dst_surface
->container
;
684 struct wined3d_device
*device
= src_texture
->resource
.device
;
685 unsigned int dst_sub_resource_idx
;
687 if (!fbo_blit_supported(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_DEPTH_BLIT
,
688 src_rect
, src_texture
->resource
.usage
, src_texture
->resource
.pool
, src_texture
->resource
.format
,
689 dst_rect
, dst_texture
->resource
.usage
, dst_texture
->resource
.pool
, dst_texture
->resource
.format
))
690 return WINED3DERR_INVALIDCALL
;
692 surface_depth_blt_fbo(device
, src_surface
, src_location
, src_rect
, dst_surface
, dst_location
, dst_rect
);
694 dst_sub_resource_idx
= surface_get_sub_resource_idx(dst_surface
);
695 wined3d_texture_validate_location(dst_texture
, dst_sub_resource_idx
, dst_location
);
696 wined3d_texture_invalidate_location(dst_texture
, dst_sub_resource_idx
, ~dst_location
);
701 /* This call just downloads data, the caller is responsible for binding the
702 * correct texture. */
703 /* Context activation is done by the caller. */
704 static void surface_download_data(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
,
707 unsigned int sub_resource_idx
= surface_get_sub_resource_idx(surface
);
708 struct wined3d_texture
*texture
= surface
->container
;
709 const struct wined3d_format
*format
= texture
->resource
.format
;
710 struct wined3d_texture_sub_resource
*sub_resource
;
711 unsigned int dst_row_pitch
, dst_slice_pitch
;
712 unsigned int src_row_pitch
, src_slice_pitch
;
713 struct wined3d_bo_address data
;
714 BYTE
*temporary_mem
= NULL
;
717 /* Only support read back of converted P8 surfaces. */
718 if (texture
->flags
& WINED3D_TEXTURE_CONVERTED
&& format
->id
!= WINED3DFMT_P8_UINT
)
720 ERR("Trying to read back converted surface %p with format %s.\n", surface
, debug_d3dformat(format
->id
));
724 sub_resource
= &texture
->sub_resources
[sub_resource_idx
];
726 if (surface
->texture_target
== GL_TEXTURE_2D_ARRAY
)
728 /* NP2 emulation is not allowed on array textures. */
729 if (texture
->flags
& WINED3D_TEXTURE_COND_NP2_EMULATED
)
730 ERR("Array texture %p uses NP2 emulation.\n", texture
);
732 WARN_(d3d_perf
)("Downloading all miplevel layers to get the surface data for a single sub-resource.\n");
734 if (!(temporary_mem
= wined3d_calloc(texture
->layer_count
, sub_resource
->size
)))
736 ERR("Out of memory.\n");
741 wined3d_texture_get_memory(texture
, sub_resource_idx
, &data
, dst_location
);
743 if (texture
->flags
& WINED3D_TEXTURE_COND_NP2_EMULATED
)
745 wined3d_texture_get_pitch(texture
, surface
->texture_level
, &dst_row_pitch
, &dst_slice_pitch
);
746 wined3d_format_calculate_pitch(format
, texture
->resource
.device
->surface_alignment
,
747 wined3d_texture_get_level_pow2_width(texture
, surface
->texture_level
),
748 wined3d_texture_get_level_pow2_height(texture
, surface
->texture_level
),
749 &src_row_pitch
, &src_slice_pitch
);
750 if (!(temporary_mem
= HeapAlloc(GetProcessHeap(), 0, src_slice_pitch
)))
752 ERR("Out of memory.\n");
756 if (data
.buffer_object
)
757 ERR("NP2 emulated texture uses PBO unexpectedly.\n");
758 if (texture
->resource
.format_flags
& WINED3DFMT_FLAG_COMPRESSED
)
759 ERR("Unexpected compressed format for NP2 emulated texture.\n");
766 else if (data
.buffer_object
)
768 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, data
.buffer_object
));
769 checkGLcall("glBindBuffer");
777 if (texture
->resource
.format_flags
& WINED3DFMT_FLAG_COMPRESSED
)
779 TRACE("Downloading compressed surface %p, level %u, format %#x, type %#x, data %p.\n",
780 surface
, surface
->texture_level
, format
->glFormat
, format
->glType
, mem
);
782 GL_EXTCALL(glGetCompressedTexImage(surface
->texture_target
, surface
->texture_level
, mem
));
783 checkGLcall("glGetCompressedTexImage");
787 TRACE("Downloading surface %p, level %u, format %#x, type %#x, data %p.\n",
788 surface
, surface
->texture_level
, format
->glFormat
, format
->glType
, mem
);
790 gl_info
->gl_ops
.gl
.p_glGetTexImage(surface
->texture_target
, surface
->texture_level
,
791 format
->glFormat
, format
->glType
, mem
);
792 checkGLcall("glGetTexImage");
795 if (texture
->flags
& WINED3D_TEXTURE_COND_NP2_EMULATED
)
797 const BYTE
*src_data
;
801 * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing
802 * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
803 * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width.
805 * We're doing this...
807 * instead of boxing the texture :
808 * |<-texture width ->| -->pow2width| /\
809 * |111111111111111111| | |
810 * |222 Texture 222222| boxed empty | texture height
811 * |3333 Data 33333333| | |
812 * |444444444444444444| | \/
813 * ----------------------------------- |
814 * | boxed empty | boxed empty | pow2height
816 * -----------------------------------
819 * we're repacking the data to the expected texture width
821 * |<-texture width ->| -->pow2width| /\
822 * |111111111111111111222222222222222| |
823 * |222333333333333333333444444444444| texture height
827 * | empty | pow2height
829 * -----------------------------------
833 * |<-texture width ->| /\
834 * |111111111111111111|
835 * |222222222222222222|texture height
836 * |333333333333333333|
837 * |444444444444444444| \/
838 * --------------------
840 * This also means that any references to surface memory should work with the data as if it were a
841 * standard texture with a non-power2 width instead of a texture boxed up to be a power2 texture.
843 * internally the texture is still stored in a boxed format so any references to textureName will
844 * get a boxed texture with width pow2width and not a texture of width resource.width. */
846 dst_data
= data
.addr
;
847 TRACE("Repacking the surface data from pitch %u to pitch %u.\n", src_row_pitch
, dst_row_pitch
);
848 h
= wined3d_texture_get_level_height(texture
, surface
->texture_level
);
849 for (y
= 0; y
< h
; ++y
)
851 memcpy(dst_data
, src_data
, dst_row_pitch
);
852 src_data
+= src_row_pitch
;
853 dst_data
+= dst_row_pitch
;
856 else if (temporary_mem
)
858 void *src_data
= temporary_mem
+ surface
->texture_layer
* sub_resource
->size
;
859 if (data
.buffer_object
)
861 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, data
.buffer_object
));
862 checkGLcall("glBindBuffer");
863 GL_EXTCALL(glBufferSubData(GL_PIXEL_PACK_BUFFER
, 0, sub_resource
->size
, src_data
));
864 checkGLcall("glBufferSubData");
868 memcpy(data
.addr
, src_data
, sub_resource
->size
);
872 if (data
.buffer_object
)
874 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, 0));
875 checkGLcall("glBindBuffer");
878 HeapFree(GetProcessHeap(), 0, temporary_mem
);
881 /* This call just uploads data, the caller is responsible for binding the
882 * correct texture. */
883 /* Context activation is done by the caller. */
884 void wined3d_surface_upload_data(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
,
885 const struct wined3d_format
*format
, const RECT
*src_rect
, UINT src_pitch
, const POINT
*dst_point
,
886 BOOL srgb
, const struct wined3d_const_bo_address
*data
)
888 unsigned int sub_resource_idx
= surface_get_sub_resource_idx(surface
);
889 struct wined3d_texture
*texture
= surface
->container
;
890 UINT update_w
= src_rect
->right
- src_rect
->left
;
891 UINT update_h
= src_rect
->bottom
- src_rect
->top
;
893 TRACE("surface %p, gl_info %p, format %s, src_rect %s, src_pitch %u, dst_point %s, srgb %#x, data {%#x:%p}.\n",
894 surface
, gl_info
, debug_d3dformat(format
->id
), wine_dbgstr_rect(src_rect
), src_pitch
,
895 wine_dbgstr_point(dst_point
), srgb
, data
->buffer_object
, data
->addr
);
897 if (texture
->sub_resources
[sub_resource_idx
].map_count
)
899 WARN("Uploading a surface that is currently mapped, setting WINED3D_TEXTURE_PIN_SYSMEM.\n");
900 texture
->flags
|= WINED3D_TEXTURE_PIN_SYSMEM
;
903 if (format
->flags
[WINED3D_GL_RES_TYPE_TEX_2D
] & WINED3DFMT_FLAG_HEIGHT_SCALE
)
905 update_h
*= format
->height_scale
.numerator
;
906 update_h
/= format
->height_scale
.denominator
;
909 if (data
->buffer_object
)
911 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER
, data
->buffer_object
));
912 checkGLcall("glBindBuffer");
915 if (format
->flags
[WINED3D_GL_RES_TYPE_TEX_2D
] & WINED3DFMT_FLAG_COMPRESSED
)
917 unsigned int dst_row_pitch
, dst_slice_pitch
;
918 const BYTE
*addr
= data
->addr
;
921 addr
+= (src_rect
->top
/ format
->block_height
) * src_pitch
;
922 addr
+= (src_rect
->left
/ format
->block_width
) * format
->block_byte_count
;
925 internal
= format
->glGammaInternal
;
926 else if (texture
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
927 && wined3d_resource_is_offscreen(&texture
->resource
))
928 internal
= format
->rtInternal
;
930 internal
= format
->glInternal
;
932 wined3d_format_calculate_pitch(format
, 1, update_w
, update_h
, &dst_row_pitch
, &dst_slice_pitch
);
934 TRACE("Uploading compressed data, target %#x, level %u, layer %u, x %d, y %d, w %u, h %u, "
935 "format %#x, image_size %#x, addr %p.\n",
936 surface
->texture_target
, surface
->texture_level
, surface
->texture_layer
,
937 dst_point
->x
, dst_point
->y
, update_w
, update_h
, internal
, dst_slice_pitch
, addr
);
939 if (dst_row_pitch
== src_pitch
)
941 if (surface
->texture_target
== GL_TEXTURE_2D_ARRAY
)
943 GL_EXTCALL(glCompressedTexSubImage3D(surface
->texture_target
, surface
->texture_level
,
944 dst_point
->x
, dst_point
->y
, surface
->texture_layer
, update_w
, update_h
, 1,
945 internal
, dst_slice_pitch
, addr
));
949 GL_EXTCALL(glCompressedTexSubImage2D(surface
->texture_target
, surface
->texture_level
,
950 dst_point
->x
, dst_point
->y
, update_w
, update_h
,
951 internal
, dst_slice_pitch
, addr
));
956 UINT row_count
= (update_h
+ format
->block_height
- 1) / format
->block_height
;
959 /* glCompressedTexSubImage2D() ignores pixel store state, so we
960 * can't use the unpack row length like for glTexSubImage2D. */
961 for (row
= 0, y
= dst_point
->y
; row
< row_count
; ++row
)
963 if (surface
->texture_target
== GL_TEXTURE_2D_ARRAY
)
965 GL_EXTCALL(glCompressedTexSubImage3D(surface
->texture_target
, surface
->texture_level
,
966 dst_point
->x
, y
, surface
->texture_layer
, update_w
, format
->block_height
, 1,
967 internal
, dst_row_pitch
, addr
));
971 GL_EXTCALL(glCompressedTexSubImage2D(surface
->texture_target
, surface
->texture_level
,
972 dst_point
->x
, y
, update_w
, format
->block_height
, internal
, dst_row_pitch
, addr
));
975 y
+= format
->block_height
;
979 checkGLcall("Upload compressed surface data");
983 const BYTE
*addr
= data
->addr
;
985 addr
+= src_rect
->top
* src_pitch
;
986 addr
+= src_rect
->left
* format
->byte_count
;
988 TRACE("Uploading data, target %#x, level %u, layer %u, x %d, y %d, w %u, h %u, "
989 "format %#x, type %#x, addr %p.\n",
990 surface
->texture_target
, surface
->texture_level
, surface
->texture_layer
,
991 dst_point
->x
, dst_point
->y
, update_w
, update_h
, format
->glFormat
, format
->glType
, addr
);
993 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_UNPACK_ROW_LENGTH
, src_pitch
/ format
->byte_count
);
994 if (surface
->texture_target
== GL_TEXTURE_2D_ARRAY
)
996 GL_EXTCALL(glTexSubImage3D(surface
->texture_target
, surface
->texture_level
,
997 dst_point
->x
, dst_point
->y
, surface
->texture_layer
, update_w
, update_h
, 1,
998 format
->glFormat
, format
->glType
, addr
));
1002 gl_info
->gl_ops
.gl
.p_glTexSubImage2D(surface
->texture_target
, surface
->texture_level
,
1003 dst_point
->x
, dst_point
->y
, update_w
, update_h
, format
->glFormat
, format
->glType
, addr
);
1005 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_UNPACK_ROW_LENGTH
, 0);
1006 checkGLcall("Upload surface data");
1009 if (data
->buffer_object
)
1011 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER
, 0));
1012 checkGLcall("glBindBuffer");
1015 if (wined3d_settings
.strict_draw_ordering
)
1016 gl_info
->gl_ops
.gl
.p_glFlush();
1018 if (gl_info
->quirks
& WINED3D_QUIRK_FBO_TEX_UPDATE
)
1020 struct wined3d_device
*device
= texture
->resource
.device
;
1023 for (i
= 0; i
< device
->context_count
; ++i
)
1025 context_surface_update(device
->contexts
[i
], surface
);
1030 static BOOL
surface_check_block_align_rect(struct wined3d_surface
*surface
, const RECT
*rect
)
1032 struct wined3d_box box
= {rect
->left
, rect
->top
, rect
->right
, rect
->bottom
, 0, 1};
1034 return wined3d_texture_check_block_align(surface
->container
, surface
->texture_level
, &box
);
1037 HRESULT
surface_upload_from_surface(struct wined3d_surface
*dst_surface
, const POINT
*dst_point
,
1038 struct wined3d_surface
*src_surface
, const RECT
*src_rect
)
1040 unsigned int src_sub_resource_idx
= surface_get_sub_resource_idx(src_surface
);
1041 unsigned int dst_sub_resource_idx
= surface_get_sub_resource_idx(dst_surface
);
1042 struct wined3d_texture
*src_texture
= src_surface
->container
;
1043 struct wined3d_texture
*dst_texture
= dst_surface
->container
;
1044 unsigned int src_row_pitch
, src_slice_pitch
;
1045 const struct wined3d_format
*src_format
;
1046 const struct wined3d_format
*dst_format
;
1047 unsigned int src_fmt_flags
, dst_fmt_flags
;
1048 const struct wined3d_gl_info
*gl_info
;
1049 struct wined3d_context
*context
;
1050 struct wined3d_bo_address data
;
1051 UINT update_w
, update_h
;
1056 TRACE("dst_surface %p, dst_point %s, src_surface %p, src_rect %s.\n",
1057 dst_surface
, wine_dbgstr_point(dst_point
),
1058 src_surface
, wine_dbgstr_rect(src_rect
));
1060 src_format
= src_texture
->resource
.format
;
1061 dst_format
= dst_texture
->resource
.format
;
1062 src_fmt_flags
= src_texture
->resource
.format_flags
;
1063 dst_fmt_flags
= dst_texture
->resource
.format_flags
;
1065 if (src_format
->id
!= dst_format
->id
)
1067 WARN("Source and destination surfaces should have the same format.\n");
1068 return WINED3DERR_INVALIDCALL
;
1077 else if (dst_point
->x
< 0 || dst_point
->y
< 0)
1079 WARN("Invalid destination point.\n");
1080 return WINED3DERR_INVALIDCALL
;
1085 SetRect(&r
, 0, 0, wined3d_texture_get_level_width(src_texture
, src_surface
->texture_level
),
1086 wined3d_texture_get_level_height(src_texture
, src_surface
->texture_level
));
1089 else if (src_rect
->left
< 0 || src_rect
->top
< 0 || IsRectEmpty(src_rect
))
1091 WARN("Invalid source rectangle.\n");
1092 return WINED3DERR_INVALIDCALL
;
1095 dst_w
= wined3d_texture_get_level_width(dst_texture
, dst_surface
->texture_level
);
1096 dst_h
= wined3d_texture_get_level_height(dst_texture
, dst_surface
->texture_level
);
1098 update_w
= src_rect
->right
- src_rect
->left
;
1099 update_h
= src_rect
->bottom
- src_rect
->top
;
1101 if (update_w
> dst_w
|| dst_point
->x
> dst_w
- update_w
1102 || update_h
> dst_h
|| dst_point
->y
> dst_h
- update_h
)
1104 WARN("Destination out of bounds.\n");
1105 return WINED3DERR_INVALIDCALL
;
1108 if ((src_fmt_flags
& WINED3DFMT_FLAG_BLOCKS
) && !surface_check_block_align_rect(src_surface
, src_rect
))
1110 WARN("Source rectangle not block-aligned.\n");
1111 return WINED3DERR_INVALIDCALL
;
1114 SetRect(&dst_rect
, dst_point
->x
, dst_point
->y
, dst_point
->x
+ update_w
, dst_point
->y
+ update_h
);
1115 if ((dst_fmt_flags
& WINED3DFMT_FLAG_BLOCKS
) && !surface_check_block_align_rect(dst_surface
, &dst_rect
))
1117 WARN("Destination rectangle not block-aligned.\n");
1118 return WINED3DERR_INVALIDCALL
;
1121 /* Use wined3d_surface_blt() instead of uploading directly if we need conversion. */
1122 if (dst_format
->convert
|| wined3d_format_get_color_key_conversion(dst_texture
, FALSE
))
1123 return wined3d_surface_blt(dst_surface
, &dst_rect
, src_surface
, src_rect
, 0, NULL
, WINED3D_TEXF_POINT
);
1125 context
= context_acquire(dst_texture
->resource
.device
, NULL
, 0);
1126 gl_info
= context
->gl_info
;
1128 /* Only load the surface for partial updates. For newly allocated texture
1129 * the texture wouldn't be the current location, and we'd upload zeroes
1130 * just to overwrite them again. */
1131 if (update_w
== dst_w
&& update_h
== dst_h
)
1132 wined3d_texture_prepare_texture(dst_texture
, context
, FALSE
);
1134 wined3d_texture_load_location(dst_texture
, dst_sub_resource_idx
, context
, WINED3D_LOCATION_TEXTURE_RGB
);
1135 wined3d_texture_bind_and_dirtify(dst_texture
, context
, FALSE
);
1137 wined3d_texture_get_memory(src_texture
, src_sub_resource_idx
, &data
,
1138 src_texture
->sub_resources
[src_sub_resource_idx
].locations
);
1139 wined3d_texture_get_pitch(src_texture
, src_surface
->texture_level
, &src_row_pitch
, &src_slice_pitch
);
1141 wined3d_surface_upload_data(dst_surface
, gl_info
, src_format
, src_rect
,
1142 src_row_pitch
, dst_point
, FALSE
, wined3d_const_bo_address(&data
));
1144 context_release(context
);
1146 wined3d_texture_validate_location(dst_texture
, dst_sub_resource_idx
, WINED3D_LOCATION_TEXTURE_RGB
);
1147 wined3d_texture_invalidate_location(dst_texture
, dst_sub_resource_idx
, ~WINED3D_LOCATION_TEXTURE_RGB
);
1152 /* In D3D the depth stencil dimensions have to be greater than or equal to the
1153 * render target dimensions. With FBOs, the dimensions have to be an exact match. */
1154 /* TODO: We should synchronize the renderbuffer's content with the texture's content. */
1155 /* Context activation is done by the caller. */
1156 void surface_set_compatible_renderbuffer(struct wined3d_surface
*surface
, const struct wined3d_surface
*rt
)
1158 const struct wined3d_gl_info
*gl_info
= &surface
->container
->resource
.device
->adapter
->gl_info
;
1159 struct wined3d_renderbuffer_entry
*entry
;
1160 GLuint renderbuffer
= 0;
1161 unsigned int src_width
, src_height
;
1162 unsigned int width
, height
;
1164 if (rt
&& rt
->container
->resource
.format
->id
!= WINED3DFMT_NULL
)
1166 width
= wined3d_texture_get_level_pow2_width(rt
->container
, rt
->texture_level
);
1167 height
= wined3d_texture_get_level_pow2_height(rt
->container
, rt
->texture_level
);
1171 width
= wined3d_texture_get_level_pow2_width(surface
->container
, surface
->texture_level
);
1172 height
= wined3d_texture_get_level_pow2_height(surface
->container
, surface
->texture_level
);
1175 src_width
= wined3d_texture_get_level_pow2_width(surface
->container
, surface
->texture_level
);
1176 src_height
= wined3d_texture_get_level_pow2_height(surface
->container
, surface
->texture_level
);
1178 /* A depth stencil smaller than the render target is not valid */
1179 if (width
> src_width
|| height
> src_height
) return;
1181 /* Remove any renderbuffer set if the sizes match */
1182 if (gl_info
->supported
[ARB_FRAMEBUFFER_OBJECT
]
1183 || (width
== src_width
&& height
== src_height
))
1185 surface
->current_renderbuffer
= NULL
;
1189 /* Look if we've already got a renderbuffer of the correct dimensions */
1190 LIST_FOR_EACH_ENTRY(entry
, &surface
->renderbuffers
, struct wined3d_renderbuffer_entry
, entry
)
1192 if (entry
->width
== width
&& entry
->height
== height
)
1194 renderbuffer
= entry
->id
;
1195 surface
->current_renderbuffer
= entry
;
1202 gl_info
->fbo_ops
.glGenRenderbuffers(1, &renderbuffer
);
1203 gl_info
->fbo_ops
.glBindRenderbuffer(GL_RENDERBUFFER
, renderbuffer
);
1204 gl_info
->fbo_ops
.glRenderbufferStorage(GL_RENDERBUFFER
,
1205 surface
->container
->resource
.format
->glInternal
, width
, height
);
1207 entry
= HeapAlloc(GetProcessHeap(), 0, sizeof(*entry
));
1208 entry
->width
= width
;
1209 entry
->height
= height
;
1210 entry
->id
= renderbuffer
;
1211 list_add_head(&surface
->renderbuffers
, &entry
->entry
);
1213 surface
->current_renderbuffer
= entry
;
1216 checkGLcall("set_compatible_renderbuffer");
1219 /* See also float_16_to_32() in wined3d_private.h */
1220 static inline unsigned short float_32_to_16(const float *in
)
1223 float tmp
= fabsf(*in
);
1224 unsigned int mantissa
;
1227 /* Deal with special numbers */
1233 return (*in
< 0.0f
? 0xfc00 : 0x7c00);
1235 if (tmp
< (float)(1u << 10))
1241 } while (tmp
< (float)(1u << 10));
1243 else if (tmp
>= (float)(1u << 11))
1249 } while (tmp
>= (float)(1u << 11));
1252 mantissa
= (unsigned int)tmp
;
1253 if (tmp
- mantissa
>= 0.5f
)
1254 ++mantissa
; /* Round to nearest, away from zero. */
1256 exp
+= 10; /* Normalize the mantissa. */
1257 exp
+= 15; /* Exponent is encoded with excess 15. */
1259 if (exp
> 30) /* too big */
1261 ret
= 0x7c00; /* INF */
1265 /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers. */
1268 mantissa
= mantissa
>> 1;
1271 ret
= mantissa
& 0x3ff;
1275 ret
= (exp
<< 10) | (mantissa
& 0x3ff);
1278 ret
|= ((*in
< 0.0f
? 1 : 0) << 15); /* Add the sign */
1282 static void convert_r32_float_r16_float(const BYTE
*src
, BYTE
*dst
,
1283 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
1285 unsigned short *dst_s
;
1289 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
1291 for (y
= 0; y
< h
; ++y
)
1293 src_f
= (const float *)(src
+ y
* pitch_in
);
1294 dst_s
= (unsigned short *) (dst
+ y
* pitch_out
);
1295 for (x
= 0; x
< w
; ++x
)
1297 dst_s
[x
] = float_32_to_16(src_f
+ x
);
1302 static void convert_r5g6b5_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
1303 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
1305 static const unsigned char convert_5to8
[] =
1307 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
1308 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
1309 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
1310 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
1312 static const unsigned char convert_6to8
[] =
1314 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
1315 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
1316 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
1317 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
1318 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
1319 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
1320 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
1321 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
1325 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
1327 for (y
= 0; y
< h
; ++y
)
1329 const WORD
*src_line
= (const WORD
*)(src
+ y
* pitch_in
);
1330 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
1331 for (x
= 0; x
< w
; ++x
)
1333 WORD pixel
= src_line
[x
];
1334 dst_line
[x
] = 0xff000000u
1335 | convert_5to8
[(pixel
& 0xf800u
) >> 11] << 16
1336 | convert_6to8
[(pixel
& 0x07e0u
) >> 5] << 8
1337 | convert_5to8
[(pixel
& 0x001fu
)];
1342 /* We use this for both B8G8R8A8 -> B8G8R8X8 and B8G8R8X8 -> B8G8R8A8, since
1343 * in both cases we're just setting the X / Alpha channel to 0xff. */
1344 static void convert_a8r8g8b8_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
1345 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
1349 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
1351 for (y
= 0; y
< h
; ++y
)
1353 const DWORD
*src_line
= (const DWORD
*)(src
+ y
* pitch_in
);
1354 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
1356 for (x
= 0; x
< w
; ++x
)
1358 dst_line
[x
] = 0xff000000 | (src_line
[x
] & 0xffffff);
1363 static inline BYTE
cliptobyte(int x
)
1365 return (BYTE
)((x
< 0) ? 0 : ((x
> 255) ? 255 : x
));
1368 static void convert_yuy2_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
1369 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
1371 int c2
, d
, e
, r2
= 0, g2
= 0, b2
= 0;
1374 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
1376 for (y
= 0; y
< h
; ++y
)
1378 const BYTE
*src_line
= src
+ y
* pitch_in
;
1379 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
1380 for (x
= 0; x
< w
; ++x
)
1382 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
1383 * C = Y - 16; D = U - 128; E = V - 128;
1384 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
1385 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
1386 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
1387 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
1388 * U and V are shared between the pixels. */
1389 if (!(x
& 1)) /* For every even pixel, read new U and V. */
1391 d
= (int) src_line
[1] - 128;
1392 e
= (int) src_line
[3] - 128;
1394 g2
= - 100 * d
- 208 * e
+ 128;
1397 c2
= 298 * ((int) src_line
[0] - 16);
1398 dst_line
[x
] = 0xff000000
1399 | cliptobyte((c2
+ r2
) >> 8) << 16 /* red */
1400 | cliptobyte((c2
+ g2
) >> 8) << 8 /* green */
1401 | cliptobyte((c2
+ b2
) >> 8); /* blue */
1402 /* Scale RGB values to 0..255 range,
1403 * then clip them if still not in range (may be negative),
1404 * then shift them within DWORD if necessary. */
1410 static void convert_yuy2_r5g6b5(const BYTE
*src
, BYTE
*dst
,
1411 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
1414 int c2
, d
, e
, r2
= 0, g2
= 0, b2
= 0;
1416 TRACE("Converting %ux%u pixels, pitches %u %u\n", w
, h
, pitch_in
, pitch_out
);
1418 for (y
= 0; y
< h
; ++y
)
1420 const BYTE
*src_line
= src
+ y
* pitch_in
;
1421 WORD
*dst_line
= (WORD
*)(dst
+ y
* pitch_out
);
1422 for (x
= 0; x
< w
; ++x
)
1424 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
1425 * C = Y - 16; D = U - 128; E = V - 128;
1426 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
1427 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
1428 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
1429 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
1430 * U and V are shared between the pixels. */
1431 if (!(x
& 1)) /* For every even pixel, read new U and V. */
1433 d
= (int) src_line
[1] - 128;
1434 e
= (int) src_line
[3] - 128;
1436 g2
= - 100 * d
- 208 * e
+ 128;
1439 c2
= 298 * ((int) src_line
[0] - 16);
1440 dst_line
[x
] = (cliptobyte((c2
+ r2
) >> 8) >> 3) << 11 /* red */
1441 | (cliptobyte((c2
+ g2
) >> 8) >> 2) << 5 /* green */
1442 | (cliptobyte((c2
+ b2
) >> 8) >> 3); /* blue */
1443 /* Scale RGB values to 0..255 range,
1444 * then clip them if still not in range (may be negative),
1445 * then shift them within DWORD if necessary. */
1451 struct d3dfmt_converter_desc
1453 enum wined3d_format_id from
, to
;
1454 void (*convert
)(const BYTE
*src
, BYTE
*dst
, DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
);
1457 static const struct d3dfmt_converter_desc converters
[] =
1459 {WINED3DFMT_R32_FLOAT
, WINED3DFMT_R16_FLOAT
, convert_r32_float_r16_float
},
1460 {WINED3DFMT_B5G6R5_UNORM
, WINED3DFMT_B8G8R8X8_UNORM
, convert_r5g6b5_x8r8g8b8
},
1461 {WINED3DFMT_B8G8R8A8_UNORM
, WINED3DFMT_B8G8R8X8_UNORM
, convert_a8r8g8b8_x8r8g8b8
},
1462 {WINED3DFMT_B8G8R8X8_UNORM
, WINED3DFMT_B8G8R8A8_UNORM
, convert_a8r8g8b8_x8r8g8b8
},
1463 {WINED3DFMT_YUY2
, WINED3DFMT_B8G8R8X8_UNORM
, convert_yuy2_x8r8g8b8
},
1464 {WINED3DFMT_YUY2
, WINED3DFMT_B5G6R5_UNORM
, convert_yuy2_r5g6b5
},
1467 static inline const struct d3dfmt_converter_desc
*find_converter(enum wined3d_format_id from
,
1468 enum wined3d_format_id to
)
1472 for (i
= 0; i
< (sizeof(converters
) / sizeof(*converters
)); ++i
)
1474 if (converters
[i
].from
== from
&& converters
[i
].to
== to
)
1475 return &converters
[i
];
1481 static struct wined3d_texture
*surface_convert_format(struct wined3d_texture
*src_texture
,
1482 unsigned int sub_resource_idx
, const struct wined3d_format
*dst_format
)
1484 unsigned int texture_level
= sub_resource_idx
% src_texture
->level_count
;
1485 const struct wined3d_format
*src_format
= src_texture
->resource
.format
;
1486 struct wined3d_device
*device
= src_texture
->resource
.device
;
1487 const struct d3dfmt_converter_desc
*conv
= NULL
;
1488 struct wined3d_texture
*dst_texture
;
1489 struct wined3d_resource_desc desc
;
1490 struct wined3d_map_desc src_map
;
1492 if (!(conv
= find_converter(src_format
->id
, dst_format
->id
)) && (!device
->d3d_initialized
1493 || !is_identity_fixup(src_format
->color_fixup
) || src_format
->convert
1494 || !is_identity_fixup(dst_format
->color_fixup
) || dst_format
->convert
1495 || (src_format
->flags
[WINED3D_GL_RES_TYPE_TEX_2D
] & WINED3DFMT_FLAG_COMPRESSED
)))
1497 FIXME("Cannot find a conversion function from format %s to %s.\n",
1498 debug_d3dformat(src_format
->id
), debug_d3dformat(dst_format
->id
));
1502 /* FIXME: Multisampled conversion? */
1503 desc
.resource_type
= WINED3D_RTYPE_TEXTURE_2D
;
1504 desc
.format
= dst_format
->id
;
1505 desc
.multisample_type
= WINED3D_MULTISAMPLE_NONE
;
1506 desc
.multisample_quality
= 0;
1508 desc
.pool
= WINED3D_POOL_SCRATCH
;
1509 desc
.width
= wined3d_texture_get_level_width(src_texture
, texture_level
);
1510 desc
.height
= wined3d_texture_get_level_height(src_texture
, texture_level
);
1513 if (FAILED(wined3d_texture_create(device
, &desc
, 1, 1,
1514 WINED3D_TEXTURE_CREATE_MAPPABLE
| WINED3D_TEXTURE_CREATE_DISCARD
,
1515 NULL
, NULL
, &wined3d_null_parent_ops
, &dst_texture
)))
1517 ERR("Failed to create a destination texture for conversion.\n");
1521 memset(&src_map
, 0, sizeof(src_map
));
1522 if (FAILED(wined3d_resource_map(&src_texture
->resource
, sub_resource_idx
,
1523 &src_map
, NULL
, WINED3D_MAP_READONLY
)))
1525 ERR("Failed to map the source texture.\n");
1526 wined3d_texture_decref(dst_texture
);
1531 struct wined3d_map_desc dst_map
;
1533 memset(&dst_map
, 0, sizeof(dst_map
));
1534 if (FAILED(wined3d_resource_map(&dst_texture
->resource
, 0, &dst_map
, NULL
, 0)))
1536 ERR("Failed to map the destination texture.\n");
1537 wined3d_resource_unmap(&src_texture
->resource
, sub_resource_idx
);
1538 wined3d_texture_decref(dst_texture
);
1542 conv
->convert(src_map
.data
, dst_map
.data
, src_map
.row_pitch
, dst_map
.row_pitch
, desc
.width
, desc
.height
);
1544 wined3d_resource_unmap(&dst_texture
->resource
, 0);
1548 struct wined3d_bo_address data
= {0, src_map
.data
};
1549 RECT src_rect
= {0, 0, desc
.width
, desc
.height
};
1550 const struct wined3d_gl_info
*gl_info
;
1551 struct wined3d_context
*context
;
1552 POINT dst_point
= {0, 0};
1554 TRACE("Using upload conversion.\n");
1555 context
= context_acquire(device
, NULL
, 0);
1556 gl_info
= context
->gl_info
;
1558 wined3d_texture_prepare_texture(dst_texture
, context
, FALSE
);
1559 wined3d_texture_bind_and_dirtify(dst_texture
, context
, FALSE
);
1560 wined3d_surface_upload_data(dst_texture
->sub_resources
[0].u
.surface
, gl_info
, src_format
,
1561 &src_rect
, src_map
.row_pitch
, &dst_point
, FALSE
, wined3d_const_bo_address(&data
));
1563 context_release(context
);
1565 wined3d_texture_validate_location(dst_texture
, 0, WINED3D_LOCATION_TEXTURE_RGB
);
1566 wined3d_texture_invalidate_location(dst_texture
, 0, ~WINED3D_LOCATION_TEXTURE_RGB
);
1568 wined3d_resource_unmap(&src_texture
->resource
, sub_resource_idx
);
1573 static HRESULT
_Blt_ColorFill(BYTE
*buf
, unsigned int width
, unsigned int height
,
1574 unsigned int bpp
, UINT pitch
, DWORD color
)
1581 #define COLORFILL_ROW(type) \
1583 type *d = (type *)buf; \
1584 for (x = 0; x < width; ++x) \
1585 d[x] = (type)color; \
1591 COLORFILL_ROW(BYTE
);
1595 COLORFILL_ROW(WORD
);
1601 for (x
= 0; x
< width
; ++x
, d
+= 3)
1603 d
[0] = (color
) & 0xff;
1604 d
[1] = (color
>> 8) & 0xff;
1605 d
[2] = (color
>> 16) & 0xff;
1610 COLORFILL_ROW(DWORD
);
1614 FIXME("Color fill not implemented for bpp %u!\n", bpp
* 8);
1615 return WINED3DERR_NOTAVAILABLE
;
1618 #undef COLORFILL_ROW
1620 /* Now copy first row. */
1622 for (y
= 1; y
< height
; ++y
)
1625 memcpy(buf
, first
, width
* bpp
);
1631 static void read_from_framebuffer(struct wined3d_surface
*surface
,
1632 struct wined3d_context
*old_ctx
, DWORD dst_location
)
1634 unsigned int sub_resource_idx
= surface_get_sub_resource_idx(surface
);
1635 struct wined3d_texture
*texture
= surface
->container
;
1636 struct wined3d_device
*device
= texture
->resource
.device
;
1637 const struct wined3d_gl_info
*gl_info
;
1638 struct wined3d_context
*context
= old_ctx
;
1639 struct wined3d_surface
*restore_rt
= NULL
;
1640 unsigned int row_pitch
, slice_pitch
;
1641 unsigned int width
, height
;
1643 BYTE
*row
, *top
, *bottom
;
1645 BOOL srcIsUpsideDown
;
1646 struct wined3d_bo_address data
;
1648 wined3d_texture_get_memory(texture
, sub_resource_idx
, &data
, dst_location
);
1650 restore_rt
= context_get_rt_surface(old_ctx
);
1651 if (restore_rt
!= surface
)
1652 context
= context_acquire(device
, texture
, sub_resource_idx
);
1656 context_apply_blit_state(context
, device
);
1657 gl_info
= context
->gl_info
;
1659 /* Select the correct read buffer, and give some debug output.
1660 * There is no need to keep track of the current read buffer or reset it, every part of the code
1661 * that reads sets the read buffer as desired.
1663 if (wined3d_resource_is_offscreen(&texture
->resource
))
1665 /* Mapping the primary render target which is not on a swapchain.
1666 * Read from the back buffer. */
1667 TRACE("Mapping offscreen render target.\n");
1668 gl_info
->gl_ops
.gl
.p_glReadBuffer(context_get_offscreen_gl_buffer(context
));
1669 srcIsUpsideDown
= TRUE
;
1673 /* Onscreen surfaces are always part of a swapchain */
1674 GLenum buffer
= wined3d_texture_get_gl_buffer(texture
);
1675 TRACE("Mapping %#x buffer.\n", buffer
);
1676 gl_info
->gl_ops
.gl
.p_glReadBuffer(buffer
);
1677 checkGLcall("glReadBuffer");
1678 srcIsUpsideDown
= FALSE
;
1681 if (data
.buffer_object
)
1683 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, data
.buffer_object
));
1684 checkGLcall("glBindBuffer");
1687 wined3d_texture_get_pitch(texture
, surface
->texture_level
, &row_pitch
, &slice_pitch
);
1689 /* Setup pixel store pack state -- to glReadPixels into the correct place */
1690 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_PACK_ROW_LENGTH
, row_pitch
/ texture
->resource
.format
->byte_count
);
1691 checkGLcall("glPixelStorei");
1693 width
= wined3d_texture_get_level_width(texture
, surface
->texture_level
);
1694 height
= wined3d_texture_get_level_height(texture
, surface
->texture_level
);
1695 gl_info
->gl_ops
.gl
.p_glReadPixels(0, 0, width
, height
,
1696 texture
->resource
.format
->glFormat
,
1697 texture
->resource
.format
->glType
, data
.addr
);
1698 checkGLcall("glReadPixels");
1700 /* Reset previous pixel store pack state */
1701 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_PACK_ROW_LENGTH
, 0);
1702 checkGLcall("glPixelStorei");
1704 if (!srcIsUpsideDown
)
1706 /* glReadPixels returns the image upside down, and there is no way to
1707 * prevent this. Flip the lines in software. */
1709 if (!(row
= HeapAlloc(GetProcessHeap(), 0, row_pitch
)))
1712 if (data
.buffer_object
)
1714 mem
= GL_EXTCALL(glMapBuffer(GL_PIXEL_PACK_BUFFER
, GL_READ_WRITE
));
1715 checkGLcall("glMapBuffer");
1721 bottom
= mem
+ row_pitch
* (height
- 1);
1722 for (i
= 0; i
< height
/ 2; i
++)
1724 memcpy(row
, top
, row_pitch
);
1725 memcpy(top
, bottom
, row_pitch
);
1726 memcpy(bottom
, row
, row_pitch
);
1728 bottom
-= row_pitch
;
1730 HeapFree(GetProcessHeap(), 0, row
);
1732 if (data
.buffer_object
)
1733 GL_EXTCALL(glUnmapBuffer(GL_PIXEL_PACK_BUFFER
));
1737 if (data
.buffer_object
)
1739 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, 0));
1740 checkGLcall("glBindBuffer");
1744 context_restore(context
, restore_rt
);
1747 /* Read the framebuffer contents into a texture. Note that this function
1748 * doesn't do any kind of flipping. Using this on an onscreen surface will
1749 * result in a flipped D3D texture.
1751 * Context activation is done by the caller. This function may temporarily
1752 * switch to a different context and restore the original one before return. */
1753 void surface_load_fb_texture(struct wined3d_surface
*surface
, BOOL srgb
, struct wined3d_context
*old_ctx
)
1755 struct wined3d_texture
*texture
= surface
->container
;
1756 struct wined3d_device
*device
= texture
->resource
.device
;
1757 const struct wined3d_gl_info
*gl_info
;
1758 struct wined3d_context
*context
= old_ctx
;
1759 struct wined3d_surface
*restore_rt
= NULL
;
1761 restore_rt
= context_get_rt_surface(old_ctx
);
1762 if (restore_rt
!= surface
)
1763 context
= context_acquire(device
, texture
, surface_get_sub_resource_idx(surface
));
1767 gl_info
= context
->gl_info
;
1768 device_invalidate_state(device
, STATE_FRAMEBUFFER
);
1770 wined3d_texture_prepare_texture(texture
, context
, srgb
);
1771 wined3d_texture_bind_and_dirtify(texture
, context
, srgb
);
1773 TRACE("Reading back offscreen render target %p.\n", surface
);
1775 if (wined3d_resource_is_offscreen(&texture
->resource
))
1776 gl_info
->gl_ops
.gl
.p_glReadBuffer(context_get_offscreen_gl_buffer(context
));
1778 gl_info
->gl_ops
.gl
.p_glReadBuffer(wined3d_texture_get_gl_buffer(texture
));
1779 checkGLcall("glReadBuffer");
1781 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(surface
->texture_target
, surface
->texture_level
,
1782 0, 0, 0, 0, wined3d_texture_get_level_width(texture
, surface
->texture_level
),
1783 wined3d_texture_get_level_height(texture
, surface
->texture_level
));
1784 checkGLcall("glCopyTexSubImage2D");
1787 context_restore(context
, restore_rt
);
1790 /* Does a direct frame buffer -> texture copy. Stretching is done with single
1791 * pixel copy calls. */
1792 static void fb_copy_to_texture_direct(struct wined3d_surface
*dst_surface
, struct wined3d_surface
*src_surface
,
1793 const RECT
*src_rect
, const RECT
*dst_rect_in
, enum wined3d_texture_filter_type filter
)
1795 unsigned int src_sub_resource_idx
= surface_get_sub_resource_idx(src_surface
);
1796 unsigned int dst_sub_resource_idx
= surface_get_sub_resource_idx(dst_surface
);
1797 struct wined3d_texture
*src_texture
= src_surface
->container
;
1798 struct wined3d_texture
*dst_texture
= dst_surface
->container
;
1799 struct wined3d_device
*device
= dst_texture
->resource
.device
;
1800 const struct wined3d_gl_info
*gl_info
;
1802 struct wined3d_context
*context
;
1803 BOOL upsidedown
= FALSE
;
1804 RECT dst_rect
= *dst_rect_in
;
1805 unsigned int src_height
;
1807 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
1808 * glCopyTexSubImage is a bit picky about the parameters we pass to it
1810 if(dst_rect
.top
> dst_rect
.bottom
) {
1811 UINT tmp
= dst_rect
.bottom
;
1812 dst_rect
.bottom
= dst_rect
.top
;
1817 context
= context_acquire(device
, src_texture
, src_sub_resource_idx
);
1818 gl_info
= context
->gl_info
;
1819 context_apply_blit_state(context
, device
);
1820 wined3d_texture_load(dst_texture
, context
, FALSE
);
1822 /* Bind the target texture */
1823 context_bind_texture(context
, dst_texture
->target
, dst_texture
->texture_rgb
.name
);
1824 if (wined3d_resource_is_offscreen(&src_texture
->resource
))
1826 TRACE("Reading from an offscreen target\n");
1827 upsidedown
= !upsidedown
;
1828 gl_info
->gl_ops
.gl
.p_glReadBuffer(context_get_offscreen_gl_buffer(context
));
1832 gl_info
->gl_ops
.gl
.p_glReadBuffer(wined3d_texture_get_gl_buffer(src_texture
));
1834 checkGLcall("glReadBuffer");
1836 xrel
= (float) (src_rect
->right
- src_rect
->left
) / (float) (dst_rect
.right
- dst_rect
.left
);
1837 yrel
= (float) (src_rect
->bottom
- src_rect
->top
) / (float) (dst_rect
.bottom
- dst_rect
.top
);
1839 if ((xrel
- 1.0f
< -eps
) || (xrel
- 1.0f
> eps
))
1841 FIXME_(d3d_perf
)("Doing a pixel by pixel copy from the framebuffer to a texture.\n");
1843 if (filter
!= WINED3D_TEXF_NONE
&& filter
!= WINED3D_TEXF_POINT
)
1844 ERR("Texture filtering not supported in direct blit.\n");
1846 else if ((filter
!= WINED3D_TEXF_NONE
&& filter
!= WINED3D_TEXF_POINT
)
1847 && ((yrel
- 1.0f
< -eps
) || (yrel
- 1.0f
> eps
)))
1849 ERR("Texture filtering not supported in direct blit\n");
1852 src_height
= wined3d_texture_get_level_height(src_texture
, src_surface
->texture_level
);
1854 && !((xrel
- 1.0f
< -eps
) || (xrel
- 1.0f
> eps
))
1855 && !((yrel
- 1.0f
< -eps
) || (yrel
- 1.0f
> eps
)))
1857 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do. */
1858 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(dst_surface
->texture_target
, dst_surface
->texture_level
,
1859 dst_rect
.left
/*xoffset */, dst_rect
.top
/* y offset */,
1860 src_rect
->left
, src_height
- src_rect
->bottom
,
1861 dst_rect
.right
- dst_rect
.left
, dst_rect
.bottom
- dst_rect
.top
);
1866 UINT yoffset
= src_height
- src_rect
->top
+ dst_rect
.top
- 1;
1867 /* I have to process this row by row to swap the image,
1868 * otherwise it would be upside down, so stretching in y direction
1869 * doesn't cost extra time
1871 * However, stretching in x direction can be avoided if not necessary
1873 for(row
= dst_rect
.top
; row
< dst_rect
.bottom
; row
++) {
1874 if ((xrel
- 1.0f
< -eps
) || (xrel
- 1.0f
> eps
))
1876 /* Well, that stuff works, but it's very slow.
1877 * find a better way instead
1881 for (col
= dst_rect
.left
; col
< dst_rect
.right
; ++col
)
1883 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(dst_surface
->texture_target
, dst_surface
->texture_level
,
1884 dst_rect
.left
+ col
/* x offset */, row
/* y offset */,
1885 src_rect
->left
+ col
* xrel
, yoffset
- (int) (row
* yrel
), 1, 1);
1890 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(dst_surface
->texture_target
, dst_surface
->texture_level
,
1891 dst_rect
.left
/* x offset */, row
/* y offset */,
1892 src_rect
->left
, yoffset
- (int) (row
* yrel
), dst_rect
.right
- dst_rect
.left
, 1);
1896 checkGLcall("glCopyTexSubImage2D");
1898 context_release(context
);
1900 /* The texture is now most up to date - If the surface is a render target
1901 * and has a drawable, this path is never entered. */
1902 wined3d_texture_validate_location(dst_texture
, dst_sub_resource_idx
, WINED3D_LOCATION_TEXTURE_RGB
);
1903 wined3d_texture_invalidate_location(dst_texture
, dst_sub_resource_idx
, ~WINED3D_LOCATION_TEXTURE_RGB
);
1906 /* Uses the hardware to stretch and flip the image */
1907 static void fb_copy_to_texture_hwstretch(struct wined3d_surface
*dst_surface
, struct wined3d_surface
*src_surface
,
1908 const RECT
*src_rect
, const RECT
*dst_rect_in
, enum wined3d_texture_filter_type filter
)
1910 unsigned int src_sub_resource_idx
= surface_get_sub_resource_idx(src_surface
);
1911 unsigned int dst_sub_resource_idx
= surface_get_sub_resource_idx(dst_surface
);
1912 unsigned int src_width
, src_height
, src_pow2_width
, src_pow2_height
;
1913 struct wined3d_texture
*src_texture
= src_surface
->container
;
1914 struct wined3d_texture
*dst_texture
= dst_surface
->container
;
1915 struct wined3d_device
*device
= dst_texture
->resource
.device
;
1916 GLuint src
, backup
= 0;
1917 float left
, right
, top
, bottom
; /* Texture coordinates */
1918 const struct wined3d_gl_info
*gl_info
;
1919 struct wined3d_context
*context
;
1920 GLenum drawBuffer
= GL_BACK
;
1921 GLenum offscreen_buffer
;
1922 GLenum texture_target
;
1923 BOOL noBackBufferBackup
;
1925 BOOL upsidedown
= FALSE
;
1926 RECT dst_rect
= *dst_rect_in
;
1928 TRACE("Using hwstretch blit\n");
1929 /* Activate the Proper context for reading from the source surface, set it up for blitting */
1930 context
= context_acquire(device
, src_texture
, src_sub_resource_idx
);
1931 gl_info
= context
->gl_info
;
1932 context_apply_blit_state(context
, device
);
1933 wined3d_texture_load(dst_texture
, context
, FALSE
);
1935 offscreen_buffer
= context_get_offscreen_gl_buffer(context
);
1936 src_width
= wined3d_texture_get_level_width(src_texture
, src_surface
->texture_level
);
1937 src_height
= wined3d_texture_get_level_height(src_texture
, src_surface
->texture_level
);
1938 src_pow2_width
= wined3d_texture_get_level_pow2_width(src_texture
, src_surface
->texture_level
);
1939 src_pow2_height
= wined3d_texture_get_level_pow2_height(src_texture
, src_surface
->texture_level
);
1941 src_offscreen
= wined3d_resource_is_offscreen(&src_texture
->resource
);
1942 noBackBufferBackup
= src_offscreen
&& wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
;
1943 if (!noBackBufferBackup
&& !src_texture
->texture_rgb
.name
)
1945 /* Get it a description */
1946 wined3d_texture_load(src_texture
, context
, FALSE
);
1949 /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
1950 * This way we don't have to wait for the 2nd readback to finish to leave this function.
1952 if (context
->aux_buffers
>= 2)
1954 /* Got more than one aux buffer? Use the 2nd aux buffer */
1955 drawBuffer
= GL_AUX1
;
1957 else if ((!src_offscreen
|| offscreen_buffer
== GL_BACK
) && context
->aux_buffers
>= 1)
1959 /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
1960 drawBuffer
= GL_AUX0
;
1963 if (noBackBufferBackup
)
1965 gl_info
->gl_ops
.gl
.p_glGenTextures(1, &backup
);
1966 checkGLcall("glGenTextures");
1967 context_bind_texture(context
, GL_TEXTURE_2D
, backup
);
1968 texture_target
= GL_TEXTURE_2D
;
1972 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
1973 * we are reading from the back buffer, the backup can be used as source texture
1975 texture_target
= src_surface
->texture_target
;
1976 context_bind_texture(context
, texture_target
, src_texture
->texture_rgb
.name
);
1977 gl_info
->gl_ops
.gl
.p_glEnable(texture_target
);
1978 checkGLcall("glEnable(texture_target)");
1980 /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
1981 surface_get_sub_resource(src_surface
)->locations
&= ~WINED3D_LOCATION_TEXTURE_RGB
;
1984 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
1985 * glCopyTexSubImage is a bit picky about the parameters we pass to it
1987 if(dst_rect
.top
> dst_rect
.bottom
) {
1988 UINT tmp
= dst_rect
.bottom
;
1989 dst_rect
.bottom
= dst_rect
.top
;
1996 TRACE("Reading from an offscreen target\n");
1997 upsidedown
= !upsidedown
;
1998 gl_info
->gl_ops
.gl
.p_glReadBuffer(offscreen_buffer
);
2002 gl_info
->gl_ops
.gl
.p_glReadBuffer(wined3d_texture_get_gl_buffer(src_texture
));
2005 /* TODO: Only back up the part that will be overwritten */
2006 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(texture_target
, 0, 0, 0, 0, 0, src_width
, src_height
);
2008 checkGLcall("glCopyTexSubImage2D");
2010 /* No issue with overriding these - the sampler is dirty due to blit usage */
2011 gl_info
->gl_ops
.gl
.p_glTexParameteri(texture_target
, GL_TEXTURE_MAG_FILTER
, wined3d_gl_mag_filter(filter
));
2012 checkGLcall("glTexParameteri");
2013 gl_info
->gl_ops
.gl
.p_glTexParameteri(texture_target
, GL_TEXTURE_MIN_FILTER
,
2014 wined3d_gl_min_mip_filter(filter
, WINED3D_TEXF_NONE
));
2015 checkGLcall("glTexParameteri");
2017 if (!src_texture
->swapchain
|| src_texture
== src_texture
->swapchain
->back_buffers
[0])
2019 src
= backup
? backup
: src_texture
->texture_rgb
.name
;
2023 gl_info
->gl_ops
.gl
.p_glReadBuffer(GL_FRONT
);
2024 checkGLcall("glReadBuffer(GL_FRONT)");
2026 gl_info
->gl_ops
.gl
.p_glGenTextures(1, &src
);
2027 checkGLcall("glGenTextures(1, &src)");
2028 context_bind_texture(context
, GL_TEXTURE_2D
, src
);
2030 /* TODO: Only copy the part that will be read. Use src_rect->left,
2031 * src_rect->bottom as origin, but with the width watch out for power
2033 gl_info
->gl_ops
.gl
.p_glTexImage2D(GL_TEXTURE_2D
, 0, GL_RGBA
, src_pow2_width
,
2034 src_pow2_height
, 0, GL_RGBA
, GL_UNSIGNED_BYTE
, NULL
);
2035 checkGLcall("glTexImage2D");
2036 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(GL_TEXTURE_2D
, 0, 0, 0, 0, 0, src_width
, src_height
);
2038 gl_info
->gl_ops
.gl
.p_glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
2039 checkGLcall("glTexParameteri");
2040 gl_info
->gl_ops
.gl
.p_glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
2041 checkGLcall("glTexParameteri");
2043 gl_info
->gl_ops
.gl
.p_glReadBuffer(GL_BACK
);
2044 checkGLcall("glReadBuffer(GL_BACK)");
2046 if (texture_target
!= GL_TEXTURE_2D
)
2048 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
2049 gl_info
->gl_ops
.gl
.p_glEnable(GL_TEXTURE_2D
);
2050 texture_target
= GL_TEXTURE_2D
;
2053 checkGLcall("glEnd and previous");
2055 left
= src_rect
->left
;
2056 right
= src_rect
->right
;
2060 top
= src_height
- src_rect
->top
;
2061 bottom
= src_height
- src_rect
->bottom
;
2065 top
= src_height
- src_rect
->bottom
;
2066 bottom
= src_height
- src_rect
->top
;
2069 if (src_texture
->flags
& WINED3D_TEXTURE_NORMALIZED_COORDS
)
2071 left
/= src_pow2_width
;
2072 right
/= src_pow2_width
;
2073 top
/= src_pow2_height
;
2074 bottom
/= src_pow2_height
;
2077 /* draw the source texture stretched and upside down. The correct surface is bound already */
2078 gl_info
->gl_ops
.gl
.p_glTexParameteri(texture_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
2079 gl_info
->gl_ops
.gl
.p_glTexParameteri(texture_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
2081 context_set_draw_buffer(context
, drawBuffer
);
2082 gl_info
->gl_ops
.gl
.p_glReadBuffer(drawBuffer
);
2084 gl_info
->gl_ops
.gl
.p_glBegin(GL_QUADS
);
2086 gl_info
->gl_ops
.gl
.p_glTexCoord2f(left
, bottom
);
2087 gl_info
->gl_ops
.gl
.p_glVertex2i(0, 0);
2090 gl_info
->gl_ops
.gl
.p_glTexCoord2f(left
, top
);
2091 gl_info
->gl_ops
.gl
.p_glVertex2i(0, dst_rect
.bottom
- dst_rect
.top
);
2094 gl_info
->gl_ops
.gl
.p_glTexCoord2f(right
, top
);
2095 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
.right
- dst_rect
.left
, dst_rect
.bottom
- dst_rect
.top
);
2098 gl_info
->gl_ops
.gl
.p_glTexCoord2f(right
, bottom
);
2099 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
.right
- dst_rect
.left
, 0);
2100 gl_info
->gl_ops
.gl
.p_glEnd();
2101 checkGLcall("glEnd and previous");
2103 if (texture_target
!= dst_surface
->texture_target
)
2105 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
2106 gl_info
->gl_ops
.gl
.p_glEnable(dst_surface
->texture_target
);
2107 texture_target
= dst_surface
->texture_target
;
2110 /* Now read the stretched and upside down image into the destination texture */
2111 context_bind_texture(context
, texture_target
, dst_texture
->texture_rgb
.name
);
2112 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(texture_target
,
2114 dst_rect
.left
, dst_rect
.top
, /* xoffset, yoffset */
2115 0, 0, /* We blitted the image to the origin */
2116 dst_rect
.right
- dst_rect
.left
, dst_rect
.bottom
- dst_rect
.top
);
2117 checkGLcall("glCopyTexSubImage2D");
2119 if (drawBuffer
== GL_BACK
)
2121 /* Write the back buffer backup back. */
2124 if (texture_target
!= GL_TEXTURE_2D
)
2126 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
2127 gl_info
->gl_ops
.gl
.p_glEnable(GL_TEXTURE_2D
);
2128 texture_target
= GL_TEXTURE_2D
;
2130 context_bind_texture(context
, GL_TEXTURE_2D
, backup
);
2134 if (texture_target
!= src_surface
->texture_target
)
2136 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
2137 gl_info
->gl_ops
.gl
.p_glEnable(src_surface
->texture_target
);
2138 texture_target
= src_surface
->texture_target
;
2140 context_bind_texture(context
, src_surface
->texture_target
, src_texture
->texture_rgb
.name
);
2143 gl_info
->gl_ops
.gl
.p_glBegin(GL_QUADS
);
2145 gl_info
->gl_ops
.gl
.p_glTexCoord2f(0.0f
, 0.0f
);
2146 gl_info
->gl_ops
.gl
.p_glVertex2i(0, src_height
);
2149 gl_info
->gl_ops
.gl
.p_glTexCoord2f(0.0f
, (float)src_height
/ (float)src_pow2_height
);
2150 gl_info
->gl_ops
.gl
.p_glVertex2i(0, 0);
2153 gl_info
->gl_ops
.gl
.p_glTexCoord2f((float)src_width
/ (float)src_pow2_width
,
2154 (float)src_height
/ (float)src_pow2_height
);
2155 gl_info
->gl_ops
.gl
.p_glVertex2i(src_width
, 0);
2158 gl_info
->gl_ops
.gl
.p_glTexCoord2f((float)src_width
/ (float)src_pow2_width
, 0.0f
);
2159 gl_info
->gl_ops
.gl
.p_glVertex2i(src_width
, src_height
);
2160 gl_info
->gl_ops
.gl
.p_glEnd();
2162 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
2163 checkGLcall("glDisable(texture_target)");
2166 if (src
!= src_texture
->texture_rgb
.name
&& src
!= backup
)
2168 gl_info
->gl_ops
.gl
.p_glDeleteTextures(1, &src
);
2169 checkGLcall("glDeleteTextures(1, &src)");
2173 gl_info
->gl_ops
.gl
.p_glDeleteTextures(1, &backup
);
2174 checkGLcall("glDeleteTextures(1, &backup)");
2177 if (wined3d_settings
.strict_draw_ordering
)
2178 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
2180 context_release(context
);
2182 /* The texture is now most up to date - If the surface is a render target
2183 * and has a drawable, this path is never entered. */
2184 wined3d_texture_validate_location(dst_texture
, dst_sub_resource_idx
, WINED3D_LOCATION_TEXTURE_RGB
);
2185 wined3d_texture_invalidate_location(dst_texture
, dst_sub_resource_idx
, ~WINED3D_LOCATION_TEXTURE_RGB
);
2188 /* Front buffer coordinates are always full screen coordinates, but our GL
2189 * drawable is limited to the window's client area. The sysmem and texture
2190 * copies do have the full screen size. Note that GL has a bottom-left
2191 * origin, while D3D has a top-left origin. */
2192 void surface_translate_drawable_coords(const struct wined3d_surface
*surface
, HWND window
, RECT
*rect
)
2194 struct wined3d_texture
*texture
= surface
->container
;
2195 UINT drawable_height
;
2197 if (texture
->swapchain
&& texture
== texture
->swapchain
->front_buffer
)
2199 POINT offset
= {0, 0};
2202 ScreenToClient(window
, &offset
);
2203 OffsetRect(rect
, offset
.x
, offset
.y
);
2205 GetClientRect(window
, &windowsize
);
2206 drawable_height
= windowsize
.bottom
- windowsize
.top
;
2210 drawable_height
= wined3d_texture_get_level_height(texture
, surface
->texture_level
);
2213 rect
->top
= drawable_height
- rect
->top
;
2214 rect
->bottom
= drawable_height
- rect
->bottom
;
2217 /* Context activation is done by the caller. */
2218 static void surface_blt_to_drawable(const struct wined3d_device
*device
,
2219 struct wined3d_context
*old_ctx
,
2220 enum wined3d_texture_filter_type filter
, BOOL alpha_test
,
2221 struct wined3d_surface
*src_surface
, const RECT
*src_rect_in
,
2222 struct wined3d_surface
*dst_surface
, const RECT
*dst_rect_in
)
2224 unsigned int dst_sub_resource_idx
= surface_get_sub_resource_idx(dst_surface
);
2225 struct wined3d_texture
*src_texture
= src_surface
->container
;
2226 struct wined3d_texture
*dst_texture
= dst_surface
->container
;
2227 const struct wined3d_gl_info
*gl_info
;
2228 struct wined3d_context
*context
= old_ctx
;
2229 struct wined3d_surface
*restore_rt
= NULL
;
2230 RECT src_rect
, dst_rect
;
2232 src_rect
= *src_rect_in
;
2233 dst_rect
= *dst_rect_in
;
2235 restore_rt
= context_get_rt_surface(old_ctx
);
2236 if (restore_rt
!= dst_surface
)
2237 context
= context_acquire(device
, dst_texture
, dst_sub_resource_idx
);
2241 gl_info
= context
->gl_info
;
2243 /* Make sure the surface is up-to-date. This should probably use
2244 * surface_load_location() and worry about the destination surface too,
2245 * unless we're overwriting it completely. */
2246 wined3d_texture_load(src_texture
, context
, FALSE
);
2248 /* Activate the destination context, set it up for blitting */
2249 context_apply_blit_state(context
, device
);
2251 if (!wined3d_resource_is_offscreen(&dst_texture
->resource
))
2252 surface_translate_drawable_coords(dst_surface
, context
->win_handle
, &dst_rect
);
2254 device
->blitter
->set_shader(device
->blit_priv
, context
, src_surface
, NULL
);
2258 gl_info
->gl_ops
.gl
.p_glEnable(GL_ALPHA_TEST
);
2259 checkGLcall("glEnable(GL_ALPHA_TEST)");
2261 /* For P8 surfaces, the alpha component contains the palette index.
2262 * Which means that the colorkey is one of the palette entries. In
2263 * other cases pixels that should be masked away have alpha set to 0. */
2264 if (src_texture
->resource
.format
->id
== WINED3DFMT_P8_UINT
)
2265 gl_info
->gl_ops
.gl
.p_glAlphaFunc(GL_NOTEQUAL
,
2266 (float)src_texture
->async
.src_blt_color_key
.color_space_low_value
/ 255.0f
);
2268 gl_info
->gl_ops
.gl
.p_glAlphaFunc(GL_NOTEQUAL
, 0.0f
);
2269 checkGLcall("glAlphaFunc");
2273 gl_info
->gl_ops
.gl
.p_glDisable(GL_ALPHA_TEST
);
2274 checkGLcall("glDisable(GL_ALPHA_TEST)");
2277 draw_textured_quad(src_surface
, context
, &src_rect
, &dst_rect
, filter
);
2281 gl_info
->gl_ops
.gl
.p_glDisable(GL_ALPHA_TEST
);
2282 checkGLcall("glDisable(GL_ALPHA_TEST)");
2285 /* Leave the opengl state valid for blitting */
2286 device
->blitter
->unset_shader(context
->gl_info
);
2288 if (wined3d_settings
.strict_draw_ordering
2289 || (dst_texture
->swapchain
&& dst_texture
->swapchain
->front_buffer
== dst_texture
))
2290 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
2293 context_restore(context
, restore_rt
);
2296 HRESULT
surface_color_fill(struct wined3d_surface
*s
, const RECT
*rect
, const struct wined3d_color
*color
)
2298 struct wined3d_resource
*resource
= &s
->container
->resource
;
2299 struct wined3d_device
*device
= resource
->device
;
2300 struct wined3d_rendertarget_view
*view
;
2301 struct wined3d_view_desc view_desc
;
2302 const struct blit_shader
*blitter
;
2305 if (!(blitter
= wined3d_select_blitter(&device
->adapter
->gl_info
, &device
->adapter
->d3d_info
,
2306 WINED3D_BLIT_OP_COLOR_FILL
, NULL
, 0, 0, NULL
, rect
, resource
->usage
, resource
->pool
, resource
->format
)))
2308 FIXME("No blitter is capable of performing the requested color fill operation.\n");
2309 return WINED3DERR_INVALIDCALL
;
2312 view_desc
.format_id
= resource
->format
->id
;
2313 view_desc
.flags
= 0;
2314 view_desc
.u
.texture
.level_idx
= s
->texture_level
;
2315 view_desc
.u
.texture
.level_count
= 1;
2316 view_desc
.u
.texture
.layer_idx
= s
->texture_layer
;
2317 view_desc
.u
.texture
.layer_count
= 1;
2318 if (FAILED(hr
= wined3d_rendertarget_view_create(&view_desc
,
2319 resource
, NULL
, &wined3d_null_parent_ops
, &view
)))
2321 ERR("Failed to create rendertarget view, hr %#x.\n", hr
);
2325 hr
= blitter
->color_fill(device
, view
, rect
, color
);
2326 wined3d_rendertarget_view_decref(view
);
2331 static HRESULT
surface_blt_special(struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
,
2332 struct wined3d_surface
*src_surface
, const RECT
*src_rect
, DWORD flags
,
2333 const struct wined3d_blt_fx
*fx
, enum wined3d_texture_filter_type filter
)
2335 struct wined3d_texture
*dst_texture
= dst_surface
->container
;
2336 struct wined3d_device
*device
= dst_texture
->resource
.device
;
2337 const struct wined3d_surface
*rt
= wined3d_rendertarget_view_get_surface(device
->fb
.render_targets
[0]);
2338 struct wined3d_swapchain
*src_swapchain
, *dst_swapchain
;
2339 struct wined3d_texture
*src_texture
;
2341 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
2342 dst_surface
, wine_dbgstr_rect(dst_rect
), src_surface
, wine_dbgstr_rect(src_rect
),
2343 flags
, fx
, debug_d3dtexturefiltertype(filter
));
2345 /* Get the swapchain. One of the surfaces has to be a primary surface */
2346 if (dst_texture
->resource
.pool
== WINED3D_POOL_SYSTEM_MEM
)
2348 WARN("Destination is in sysmem, rejecting gl blt\n");
2349 return WINED3DERR_INVALIDCALL
;
2352 dst_swapchain
= dst_texture
->swapchain
;
2356 src_texture
= src_surface
->container
;
2357 if (src_texture
->resource
.pool
== WINED3D_POOL_SYSTEM_MEM
)
2359 WARN("Src is in sysmem, rejecting gl blt\n");
2360 return WINED3DERR_INVALIDCALL
;
2363 src_swapchain
= src_texture
->swapchain
;
2368 src_swapchain
= NULL
;
2371 /* Early sort out of cases where no render target is used */
2372 if (!dst_swapchain
&& !src_swapchain
&& src_surface
!= rt
&& dst_surface
!= rt
)
2374 TRACE("No surface is render target, not using hardware blit.\n");
2375 return WINED3DERR_INVALIDCALL
;
2378 /* No destination color keying supported */
2379 if (flags
& (WINED3D_BLT_DST_CKEY
| WINED3D_BLT_DST_CKEY_OVERRIDE
))
2381 /* Can we support that with glBlendFunc if blitting to the frame buffer? */
2382 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
2383 return WINED3DERR_INVALIDCALL
;
2386 if (dst_swapchain
&& dst_swapchain
== src_swapchain
)
2388 FIXME("Implement hardware blit between two surfaces on the same swapchain\n");
2389 return WINED3DERR_INVALIDCALL
;
2392 if (dst_swapchain
&& src_swapchain
)
2394 FIXME("Implement hardware blit between two different swapchains\n");
2395 return WINED3DERR_INVALIDCALL
;
2400 /* Handled with regular texture -> swapchain blit */
2401 if (src_surface
== rt
)
2402 TRACE("Blit from active render target to a swapchain\n");
2404 else if (src_swapchain
&& dst_surface
== rt
)
2406 FIXME("Implement blit from a swapchain to the active render target\n");
2407 return WINED3DERR_INVALIDCALL
;
2410 if ((src_swapchain
|| src_surface
== rt
) && !dst_swapchain
)
2412 unsigned int src_width
, src_height
;
2413 /* Blit from render target to texture */
2416 /* P8 read back is not implemented */
2417 if (src_texture
->resource
.format
->id
== WINED3DFMT_P8_UINT
2418 || dst_texture
->resource
.format
->id
== WINED3DFMT_P8_UINT
)
2420 TRACE("P8 read back not supported by frame buffer to texture blit\n");
2421 return WINED3DERR_INVALIDCALL
;
2424 if (flags
& (WINED3D_BLT_SRC_CKEY
| WINED3D_BLT_SRC_CKEY_OVERRIDE
))
2426 TRACE("Color keying not supported by frame buffer to texture blit\n");
2427 return WINED3DERR_INVALIDCALL
;
2428 /* Destination color key is checked above */
2431 if (dst_rect
->right
- dst_rect
->left
!= src_rect
->right
- src_rect
->left
)
2436 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
2437 * flip the image nor scale it.
2439 * -> If the app asks for an unscaled, upside down copy, just perform one glCopyTexSubImage2D call
2440 * -> If the app wants an image width an unscaled width, copy it line per line
2441 * -> If the app wants an image that is scaled on the x axis, and the destination rectangle is smaller
2442 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
2443 * back buffer. This is slower than reading line per line, thus not used for flipping
2444 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
2445 * pixel by pixel. */
2446 src_width
= wined3d_texture_get_level_width(src_texture
, src_surface
->texture_level
);
2447 src_height
= wined3d_texture_get_level_height(src_texture
, src_surface
->texture_level
);
2448 if (!stretchx
|| dst_rect
->right
- dst_rect
->left
> src_width
2449 || dst_rect
->bottom
- dst_rect
->top
> src_height
)
2451 TRACE("No stretching in x direction, using direct framebuffer -> texture copy.\n");
2452 fb_copy_to_texture_direct(dst_surface
, src_surface
, src_rect
, dst_rect
, filter
);
2456 TRACE("Using hardware stretching to flip / stretch the texture.\n");
2457 fb_copy_to_texture_hwstretch(dst_surface
, src_surface
, src_rect
, dst_rect
, filter
);
2463 /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
2464 TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
2465 return WINED3DERR_INVALIDCALL
;
2468 /* Context activation is done by the caller. */
2469 static BOOL
surface_load_sysmem(struct wined3d_surface
*surface
,
2470 struct wined3d_context
*context
, DWORD dst_location
)
2472 unsigned int sub_resource_idx
= surface_get_sub_resource_idx(surface
);
2473 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
2474 struct wined3d_texture
*texture
= surface
->container
;
2475 struct wined3d_texture_sub_resource
*sub_resource
;
2477 sub_resource
= &texture
->sub_resources
[sub_resource_idx
];
2478 wined3d_texture_prepare_location(texture
, sub_resource_idx
, context
, dst_location
);
2480 if (sub_resource
->locations
& (WINED3D_LOCATION_RB_MULTISAMPLE
| WINED3D_LOCATION_RB_RESOLVED
))
2481 wined3d_texture_load_location(texture
, sub_resource_idx
, context
, WINED3D_LOCATION_TEXTURE_RGB
);
2483 /* Download the surface to system memory. */
2484 if (sub_resource
->locations
& (WINED3D_LOCATION_TEXTURE_RGB
| WINED3D_LOCATION_TEXTURE_SRGB
))
2486 wined3d_texture_bind_and_dirtify(texture
, context
,
2487 !(sub_resource
->locations
& WINED3D_LOCATION_TEXTURE_RGB
));
2488 surface_download_data(surface
, gl_info
, dst_location
);
2489 ++texture
->download_count
;
2494 if (!(texture
->resource
.usage
& WINED3DUSAGE_DEPTHSTENCIL
)
2495 && (sub_resource
->locations
& WINED3D_LOCATION_DRAWABLE
))
2497 read_from_framebuffer(surface
, context
, dst_location
);
2501 FIXME("Can't load surface %p with location flags %s into sysmem.\n",
2502 surface
, wined3d_debug_location(sub_resource
->locations
));
2506 /* Context activation is done by the caller. */
2507 static BOOL
surface_load_drawable(struct wined3d_surface
*surface
,
2508 struct wined3d_context
*context
)
2510 unsigned int sub_resource_idx
= surface_get_sub_resource_idx(surface
);
2511 struct wined3d_texture
*texture
= surface
->container
;
2514 if (texture
->resource
.usage
& WINED3DUSAGE_DEPTHSTENCIL
)
2516 DWORD current
= texture
->sub_resources
[sub_resource_idx
].locations
;
2517 FIXME("Unimplemented copy from %s for depth/stencil buffers.\n",
2518 wined3d_debug_location(current
));
2522 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
2523 && wined3d_resource_is_offscreen(&texture
->resource
))
2525 ERR("Trying to load offscreen surface into WINED3D_LOCATION_DRAWABLE.\n");
2529 surface_get_rect(surface
, NULL
, &r
);
2530 wined3d_texture_load_location(texture
, sub_resource_idx
, context
, WINED3D_LOCATION_TEXTURE_RGB
);
2531 surface_blt_to_drawable(texture
->resource
.device
, context
,
2532 WINED3D_TEXF_POINT
, FALSE
, surface
, &r
, surface
, &r
);
2537 static BOOL
surface_load_texture(struct wined3d_surface
*surface
,
2538 struct wined3d_context
*context
, BOOL srgb
)
2540 unsigned int width
, height
, src_row_pitch
, src_slice_pitch
, dst_row_pitch
, dst_slice_pitch
;
2541 unsigned int sub_resource_idx
= surface_get_sub_resource_idx(surface
);
2542 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
2543 struct wined3d_texture
*texture
= surface
->container
;
2544 struct wined3d_device
*device
= texture
->resource
.device
;
2545 const struct wined3d_color_key_conversion
*conversion
;
2546 struct wined3d_texture_sub_resource
*sub_resource
;
2547 struct wined3d_bo_address data
;
2548 BYTE
*src_mem
, *dst_mem
= NULL
;
2549 struct wined3d_format format
;
2550 POINT dst_point
= {0, 0};
2554 depth
= texture
->resource
.usage
& WINED3DUSAGE_DEPTHSTENCIL
;
2555 sub_resource
= surface_get_sub_resource(surface
);
2557 if (!depth
&& wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
2558 && wined3d_resource_is_offscreen(&texture
->resource
)
2559 && (sub_resource
->locations
& WINED3D_LOCATION_DRAWABLE
))
2561 surface_load_fb_texture(surface
, srgb
, context
);
2566 width
= wined3d_texture_get_level_width(texture
, surface
->texture_level
);
2567 height
= wined3d_texture_get_level_height(texture
, surface
->texture_level
);
2568 SetRect(&src_rect
, 0, 0, width
, height
);
2570 if (!depth
&& sub_resource
->locations
& (WINED3D_LOCATION_TEXTURE_SRGB
| WINED3D_LOCATION_TEXTURE_RGB
)
2571 && (texture
->resource
.format_flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB
)
2572 && fbo_blit_supported(gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
2573 NULL
, texture
->resource
.usage
, texture
->resource
.pool
, texture
->resource
.format
,
2574 NULL
, texture
->resource
.usage
, texture
->resource
.pool
, texture
->resource
.format
))
2577 surface_blt_fbo(device
, context
, WINED3D_TEXF_POINT
, surface
, WINED3D_LOCATION_TEXTURE_RGB
,
2578 &src_rect
, surface
, WINED3D_LOCATION_TEXTURE_SRGB
, &src_rect
);
2580 surface_blt_fbo(device
, context
, WINED3D_TEXF_POINT
, surface
, WINED3D_LOCATION_TEXTURE_SRGB
,
2581 &src_rect
, surface
, WINED3D_LOCATION_TEXTURE_RGB
, &src_rect
);
2586 if (!depth
&& sub_resource
->locations
& (WINED3D_LOCATION_RB_MULTISAMPLE
| WINED3D_LOCATION_RB_RESOLVED
)
2587 && (!srgb
|| (texture
->resource
.format_flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB
))
2588 && fbo_blit_supported(gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
2589 NULL
, texture
->resource
.usage
, texture
->resource
.pool
, texture
->resource
.format
,
2590 NULL
, texture
->resource
.usage
, texture
->resource
.pool
, texture
->resource
.format
))
2592 DWORD src_location
= sub_resource
->locations
& WINED3D_LOCATION_RB_RESOLVED
?
2593 WINED3D_LOCATION_RB_RESOLVED
: WINED3D_LOCATION_RB_MULTISAMPLE
;
2594 DWORD dst_location
= srgb
? WINED3D_LOCATION_TEXTURE_SRGB
: WINED3D_LOCATION_TEXTURE_RGB
;
2596 surface_blt_fbo(device
, context
, WINED3D_TEXF_POINT
, surface
, src_location
,
2597 &src_rect
, surface
, dst_location
, &src_rect
);
2602 /* Upload from system memory */
2606 if ((sub_resource
->locations
& (WINED3D_LOCATION_TEXTURE_RGB
| texture
->resource
.map_binding
))
2607 == WINED3D_LOCATION_TEXTURE_RGB
)
2609 FIXME_(d3d_perf
)("Downloading RGB surface %p to reload it as sRGB.\n", surface
);
2610 wined3d_texture_load_location(texture
, sub_resource_idx
, context
, texture
->resource
.map_binding
);
2615 if ((sub_resource
->locations
& (WINED3D_LOCATION_TEXTURE_SRGB
| texture
->resource
.map_binding
))
2616 == WINED3D_LOCATION_TEXTURE_SRGB
)
2618 FIXME_(d3d_perf
)("Downloading sRGB surface %p to reload it as RGB.\n", surface
);
2619 wined3d_texture_load_location(texture
, sub_resource_idx
, context
, texture
->resource
.map_binding
);
2623 if (!(sub_resource
->locations
& surface_simple_locations
))
2625 WARN("Trying to load a texture from sysmem, but no simple location is valid.\n");
2626 /* Lets hope we get it from somewhere... */
2627 wined3d_texture_load_location(texture
, sub_resource_idx
, context
, WINED3D_LOCATION_SYSMEM
);
2630 wined3d_texture_prepare_texture(texture
, context
, srgb
);
2631 wined3d_texture_bind_and_dirtify(texture
, context
, srgb
);
2632 wined3d_texture_get_pitch(texture
, surface
->texture_level
, &src_row_pitch
, &src_slice_pitch
);
2634 format
= *texture
->resource
.format
;
2635 if ((conversion
= wined3d_format_get_color_key_conversion(texture
, TRUE
)))
2636 format
= *wined3d_get_format(gl_info
, conversion
->dst_format
, texture
->resource
.usage
);
2638 /* Don't use PBOs for converted surfaces. During PBO conversion we look at
2639 * WINED3D_TEXTURE_CONVERTED but it isn't set (yet) in all cases it is
2640 * getting called. */
2641 if ((format
.convert
|| conversion
) && texture
->sub_resources
[sub_resource_idx
].buffer_object
)
2643 TRACE("Removing the pbo attached to surface %p.\n", surface
);
2645 wined3d_texture_load_location(texture
, sub_resource_idx
, context
, WINED3D_LOCATION_SYSMEM
);
2646 wined3d_texture_set_map_binding(texture
, WINED3D_LOCATION_SYSMEM
);
2649 wined3d_texture_get_memory(texture
, sub_resource_idx
, &data
, sub_resource
->locations
);
2652 /* This code is entered for texture formats which need a fixup. */
2653 format
.byte_count
= format
.conv_byte_count
;
2654 wined3d_format_calculate_pitch(&format
, 1, width
, height
, &dst_row_pitch
, &dst_slice_pitch
);
2656 src_mem
= wined3d_texture_map_bo_address(&data
, src_slice_pitch
,
2657 gl_info
, GL_PIXEL_UNPACK_BUFFER
, WINED3D_MAP_READONLY
);
2658 if (!(dst_mem
= HeapAlloc(GetProcessHeap(), 0, dst_slice_pitch
)))
2660 ERR("Out of memory (%u).\n", dst_slice_pitch
);
2661 context_release(context
);
2664 format
.convert(src_mem
, dst_mem
, src_row_pitch
, src_slice_pitch
,
2665 dst_row_pitch
, dst_slice_pitch
, width
, height
, 1);
2666 src_row_pitch
= dst_row_pitch
;
2667 wined3d_texture_unmap_bo_address(&data
, gl_info
, GL_PIXEL_UNPACK_BUFFER
);
2669 data
.buffer_object
= 0;
2670 data
.addr
= dst_mem
;
2672 else if (conversion
)
2674 /* This code is only entered for color keying fixups */
2675 struct wined3d_palette
*palette
= NULL
;
2677 wined3d_format_calculate_pitch(&format
, device
->surface_alignment
,
2678 width
, height
, &dst_row_pitch
, &dst_slice_pitch
);
2680 src_mem
= wined3d_texture_map_bo_address(&data
, src_slice_pitch
,
2681 gl_info
, GL_PIXEL_UNPACK_BUFFER
, WINED3D_MAP_READONLY
);
2682 if (!(dst_mem
= HeapAlloc(GetProcessHeap(), 0, dst_slice_pitch
)))
2684 ERR("Out of memory (%u).\n", dst_slice_pitch
);
2685 context_release(context
);
2688 if (texture
->swapchain
&& texture
->swapchain
->palette
)
2689 palette
= texture
->swapchain
->palette
;
2690 conversion
->convert(src_mem
, src_row_pitch
, dst_mem
, dst_row_pitch
,
2691 width
, height
, palette
, &texture
->async
.gl_color_key
);
2692 src_row_pitch
= dst_row_pitch
;
2693 wined3d_texture_unmap_bo_address(&data
, gl_info
, GL_PIXEL_UNPACK_BUFFER
);
2695 data
.buffer_object
= 0;
2696 data
.addr
= dst_mem
;
2699 wined3d_surface_upload_data(surface
, gl_info
, &format
, &src_rect
,
2700 src_row_pitch
, &dst_point
, srgb
, wined3d_const_bo_address(&data
));
2702 HeapFree(GetProcessHeap(), 0, dst_mem
);
2707 /* Context activation is done by the caller. */
2708 static BOOL
surface_load_renderbuffer(struct wined3d_surface
*surface
, struct wined3d_context
*context
,
2711 struct wined3d_texture
*texture
= surface
->container
;
2712 const RECT rect
= {0, 0,
2713 wined3d_texture_get_level_width(texture
, surface
->texture_level
),
2714 wined3d_texture_get_level_height(texture
, surface
->texture_level
)};
2715 DWORD locations
= surface_get_sub_resource(surface
)->locations
;
2718 if (texture
->resource
.usage
& WINED3DUSAGE_DEPTHSTENCIL
)
2720 FIXME("Unimplemented copy from %s for depth/stencil buffers.\n",
2721 wined3d_debug_location(locations
));
2725 if (locations
& WINED3D_LOCATION_RB_MULTISAMPLE
)
2726 src_location
= WINED3D_LOCATION_RB_MULTISAMPLE
;
2727 else if (locations
& WINED3D_LOCATION_RB_RESOLVED
)
2728 src_location
= WINED3D_LOCATION_RB_RESOLVED
;
2729 else if (locations
& WINED3D_LOCATION_TEXTURE_SRGB
)
2730 src_location
= WINED3D_LOCATION_TEXTURE_SRGB
;
2731 else /* surface_blt_fbo will load the source location if necessary. */
2732 src_location
= WINED3D_LOCATION_TEXTURE_RGB
;
2734 surface_blt_fbo(texture
->resource
.device
, context
, WINED3D_TEXF_POINT
,
2735 surface
, src_location
, &rect
, surface
, dst_location
, &rect
);
2740 /* Context activation is done by the caller. Context may be NULL in ddraw-only mode. */
2741 BOOL
surface_load_location(struct wined3d_surface
*surface
, struct wined3d_context
*context
, DWORD location
)
2743 TRACE("surface %p, location %s.\n", surface
, wined3d_debug_location(location
));
2747 case WINED3D_LOCATION_USER_MEMORY
:
2748 case WINED3D_LOCATION_SYSMEM
:
2749 case WINED3D_LOCATION_BUFFER
:
2750 return surface_load_sysmem(surface
, context
, location
);
2752 case WINED3D_LOCATION_DRAWABLE
:
2753 return surface_load_drawable(surface
, context
);
2755 case WINED3D_LOCATION_RB_RESOLVED
:
2756 case WINED3D_LOCATION_RB_MULTISAMPLE
:
2757 return surface_load_renderbuffer(surface
, context
, location
);
2759 case WINED3D_LOCATION_TEXTURE_RGB
:
2760 case WINED3D_LOCATION_TEXTURE_SRGB
:
2761 return surface_load_texture(surface
, context
,
2762 location
== WINED3D_LOCATION_TEXTURE_SRGB
);
2765 ERR("Don't know how to handle location %#x.\n", location
);
2770 static HRESULT
ffp_blit_alloc(struct wined3d_device
*device
) { return WINED3D_OK
; }
2771 /* Context activation is done by the caller. */
2772 static void ffp_blit_free(struct wined3d_device
*device
) { }
2774 /* Context activation is done by the caller. */
2775 static HRESULT
ffp_blit_set(void *blit_priv
, struct wined3d_context
*context
, const struct wined3d_surface
*surface
,
2776 const struct wined3d_color_key
*color_key
)
2778 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
2780 gl_info
->gl_ops
.gl
.p_glEnable(surface
->container
->target
);
2781 checkGLcall("glEnable(target)");
2786 /* Context activation is done by the caller. */
2787 static void ffp_blit_unset(const struct wined3d_gl_info
*gl_info
)
2789 gl_info
->gl_ops
.gl
.p_glDisable(GL_TEXTURE_2D
);
2790 checkGLcall("glDisable(GL_TEXTURE_2D)");
2791 if (gl_info
->supported
[ARB_TEXTURE_CUBE_MAP
])
2793 gl_info
->gl_ops
.gl
.p_glDisable(GL_TEXTURE_CUBE_MAP_ARB
);
2794 checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
2796 if (gl_info
->supported
[ARB_TEXTURE_RECTANGLE
])
2798 gl_info
->gl_ops
.gl
.p_glDisable(GL_TEXTURE_RECTANGLE_ARB
);
2799 checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)");
2803 static BOOL
ffp_blit_supported(const struct wined3d_gl_info
*gl_info
,
2804 const struct wined3d_d3d_info
*d3d_info
, enum wined3d_blit_op blit_op
,
2805 const RECT
*src_rect
, DWORD src_usage
, enum wined3d_pool src_pool
, const struct wined3d_format
*src_format
,
2806 const RECT
*dst_rect
, DWORD dst_usage
, enum wined3d_pool dst_pool
, const struct wined3d_format
*dst_format
)
2810 decompress
= src_format
&& (src_format
->flags
[WINED3D_GL_RES_TYPE_TEX_2D
] & WINED3DFMT_FLAG_COMPRESSED
)
2811 && !(dst_format
->flags
[WINED3D_GL_RES_TYPE_TEX_2D
] & WINED3DFMT_FLAG_COMPRESSED
);
2812 if (!decompress
&& (src_pool
== WINED3D_POOL_SYSTEM_MEM
|| dst_pool
== WINED3D_POOL_SYSTEM_MEM
))
2814 TRACE("Source or destination is in system memory.\n");
2820 case WINED3D_BLIT_OP_COLOR_BLIT_CKEY
:
2821 if (d3d_info
->shader_color_key
)
2823 TRACE("Color keying requires converted textures.\n");
2826 case WINED3D_BLIT_OP_COLOR_BLIT
:
2827 case WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST
:
2830 TRACE("Checking support for fixup:\n");
2831 dump_color_fixup_desc(src_format
->color_fixup
);
2834 /* We only support identity conversions. */
2835 if (!is_identity_fixup(src_format
->color_fixup
)
2836 || !is_identity_fixup(dst_format
->color_fixup
))
2838 TRACE("Fixups are not supported.\n");
2842 if (!(dst_usage
& WINED3DUSAGE_RENDERTARGET
))
2844 TRACE("Can only blit to render targets.\n");
2849 case WINED3D_BLIT_OP_COLOR_FILL
:
2850 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
)
2852 if (!((dst_format
->flags
[WINED3D_GL_RES_TYPE_TEX_2D
] & WINED3DFMT_FLAG_FBO_ATTACHABLE
)
2853 || (dst_usage
& WINED3DUSAGE_RENDERTARGET
)))
2856 else if (!(dst_usage
& WINED3DUSAGE_RENDERTARGET
))
2858 TRACE("Color fill not supported\n");
2862 /* FIXME: We should reject color fills on formats with fixups,
2863 * but this would break P8 color fills for example. */
2867 case WINED3D_BLIT_OP_DEPTH_FILL
:
2871 TRACE("Unsupported blit_op=%d\n", blit_op
);
2876 static HRESULT
ffp_blit_color_fill(struct wined3d_device
*device
, struct wined3d_rendertarget_view
*view
,
2877 const RECT
*rect
, const struct wined3d_color
*color
)
2879 const RECT draw_rect
= {0, 0, view
->width
, view
->height
};
2880 struct wined3d_fb_state fb
= {&view
, NULL
};
2882 device_clear_render_targets(device
, 1, &fb
, 1, rect
, &draw_rect
, WINED3DCLEAR_TARGET
, color
, 0.0f
, 0);
2887 static HRESULT
ffp_blit_depth_fill(struct wined3d_device
*device
,
2888 struct wined3d_rendertarget_view
*view
, const RECT
*rect
, DWORD clear_flags
,
2889 float depth
, DWORD stencil
)
2891 const RECT draw_rect
= {0, 0, view
->width
, view
->height
};
2892 struct wined3d_fb_state fb
= {NULL
, view
};
2894 device_clear_render_targets(device
, 0, &fb
, 1, rect
, &draw_rect
, clear_flags
, NULL
, depth
, stencil
);
2899 static void ffp_blit_blit_surface(struct wined3d_device
*device
, enum wined3d_blit_op op
, DWORD filter
,
2900 struct wined3d_surface
*src_surface
, const RECT
*src_rect
,
2901 struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
,
2902 const struct wined3d_color_key
*color_key
)
2904 unsigned int dst_sub_resource_idx
= surface_get_sub_resource_idx(dst_surface
);
2905 struct wined3d_texture
*dst_texture
= dst_surface
->container
;
2906 struct wined3d_texture
*src_texture
= src_surface
->container
;
2907 const struct wined3d_gl_info
*gl_info
;
2908 struct wined3d_context
*context
;
2910 /* Blit from offscreen surface to render target */
2911 struct wined3d_color_key old_blt_key
= src_texture
->async
.src_blt_color_key
;
2912 DWORD old_color_key_flags
= src_texture
->async
.color_key_flags
;
2914 TRACE("Blt from surface %p to rendertarget %p\n", src_surface
, dst_surface
);
2916 wined3d_texture_set_color_key(src_texture
, WINED3D_CKEY_SRC_BLT
, color_key
);
2918 context
= context_acquire(device
, dst_texture
, dst_sub_resource_idx
);
2919 gl_info
= context
->gl_info
;
2921 if (op
== WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST
)
2922 gl_info
->gl_ops
.gl
.p_glEnable(GL_ALPHA_TEST
);
2924 surface_blt_to_drawable(device
, context
, filter
,
2925 !!color_key
, src_surface
, src_rect
, dst_surface
, dst_rect
);
2927 if (op
== WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST
)
2928 gl_info
->gl_ops
.gl
.p_glDisable(GL_ALPHA_TEST
);
2930 context_release(context
);
2932 /* Restore the color key parameters */
2933 wined3d_texture_set_color_key(src_texture
, WINED3D_CKEY_SRC_BLT
,
2934 (old_color_key_flags
& WINED3D_CKEY_SRC_BLT
) ? &old_blt_key
: NULL
);
2936 wined3d_texture_validate_location(dst_texture
, dst_sub_resource_idx
, dst_texture
->resource
.draw_binding
);
2937 wined3d_texture_invalidate_location(dst_texture
, dst_sub_resource_idx
, ~dst_texture
->resource
.draw_binding
);
2940 const struct blit_shader ffp_blit
= {
2946 ffp_blit_color_fill
,
2947 ffp_blit_depth_fill
,
2948 ffp_blit_blit_surface
,
2951 static HRESULT
cpu_blit_alloc(struct wined3d_device
*device
)
2956 /* Context activation is done by the caller. */
2957 static void cpu_blit_free(struct wined3d_device
*device
)
2961 /* Context activation is done by the caller. */
2962 static HRESULT
cpu_blit_set(void *blit_priv
, struct wined3d_context
*context
, const struct wined3d_surface
*surface
,
2963 const struct wined3d_color_key
*color_key
)
2968 /* Context activation is done by the caller. */
2969 static void cpu_blit_unset(const struct wined3d_gl_info
*gl_info
)
2973 static BOOL
cpu_blit_supported(const struct wined3d_gl_info
*gl_info
,
2974 const struct wined3d_d3d_info
*d3d_info
, enum wined3d_blit_op blit_op
,
2975 const RECT
*src_rect
, DWORD src_usage
, enum wined3d_pool src_pool
, const struct wined3d_format
*src_format
,
2976 const RECT
*dst_rect
, DWORD dst_usage
, enum wined3d_pool dst_pool
, const struct wined3d_format
*dst_format
)
2978 if (blit_op
== WINED3D_BLIT_OP_COLOR_FILL
|| blit_op
== WINED3D_BLIT_OP_DEPTH_FILL
)
2984 static HRESULT
surface_cpu_blt_compressed(const BYTE
*src_data
, BYTE
*dst_data
,
2985 UINT src_pitch
, UINT dst_pitch
, UINT update_w
, UINT update_h
,
2986 const struct wined3d_format
*format
, DWORD flags
, const struct wined3d_blt_fx
*fx
)
2988 UINT row_block_count
;
2989 const BYTE
*src_row
;
2996 row_block_count
= (update_w
+ format
->block_width
- 1) / format
->block_width
;
3000 for (y
= 0; y
< update_h
; y
+= format
->block_height
)
3002 memcpy(dst_row
, src_row
, row_block_count
* format
->block_byte_count
);
3003 src_row
+= src_pitch
;
3004 dst_row
+= dst_pitch
;
3010 if (flags
== WINED3D_BLT_FX
&& fx
->fx
== WINEDDBLTFX_MIRRORUPDOWN
)
3012 src_row
+= (((update_h
/ format
->block_height
) - 1) * src_pitch
);
3016 case WINED3DFMT_DXT1
:
3017 for (y
= 0; y
< update_h
; y
+= format
->block_height
)
3022 BYTE control_row
[4];
3025 const struct block
*s
= (const struct block
*)src_row
;
3026 struct block
*d
= (struct block
*)dst_row
;
3028 for (x
= 0; x
< row_block_count
; ++x
)
3030 d
[x
].color
[0] = s
[x
].color
[0];
3031 d
[x
].color
[1] = s
[x
].color
[1];
3032 d
[x
].control_row
[0] = s
[x
].control_row
[3];
3033 d
[x
].control_row
[1] = s
[x
].control_row
[2];
3034 d
[x
].control_row
[2] = s
[x
].control_row
[1];
3035 d
[x
].control_row
[3] = s
[x
].control_row
[0];
3037 src_row
-= src_pitch
;
3038 dst_row
+= dst_pitch
;
3042 case WINED3DFMT_DXT2
:
3043 case WINED3DFMT_DXT3
:
3044 for (y
= 0; y
< update_h
; y
+= format
->block_height
)
3050 BYTE control_row
[4];
3053 const struct block
*s
= (const struct block
*)src_row
;
3054 struct block
*d
= (struct block
*)dst_row
;
3056 for (x
= 0; x
< row_block_count
; ++x
)
3058 d
[x
].alpha_row
[0] = s
[x
].alpha_row
[3];
3059 d
[x
].alpha_row
[1] = s
[x
].alpha_row
[2];
3060 d
[x
].alpha_row
[2] = s
[x
].alpha_row
[1];
3061 d
[x
].alpha_row
[3] = s
[x
].alpha_row
[0];
3062 d
[x
].color
[0] = s
[x
].color
[0];
3063 d
[x
].color
[1] = s
[x
].color
[1];
3064 d
[x
].control_row
[0] = s
[x
].control_row
[3];
3065 d
[x
].control_row
[1] = s
[x
].control_row
[2];
3066 d
[x
].control_row
[2] = s
[x
].control_row
[1];
3067 d
[x
].control_row
[3] = s
[x
].control_row
[0];
3069 src_row
-= src_pitch
;
3070 dst_row
+= dst_pitch
;
3075 FIXME("Compressed flip not implemented for format %s.\n",
3076 debug_d3dformat(format
->id
));
3081 FIXME("Unsupported blit on compressed surface (format %s, flags %#x, DDFX %#x).\n",
3082 debug_d3dformat(format
->id
), flags
, flags
& WINED3D_BLT_FX
? fx
->fx
: 0);
3087 static HRESULT
surface_cpu_blt(struct wined3d_texture
*dst_texture
, unsigned int dst_sub_resource_idx
,
3088 const struct wined3d_box
*dst_box
, struct wined3d_texture
*src_texture
, unsigned int src_sub_resource_idx
,
3089 const struct wined3d_box
*src_box
, DWORD flags
, const struct wined3d_blt_fx
*fx
,
3090 enum wined3d_texture_filter_type filter
)
3092 unsigned int bpp
, src_height
, src_width
, dst_height
, dst_width
, row_byte_count
;
3093 const struct wined3d_format
*src_format
, *dst_format
;
3094 struct wined3d_texture
*converted_texture
= NULL
;
3095 unsigned int src_fmt_flags
, dst_fmt_flags
;
3096 struct wined3d_map_desc dst_map
, src_map
;
3097 const BYTE
*sbase
= NULL
;
3098 HRESULT hr
= WINED3D_OK
;
3099 BOOL same_sub_resource
;
3104 TRACE("dst_texture %p, dst_sub_resource_idx %u, dst_box %s, src_texture %p, "
3105 "src_sub_resource_idx %u, src_box %s, flags %#x, fx %p, filter %s.\n",
3106 dst_texture
, dst_sub_resource_idx
, debug_box(dst_box
), src_texture
,
3107 src_sub_resource_idx
, debug_box(src_box
), flags
, fx
, debug_d3dtexturefiltertype(filter
));
3109 if (src_texture
== dst_texture
&& src_sub_resource_idx
== dst_sub_resource_idx
)
3111 same_sub_resource
= TRUE
;
3112 wined3d_resource_map(&dst_texture
->resource
, dst_sub_resource_idx
, &dst_map
, NULL
, 0);
3114 src_format
= dst_texture
->resource
.format
;
3115 dst_format
= src_format
;
3116 dst_fmt_flags
= dst_texture
->resource
.format_flags
;
3117 src_fmt_flags
= dst_fmt_flags
;
3121 same_sub_resource
= FALSE
;
3122 dst_format
= dst_texture
->resource
.format
;
3123 dst_fmt_flags
= dst_texture
->resource
.format_flags
;
3126 if (dst_texture
->resource
.format
->id
!= src_texture
->resource
.format
->id
)
3128 if (!(converted_texture
= surface_convert_format(src_texture
, src_sub_resource_idx
, dst_format
)))
3130 FIXME("Cannot convert %s to %s.\n", debug_d3dformat(src_texture
->resource
.format
->id
),
3131 debug_d3dformat(dst_texture
->resource
.format
->id
));
3132 return WINED3DERR_NOTAVAILABLE
;
3134 src_texture
= converted_texture
;
3135 src_sub_resource_idx
= 0;
3137 wined3d_resource_map(&src_texture
->resource
, src_sub_resource_idx
, &src_map
, NULL
, WINED3D_MAP_READONLY
);
3138 src_format
= src_texture
->resource
.format
;
3139 src_fmt_flags
= src_texture
->resource
.format_flags
;
3143 src_format
= dst_format
;
3144 src_fmt_flags
= dst_fmt_flags
;
3147 wined3d_resource_map(&dst_texture
->resource
, dst_sub_resource_idx
, &dst_map
, dst_box
, 0);
3150 bpp
= dst_format
->byte_count
;
3151 src_height
= src_box
->bottom
- src_box
->top
;
3152 src_width
= src_box
->right
- src_box
->left
;
3153 dst_height
= dst_box
->bottom
- dst_box
->top
;
3154 dst_width
= dst_box
->right
- dst_box
->left
;
3155 row_byte_count
= dst_width
* bpp
;
3158 sbase
= (BYTE
*)src_map
.data
3159 + ((src_box
->top
/ src_format
->block_height
) * src_map
.row_pitch
)
3160 + ((src_box
->left
/ src_format
->block_width
) * src_format
->block_byte_count
);
3161 if (same_sub_resource
)
3162 dbuf
= (BYTE
*)dst_map
.data
3163 + ((dst_box
->top
/ dst_format
->block_height
) * dst_map
.row_pitch
)
3164 + ((dst_box
->left
/ dst_format
->block_width
) * dst_format
->block_byte_count
);
3166 dbuf
= dst_map
.data
;
3168 if (src_fmt_flags
& dst_fmt_flags
& WINED3DFMT_FLAG_BLOCKS
)
3170 TRACE("%s -> %s copy.\n", debug_d3dformat(src_format
->id
), debug_d3dformat(dst_format
->id
));
3172 if (same_sub_resource
)
3174 FIXME("Only plain blits supported on compressed surfaces.\n");
3179 if (src_height
!= dst_height
|| src_width
!= dst_width
)
3181 WARN("Stretching not supported on compressed surfaces.\n");
3182 hr
= WINED3DERR_INVALIDCALL
;
3186 if (!wined3d_texture_check_block_align(src_texture
,
3187 src_sub_resource_idx
% src_texture
->level_count
, src_box
))
3189 WARN("Source rectangle not block-aligned.\n");
3190 hr
= WINED3DERR_INVALIDCALL
;
3194 if (!wined3d_texture_check_block_align(dst_texture
,
3195 dst_sub_resource_idx
% dst_texture
->level_count
, dst_box
))
3197 WARN("Destination rectangle not block-aligned.\n");
3198 hr
= WINED3DERR_INVALIDCALL
;
3202 hr
= surface_cpu_blt_compressed(sbase
, dbuf
,
3203 src_map
.row_pitch
, dst_map
.row_pitch
, dst_width
, dst_height
,
3204 src_format
, flags
, fx
);
3208 /* First, all the 'source-less' blits */
3209 if (flags
& (WINED3D_BLT_COLOR_FILL
| WINED3D_BLT_DEPTH_FILL
))
3211 hr
= _Blt_ColorFill(dbuf
, dst_width
, dst_height
, bpp
, dst_map
.row_pitch
, fx
->fill_color
);
3212 flags
&= ~(WINED3D_BLT_COLOR_FILL
| WINED3D_BLT_DEPTH_FILL
);
3215 /* Now the 'with source' blits. */
3218 int sx
, xinc
, sy
, yinc
;
3220 if (!dst_width
|| !dst_height
) /* Hmm... stupid program? */
3223 if (filter
!= WINED3D_TEXF_NONE
&& filter
!= WINED3D_TEXF_POINT
3224 && (src_width
!= dst_width
|| src_height
!= dst_height
))
3226 /* Can happen when d3d9 apps do a StretchRect() call which isn't handled in GL. */
3227 FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(filter
));
3230 xinc
= (src_width
<< 16) / dst_width
;
3231 yinc
= (src_height
<< 16) / dst_height
;
3235 /* No effects, we can cheat here. */
3236 if (dst_width
== src_width
)
3238 if (dst_height
== src_height
)
3240 /* No stretching in either direction. This needs to be as
3241 * fast as possible. */
3244 /* Check for overlapping surfaces. */
3245 if (!same_sub_resource
|| dst_box
->top
< src_box
->top
3246 || dst_box
->right
<= src_box
->left
|| src_box
->right
<= dst_box
->left
)
3248 /* No overlap, or dst above src, so copy from top downwards. */
3249 for (y
= 0; y
< dst_height
; ++y
)
3251 memcpy(dbuf
, sbuf
, row_byte_count
);
3252 sbuf
+= src_map
.row_pitch
;
3253 dbuf
+= dst_map
.row_pitch
;
3256 else if (dst_box
->top
> src_box
->top
)
3258 /* Copy from bottom upwards. */
3259 sbuf
+= src_map
.row_pitch
* dst_height
;
3260 dbuf
+= dst_map
.row_pitch
* dst_height
;
3261 for (y
= 0; y
< dst_height
; ++y
)
3263 sbuf
-= src_map
.row_pitch
;
3264 dbuf
-= dst_map
.row_pitch
;
3265 memcpy(dbuf
, sbuf
, row_byte_count
);
3270 /* Src and dst overlapping on the same line, use memmove. */
3271 for (y
= 0; y
< dst_height
; ++y
)
3273 memmove(dbuf
, sbuf
, row_byte_count
);
3274 sbuf
+= src_map
.row_pitch
;
3275 dbuf
+= dst_map
.row_pitch
;
3281 /* Stretching in y direction only. */
3282 for (y
= sy
= 0; y
< dst_height
; ++y
, sy
+= yinc
)
3284 sbuf
= sbase
+ (sy
>> 16) * src_map
.row_pitch
;
3285 memcpy(dbuf
, sbuf
, row_byte_count
);
3286 dbuf
+= dst_map
.row_pitch
;
3292 /* Stretching in X direction. */
3294 for (y
= sy
= 0; y
< dst_height
; ++y
, sy
+= yinc
)
3296 sbuf
= sbase
+ (sy
>> 16) * src_map
.row_pitch
;
3298 if ((sy
>> 16) == (last_sy
>> 16))
3300 /* This source row is the same as last source row -
3301 * Copy the already stretched row. */
3302 memcpy(dbuf
, dbuf
- dst_map
.row_pitch
, row_byte_count
);
3306 #define STRETCH_ROW(type) \
3308 const type *s = (const type *)sbuf; \
3309 type *d = (type *)dbuf; \
3310 for (x = sx = 0; x < dst_width; ++x, sx += xinc) \
3311 d[x] = s[sx >> 16]; \
3329 for (x
= sx
= 0; x
< dst_width
; x
++, sx
+= xinc
)
3333 s
= sbuf
+ 3 * (sx
>> 16);
3334 pixel
= s
[0] | (s
[1] << 8) | (s
[2] << 16);
3335 d
[0] = (pixel
) & 0xff;
3336 d
[1] = (pixel
>> 8) & 0xff;
3337 d
[2] = (pixel
>> 16) & 0xff;
3343 FIXME("Stretched blit not implemented for bpp %u!\n", bpp
* 8);
3344 hr
= WINED3DERR_NOTAVAILABLE
;
3349 dbuf
+= dst_map
.row_pitch
;
3356 LONG dstyinc
= dst_map
.row_pitch
, dstxinc
= bpp
;
3357 DWORD keylow
= 0xffffffff, keyhigh
= 0, keymask
= 0xffffffff;
3358 DWORD destkeylow
= 0x0, destkeyhigh
= 0xffffffff, destkeymask
= 0xffffffff;
3359 if (flags
& (WINED3D_BLT_SRC_CKEY
| WINED3D_BLT_DST_CKEY
3360 | WINED3D_BLT_SRC_CKEY_OVERRIDE
| WINED3D_BLT_DST_CKEY_OVERRIDE
))
3362 /* The color keying flags are checked for correctness in ddraw */
3363 if (flags
& WINED3D_BLT_SRC_CKEY
)
3365 keylow
= src_texture
->async
.src_blt_color_key
.color_space_low_value
;
3366 keyhigh
= src_texture
->async
.src_blt_color_key
.color_space_high_value
;
3368 else if (flags
& WINED3D_BLT_SRC_CKEY_OVERRIDE
)
3370 keylow
= fx
->src_color_key
.color_space_low_value
;
3371 keyhigh
= fx
->src_color_key
.color_space_high_value
;
3374 if (flags
& WINED3D_BLT_DST_CKEY
)
3376 /* Destination color keys are taken from the source surface! */
3377 destkeylow
= src_texture
->async
.dst_blt_color_key
.color_space_low_value
;
3378 destkeyhigh
= src_texture
->async
.dst_blt_color_key
.color_space_high_value
;
3380 else if (flags
& WINED3D_BLT_DST_CKEY_OVERRIDE
)
3382 destkeylow
= fx
->dst_color_key
.color_space_low_value
;
3383 destkeyhigh
= fx
->dst_color_key
.color_space_high_value
;
3393 get_color_masks(src_format
, masks
);
3398 flags
&= ~(WINED3D_BLT_SRC_CKEY
| WINED3D_BLT_DST_CKEY
3399 | WINED3D_BLT_SRC_CKEY_OVERRIDE
| WINED3D_BLT_DST_CKEY_OVERRIDE
);
3402 if (flags
& WINED3D_BLT_FX
)
3404 BYTE
*dTopLeft
, *dTopRight
, *dBottomLeft
, *dBottomRight
, *tmp
;
3407 dTopRight
= dbuf
+ ((dst_width
- 1) * bpp
);
3408 dBottomLeft
= dTopLeft
+ ((dst_height
- 1) * dst_map
.row_pitch
);
3409 dBottomRight
= dBottomLeft
+ ((dst_width
- 1) * bpp
);
3411 if (fx
->fx
& WINEDDBLTFX_ARITHSTRETCHY
)
3413 /* I don't think we need to do anything about this flag */
3414 WARN("Nothing done for WINEDDBLTFX_ARITHSTRETCHY.\n");
3416 if (fx
->fx
& WINEDDBLTFX_MIRRORLEFTRIGHT
)
3419 dTopRight
= dTopLeft
;
3422 dBottomRight
= dBottomLeft
;
3424 dstxinc
= dstxinc
* -1;
3426 if (fx
->fx
& WINEDDBLTFX_MIRRORUPDOWN
)
3429 dTopLeft
= dBottomLeft
;
3432 dTopRight
= dBottomRight
;
3434 dstyinc
= dstyinc
* -1;
3436 if (fx
->fx
& WINEDDBLTFX_NOTEARING
)
3438 /* I don't think we need to do anything about this flag */
3439 WARN("Nothing done for WINEDDBLTFX_NOTEARING.\n");
3441 if (fx
->fx
& WINEDDBLTFX_ROTATE180
)
3444 dBottomRight
= dTopLeft
;
3447 dBottomLeft
= dTopRight
;
3449 dstxinc
= dstxinc
* -1;
3450 dstyinc
= dstyinc
* -1;
3452 if (fx
->fx
& WINEDDBLTFX_ROTATE270
)
3455 dTopLeft
= dBottomLeft
;
3456 dBottomLeft
= dBottomRight
;
3457 dBottomRight
= dTopRight
;
3462 dstxinc
= dstxinc
* -1;
3464 if (fx
->fx
& WINEDDBLTFX_ROTATE90
)
3467 dTopLeft
= dTopRight
;
3468 dTopRight
= dBottomRight
;
3469 dBottomRight
= dBottomLeft
;
3474 dstyinc
= dstyinc
* -1;
3476 if (fx
->fx
& WINEDDBLTFX_ZBUFFERBASEDEST
)
3478 /* I don't think we need to do anything about this flag */
3479 WARN("Nothing done for WINEDDBLTFX_ZBUFFERBASEDEST.\n");
3482 flags
&= ~(WINED3D_BLT_FX
);
3485 #define COPY_COLORKEY_FX(type) \
3488 type *d = (type *)dbuf, *dx, tmp; \
3489 for (y = sy = 0; y < dst_height; ++y, sy += yinc) \
3491 s = (const type *)(sbase + (sy >> 16) * src_map.row_pitch); \
3493 for (x = sx = 0; x < dst_width; ++x, sx += xinc) \
3495 tmp = s[sx >> 16]; \
3496 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) \
3497 && ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) \
3501 dx = (type *)(((BYTE *)dx) + dstxinc); \
3503 d = (type *)(((BYTE *)d) + dstyinc); \
3510 COPY_COLORKEY_FX(BYTE
);
3513 COPY_COLORKEY_FX(WORD
);
3516 COPY_COLORKEY_FX(DWORD
);
3521 BYTE
*d
= dbuf
, *dx
;
3522 for (y
= sy
= 0; y
< dst_height
; ++y
, sy
+= yinc
)
3524 sbuf
= sbase
+ (sy
>> 16) * src_map
.row_pitch
;
3526 for (x
= sx
= 0; x
< dst_width
; ++x
, sx
+= xinc
)
3528 DWORD pixel
, dpixel
= 0;
3529 s
= sbuf
+ 3 * (sx
>>16);
3530 pixel
= s
[0] | (s
[1] << 8) | (s
[2] << 16);
3531 dpixel
= dx
[0] | (dx
[1] << 8 ) | (dx
[2] << 16);
3532 if (((pixel
& keymask
) < keylow
|| (pixel
& keymask
) > keyhigh
)
3533 && ((dpixel
& keymask
) >= destkeylow
|| (dpixel
& keymask
) <= keyhigh
))
3535 dx
[0] = (pixel
) & 0xff;
3536 dx
[1] = (pixel
>> 8) & 0xff;
3537 dx
[2] = (pixel
>> 16) & 0xff;
3546 FIXME("%s color-keyed blit not implemented for bpp %u!\n",
3547 (flags
& WINED3D_BLT_SRC_CKEY
) ? "Source" : "Destination", bpp
* 8);
3548 hr
= WINED3DERR_NOTAVAILABLE
;
3550 #undef COPY_COLORKEY_FX
3557 FIXME(" Unsupported flags %#x.\n", flags
);
3560 wined3d_resource_unmap(&dst_texture
->resource
, dst_sub_resource_idx
);
3561 if (src_texture
&& !same_sub_resource
)
3562 wined3d_resource_unmap(&src_texture
->resource
, src_sub_resource_idx
);
3563 if (converted_texture
)
3564 wined3d_texture_decref(converted_texture
);
3569 static HRESULT
cpu_blit_color_fill(struct wined3d_device
*device
, struct wined3d_rendertarget_view
*view
,
3570 const RECT
*rect
, const struct wined3d_color
*color
)
3572 const struct wined3d_box box
= {rect
->left
, rect
->top
, rect
->right
, rect
->bottom
, 0, 1};
3573 static const struct wined3d_box src_box
;
3574 struct wined3d_blt_fx fx
;
3576 fx
.fill_color
= wined3d_format_convert_from_float(view
->format
, color
);
3577 return surface_cpu_blt(texture_from_resource(view
->resource
), view
->sub_resource_idx
,
3578 &box
, NULL
, 0, &src_box
, WINED3D_BLT_COLOR_FILL
, &fx
, WINED3D_TEXF_POINT
);
3581 static HRESULT
cpu_blit_depth_fill(struct wined3d_device
*device
,
3582 struct wined3d_rendertarget_view
*view
, const RECT
*rect
, DWORD clear_flags
,
3583 float depth
, DWORD stencil
)
3585 const struct wined3d_box box
= {rect
->left
, rect
->top
, rect
->right
, rect
->bottom
, 0, 1};
3586 struct wined3d_color color
= {depth
, 0.0f
, 0.0f
, 0.0f
};
3587 static const struct wined3d_box src_box
;
3588 struct wined3d_blt_fx fx
;
3590 if (clear_flags
!= WINED3DCLEAR_ZBUFFER
)
3592 FIXME("clear_flags %#x not implemented.\n", clear_flags
);
3593 return WINED3DERR_INVALIDCALL
;
3596 fx
.fill_color
= wined3d_format_convert_from_float(view
->format
, &color
);
3597 return surface_cpu_blt(texture_from_resource(view
->resource
), view
->sub_resource_idx
,
3598 &box
, NULL
, 0, &src_box
, WINED3D_BLT_DEPTH_FILL
, &fx
, WINED3D_TEXF_POINT
);
3601 static void cpu_blit_blit_surface(struct wined3d_device
*device
, enum wined3d_blit_op op
, DWORD filter
,
3602 struct wined3d_surface
*src_surface
, const RECT
*src_rect
,
3603 struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
,
3604 const struct wined3d_color_key
*color_key
)
3606 /* FIXME: Remove error returns from surface_blt_cpu. */
3607 ERR("Blit method not implemented by cpu_blit.\n");
3610 const struct blit_shader cpu_blit
= {
3616 cpu_blit_color_fill
,
3617 cpu_blit_depth_fill
,
3618 cpu_blit_blit_surface
,
3621 HRESULT
wined3d_surface_blt(struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
,
3622 struct wined3d_surface
*src_surface
, const RECT
*src_rect
, DWORD flags
,
3623 const struct wined3d_blt_fx
*fx
, enum wined3d_texture_filter_type filter
)
3625 struct wined3d_box dst_box
= {dst_rect
->left
, dst_rect
->top
, dst_rect
->right
, dst_rect
->bottom
, 0, 1};
3626 struct wined3d_box src_box
= {src_rect
->left
, src_rect
->top
, src_rect
->right
, src_rect
->bottom
, 0, 1};
3627 unsigned int dst_sub_resource_idx
= surface_get_sub_resource_idx(dst_surface
);
3628 struct wined3d_texture
*dst_texture
= dst_surface
->container
;
3629 struct wined3d_device
*device
= dst_texture
->resource
.device
;
3630 struct wined3d_swapchain
*src_swapchain
, *dst_swapchain
;
3631 struct wined3d_texture
*src_texture
= NULL
;
3632 unsigned int dst_w
, dst_h
, src_w
, src_h
;
3633 unsigned int src_sub_resource_idx
= 0;
3634 DWORD src_ds_flags
, dst_ds_flags
;
3635 BOOL scale
, convert
;
3637 static const DWORD simple_blit
= WINED3D_BLT_ASYNC
3638 | WINED3D_BLT_COLOR_FILL
3639 | WINED3D_BLT_SRC_CKEY
3640 | WINED3D_BLT_SRC_CKEY_OVERRIDE
3642 | WINED3D_BLT_DEPTH_FILL
3643 | WINED3D_BLT_DO_NOT_WAIT
3644 | WINED3D_BLT_ALPHA_TEST
;
3646 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
3647 dst_surface
, wine_dbgstr_rect(dst_rect
), src_surface
, wine_dbgstr_rect(src_rect
),
3648 flags
, fx
, debug_d3dtexturefiltertype(filter
));
3649 TRACE("Usage is %s.\n", debug_d3dusage(dst_texture
->resource
.usage
));
3653 TRACE("fx %#x.\n", fx
->fx
);
3654 TRACE("fill_color 0x%08x.\n", fx
->fill_color
);
3655 TRACE("dst_color_key {0x%08x, 0x%08x}.\n",
3656 fx
->dst_color_key
.color_space_low_value
,
3657 fx
->dst_color_key
.color_space_high_value
);
3658 TRACE("src_color_key {0x%08x, 0x%08x}.\n",
3659 fx
->src_color_key
.color_space_low_value
,
3660 fx
->src_color_key
.color_space_high_value
);
3665 src_texture
= src_surface
->container
;
3666 src_sub_resource_idx
= surface_get_sub_resource_idx(src_surface
);
3669 if (dst_texture
->sub_resources
[dst_sub_resource_idx
].map_count
3670 || (src_texture
&& src_texture
->sub_resources
[src_sub_resource_idx
].map_count
))
3672 WARN("Surface is busy, returning WINEDDERR_SURFACEBUSY.\n");
3673 return WINEDDERR_SURFACEBUSY
;
3676 dst_w
= wined3d_texture_get_level_width(dst_texture
, dst_surface
->texture_level
);
3677 dst_h
= wined3d_texture_get_level_height(dst_texture
, dst_surface
->texture_level
);
3678 if (IsRectEmpty(dst_rect
) || dst_rect
->left
> dst_w
|| dst_rect
->left
< 0
3679 || dst_rect
->top
> dst_h
|| dst_rect
->top
< 0
3680 || dst_rect
->right
> dst_w
|| dst_rect
->right
< 0
3681 || dst_rect
->bottom
> dst_h
|| dst_rect
->bottom
< 0)
3683 WARN("The application gave us a bad destination rectangle.\n");
3684 return WINEDDERR_INVALIDRECT
;
3689 src_w
= wined3d_texture_get_level_width(src_texture
, src_surface
->texture_level
);
3690 src_h
= wined3d_texture_get_level_height(src_texture
, src_surface
->texture_level
);
3691 if (IsRectEmpty(src_rect
) || src_rect
->left
> src_w
|| src_rect
->left
< 0
3692 || src_rect
->top
> src_h
|| src_rect
->top
< 0
3693 || src_rect
->right
> src_w
|| src_rect
->right
< 0
3694 || src_rect
->bottom
> src_h
|| src_rect
->bottom
< 0)
3696 WARN("The application gave us a bad source rectangle.\n");
3697 return WINEDDERR_INVALIDRECT
;
3701 if (!fx
|| !(fx
->fx
))
3702 flags
&= ~WINED3D_BLT_FX
;
3704 if (flags
& WINED3D_BLT_WAIT
)
3705 flags
&= ~WINED3D_BLT_WAIT
;
3707 if (flags
& WINED3D_BLT_ASYNC
)
3709 static unsigned int once
;
3712 FIXME("Can't handle WINED3D_BLT_ASYNC flag.\n");
3713 flags
&= ~WINED3D_BLT_ASYNC
;
3716 /* WINED3D_BLT_DO_NOT_WAIT appeared in DX7. */
3717 if (flags
& WINED3D_BLT_DO_NOT_WAIT
)
3719 static unsigned int once
;
3722 FIXME("Can't handle WINED3D_BLT_DO_NOT_WAIT flag.\n");
3723 flags
&= ~WINED3D_BLT_DO_NOT_WAIT
;
3726 if (!device
->d3d_initialized
)
3728 WARN("D3D not initialized, using fallback.\n");
3732 /* We want to avoid invalidating the sysmem location for converted
3733 * surfaces, since otherwise we'd have to convert the data back when
3735 if (dst_texture
->flags
& WINED3D_TEXTURE_CONVERTED
|| dst_texture
->resource
.format
->convert
3736 || wined3d_format_get_color_key_conversion(dst_texture
, TRUE
))
3738 WARN_(d3d_perf
)("Converted surface, using CPU blit.\n");
3742 if (flags
& ~simple_blit
)
3744 WARN_(d3d_perf
)("Using fallback for complex blit (%#x).\n", flags
);
3749 src_swapchain
= src_texture
->swapchain
;
3751 src_swapchain
= NULL
;
3753 dst_swapchain
= dst_texture
->swapchain
;
3755 /* This isn't strictly needed. FBO blits for example could deal with
3756 * cross-swapchain blits by first downloading the source to a texture
3757 * before switching to the destination context. We just have this here to
3758 * not have to deal with the issue, since cross-swapchain blits should be
3760 if (src_swapchain
&& dst_swapchain
&& src_swapchain
!= dst_swapchain
)
3762 FIXME("Using fallback for cross-swapchain blit.\n");
3767 && (src_rect
->right
- src_rect
->left
!= dst_rect
->right
- dst_rect
->left
3768 || src_rect
->bottom
- src_rect
->top
!= dst_rect
->bottom
- dst_rect
->top
);
3769 convert
= src_texture
&& src_texture
->resource
.format
->id
!= dst_texture
->resource
.format
->id
;
3771 dst_ds_flags
= dst_texture
->resource
.format_flags
3772 & (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
3774 src_ds_flags
= src_texture
->resource
.format_flags
3775 & (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
3779 if (src_ds_flags
|| dst_ds_flags
)
3781 if (flags
& WINED3D_BLT_DEPTH_FILL
)
3783 struct wined3d_color color
;
3785 TRACE("Depth fill.\n");
3787 if (!wined3d_format_convert_color_to_float(dst_texture
->resource
.format
, NULL
, fx
->fill_color
, &color
))
3788 return WINED3DERR_INVALIDCALL
;
3790 if (SUCCEEDED(wined3d_surface_depth_fill(dst_surface
, dst_rect
, color
.r
)))
3795 if (src_ds_flags
!= dst_ds_flags
)
3797 WARN("Rejecting depth / stencil blit between incompatible formats.\n");
3798 return WINED3DERR_INVALIDCALL
;
3801 if (SUCCEEDED(wined3d_surface_depth_blt(src_surface
, src_texture
->resource
.draw_binding
,
3802 src_rect
, dst_surface
, dst_texture
->resource
.draw_binding
, dst_rect
)))
3808 struct wined3d_texture_sub_resource
*src_sub_resource
, *dst_sub_resource
;
3809 const struct blit_shader
*blitter
;
3811 dst_sub_resource
= surface_get_sub_resource(dst_surface
);
3812 src_sub_resource
= src_texture
? &src_texture
->sub_resources
[src_sub_resource_idx
] : NULL
;
3814 /* In principle this would apply to depth blits as well, but we don't
3815 * implement those in the CPU blitter at the moment. */
3816 if ((dst_sub_resource
->locations
& dst_texture
->resource
.map_binding
)
3817 && (!src_texture
|| (src_sub_resource
->locations
& src_texture
->resource
.map_binding
)))
3820 TRACE("Not doing sysmem blit because of scaling.\n");
3822 TRACE("Not doing sysmem blit because of format conversion.\n");
3827 if (flags
& WINED3D_BLT_COLOR_FILL
)
3829 struct wined3d_color color
;
3830 const struct wined3d_palette
*palette
= dst_swapchain
? dst_swapchain
->palette
: NULL
;
3832 TRACE("Color fill.\n");
3834 if (!wined3d_format_convert_color_to_float(dst_texture
->resource
.format
,
3835 palette
, fx
->fill_color
, &color
))
3838 if (SUCCEEDED(surface_color_fill(dst_surface
, dst_rect
, &color
)))
3843 enum wined3d_blit_op blit_op
= WINED3D_BLIT_OP_COLOR_BLIT
;
3844 const struct wined3d_color_key
*color_key
= NULL
;
3846 TRACE("Color blit.\n");
3847 if (flags
& WINED3D_BLT_SRC_CKEY_OVERRIDE
)
3849 color_key
= &fx
->src_color_key
;
3850 blit_op
= WINED3D_BLIT_OP_COLOR_BLIT_CKEY
;
3852 else if (flags
& WINED3D_BLT_SRC_CKEY
)
3854 color_key
= &src_texture
->async
.src_blt_color_key
;
3855 blit_op
= WINED3D_BLIT_OP_COLOR_BLIT_CKEY
;
3857 else if (flags
& WINED3D_BLT_ALPHA_TEST
)
3859 blit_op
= WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST
;
3861 else if ((src_sub_resource
->locations
& WINED3D_LOCATION_SYSMEM
)
3862 && !(dst_sub_resource
->locations
& WINED3D_LOCATION_SYSMEM
))
3866 TRACE("Not doing upload because of scaling.\n");
3868 TRACE("Not doing upload because of format conversion.\n");
3871 POINT dst_point
= {dst_rect
->left
, dst_rect
->top
};
3873 if (SUCCEEDED(surface_upload_from_surface(dst_surface
, &dst_point
, src_surface
, src_rect
)))
3875 if (!wined3d_resource_is_offscreen(&dst_texture
->resource
))
3877 struct wined3d_context
*context
= context_acquire(device
,
3878 dst_texture
, dst_sub_resource_idx
);
3879 wined3d_texture_load_location(dst_texture
, dst_sub_resource_idx
,
3880 context
, dst_texture
->resource
.draw_binding
);
3881 context_release(context
);
3887 else if (dst_swapchain
&& dst_swapchain
->back_buffers
3888 && dst_texture
== dst_swapchain
->front_buffer
3889 && src_texture
== dst_swapchain
->back_buffers
[0])
3891 /* Use present for back -> front blits. The idea behind this is
3892 * that present is potentially faster than a blit, in particular
3893 * when FBO blits aren't available. Some ddraw applications like
3894 * Half-Life and Prince of Persia 3D use Blt() from the backbuffer
3895 * to the frontbuffer instead of doing a Flip(). D3D8 and D3D9
3896 * applications can't blit directly to the frontbuffer. */
3897 enum wined3d_swap_effect swap_effect
= dst_swapchain
->desc
.swap_effect
;
3899 TRACE("Using present for backbuffer -> frontbuffer blit.\n");
3901 /* Set the swap effect to COPY, we don't want the backbuffer
3902 * to become undefined. */
3903 dst_swapchain
->desc
.swap_effect
= WINED3D_SWAP_EFFECT_COPY
;
3904 wined3d_swapchain_present(dst_swapchain
, NULL
, NULL
, dst_swapchain
->win_handle
, 0);
3905 dst_swapchain
->desc
.swap_effect
= swap_effect
;
3910 if (fbo_blit_supported(&device
->adapter
->gl_info
, blit_op
,
3911 src_rect
, src_texture
->resource
.usage
, src_texture
->resource
.pool
, src_texture
->resource
.format
,
3912 dst_rect
, dst_texture
->resource
.usage
, dst_texture
->resource
.pool
, dst_texture
->resource
.format
))
3914 struct wined3d_context
*context
;
3915 TRACE("Using FBO blit.\n");
3917 context
= context_acquire(device
, NULL
, 0);
3918 surface_blt_fbo(device
, context
, filter
,
3919 src_surface
, src_texture
->resource
.draw_binding
, src_rect
,
3920 dst_surface
, dst_texture
->resource
.draw_binding
, dst_rect
);
3921 context_release(context
);
3923 wined3d_texture_validate_location(dst_texture
, dst_sub_resource_idx
,
3924 dst_texture
->resource
.draw_binding
);
3925 wined3d_texture_invalidate_location(dst_texture
, dst_sub_resource_idx
,
3926 ~dst_texture
->resource
.draw_binding
);
3931 blitter
= wined3d_select_blitter(&device
->adapter
->gl_info
, &device
->adapter
->d3d_info
, blit_op
,
3932 src_rect
, src_texture
->resource
.usage
, src_texture
->resource
.pool
, src_texture
->resource
.format
,
3933 dst_rect
, dst_texture
->resource
.usage
, dst_texture
->resource
.pool
, dst_texture
->resource
.format
);
3936 blitter
->blit_surface(device
, blit_op
, filter
, src_surface
,
3937 src_rect
, dst_surface
, dst_rect
, color_key
);
3944 /* Special cases for render targets. */
3945 if (SUCCEEDED(surface_blt_special(dst_surface
, dst_rect
, src_surface
, src_rect
, flags
, fx
, filter
)))
3949 return surface_cpu_blt(dst_texture
, dst_sub_resource_idx
, &dst_box
,
3950 src_texture
, src_sub_resource_idx
, &src_box
, flags
, fx
, filter
);