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
;
39 void surface_get_drawable_size(const struct wined3d_surface
*surface
, const struct wined3d_context
*context
,
40 unsigned int *width
, unsigned int *height
)
42 if (surface
->container
->swapchain
)
44 /* The drawable size of an onscreen drawable is the surface size.
45 * (Actually: The window size, but the surface is created in window
47 *width
= context
->current_rt
.texture
->resource
.width
;
48 *height
= context
->current_rt
.texture
->resource
.height
;
50 else if (wined3d_settings
.offscreen_rendering_mode
== ORM_BACKBUFFER
)
52 const struct wined3d_swapchain
*swapchain
= context
->swapchain
;
54 /* The drawable size of a backbuffer / aux buffer offscreen target is
55 * the size of the current context's drawable, which is the size of
56 * the back buffer of the swapchain the active context belongs to. */
57 *width
= swapchain
->desc
.backbuffer_width
;
58 *height
= swapchain
->desc
.backbuffer_height
;
62 struct wined3d_surface
*rt
;
64 /* The drawable size of an FBO target is the OpenGL texture size,
65 * which is the power of two size. */
66 rt
= context
->current_rt
.texture
->sub_resources
[context
->current_rt
.sub_resource_idx
].u
.surface
;
67 *width
= wined3d_texture_get_level_pow2_width(rt
->container
, rt
->texture_level
);
68 *height
= wined3d_texture_get_level_pow2_height(rt
->container
, rt
->texture_level
);
76 enum wined3d_gl_resource_type tex_type
;
88 static inline void cube_coords_float(const RECT
*r
, UINT w
, UINT h
, struct float_rect
*f
)
90 f
->l
= ((r
->left
* 2.0f
) / w
) - 1.0f
;
91 f
->t
= ((r
->top
* 2.0f
) / h
) - 1.0f
;
92 f
->r
= ((r
->right
* 2.0f
) / w
) - 1.0f
;
93 f
->b
= ((r
->bottom
* 2.0f
) / h
) - 1.0f
;
96 static void surface_get_blt_info(GLenum target
, const RECT
*rect
, GLsizei w
, GLsizei h
, struct blt_info
*info
)
98 GLfloat (*coords
)[3] = info
->coords
;
104 FIXME("Unsupported texture target %#x\n", target
);
105 /* Fall back to GL_TEXTURE_2D */
107 info
->binding
= GL_TEXTURE_BINDING_2D
;
108 info
->bind_target
= GL_TEXTURE_2D
;
109 info
->tex_type
= WINED3D_GL_RES_TYPE_TEX_2D
;
110 coords
[0][0] = (float)rect
->left
/ w
;
111 coords
[0][1] = (float)rect
->top
/ h
;
114 coords
[1][0] = (float)rect
->right
/ w
;
115 coords
[1][1] = (float)rect
->top
/ h
;
118 coords
[2][0] = (float)rect
->left
/ w
;
119 coords
[2][1] = (float)rect
->bottom
/ h
;
122 coords
[3][0] = (float)rect
->right
/ w
;
123 coords
[3][1] = (float)rect
->bottom
/ h
;
127 case GL_TEXTURE_RECTANGLE_ARB
:
128 info
->binding
= GL_TEXTURE_BINDING_RECTANGLE_ARB
;
129 info
->bind_target
= GL_TEXTURE_RECTANGLE_ARB
;
130 info
->tex_type
= WINED3D_GL_RES_TYPE_TEX_RECT
;
131 coords
[0][0] = rect
->left
; coords
[0][1] = rect
->top
; coords
[0][2] = 0.0f
;
132 coords
[1][0] = rect
->right
; coords
[1][1] = rect
->top
; coords
[1][2] = 0.0f
;
133 coords
[2][0] = rect
->left
; coords
[2][1] = rect
->bottom
; coords
[2][2] = 0.0f
;
134 coords
[3][0] = rect
->right
; coords
[3][1] = rect
->bottom
; coords
[3][2] = 0.0f
;
137 case GL_TEXTURE_CUBE_MAP_POSITIVE_X
:
138 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
139 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
140 info
->tex_type
= WINED3D_GL_RES_TYPE_TEX_CUBE
;
141 cube_coords_float(rect
, w
, h
, &f
);
143 coords
[0][0] = 1.0f
; coords
[0][1] = -f
.t
; coords
[0][2] = -f
.l
;
144 coords
[1][0] = 1.0f
; coords
[1][1] = -f
.t
; coords
[1][2] = -f
.r
;
145 coords
[2][0] = 1.0f
; coords
[2][1] = -f
.b
; coords
[2][2] = -f
.l
;
146 coords
[3][0] = 1.0f
; coords
[3][1] = -f
.b
; coords
[3][2] = -f
.r
;
149 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X
:
150 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
151 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
152 info
->tex_type
= WINED3D_GL_RES_TYPE_TEX_CUBE
;
153 cube_coords_float(rect
, w
, h
, &f
);
155 coords
[0][0] = -1.0f
; coords
[0][1] = -f
.t
; coords
[0][2] = f
.l
;
156 coords
[1][0] = -1.0f
; coords
[1][1] = -f
.t
; coords
[1][2] = f
.r
;
157 coords
[2][0] = -1.0f
; coords
[2][1] = -f
.b
; coords
[2][2] = f
.l
;
158 coords
[3][0] = -1.0f
; coords
[3][1] = -f
.b
; coords
[3][2] = f
.r
;
161 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y
:
162 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
163 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
164 info
->tex_type
= WINED3D_GL_RES_TYPE_TEX_CUBE
;
165 cube_coords_float(rect
, w
, h
, &f
);
167 coords
[0][0] = f
.l
; coords
[0][1] = 1.0f
; coords
[0][2] = f
.t
;
168 coords
[1][0] = f
.r
; coords
[1][1] = 1.0f
; coords
[1][2] = f
.t
;
169 coords
[2][0] = f
.l
; coords
[2][1] = 1.0f
; coords
[2][2] = f
.b
;
170 coords
[3][0] = f
.r
; coords
[3][1] = 1.0f
; coords
[3][2] = f
.b
;
173 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
:
174 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
175 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
176 info
->tex_type
= WINED3D_GL_RES_TYPE_TEX_CUBE
;
177 cube_coords_float(rect
, w
, h
, &f
);
179 coords
[0][0] = f
.l
; coords
[0][1] = -1.0f
; coords
[0][2] = -f
.t
;
180 coords
[1][0] = f
.r
; coords
[1][1] = -1.0f
; coords
[1][2] = -f
.t
;
181 coords
[2][0] = f
.l
; coords
[2][1] = -1.0f
; coords
[2][2] = -f
.b
;
182 coords
[3][0] = f
.r
; coords
[3][1] = -1.0f
; coords
[3][2] = -f
.b
;
185 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z
:
186 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
187 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
188 info
->tex_type
= WINED3D_GL_RES_TYPE_TEX_CUBE
;
189 cube_coords_float(rect
, w
, h
, &f
);
191 coords
[0][0] = f
.l
; coords
[0][1] = -f
.t
; coords
[0][2] = 1.0f
;
192 coords
[1][0] = f
.r
; coords
[1][1] = -f
.t
; coords
[1][2] = 1.0f
;
193 coords
[2][0] = f
.l
; coords
[2][1] = -f
.b
; coords
[2][2] = 1.0f
;
194 coords
[3][0] = f
.r
; coords
[3][1] = -f
.b
; coords
[3][2] = 1.0f
;
197 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
:
198 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
199 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
200 info
->tex_type
= WINED3D_GL_RES_TYPE_TEX_CUBE
;
201 cube_coords_float(rect
, w
, h
, &f
);
203 coords
[0][0] = -f
.l
; coords
[0][1] = -f
.t
; coords
[0][2] = -1.0f
;
204 coords
[1][0] = -f
.r
; coords
[1][1] = -f
.t
; coords
[1][2] = -1.0f
;
205 coords
[2][0] = -f
.l
; coords
[2][1] = -f
.b
; coords
[2][2] = -1.0f
;
206 coords
[3][0] = -f
.r
; coords
[3][1] = -f
.b
; coords
[3][2] = -1.0f
;
211 static void surface_get_rect(const struct wined3d_surface
*surface
, const RECT
*rect_in
, RECT
*rect_out
)
214 *rect_out
= *rect_in
;
217 const struct wined3d_texture
*texture
= surface
->container
;
219 SetRect(rect_out
, 0, 0, wined3d_texture_get_level_width(texture
, surface
->texture_level
),
220 wined3d_texture_get_level_height(texture
, surface
->texture_level
));
224 /* Context activation is done by the caller. */
225 void draw_textured_quad(const struct wined3d_surface
*src_surface
, struct wined3d_context
*context
,
226 const RECT
*src_rect
, const RECT
*dst_rect
, enum wined3d_texture_filter_type filter
)
228 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
229 struct wined3d_texture
*texture
= src_surface
->container
;
230 struct blt_info info
;
232 surface_get_blt_info(src_surface
->texture_target
, src_rect
,
233 wined3d_texture_get_level_pow2_width(texture
, src_surface
->texture_level
),
234 wined3d_texture_get_level_pow2_height(texture
, src_surface
->texture_level
), &info
);
236 gl_info
->gl_ops
.gl
.p_glEnable(info
.bind_target
);
237 checkGLcall("glEnable(bind_target)");
239 context_bind_texture(context
, info
.bind_target
, texture
->texture_rgb
.name
);
241 /* Filtering for StretchRect */
242 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_MAG_FILTER
, wined3d_gl_mag_filter(filter
));
243 checkGLcall("glTexParameteri");
244 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_MIN_FILTER
,
245 wined3d_gl_min_mip_filter(filter
, WINED3D_TEXF_NONE
));
246 checkGLcall("glTexParameteri");
247 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
248 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
249 if (context
->gl_info
->supported
[EXT_TEXTURE_SRGB_DECODE
])
250 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_SRGB_DECODE_EXT
, GL_SKIP_DECODE_EXT
);
251 gl_info
->gl_ops
.gl
.p_glTexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_REPLACE
);
252 checkGLcall("glTexEnvi");
255 gl_info
->gl_ops
.gl
.p_glBegin(GL_TRIANGLE_STRIP
);
256 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[0]);
257 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
->left
, dst_rect
->top
);
259 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[1]);
260 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
->right
, dst_rect
->top
);
262 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[2]);
263 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
->left
, dst_rect
->bottom
);
265 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[3]);
266 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
->right
, dst_rect
->bottom
);
267 gl_info
->gl_ops
.gl
.p_glEnd();
269 /* Unbind the texture */
270 context_bind_texture(context
, info
.bind_target
, 0);
272 /* We changed the filtering settings on the texture. Inform the
273 * container about this to get the filters reset properly next draw. */
274 texture
->texture_rgb
.sampler_desc
.mag_filter
= WINED3D_TEXF_POINT
;
275 texture
->texture_rgb
.sampler_desc
.min_filter
= WINED3D_TEXF_POINT
;
276 texture
->texture_rgb
.sampler_desc
.mip_filter
= WINED3D_TEXF_NONE
;
277 texture
->texture_rgb
.sampler_desc
.srgb_decode
= FALSE
;
280 /* Works correctly only for <= 4 bpp formats. */
281 static void get_color_masks(const struct wined3d_format
*format
, DWORD
*masks
)
283 masks
[0] = ((1u << format
->red_size
) - 1) << format
->red_offset
;
284 masks
[1] = ((1u << format
->green_size
) - 1) << format
->green_offset
;
285 masks
[2] = ((1u << format
->blue_size
) - 1) << format
->blue_offset
;
288 void wined3d_surface_destroy_dc(struct wined3d_surface
*surface
)
290 unsigned int sub_resource_idx
= surface_get_sub_resource_idx(surface
);
291 struct wined3d_texture
*texture
= surface
->container
;
292 struct wined3d_device
*device
= texture
->resource
.device
;
293 const struct wined3d_gl_info
*gl_info
= NULL
;
294 D3DKMT_DESTROYDCFROMMEMORY destroy_desc
;
295 struct wined3d_context
*context
= NULL
;
296 struct wined3d_bo_address data
;
301 ERR("Surface %p has no DC.\n", surface
);
305 TRACE("dc %p, bitmap %p.\n", surface
->dc
, surface
->bitmap
);
307 destroy_desc
.hDc
= surface
->dc
;
308 destroy_desc
.hBitmap
= surface
->bitmap
;
309 if ((status
= D3DKMTDestroyDCFromMemory(&destroy_desc
)))
310 ERR("Failed to destroy dc, status %#x.\n", status
);
312 surface
->bitmap
= NULL
;
314 if (device
->d3d_initialized
)
316 context
= context_acquire(device
, NULL
);
317 gl_info
= context
->gl_info
;
320 wined3d_texture_get_memory(texture
, sub_resource_idx
, &data
, texture
->resource
.map_binding
);
321 wined3d_texture_unmap_bo_address(&data
, gl_info
, GL_PIXEL_UNPACK_BUFFER
);
324 context_release(context
);
327 HRESULT
wined3d_surface_create_dc(struct wined3d_surface
*surface
)
329 unsigned int sub_resource_idx
= surface_get_sub_resource_idx(surface
);
330 struct wined3d_texture
*texture
= surface
->container
;
331 const struct wined3d_format
*format
= texture
->resource
.format
;
332 struct wined3d_device
*device
= texture
->resource
.device
;
333 const struct wined3d_gl_info
*gl_info
= NULL
;
334 struct wined3d_context
*context
= NULL
;
335 unsigned int row_pitch
, slice_pitch
;
336 struct wined3d_bo_address data
;
337 D3DKMT_CREATEDCFROMMEMORY desc
;
340 TRACE("surface %p.\n", surface
);
342 if (!format
->ddi_format
)
344 WARN("Cannot create a DC for format %s.\n", debug_d3dformat(format
->id
));
345 return WINED3DERR_INVALIDCALL
;
348 wined3d_texture_get_pitch(texture
, surface
->texture_level
, &row_pitch
, &slice_pitch
);
350 if (device
->d3d_initialized
)
352 context
= context_acquire(device
, NULL
);
353 gl_info
= context
->gl_info
;
356 wined3d_texture_get_memory(texture
, sub_resource_idx
, &data
, texture
->resource
.map_binding
);
357 desc
.pMemory
= wined3d_texture_map_bo_address(&data
, texture
->sub_resources
[sub_resource_idx
].size
,
358 gl_info
, GL_PIXEL_UNPACK_BUFFER
, 0);
361 context_release(context
);
363 desc
.Format
= format
->ddi_format
;
364 desc
.Width
= wined3d_texture_get_level_width(texture
, surface
->texture_level
);
365 desc
.Height
= wined3d_texture_get_level_height(texture
, surface
->texture_level
);
366 desc
.Pitch
= row_pitch
;
367 desc
.hDeviceDc
= CreateCompatibleDC(NULL
);
368 desc
.pColorTable
= NULL
;
370 status
= D3DKMTCreateDCFromMemory(&desc
);
371 DeleteDC(desc
.hDeviceDc
);
374 WARN("Failed to create DC, status %#x.\n", status
);
375 return WINED3DERR_INVALIDCALL
;
378 surface
->dc
= desc
.hDc
;
379 surface
->bitmap
= desc
.hBitmap
;
381 TRACE("Created DC %p, bitmap %p for surface %p.\n", surface
->dc
, surface
->bitmap
, surface
);
386 static BOOL
surface_is_full_rect(const struct wined3d_surface
*surface
, const RECT
*r
)
390 t
= wined3d_texture_get_level_width(surface
->container
, surface
->texture_level
);
391 if ((r
->left
&& r
->right
) || abs(r
->right
- r
->left
) != t
)
393 t
= wined3d_texture_get_level_height(surface
->container
, surface
->texture_level
);
394 if ((r
->top
&& r
->bottom
) || abs(r
->bottom
- r
->top
) != t
)
399 static void surface_depth_blt_fbo(const struct wined3d_device
*device
,
400 struct wined3d_surface
*src_surface
, DWORD src_location
, const RECT
*src_rect
,
401 struct wined3d_surface
*dst_surface
, DWORD dst_location
, const RECT
*dst_rect
)
403 unsigned int dst_sub_resource_idx
= surface_get_sub_resource_idx(dst_surface
);
404 unsigned int src_sub_resource_idx
= surface_get_sub_resource_idx(src_surface
);
405 struct wined3d_texture
*dst_texture
= dst_surface
->container
;
406 struct wined3d_texture
*src_texture
= src_surface
->container
;
407 const struct wined3d_gl_info
*gl_info
;
408 struct wined3d_context
*context
;
409 DWORD src_mask
, dst_mask
;
412 TRACE("device %p\n", device
);
413 TRACE("src_surface %p, src_location %s, src_rect %s,\n",
414 src_surface
, wined3d_debug_location(src_location
), wine_dbgstr_rect(src_rect
));
415 TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n",
416 dst_surface
, wined3d_debug_location(dst_location
), wine_dbgstr_rect(dst_rect
));
418 src_mask
= src_texture
->resource
.format_flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
419 dst_mask
= dst_texture
->resource
.format_flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
421 if (src_mask
!= dst_mask
)
423 ERR("Incompatible formats %s and %s.\n",
424 debug_d3dformat(src_texture
->resource
.format
->id
),
425 debug_d3dformat(dst_texture
->resource
.format
->id
));
431 ERR("Not a depth / stencil format: %s.\n",
432 debug_d3dformat(src_texture
->resource
.format
->id
));
437 if (src_mask
& WINED3DFMT_FLAG_DEPTH
)
438 gl_mask
|= GL_DEPTH_BUFFER_BIT
;
439 if (src_mask
& WINED3DFMT_FLAG_STENCIL
)
440 gl_mask
|= GL_STENCIL_BUFFER_BIT
;
442 context
= context_acquire(device
, NULL
);
445 context_release(context
);
446 WARN("Invalid context, skipping blit.\n");
450 /* Make sure the locations are up-to-date. Loading the destination
451 * surface isn't required if the entire surface is overwritten. */
452 wined3d_texture_load_location(src_texture
, src_sub_resource_idx
, context
, src_location
);
453 if (!surface_is_full_rect(dst_surface
, dst_rect
))
454 wined3d_texture_load_location(dst_texture
, dst_sub_resource_idx
, context
, dst_location
);
456 wined3d_texture_prepare_location(dst_texture
, dst_sub_resource_idx
, context
, dst_location
);
458 gl_info
= context
->gl_info
;
460 context_apply_fbo_state_blit(context
, GL_READ_FRAMEBUFFER
, NULL
, src_surface
, src_location
);
461 context_check_fbo_status(context
, GL_READ_FRAMEBUFFER
);
463 context_apply_fbo_state_blit(context
, GL_DRAW_FRAMEBUFFER
, NULL
, dst_surface
, dst_location
);
464 context_set_draw_buffer(context
, GL_NONE
);
465 context_check_fbo_status(context
, GL_DRAW_FRAMEBUFFER
);
466 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
468 if (gl_mask
& GL_DEPTH_BUFFER_BIT
)
470 gl_info
->gl_ops
.gl
.p_glDepthMask(GL_TRUE
);
471 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_ZWRITEENABLE
));
473 if (gl_mask
& GL_STENCIL_BUFFER_BIT
)
475 if (context
->gl_info
->supported
[EXT_STENCIL_TWO_SIDE
])
477 gl_info
->gl_ops
.gl
.p_glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT
);
478 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_TWOSIDEDSTENCILMODE
));
480 gl_info
->gl_ops
.gl
.p_glStencilMask(~0U);
481 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_STENCILWRITEMASK
));
484 gl_info
->gl_ops
.gl
.p_glDisable(GL_SCISSOR_TEST
);
485 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE
));
487 gl_info
->fbo_ops
.glBlitFramebuffer(src_rect
->left
, src_rect
->top
, src_rect
->right
, src_rect
->bottom
,
488 dst_rect
->left
, dst_rect
->top
, dst_rect
->right
, dst_rect
->bottom
, gl_mask
, GL_NEAREST
);
489 checkGLcall("glBlitFramebuffer()");
491 if (wined3d_settings
.strict_draw_ordering
)
492 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
494 context_release(context
);
497 /* Blit between surface locations. Onscreen on different swapchains is not supported.
498 * Depth / stencil is not supported. Context activation is done by the caller. */
499 static void surface_blt_fbo(const struct wined3d_device
*device
,
500 struct wined3d_context
*old_ctx
, enum wined3d_texture_filter_type filter
,
501 struct wined3d_surface
*src_surface
, DWORD src_location
, const RECT
*src_rect_in
,
502 struct wined3d_surface
*dst_surface
, DWORD dst_location
, const RECT
*dst_rect_in
)
504 unsigned int dst_sub_resource_idx
= surface_get_sub_resource_idx(dst_surface
);
505 unsigned int src_sub_resource_idx
= surface_get_sub_resource_idx(src_surface
);
506 struct wined3d_texture
*dst_texture
= dst_surface
->container
;
507 struct wined3d_texture
*src_texture
= src_surface
->container
;
508 const struct wined3d_gl_info
*gl_info
;
509 struct wined3d_context
*context
= old_ctx
;
510 struct wined3d_surface
*required_rt
, *restore_rt
= NULL
;
511 RECT src_rect
, dst_rect
;
515 TRACE("device %p, filter %s,\n", device
, debug_d3dtexturefiltertype(filter
));
516 TRACE("src_surface %p, src_location %s, src_rect %s,\n",
517 src_surface
, wined3d_debug_location(src_location
), wine_dbgstr_rect(src_rect_in
));
518 TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n",
519 dst_surface
, wined3d_debug_location(dst_location
), wine_dbgstr_rect(dst_rect_in
));
521 src_rect
= *src_rect_in
;
522 dst_rect
= *dst_rect_in
;
526 case WINED3D_TEXF_LINEAR
:
527 gl_filter
= GL_LINEAR
;
531 FIXME("Unsupported filter mode %s (%#x).\n", debug_d3dtexturefiltertype(filter
), filter
);
532 case WINED3D_TEXF_NONE
:
533 case WINED3D_TEXF_POINT
:
534 gl_filter
= GL_NEAREST
;
538 /* Resolve the source surface first if needed. */
539 if (src_location
== WINED3D_LOCATION_RB_MULTISAMPLE
540 && (src_texture
->resource
.format
->id
!= dst_texture
->resource
.format
->id
541 || abs(src_rect
.bottom
- src_rect
.top
) != abs(dst_rect
.bottom
- dst_rect
.top
)
542 || abs(src_rect
.right
- src_rect
.left
) != abs(dst_rect
.right
- dst_rect
.left
)))
543 src_location
= WINED3D_LOCATION_RB_RESOLVED
;
545 /* Make sure the locations are up-to-date. Loading the destination
546 * surface isn't required if the entire surface is overwritten. (And is
547 * in fact harmful if we're being called by surface_load_location() with
548 * the purpose of loading the destination surface.) */
549 wined3d_texture_load_location(src_texture
, src_sub_resource_idx
, old_ctx
, src_location
);
550 if (!surface_is_full_rect(dst_surface
, &dst_rect
))
551 wined3d_texture_load_location(dst_texture
, dst_sub_resource_idx
, old_ctx
, dst_location
);
553 wined3d_texture_prepare_location(dst_texture
, dst_sub_resource_idx
, old_ctx
, dst_location
);
556 if (src_location
== WINED3D_LOCATION_DRAWABLE
) required_rt
= src_surface
;
557 else if (dst_location
== WINED3D_LOCATION_DRAWABLE
) required_rt
= dst_surface
;
558 else required_rt
= NULL
;
560 restore_rt
= context_get_rt_surface(old_ctx
);
561 if (restore_rt
!= required_rt
)
562 context
= context_acquire(device
, required_rt
);
568 context_release(context
);
569 WARN("Invalid context, skipping blit.\n");
573 gl_info
= context
->gl_info
;
575 if (src_location
== WINED3D_LOCATION_DRAWABLE
)
577 TRACE("Source surface %p is onscreen.\n", src_surface
);
578 buffer
= wined3d_texture_get_gl_buffer(src_texture
);
579 surface_translate_drawable_coords(src_surface
, context
->win_handle
, &src_rect
);
583 TRACE("Source surface %p is offscreen.\n", src_surface
);
584 buffer
= GL_COLOR_ATTACHMENT0
;
587 context_apply_fbo_state_blit(context
, GL_READ_FRAMEBUFFER
, src_surface
, NULL
, src_location
);
588 gl_info
->gl_ops
.gl
.p_glReadBuffer(buffer
);
589 checkGLcall("glReadBuffer()");
590 context_check_fbo_status(context
, GL_READ_FRAMEBUFFER
);
592 if (dst_location
== WINED3D_LOCATION_DRAWABLE
)
594 TRACE("Destination surface %p is onscreen.\n", dst_surface
);
595 buffer
= wined3d_texture_get_gl_buffer(dst_texture
);
596 surface_translate_drawable_coords(dst_surface
, context
->win_handle
, &dst_rect
);
600 TRACE("Destination surface %p is offscreen.\n", dst_surface
);
601 buffer
= GL_COLOR_ATTACHMENT0
;
604 context_apply_fbo_state_blit(context
, GL_DRAW_FRAMEBUFFER
, dst_surface
, NULL
, dst_location
);
605 context_set_draw_buffer(context
, buffer
);
606 context_check_fbo_status(context
, GL_DRAW_FRAMEBUFFER
);
607 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
609 gl_info
->gl_ops
.gl
.p_glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
610 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE
));
611 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE1
));
612 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE2
));
613 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE3
));
615 gl_info
->gl_ops
.gl
.p_glDisable(GL_SCISSOR_TEST
);
616 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE
));
618 gl_info
->fbo_ops
.glBlitFramebuffer(src_rect
.left
, src_rect
.top
, src_rect
.right
, src_rect
.bottom
,
619 dst_rect
.left
, dst_rect
.top
, dst_rect
.right
, dst_rect
.bottom
, GL_COLOR_BUFFER_BIT
, gl_filter
);
620 checkGLcall("glBlitFramebuffer()");
622 if (wined3d_settings
.strict_draw_ordering
|| (dst_location
== WINED3D_LOCATION_DRAWABLE
623 && dst_texture
->swapchain
->front_buffer
== dst_texture
))
624 gl_info
->gl_ops
.gl
.p_glFlush();
627 context_restore(context
, restore_rt
);
630 static BOOL
fbo_blit_supported(const struct wined3d_gl_info
*gl_info
, enum wined3d_blit_op blit_op
,
631 const RECT
*src_rect
, DWORD src_usage
, enum wined3d_pool src_pool
, const struct wined3d_format
*src_format
,
632 const RECT
*dst_rect
, DWORD dst_usage
, enum wined3d_pool dst_pool
, const struct wined3d_format
*dst_format
)
634 if ((wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
) || !gl_info
->fbo_ops
.glBlitFramebuffer
)
637 /* Source and/or destination need to be on the GL side */
638 if (src_pool
== WINED3D_POOL_SYSTEM_MEM
|| dst_pool
== WINED3D_POOL_SYSTEM_MEM
)
643 case WINED3D_BLIT_OP_COLOR_BLIT
:
644 if (!((src_format
->flags
[WINED3D_GL_RES_TYPE_TEX_2D
] & WINED3DFMT_FLAG_FBO_ATTACHABLE
)
645 || (src_usage
& WINED3DUSAGE_RENDERTARGET
)))
647 if (!((dst_format
->flags
[WINED3D_GL_RES_TYPE_TEX_2D
] & WINED3DFMT_FLAG_FBO_ATTACHABLE
)
648 || (dst_usage
& WINED3DUSAGE_RENDERTARGET
)))
650 if (!(src_format
->id
== dst_format
->id
651 || (is_identity_fixup(src_format
->color_fixup
)
652 && is_identity_fixup(dst_format
->color_fixup
))))
656 case WINED3D_BLIT_OP_DEPTH_BLIT
:
657 if (!(src_format
->flags
[WINED3D_GL_RES_TYPE_TEX_2D
] & (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
)))
659 if (!(dst_format
->flags
[WINED3D_GL_RES_TYPE_TEX_2D
] & (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
)))
661 /* Accept pure swizzle fixups for depth formats. In general we
662 * ignore the stencil component (if present) at the moment and the
663 * swizzle is not relevant with just the depth component. */
664 if (is_complex_fixup(src_format
->color_fixup
) || is_complex_fixup(dst_format
->color_fixup
)
665 || is_scaling_fixup(src_format
->color_fixup
) || is_scaling_fixup(dst_format
->color_fixup
))
676 static BOOL
surface_convert_depth_to_float(const struct wined3d_surface
*surface
, DWORD depth
, float *float_depth
)
678 const struct wined3d_format
*format
= surface
->container
->resource
.format
;
682 case WINED3DFMT_S1_UINT_D15_UNORM
:
683 *float_depth
= depth
/ (float)0x00007fff;
686 case WINED3DFMT_D16_UNORM
:
687 *float_depth
= depth
/ (float)0x0000ffff;
690 case WINED3DFMT_D24_UNORM_S8_UINT
:
691 case WINED3DFMT_X8D24_UNORM
:
692 *float_depth
= depth
/ (float)0x00ffffff;
695 case WINED3DFMT_D32_UNORM
:
696 *float_depth
= depth
/ (float)0xffffffff;
700 ERR("Unhandled conversion from %s to floating point.\n", debug_d3dformat(format
->id
));
707 static HRESULT
wined3d_surface_depth_fill(struct wined3d_surface
*surface
, const RECT
*rect
, float depth
)
709 struct wined3d_resource
*resource
= &surface
->container
->resource
;
710 struct wined3d_device
*device
= resource
->device
;
711 struct wined3d_rendertarget_view_desc view_desc
;
712 struct wined3d_rendertarget_view
*view
;
713 const struct blit_shader
*blitter
;
716 if (!(blitter
= wined3d_select_blitter(&device
->adapter
->gl_info
, &device
->adapter
->d3d_info
,
717 WINED3D_BLIT_OP_DEPTH_FILL
, NULL
, 0, 0, NULL
, rect
, resource
->usage
, resource
->pool
, resource
->format
)))
719 FIXME("No blitter is capable of performing the requested depth fill operation.\n");
720 return WINED3DERR_INVALIDCALL
;
723 view_desc
.format_id
= resource
->format
->id
;
724 view_desc
.u
.texture
.level_idx
= surface
->texture_level
;
725 view_desc
.u
.texture
.layer_idx
= surface
->texture_layer
;
726 view_desc
.u
.texture
.layer_count
= 1;
727 if (FAILED(hr
= wined3d_rendertarget_view_create(&view_desc
,
728 resource
, NULL
, &wined3d_null_parent_ops
, &view
)))
730 ERR("Failed to create rendertarget view, hr %#x.\n", hr
);
734 hr
= blitter
->depth_fill(device
, view
, rect
, WINED3DCLEAR_ZBUFFER
, depth
, 0);
735 wined3d_rendertarget_view_decref(view
);
740 static HRESULT
wined3d_surface_depth_blt(struct wined3d_surface
*src_surface
, DWORD src_location
, const RECT
*src_rect
,
741 struct wined3d_surface
*dst_surface
, DWORD dst_location
, const RECT
*dst_rect
)
743 struct wined3d_texture
*src_texture
= src_surface
->container
;
744 struct wined3d_texture
*dst_texture
= dst_surface
->container
;
745 struct wined3d_device
*device
= src_texture
->resource
.device
;
747 if (!fbo_blit_supported(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_DEPTH_BLIT
,
748 src_rect
, src_texture
->resource
.usage
, src_texture
->resource
.pool
, src_texture
->resource
.format
,
749 dst_rect
, dst_texture
->resource
.usage
, dst_texture
->resource
.pool
, dst_texture
->resource
.format
))
750 return WINED3DERR_INVALIDCALL
;
752 surface_depth_blt_fbo(device
, src_surface
, src_location
, src_rect
, dst_surface
, dst_location
, dst_rect
);
754 surface_modify_ds_location(dst_surface
, dst_location
,
755 dst_surface
->ds_current_size
.cx
, dst_surface
->ds_current_size
.cy
);
760 /* This call just downloads data, the caller is responsible for binding the
761 * correct texture. */
762 /* Context activation is done by the caller. */
763 static void surface_download_data(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
,
766 unsigned int sub_resource_idx
= surface_get_sub_resource_idx(surface
);
767 struct wined3d_texture
*texture
= surface
->container
;
768 const struct wined3d_format
*format
= texture
->resource
.format
;
769 struct wined3d_texture_sub_resource
*sub_resource
;
770 unsigned int dst_row_pitch
, dst_slice_pitch
;
771 unsigned int src_row_pitch
, src_slice_pitch
;
772 struct wined3d_bo_address data
;
773 BYTE
*temporary_mem
= NULL
;
776 /* Only support read back of converted P8 surfaces. */
777 if (texture
->flags
& WINED3D_TEXTURE_CONVERTED
&& format
->id
!= WINED3DFMT_P8_UINT
)
779 ERR("Trying to read back converted surface %p with format %s.\n", surface
, debug_d3dformat(format
->id
));
783 sub_resource
= &texture
->sub_resources
[sub_resource_idx
];
785 if (surface
->texture_target
== GL_TEXTURE_2D_ARRAY
)
787 /* NP2 emulation is not allowed on array textures. */
788 if (texture
->flags
& WINED3D_TEXTURE_COND_NP2_EMULATED
)
789 ERR("Array texture %p uses NP2 emulation.\n", texture
);
791 WARN_(d3d_perf
)("Downloading all miplevel layers to get the surface data for a single sub-resource.\n");
793 if (!(temporary_mem
= wined3d_calloc(texture
->layer_count
, sub_resource
->size
)))
795 ERR("Out of memory.\n");
800 wined3d_texture_get_memory(texture
, sub_resource_idx
, &data
, dst_location
);
802 if (texture
->flags
& WINED3D_TEXTURE_COND_NP2_EMULATED
)
804 wined3d_texture_get_pitch(texture
, surface
->texture_level
, &dst_row_pitch
, &dst_slice_pitch
);
805 wined3d_format_calculate_pitch(format
, texture
->resource
.device
->surface_alignment
,
806 wined3d_texture_get_level_pow2_width(texture
, surface
->texture_level
),
807 wined3d_texture_get_level_pow2_height(texture
, surface
->texture_level
),
808 &src_row_pitch
, &src_slice_pitch
);
809 if (!(temporary_mem
= HeapAlloc(GetProcessHeap(), 0, src_slice_pitch
)))
811 ERR("Out of memory.\n");
815 if (data
.buffer_object
)
816 ERR("NP2 emulated texture uses PBO unexpectedly.\n");
817 if (texture
->resource
.format_flags
& WINED3DFMT_FLAG_COMPRESSED
)
818 ERR("Unexpected compressed format for NP2 emulated texture.\n");
825 else if (data
.buffer_object
)
827 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, data
.buffer_object
));
828 checkGLcall("glBindBuffer");
836 if (texture
->resource
.format_flags
& WINED3DFMT_FLAG_COMPRESSED
)
838 TRACE("Downloading compressed surface %p, level %u, format %#x, type %#x, data %p.\n",
839 surface
, surface
->texture_level
, format
->glFormat
, format
->glType
, mem
);
841 GL_EXTCALL(glGetCompressedTexImage(surface
->texture_target
, surface
->texture_level
, mem
));
842 checkGLcall("glGetCompressedTexImage");
846 TRACE("Downloading surface %p, level %u, format %#x, type %#x, data %p.\n",
847 surface
, surface
->texture_level
, format
->glFormat
, format
->glType
, mem
);
849 gl_info
->gl_ops
.gl
.p_glGetTexImage(surface
->texture_target
, surface
->texture_level
,
850 format
->glFormat
, format
->glType
, mem
);
851 checkGLcall("glGetTexImage");
854 if (texture
->flags
& WINED3D_TEXTURE_COND_NP2_EMULATED
)
856 const BYTE
*src_data
;
860 * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing
861 * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
862 * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width.
864 * We're doing this...
866 * instead of boxing the texture :
867 * |<-texture width ->| -->pow2width| /\
868 * |111111111111111111| | |
869 * |222 Texture 222222| boxed empty | texture height
870 * |3333 Data 33333333| | |
871 * |444444444444444444| | \/
872 * ----------------------------------- |
873 * | boxed empty | boxed empty | pow2height
875 * -----------------------------------
878 * we're repacking the data to the expected texture width
880 * |<-texture width ->| -->pow2width| /\
881 * |111111111111111111222222222222222| |
882 * |222333333333333333333444444444444| texture height
886 * | empty | pow2height
888 * -----------------------------------
892 * |<-texture width ->| /\
893 * |111111111111111111|
894 * |222222222222222222|texture height
895 * |333333333333333333|
896 * |444444444444444444| \/
897 * --------------------
899 * This also means that any references to surface memory should work with the data as if it were a
900 * standard texture with a non-power2 width instead of a texture boxed up to be a power2 texture.
902 * internally the texture is still stored in a boxed format so any references to textureName will
903 * get a boxed texture with width pow2width and not a texture of width resource.width. */
905 dst_data
= data
.addr
;
906 TRACE("Repacking the surface data from pitch %u to pitch %u.\n", src_row_pitch
, dst_row_pitch
);
907 h
= wined3d_texture_get_level_height(texture
, surface
->texture_level
);
908 for (y
= 0; y
< h
; ++y
)
910 memcpy(dst_data
, src_data
, dst_row_pitch
);
911 src_data
+= src_row_pitch
;
912 dst_data
+= dst_row_pitch
;
915 else if (temporary_mem
)
917 void *src_data
= temporary_mem
+ surface
->texture_layer
* sub_resource
->size
;
918 if (data
.buffer_object
)
920 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, data
.buffer_object
));
921 checkGLcall("glBindBuffer");
922 GL_EXTCALL(glBufferSubData(GL_PIXEL_PACK_BUFFER
, 0, sub_resource
->size
, src_data
));
923 checkGLcall("glBufferSubData");
927 memcpy(data
.addr
, src_data
, sub_resource
->size
);
931 if (data
.buffer_object
)
933 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, 0));
934 checkGLcall("glBindBuffer");
937 HeapFree(GetProcessHeap(), 0, temporary_mem
);
940 /* This call just uploads data, the caller is responsible for binding the
941 * correct texture. */
942 /* Context activation is done by the caller. */
943 void wined3d_surface_upload_data(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
,
944 const struct wined3d_format
*format
, const RECT
*src_rect
, UINT src_pitch
, const POINT
*dst_point
,
945 BOOL srgb
, const struct wined3d_const_bo_address
*data
)
947 unsigned int sub_resource_idx
= surface_get_sub_resource_idx(surface
);
948 struct wined3d_texture
*texture
= surface
->container
;
949 UINT update_w
= src_rect
->right
- src_rect
->left
;
950 UINT update_h
= src_rect
->bottom
- src_rect
->top
;
952 TRACE("surface %p, gl_info %p, format %s, src_rect %s, src_pitch %u, dst_point %s, srgb %#x, data {%#x:%p}.\n",
953 surface
, gl_info
, debug_d3dformat(format
->id
), wine_dbgstr_rect(src_rect
), src_pitch
,
954 wine_dbgstr_point(dst_point
), srgb
, data
->buffer_object
, data
->addr
);
956 if (texture
->sub_resources
[sub_resource_idx
].map_count
)
958 WARN("Uploading a surface that is currently mapped, setting WINED3D_TEXTURE_PIN_SYSMEM.\n");
959 texture
->flags
|= WINED3D_TEXTURE_PIN_SYSMEM
;
962 if (format
->flags
[WINED3D_GL_RES_TYPE_TEX_2D
] & WINED3DFMT_FLAG_HEIGHT_SCALE
)
964 update_h
*= format
->height_scale
.numerator
;
965 update_h
/= format
->height_scale
.denominator
;
968 if (data
->buffer_object
)
970 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER
, data
->buffer_object
));
971 checkGLcall("glBindBuffer");
974 if (format
->flags
[WINED3D_GL_RES_TYPE_TEX_2D
] & WINED3DFMT_FLAG_COMPRESSED
)
976 UINT row_length
= wined3d_format_calculate_size(format
, 1, update_w
, 1, 1);
977 UINT row_count
= (update_h
+ format
->block_height
- 1) / format
->block_height
;
978 const BYTE
*addr
= data
->addr
;
981 addr
+= (src_rect
->top
/ format
->block_height
) * src_pitch
;
982 addr
+= (src_rect
->left
/ format
->block_width
) * format
->block_byte_count
;
985 internal
= format
->glGammaInternal
;
986 else if (texture
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
987 && wined3d_resource_is_offscreen(&texture
->resource
))
988 internal
= format
->rtInternal
;
990 internal
= format
->glInternal
;
992 TRACE("Uploading compressed data, target %#x, level %u, layer %u, x %d, y %d, w %u, h %u, "
993 "format %#x, image_size %#x, addr %p.\n",
994 surface
->texture_target
, surface
->texture_level
, surface
->texture_layer
,
995 dst_point
->x
, dst_point
->y
, update_w
, update_h
, internal
, row_count
* row_length
, addr
);
997 if (row_length
== src_pitch
)
999 if (surface
->texture_target
== GL_TEXTURE_2D_ARRAY
)
1001 GL_EXTCALL(glCompressedTexSubImage3D(surface
->texture_target
, surface
->texture_level
,
1002 dst_point
->x
, dst_point
->y
, surface
->texture_layer
, update_w
, update_h
, 1,
1003 internal
, row_count
* row_length
, addr
));
1007 GL_EXTCALL(glCompressedTexSubImage2D(surface
->texture_target
, surface
->texture_level
,
1008 dst_point
->x
, dst_point
->y
, update_w
, update_h
,
1009 internal
, row_count
* row_length
, addr
));
1016 /* glCompressedTexSubImage2D() ignores pixel store state, so we
1017 * can't use the unpack row length like for glTexSubImage2D. */
1018 for (row
= 0, y
= dst_point
->y
; row
< row_count
; ++row
)
1020 if (surface
->texture_target
== GL_TEXTURE_2D_ARRAY
)
1022 GL_EXTCALL(glCompressedTexSubImage3D(surface
->texture_target
, surface
->texture_level
,
1023 dst_point
->x
, y
, surface
->texture_layer
, update_w
, format
->block_height
, 1,
1024 internal
, row_length
, addr
));
1028 GL_EXTCALL(glCompressedTexSubImage2D(surface
->texture_target
, surface
->texture_level
,
1029 dst_point
->x
, y
, update_w
, format
->block_height
, internal
, row_length
, addr
));
1032 y
+= format
->block_height
;
1036 checkGLcall("Upload compressed surface data");
1040 const BYTE
*addr
= data
->addr
;
1042 addr
+= src_rect
->top
* src_pitch
;
1043 addr
+= src_rect
->left
* format
->byte_count
;
1045 TRACE("Uploading data, target %#x, level %u, layer %u, x %d, y %d, w %u, h %u, "
1046 "format %#x, type %#x, addr %p.\n",
1047 surface
->texture_target
, surface
->texture_level
, surface
->texture_layer
,
1048 dst_point
->x
, dst_point
->y
, update_w
, update_h
, format
->glFormat
, format
->glType
, addr
);
1050 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_UNPACK_ROW_LENGTH
, src_pitch
/ format
->byte_count
);
1051 if (surface
->texture_target
== GL_TEXTURE_2D_ARRAY
)
1053 GL_EXTCALL(glTexSubImage3D(surface
->texture_target
, surface
->texture_level
,
1054 dst_point
->x
, dst_point
->y
, surface
->texture_layer
, update_w
, update_h
, 1,
1055 format
->glFormat
, format
->glType
, addr
));
1059 gl_info
->gl_ops
.gl
.p_glTexSubImage2D(surface
->texture_target
, surface
->texture_level
,
1060 dst_point
->x
, dst_point
->y
, update_w
, update_h
, format
->glFormat
, format
->glType
, addr
);
1062 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_UNPACK_ROW_LENGTH
, 0);
1063 checkGLcall("Upload surface data");
1066 if (data
->buffer_object
)
1068 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER
, 0));
1069 checkGLcall("glBindBuffer");
1072 if (wined3d_settings
.strict_draw_ordering
)
1073 gl_info
->gl_ops
.gl
.p_glFlush();
1075 if (gl_info
->quirks
& WINED3D_QUIRK_FBO_TEX_UPDATE
)
1077 struct wined3d_device
*device
= texture
->resource
.device
;
1080 for (i
= 0; i
< device
->context_count
; ++i
)
1082 context_surface_update(device
->contexts
[i
], surface
);
1087 static BOOL
surface_check_block_align_rect(struct wined3d_surface
*surface
, const RECT
*rect
)
1089 struct wined3d_box box
= {rect
->left
, rect
->top
, rect
->right
, rect
->bottom
, 0, 1};
1091 return wined3d_texture_check_block_align(surface
->container
, surface
->texture_level
, &box
);
1094 HRESULT
surface_upload_from_surface(struct wined3d_surface
*dst_surface
, const POINT
*dst_point
,
1095 struct wined3d_surface
*src_surface
, const RECT
*src_rect
)
1097 unsigned int src_sub_resource_idx
= surface_get_sub_resource_idx(src_surface
);
1098 unsigned int dst_sub_resource_idx
= surface_get_sub_resource_idx(dst_surface
);
1099 struct wined3d_texture
*src_texture
= src_surface
->container
;
1100 struct wined3d_texture
*dst_texture
= dst_surface
->container
;
1101 unsigned int src_row_pitch
, src_slice_pitch
;
1102 const struct wined3d_format
*src_format
;
1103 const struct wined3d_format
*dst_format
;
1104 unsigned int src_fmt_flags
, dst_fmt_flags
;
1105 const struct wined3d_gl_info
*gl_info
;
1106 struct wined3d_context
*context
;
1107 struct wined3d_bo_address data
;
1108 UINT update_w
, update_h
;
1113 TRACE("dst_surface %p, dst_point %s, src_surface %p, src_rect %s.\n",
1114 dst_surface
, wine_dbgstr_point(dst_point
),
1115 src_surface
, wine_dbgstr_rect(src_rect
));
1117 src_format
= src_texture
->resource
.format
;
1118 dst_format
= dst_texture
->resource
.format
;
1119 src_fmt_flags
= src_texture
->resource
.format_flags
;
1120 dst_fmt_flags
= dst_texture
->resource
.format_flags
;
1122 if (src_format
->id
!= dst_format
->id
)
1124 WARN("Source and destination surfaces should have the same format.\n");
1125 return WINED3DERR_INVALIDCALL
;
1134 else if (dst_point
->x
< 0 || dst_point
->y
< 0)
1136 WARN("Invalid destination point.\n");
1137 return WINED3DERR_INVALIDCALL
;
1142 SetRect(&r
, 0, 0, wined3d_texture_get_level_width(src_texture
, src_surface
->texture_level
),
1143 wined3d_texture_get_level_height(src_texture
, src_surface
->texture_level
));
1146 else if (src_rect
->left
< 0 || src_rect
->top
< 0 || IsRectEmpty(src_rect
))
1148 WARN("Invalid source rectangle.\n");
1149 return WINED3DERR_INVALIDCALL
;
1152 dst_w
= wined3d_texture_get_level_width(dst_texture
, dst_surface
->texture_level
);
1153 dst_h
= wined3d_texture_get_level_height(dst_texture
, dst_surface
->texture_level
);
1155 update_w
= src_rect
->right
- src_rect
->left
;
1156 update_h
= src_rect
->bottom
- src_rect
->top
;
1158 if (update_w
> dst_w
|| dst_point
->x
> dst_w
- update_w
1159 || update_h
> dst_h
|| dst_point
->y
> dst_h
- update_h
)
1161 WARN("Destination out of bounds.\n");
1162 return WINED3DERR_INVALIDCALL
;
1165 if ((src_fmt_flags
& WINED3DFMT_FLAG_BLOCKS
) && !surface_check_block_align_rect(src_surface
, src_rect
))
1167 WARN("Source rectangle not block-aligned.\n");
1168 return WINED3DERR_INVALIDCALL
;
1171 SetRect(&dst_rect
, dst_point
->x
, dst_point
->y
, dst_point
->x
+ update_w
, dst_point
->y
+ update_h
);
1172 if ((dst_fmt_flags
& WINED3DFMT_FLAG_BLOCKS
) && !surface_check_block_align_rect(dst_surface
, &dst_rect
))
1174 WARN("Destination rectangle not block-aligned.\n");
1175 return WINED3DERR_INVALIDCALL
;
1178 /* Use wined3d_surface_blt() instead of uploading directly if we need conversion. */
1179 if (dst_format
->convert
|| wined3d_format_get_color_key_conversion(dst_texture
, FALSE
))
1180 return wined3d_surface_blt(dst_surface
, &dst_rect
, src_surface
, src_rect
, 0, NULL
, WINED3D_TEXF_POINT
);
1182 context
= context_acquire(dst_texture
->resource
.device
, NULL
);
1183 gl_info
= context
->gl_info
;
1185 /* Only load the surface for partial updates. For newly allocated texture
1186 * the texture wouldn't be the current location, and we'd upload zeroes
1187 * just to overwrite them again. */
1188 if (update_w
== dst_w
&& update_h
== dst_h
)
1189 wined3d_texture_prepare_texture(dst_texture
, context
, FALSE
);
1191 wined3d_texture_load_location(dst_texture
, dst_sub_resource_idx
, context
, WINED3D_LOCATION_TEXTURE_RGB
);
1192 wined3d_texture_bind_and_dirtify(dst_texture
, context
, FALSE
);
1194 wined3d_texture_get_memory(src_texture
, src_sub_resource_idx
, &data
,
1195 src_texture
->sub_resources
[src_sub_resource_idx
].locations
);
1196 wined3d_texture_get_pitch(src_texture
, src_surface
->texture_level
, &src_row_pitch
, &src_slice_pitch
);
1198 wined3d_surface_upload_data(dst_surface
, gl_info
, src_format
, src_rect
,
1199 src_row_pitch
, dst_point
, FALSE
, wined3d_const_bo_address(&data
));
1201 context_release(context
);
1203 wined3d_texture_validate_location(dst_texture
, dst_sub_resource_idx
, WINED3D_LOCATION_TEXTURE_RGB
);
1204 wined3d_texture_invalidate_location(dst_texture
, dst_sub_resource_idx
, ~WINED3D_LOCATION_TEXTURE_RGB
);
1209 /* In D3D the depth stencil dimensions have to be greater than or equal to the
1210 * render target dimensions. With FBOs, the dimensions have to be an exact match. */
1211 /* TODO: We should synchronize the renderbuffer's content with the texture's content. */
1212 /* Context activation is done by the caller. */
1213 void surface_set_compatible_renderbuffer(struct wined3d_surface
*surface
, const struct wined3d_surface
*rt
)
1215 const struct wined3d_gl_info
*gl_info
= &surface
->container
->resource
.device
->adapter
->gl_info
;
1216 struct wined3d_renderbuffer_entry
*entry
;
1217 GLuint renderbuffer
= 0;
1218 unsigned int src_width
, src_height
;
1219 unsigned int width
, height
;
1221 if (rt
&& rt
->container
->resource
.format
->id
!= WINED3DFMT_NULL
)
1223 width
= wined3d_texture_get_level_pow2_width(rt
->container
, rt
->texture_level
);
1224 height
= wined3d_texture_get_level_pow2_height(rt
->container
, rt
->texture_level
);
1228 width
= wined3d_texture_get_level_pow2_width(surface
->container
, surface
->texture_level
);
1229 height
= wined3d_texture_get_level_pow2_height(surface
->container
, surface
->texture_level
);
1232 src_width
= wined3d_texture_get_level_pow2_width(surface
->container
, surface
->texture_level
);
1233 src_height
= wined3d_texture_get_level_pow2_height(surface
->container
, surface
->texture_level
);
1235 /* A depth stencil smaller than the render target is not valid */
1236 if (width
> src_width
|| height
> src_height
) return;
1238 /* Remove any renderbuffer set if the sizes match */
1239 if (gl_info
->supported
[ARB_FRAMEBUFFER_OBJECT
]
1240 || (width
== src_width
&& height
== src_height
))
1242 surface
->current_renderbuffer
= NULL
;
1246 /* Look if we've already got a renderbuffer of the correct dimensions */
1247 LIST_FOR_EACH_ENTRY(entry
, &surface
->renderbuffers
, struct wined3d_renderbuffer_entry
, entry
)
1249 if (entry
->width
== width
&& entry
->height
== height
)
1251 renderbuffer
= entry
->id
;
1252 surface
->current_renderbuffer
= entry
;
1259 gl_info
->fbo_ops
.glGenRenderbuffers(1, &renderbuffer
);
1260 gl_info
->fbo_ops
.glBindRenderbuffer(GL_RENDERBUFFER
, renderbuffer
);
1261 gl_info
->fbo_ops
.glRenderbufferStorage(GL_RENDERBUFFER
,
1262 surface
->container
->resource
.format
->glInternal
, width
, height
);
1264 entry
= HeapAlloc(GetProcessHeap(), 0, sizeof(*entry
));
1265 entry
->width
= width
;
1266 entry
->height
= height
;
1267 entry
->id
= renderbuffer
;
1268 list_add_head(&surface
->renderbuffers
, &entry
->entry
);
1270 surface
->current_renderbuffer
= entry
;
1273 checkGLcall("set_compatible_renderbuffer");
1276 /* See also float_16_to_32() in wined3d_private.h */
1277 static inline unsigned short float_32_to_16(const float *in
)
1280 float tmp
= fabsf(*in
);
1281 unsigned int mantissa
;
1284 /* Deal with special numbers */
1290 return (*in
< 0.0f
? 0xfc00 : 0x7c00);
1292 if (tmp
< (float)(1u << 10))
1298 } while (tmp
< (float)(1u << 10));
1300 else if (tmp
>= (float)(1u << 11))
1306 } while (tmp
>= (float)(1u << 11));
1309 mantissa
= (unsigned int)tmp
;
1310 if (tmp
- mantissa
>= 0.5f
)
1311 ++mantissa
; /* Round to nearest, away from zero. */
1313 exp
+= 10; /* Normalize the mantissa. */
1314 exp
+= 15; /* Exponent is encoded with excess 15. */
1316 if (exp
> 30) /* too big */
1318 ret
= 0x7c00; /* INF */
1322 /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers. */
1325 mantissa
= mantissa
>> 1;
1328 ret
= mantissa
& 0x3ff;
1332 ret
= (exp
<< 10) | (mantissa
& 0x3ff);
1335 ret
|= ((*in
< 0.0f
? 1 : 0) << 15); /* Add the sign */
1339 static void convert_r32_float_r16_float(const BYTE
*src
, BYTE
*dst
,
1340 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
1342 unsigned short *dst_s
;
1346 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
1348 for (y
= 0; y
< h
; ++y
)
1350 src_f
= (const float *)(src
+ y
* pitch_in
);
1351 dst_s
= (unsigned short *) (dst
+ y
* pitch_out
);
1352 for (x
= 0; x
< w
; ++x
)
1354 dst_s
[x
] = float_32_to_16(src_f
+ x
);
1359 static void convert_r5g6b5_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
1360 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
1362 static const unsigned char convert_5to8
[] =
1364 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
1365 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
1366 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
1367 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
1369 static const unsigned char convert_6to8
[] =
1371 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
1372 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
1373 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
1374 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
1375 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
1376 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
1377 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
1378 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
1382 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
1384 for (y
= 0; y
< h
; ++y
)
1386 const WORD
*src_line
= (const WORD
*)(src
+ y
* pitch_in
);
1387 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
1388 for (x
= 0; x
< w
; ++x
)
1390 WORD pixel
= src_line
[x
];
1391 dst_line
[x
] = 0xff000000u
1392 | convert_5to8
[(pixel
& 0xf800u
) >> 11] << 16
1393 | convert_6to8
[(pixel
& 0x07e0u
) >> 5] << 8
1394 | convert_5to8
[(pixel
& 0x001fu
)];
1399 /* We use this for both B8G8R8A8 -> B8G8R8X8 and B8G8R8X8 -> B8G8R8A8, since
1400 * in both cases we're just setting the X / Alpha channel to 0xff. */
1401 static void convert_a8r8g8b8_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
1402 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
1406 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
1408 for (y
= 0; y
< h
; ++y
)
1410 const DWORD
*src_line
= (const DWORD
*)(src
+ y
* pitch_in
);
1411 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
1413 for (x
= 0; x
< w
; ++x
)
1415 dst_line
[x
] = 0xff000000 | (src_line
[x
] & 0xffffff);
1420 static inline BYTE
cliptobyte(int x
)
1422 return (BYTE
)((x
< 0) ? 0 : ((x
> 255) ? 255 : x
));
1425 static void convert_yuy2_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
1426 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
1428 int c2
, d
, e
, r2
= 0, g2
= 0, b2
= 0;
1431 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
1433 for (y
= 0; y
< h
; ++y
)
1435 const BYTE
*src_line
= src
+ y
* pitch_in
;
1436 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
1437 for (x
= 0; x
< w
; ++x
)
1439 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
1440 * C = Y - 16; D = U - 128; E = V - 128;
1441 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
1442 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
1443 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
1444 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
1445 * U and V are shared between the pixels. */
1446 if (!(x
& 1)) /* For every even pixel, read new U and V. */
1448 d
= (int) src_line
[1] - 128;
1449 e
= (int) src_line
[3] - 128;
1451 g2
= - 100 * d
- 208 * e
+ 128;
1454 c2
= 298 * ((int) src_line
[0] - 16);
1455 dst_line
[x
] = 0xff000000
1456 | cliptobyte((c2
+ r2
) >> 8) << 16 /* red */
1457 | cliptobyte((c2
+ g2
) >> 8) << 8 /* green */
1458 | cliptobyte((c2
+ b2
) >> 8); /* blue */
1459 /* Scale RGB values to 0..255 range,
1460 * then clip them if still not in range (may be negative),
1461 * then shift them within DWORD if necessary. */
1467 static void convert_yuy2_r5g6b5(const BYTE
*src
, BYTE
*dst
,
1468 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
1471 int c2
, d
, e
, r2
= 0, g2
= 0, b2
= 0;
1473 TRACE("Converting %ux%u pixels, pitches %u %u\n", w
, h
, pitch_in
, pitch_out
);
1475 for (y
= 0; y
< h
; ++y
)
1477 const BYTE
*src_line
= src
+ y
* pitch_in
;
1478 WORD
*dst_line
= (WORD
*)(dst
+ y
* pitch_out
);
1479 for (x
= 0; x
< w
; ++x
)
1481 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
1482 * C = Y - 16; D = U - 128; E = V - 128;
1483 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
1484 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
1485 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
1486 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
1487 * U and V are shared between the pixels. */
1488 if (!(x
& 1)) /* For every even pixel, read new U and V. */
1490 d
= (int) src_line
[1] - 128;
1491 e
= (int) src_line
[3] - 128;
1493 g2
= - 100 * d
- 208 * e
+ 128;
1496 c2
= 298 * ((int) src_line
[0] - 16);
1497 dst_line
[x
] = (cliptobyte((c2
+ r2
) >> 8) >> 3) << 11 /* red */
1498 | (cliptobyte((c2
+ g2
) >> 8) >> 2) << 5 /* green */
1499 | (cliptobyte((c2
+ b2
) >> 8) >> 3); /* blue */
1500 /* Scale RGB values to 0..255 range,
1501 * then clip them if still not in range (may be negative),
1502 * then shift them within DWORD if necessary. */
1508 struct d3dfmt_converter_desc
1510 enum wined3d_format_id from
, to
;
1511 void (*convert
)(const BYTE
*src
, BYTE
*dst
, DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
);
1514 static const struct d3dfmt_converter_desc converters
[] =
1516 {WINED3DFMT_R32_FLOAT
, WINED3DFMT_R16_FLOAT
, convert_r32_float_r16_float
},
1517 {WINED3DFMT_B5G6R5_UNORM
, WINED3DFMT_B8G8R8X8_UNORM
, convert_r5g6b5_x8r8g8b8
},
1518 {WINED3DFMT_B8G8R8A8_UNORM
, WINED3DFMT_B8G8R8X8_UNORM
, convert_a8r8g8b8_x8r8g8b8
},
1519 {WINED3DFMT_B8G8R8X8_UNORM
, WINED3DFMT_B8G8R8A8_UNORM
, convert_a8r8g8b8_x8r8g8b8
},
1520 {WINED3DFMT_YUY2
, WINED3DFMT_B8G8R8X8_UNORM
, convert_yuy2_x8r8g8b8
},
1521 {WINED3DFMT_YUY2
, WINED3DFMT_B5G6R5_UNORM
, convert_yuy2_r5g6b5
},
1524 static inline const struct d3dfmt_converter_desc
*find_converter(enum wined3d_format_id from
,
1525 enum wined3d_format_id to
)
1529 for (i
= 0; i
< (sizeof(converters
) / sizeof(*converters
)); ++i
)
1531 if (converters
[i
].from
== from
&& converters
[i
].to
== to
)
1532 return &converters
[i
];
1538 static struct wined3d_texture
*surface_convert_format(struct wined3d_texture
*src_texture
,
1539 unsigned int sub_resource_idx
, const struct wined3d_format
*dst_format
)
1541 unsigned int texture_level
= sub_resource_idx
% src_texture
->level_count
;
1542 const struct wined3d_format
*src_format
= src_texture
->resource
.format
;
1543 struct wined3d_device
*device
= src_texture
->resource
.device
;
1544 const struct d3dfmt_converter_desc
*conv
= NULL
;
1545 struct wined3d_texture
*dst_texture
;
1546 struct wined3d_resource_desc desc
;
1547 struct wined3d_map_desc src_map
;
1549 if (!(conv
= find_converter(src_format
->id
, dst_format
->id
)) && (!device
->d3d_initialized
1550 || !is_identity_fixup(src_format
->color_fixup
) || src_format
->convert
1551 || !is_identity_fixup(dst_format
->color_fixup
) || dst_format
->convert
))
1553 FIXME("Cannot find a conversion function from format %s to %s.\n",
1554 debug_d3dformat(src_format
->id
), debug_d3dformat(dst_format
->id
));
1558 /* FIXME: Multisampled conversion? */
1559 desc
.resource_type
= WINED3D_RTYPE_TEXTURE_2D
;
1560 desc
.format
= dst_format
->id
;
1561 desc
.multisample_type
= WINED3D_MULTISAMPLE_NONE
;
1562 desc
.multisample_quality
= 0;
1564 desc
.pool
= WINED3D_POOL_SCRATCH
;
1565 desc
.width
= wined3d_texture_get_level_width(src_texture
, texture_level
);
1566 desc
.height
= wined3d_texture_get_level_height(src_texture
, texture_level
);
1569 if (FAILED(wined3d_texture_create(device
, &desc
, 1, 1,
1570 WINED3D_TEXTURE_CREATE_MAPPABLE
| WINED3D_TEXTURE_CREATE_DISCARD
,
1571 NULL
, NULL
, &wined3d_null_parent_ops
, &dst_texture
)))
1573 ERR("Failed to create a destination texture for conversion.\n");
1577 memset(&src_map
, 0, sizeof(src_map
));
1578 if (FAILED(wined3d_resource_map(&src_texture
->resource
, sub_resource_idx
,
1579 &src_map
, NULL
, WINED3D_MAP_READONLY
)))
1581 ERR("Failed to map the source texture.\n");
1582 wined3d_texture_decref(dst_texture
);
1587 struct wined3d_map_desc dst_map
;
1589 memset(&dst_map
, 0, sizeof(dst_map
));
1590 if (FAILED(wined3d_resource_map(&dst_texture
->resource
, 0, &dst_map
, NULL
, 0)))
1592 ERR("Failed to map the destination texture.\n");
1593 wined3d_resource_unmap(&src_texture
->resource
, sub_resource_idx
);
1594 wined3d_texture_decref(dst_texture
);
1598 conv
->convert(src_map
.data
, dst_map
.data
, src_map
.row_pitch
, dst_map
.row_pitch
, desc
.width
, desc
.height
);
1600 wined3d_resource_unmap(&dst_texture
->resource
, 0);
1604 struct wined3d_bo_address data
= {0, src_map
.data
};
1605 RECT src_rect
= {0, 0, desc
.width
, desc
.height
};
1606 const struct wined3d_gl_info
*gl_info
;
1607 struct wined3d_context
*context
;
1608 POINT dst_point
= {0, 0};
1610 TRACE("Using upload conversion.\n");
1611 context
= context_acquire(device
, NULL
);
1612 gl_info
= context
->gl_info
;
1614 wined3d_texture_prepare_texture(dst_texture
, context
, FALSE
);
1615 wined3d_texture_bind_and_dirtify(dst_texture
, context
, FALSE
);
1616 wined3d_surface_upload_data(dst_texture
->sub_resources
[0].u
.surface
, gl_info
, src_format
,
1617 &src_rect
, src_map
.row_pitch
, &dst_point
, FALSE
, wined3d_const_bo_address(&data
));
1619 context_release(context
);
1621 wined3d_texture_validate_location(dst_texture
, 0, WINED3D_LOCATION_TEXTURE_RGB
);
1622 wined3d_texture_invalidate_location(dst_texture
, 0, ~WINED3D_LOCATION_TEXTURE_RGB
);
1624 wined3d_resource_unmap(&src_texture
->resource
, sub_resource_idx
);
1629 static HRESULT
_Blt_ColorFill(BYTE
*buf
, unsigned int width
, unsigned int height
,
1630 unsigned int bpp
, UINT pitch
, DWORD color
)
1637 #define COLORFILL_ROW(type) \
1639 type *d = (type *)buf; \
1640 for (x = 0; x < width; ++x) \
1641 d[x] = (type)color; \
1647 COLORFILL_ROW(BYTE
);
1651 COLORFILL_ROW(WORD
);
1657 for (x
= 0; x
< width
; ++x
, d
+= 3)
1659 d
[0] = (color
) & 0xff;
1660 d
[1] = (color
>> 8) & 0xff;
1661 d
[2] = (color
>> 16) & 0xff;
1666 COLORFILL_ROW(DWORD
);
1670 FIXME("Color fill not implemented for bpp %u!\n", bpp
* 8);
1671 return WINED3DERR_NOTAVAILABLE
;
1674 #undef COLORFILL_ROW
1676 /* Now copy first row. */
1678 for (y
= 1; y
< height
; ++y
)
1681 memcpy(buf
, first
, width
* bpp
);
1687 static void read_from_framebuffer(struct wined3d_surface
*surface
,
1688 struct wined3d_context
*old_ctx
, DWORD dst_location
)
1690 unsigned int sub_resource_idx
= surface_get_sub_resource_idx(surface
);
1691 struct wined3d_texture
*texture
= surface
->container
;
1692 struct wined3d_device
*device
= texture
->resource
.device
;
1693 const struct wined3d_gl_info
*gl_info
;
1694 struct wined3d_context
*context
= old_ctx
;
1695 struct wined3d_surface
*restore_rt
= NULL
;
1696 unsigned int row_pitch
, slice_pitch
;
1697 unsigned int width
, height
;
1699 BYTE
*row
, *top
, *bottom
;
1701 BOOL srcIsUpsideDown
;
1702 struct wined3d_bo_address data
;
1704 wined3d_texture_get_memory(texture
, sub_resource_idx
, &data
, dst_location
);
1706 restore_rt
= context_get_rt_surface(old_ctx
);
1707 if (restore_rt
!= surface
)
1708 context
= context_acquire(device
, surface
);
1712 context_apply_blit_state(context
, device
);
1713 gl_info
= context
->gl_info
;
1715 /* Select the correct read buffer, and give some debug output.
1716 * There is no need to keep track of the current read buffer or reset it, every part of the code
1717 * that reads sets the read buffer as desired.
1719 if (wined3d_resource_is_offscreen(&texture
->resource
))
1721 /* Mapping the primary render target which is not on a swapchain.
1722 * Read from the back buffer. */
1723 TRACE("Mapping offscreen render target.\n");
1724 gl_info
->gl_ops
.gl
.p_glReadBuffer(context_get_offscreen_gl_buffer(context
));
1725 srcIsUpsideDown
= TRUE
;
1729 /* Onscreen surfaces are always part of a swapchain */
1730 GLenum buffer
= wined3d_texture_get_gl_buffer(texture
);
1731 TRACE("Mapping %#x buffer.\n", buffer
);
1732 gl_info
->gl_ops
.gl
.p_glReadBuffer(buffer
);
1733 checkGLcall("glReadBuffer");
1734 srcIsUpsideDown
= FALSE
;
1737 if (data
.buffer_object
)
1739 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, data
.buffer_object
));
1740 checkGLcall("glBindBuffer");
1743 wined3d_texture_get_pitch(texture
, surface
->texture_level
, &row_pitch
, &slice_pitch
);
1745 /* Setup pixel store pack state -- to glReadPixels into the correct place */
1746 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_PACK_ROW_LENGTH
, row_pitch
/ texture
->resource
.format
->byte_count
);
1747 checkGLcall("glPixelStorei");
1749 width
= wined3d_texture_get_level_width(texture
, surface
->texture_level
);
1750 height
= wined3d_texture_get_level_height(texture
, surface
->texture_level
);
1751 gl_info
->gl_ops
.gl
.p_glReadPixels(0, 0, width
, height
,
1752 texture
->resource
.format
->glFormat
,
1753 texture
->resource
.format
->glType
, data
.addr
);
1754 checkGLcall("glReadPixels");
1756 /* Reset previous pixel store pack state */
1757 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_PACK_ROW_LENGTH
, 0);
1758 checkGLcall("glPixelStorei");
1760 if (!srcIsUpsideDown
)
1762 /* glReadPixels returns the image upside down, and there is no way to
1763 * prevent this. Flip the lines in software. */
1765 if (!(row
= HeapAlloc(GetProcessHeap(), 0, row_pitch
)))
1768 if (data
.buffer_object
)
1770 mem
= GL_EXTCALL(glMapBuffer(GL_PIXEL_PACK_BUFFER
, GL_READ_WRITE
));
1771 checkGLcall("glMapBuffer");
1777 bottom
= mem
+ row_pitch
* (height
- 1);
1778 for (i
= 0; i
< height
/ 2; i
++)
1780 memcpy(row
, top
, row_pitch
);
1781 memcpy(top
, bottom
, row_pitch
);
1782 memcpy(bottom
, row
, row_pitch
);
1784 bottom
-= row_pitch
;
1786 HeapFree(GetProcessHeap(), 0, row
);
1788 if (data
.buffer_object
)
1789 GL_EXTCALL(glUnmapBuffer(GL_PIXEL_PACK_BUFFER
));
1793 if (data
.buffer_object
)
1795 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, 0));
1796 checkGLcall("glBindBuffer");
1800 context_restore(context
, restore_rt
);
1803 /* Read the framebuffer contents into a texture. Note that this function
1804 * doesn't do any kind of flipping. Using this on an onscreen surface will
1805 * result in a flipped D3D texture.
1807 * Context activation is done by the caller. This function may temporarily
1808 * switch to a different context and restore the original one before return. */
1809 void surface_load_fb_texture(struct wined3d_surface
*surface
, BOOL srgb
, struct wined3d_context
*old_ctx
)
1811 struct wined3d_texture
*texture
= surface
->container
;
1812 struct wined3d_device
*device
= texture
->resource
.device
;
1813 const struct wined3d_gl_info
*gl_info
;
1814 struct wined3d_context
*context
= old_ctx
;
1815 struct wined3d_surface
*restore_rt
= NULL
;
1817 restore_rt
= context_get_rt_surface(old_ctx
);
1818 if (restore_rt
!= surface
)
1819 context
= context_acquire(device
, surface
);
1823 gl_info
= context
->gl_info
;
1824 device_invalidate_state(device
, STATE_FRAMEBUFFER
);
1826 wined3d_texture_prepare_texture(texture
, context
, srgb
);
1827 wined3d_texture_bind_and_dirtify(texture
, context
, srgb
);
1829 TRACE("Reading back offscreen render target %p.\n", surface
);
1831 if (wined3d_resource_is_offscreen(&texture
->resource
))
1832 gl_info
->gl_ops
.gl
.p_glReadBuffer(context_get_offscreen_gl_buffer(context
));
1834 gl_info
->gl_ops
.gl
.p_glReadBuffer(wined3d_texture_get_gl_buffer(texture
));
1835 checkGLcall("glReadBuffer");
1837 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(surface
->texture_target
, surface
->texture_level
,
1838 0, 0, 0, 0, wined3d_texture_get_level_width(texture
, surface
->texture_level
),
1839 wined3d_texture_get_level_height(texture
, surface
->texture_level
));
1840 checkGLcall("glCopyTexSubImage2D");
1843 context_restore(context
, restore_rt
);
1846 /* Does a direct frame buffer -> texture copy. Stretching is done with single
1847 * pixel copy calls. */
1848 static void fb_copy_to_texture_direct(struct wined3d_surface
*dst_surface
, struct wined3d_surface
*src_surface
,
1849 const RECT
*src_rect
, const RECT
*dst_rect_in
, enum wined3d_texture_filter_type filter
)
1851 unsigned int dst_sub_resource_idx
= surface_get_sub_resource_idx(dst_surface
);
1852 struct wined3d_texture
*src_texture
= src_surface
->container
;
1853 struct wined3d_texture
*dst_texture
= dst_surface
->container
;
1854 struct wined3d_device
*device
= dst_texture
->resource
.device
;
1855 const struct wined3d_gl_info
*gl_info
;
1857 struct wined3d_context
*context
;
1858 BOOL upsidedown
= FALSE
;
1859 RECT dst_rect
= *dst_rect_in
;
1860 unsigned int src_height
;
1862 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
1863 * glCopyTexSubImage is a bit picky about the parameters we pass to it
1865 if(dst_rect
.top
> dst_rect
.bottom
) {
1866 UINT tmp
= dst_rect
.bottom
;
1867 dst_rect
.bottom
= dst_rect
.top
;
1872 context
= context_acquire(device
, src_surface
);
1873 gl_info
= context
->gl_info
;
1874 context_apply_blit_state(context
, device
);
1875 wined3d_texture_load(dst_texture
, context
, FALSE
);
1877 /* Bind the target texture */
1878 context_bind_texture(context
, dst_texture
->target
, dst_texture
->texture_rgb
.name
);
1879 if (wined3d_resource_is_offscreen(&src_texture
->resource
))
1881 TRACE("Reading from an offscreen target\n");
1882 upsidedown
= !upsidedown
;
1883 gl_info
->gl_ops
.gl
.p_glReadBuffer(context_get_offscreen_gl_buffer(context
));
1887 gl_info
->gl_ops
.gl
.p_glReadBuffer(wined3d_texture_get_gl_buffer(src_texture
));
1889 checkGLcall("glReadBuffer");
1891 xrel
= (float) (src_rect
->right
- src_rect
->left
) / (float) (dst_rect
.right
- dst_rect
.left
);
1892 yrel
= (float) (src_rect
->bottom
- src_rect
->top
) / (float) (dst_rect
.bottom
- dst_rect
.top
);
1894 if ((xrel
- 1.0f
< -eps
) || (xrel
- 1.0f
> eps
))
1896 FIXME_(d3d_perf
)("Doing a pixel by pixel copy from the framebuffer to a texture.\n");
1898 if (filter
!= WINED3D_TEXF_NONE
&& filter
!= WINED3D_TEXF_POINT
)
1899 ERR("Texture filtering not supported in direct blit.\n");
1901 else if ((filter
!= WINED3D_TEXF_NONE
&& filter
!= WINED3D_TEXF_POINT
)
1902 && ((yrel
- 1.0f
< -eps
) || (yrel
- 1.0f
> eps
)))
1904 ERR("Texture filtering not supported in direct blit\n");
1907 src_height
= wined3d_texture_get_level_height(src_texture
, src_surface
->texture_level
);
1909 && !((xrel
- 1.0f
< -eps
) || (xrel
- 1.0f
> eps
))
1910 && !((yrel
- 1.0f
< -eps
) || (yrel
- 1.0f
> eps
)))
1912 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do. */
1913 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(dst_surface
->texture_target
, dst_surface
->texture_level
,
1914 dst_rect
.left
/*xoffset */, dst_rect
.top
/* y offset */,
1915 src_rect
->left
, src_height
- src_rect
->bottom
,
1916 dst_rect
.right
- dst_rect
.left
, dst_rect
.bottom
- dst_rect
.top
);
1921 UINT yoffset
= src_height
- src_rect
->top
+ dst_rect
.top
- 1;
1922 /* I have to process this row by row to swap the image,
1923 * otherwise it would be upside down, so stretching in y direction
1924 * doesn't cost extra time
1926 * However, stretching in x direction can be avoided if not necessary
1928 for(row
= dst_rect
.top
; row
< dst_rect
.bottom
; row
++) {
1929 if ((xrel
- 1.0f
< -eps
) || (xrel
- 1.0f
> eps
))
1931 /* Well, that stuff works, but it's very slow.
1932 * find a better way instead
1936 for (col
= dst_rect
.left
; col
< dst_rect
.right
; ++col
)
1938 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(dst_surface
->texture_target
, dst_surface
->texture_level
,
1939 dst_rect
.left
+ col
/* x offset */, row
/* y offset */,
1940 src_rect
->left
+ col
* xrel
, yoffset
- (int) (row
* yrel
), 1, 1);
1945 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(dst_surface
->texture_target
, dst_surface
->texture_level
,
1946 dst_rect
.left
/* x offset */, row
/* y offset */,
1947 src_rect
->left
, yoffset
- (int) (row
* yrel
), dst_rect
.right
- dst_rect
.left
, 1);
1951 checkGLcall("glCopyTexSubImage2D");
1953 context_release(context
);
1955 /* The texture is now most up to date - If the surface is a render target
1956 * and has a drawable, this path is never entered. */
1957 wined3d_texture_validate_location(dst_texture
, dst_sub_resource_idx
, WINED3D_LOCATION_TEXTURE_RGB
);
1958 wined3d_texture_invalidate_location(dst_texture
, dst_sub_resource_idx
, ~WINED3D_LOCATION_TEXTURE_RGB
);
1961 /* Uses the hardware to stretch and flip the image */
1962 static void fb_copy_to_texture_hwstretch(struct wined3d_surface
*dst_surface
, struct wined3d_surface
*src_surface
,
1963 const RECT
*src_rect
, const RECT
*dst_rect_in
, enum wined3d_texture_filter_type filter
)
1965 unsigned int dst_sub_resource_idx
= surface_get_sub_resource_idx(dst_surface
);
1966 unsigned int src_width
, src_height
, src_pow2_width
, src_pow2_height
;
1967 struct wined3d_texture
*src_texture
= src_surface
->container
;
1968 struct wined3d_texture
*dst_texture
= dst_surface
->container
;
1969 struct wined3d_device
*device
= dst_texture
->resource
.device
;
1970 GLuint src
, backup
= 0;
1971 float left
, right
, top
, bottom
; /* Texture coordinates */
1972 const struct wined3d_gl_info
*gl_info
;
1973 struct wined3d_context
*context
;
1974 GLenum drawBuffer
= GL_BACK
;
1975 GLenum offscreen_buffer
;
1976 GLenum texture_target
;
1977 BOOL noBackBufferBackup
;
1979 BOOL upsidedown
= FALSE
;
1980 RECT dst_rect
= *dst_rect_in
;
1982 TRACE("Using hwstretch blit\n");
1983 /* Activate the Proper context for reading from the source surface, set it up for blitting */
1984 context
= context_acquire(device
, src_surface
);
1985 gl_info
= context
->gl_info
;
1986 context_apply_blit_state(context
, device
);
1987 wined3d_texture_load(dst_texture
, context
, FALSE
);
1989 offscreen_buffer
= context_get_offscreen_gl_buffer(context
);
1990 src_width
= wined3d_texture_get_level_width(src_texture
, src_surface
->texture_level
);
1991 src_height
= wined3d_texture_get_level_height(src_texture
, src_surface
->texture_level
);
1992 src_pow2_width
= wined3d_texture_get_level_pow2_width(src_texture
, src_surface
->texture_level
);
1993 src_pow2_height
= wined3d_texture_get_level_pow2_height(src_texture
, src_surface
->texture_level
);
1995 src_offscreen
= wined3d_resource_is_offscreen(&src_texture
->resource
);
1996 noBackBufferBackup
= src_offscreen
&& wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
;
1997 if (!noBackBufferBackup
&& !src_texture
->texture_rgb
.name
)
1999 /* Get it a description */
2000 wined3d_texture_load(src_texture
, context
, FALSE
);
2003 /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
2004 * This way we don't have to wait for the 2nd readback to finish to leave this function.
2006 if (context
->aux_buffers
>= 2)
2008 /* Got more than one aux buffer? Use the 2nd aux buffer */
2009 drawBuffer
= GL_AUX1
;
2011 else if ((!src_offscreen
|| offscreen_buffer
== GL_BACK
) && context
->aux_buffers
>= 1)
2013 /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
2014 drawBuffer
= GL_AUX0
;
2017 if (noBackBufferBackup
)
2019 gl_info
->gl_ops
.gl
.p_glGenTextures(1, &backup
);
2020 checkGLcall("glGenTextures");
2021 context_bind_texture(context
, GL_TEXTURE_2D
, backup
);
2022 texture_target
= GL_TEXTURE_2D
;
2026 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
2027 * we are reading from the back buffer, the backup can be used as source texture
2029 texture_target
= src_surface
->texture_target
;
2030 context_bind_texture(context
, texture_target
, src_texture
->texture_rgb
.name
);
2031 gl_info
->gl_ops
.gl
.p_glEnable(texture_target
);
2032 checkGLcall("glEnable(texture_target)");
2034 /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
2035 surface_get_sub_resource(src_surface
)->locations
&= ~WINED3D_LOCATION_TEXTURE_RGB
;
2038 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
2039 * glCopyTexSubImage is a bit picky about the parameters we pass to it
2041 if(dst_rect
.top
> dst_rect
.bottom
) {
2042 UINT tmp
= dst_rect
.bottom
;
2043 dst_rect
.bottom
= dst_rect
.top
;
2050 TRACE("Reading from an offscreen target\n");
2051 upsidedown
= !upsidedown
;
2052 gl_info
->gl_ops
.gl
.p_glReadBuffer(offscreen_buffer
);
2056 gl_info
->gl_ops
.gl
.p_glReadBuffer(wined3d_texture_get_gl_buffer(src_texture
));
2059 /* TODO: Only back up the part that will be overwritten */
2060 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(texture_target
, 0, 0, 0, 0, 0, src_width
, src_height
);
2062 checkGLcall("glCopyTexSubImage2D");
2064 /* No issue with overriding these - the sampler is dirty due to blit usage */
2065 gl_info
->gl_ops
.gl
.p_glTexParameteri(texture_target
, GL_TEXTURE_MAG_FILTER
, wined3d_gl_mag_filter(filter
));
2066 checkGLcall("glTexParameteri");
2067 gl_info
->gl_ops
.gl
.p_glTexParameteri(texture_target
, GL_TEXTURE_MIN_FILTER
,
2068 wined3d_gl_min_mip_filter(filter
, WINED3D_TEXF_NONE
));
2069 checkGLcall("glTexParameteri");
2071 if (!src_texture
->swapchain
|| src_texture
== src_texture
->swapchain
->back_buffers
[0])
2073 src
= backup
? backup
: src_texture
->texture_rgb
.name
;
2077 gl_info
->gl_ops
.gl
.p_glReadBuffer(GL_FRONT
);
2078 checkGLcall("glReadBuffer(GL_FRONT)");
2080 gl_info
->gl_ops
.gl
.p_glGenTextures(1, &src
);
2081 checkGLcall("glGenTextures(1, &src)");
2082 context_bind_texture(context
, GL_TEXTURE_2D
, src
);
2084 /* TODO: Only copy the part that will be read. Use src_rect->left,
2085 * src_rect->bottom as origin, but with the width watch out for power
2087 gl_info
->gl_ops
.gl
.p_glTexImage2D(GL_TEXTURE_2D
, 0, GL_RGBA
, src_pow2_width
,
2088 src_pow2_height
, 0, GL_RGBA
, GL_UNSIGNED_BYTE
, NULL
);
2089 checkGLcall("glTexImage2D");
2090 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(GL_TEXTURE_2D
, 0, 0, 0, 0, 0, src_width
, src_height
);
2092 gl_info
->gl_ops
.gl
.p_glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
2093 checkGLcall("glTexParameteri");
2094 gl_info
->gl_ops
.gl
.p_glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
2095 checkGLcall("glTexParameteri");
2097 gl_info
->gl_ops
.gl
.p_glReadBuffer(GL_BACK
);
2098 checkGLcall("glReadBuffer(GL_BACK)");
2100 if (texture_target
!= GL_TEXTURE_2D
)
2102 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
2103 gl_info
->gl_ops
.gl
.p_glEnable(GL_TEXTURE_2D
);
2104 texture_target
= GL_TEXTURE_2D
;
2107 checkGLcall("glEnd and previous");
2109 left
= src_rect
->left
;
2110 right
= src_rect
->right
;
2114 top
= src_height
- src_rect
->top
;
2115 bottom
= src_height
- src_rect
->bottom
;
2119 top
= src_height
- src_rect
->bottom
;
2120 bottom
= src_height
- src_rect
->top
;
2123 if (src_texture
->flags
& WINED3D_TEXTURE_NORMALIZED_COORDS
)
2125 left
/= src_pow2_width
;
2126 right
/= src_pow2_width
;
2127 top
/= src_pow2_height
;
2128 bottom
/= src_pow2_height
;
2131 /* draw the source texture stretched and upside down. The correct surface is bound already */
2132 gl_info
->gl_ops
.gl
.p_glTexParameteri(texture_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
2133 gl_info
->gl_ops
.gl
.p_glTexParameteri(texture_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
2135 context_set_draw_buffer(context
, drawBuffer
);
2136 gl_info
->gl_ops
.gl
.p_glReadBuffer(drawBuffer
);
2138 gl_info
->gl_ops
.gl
.p_glBegin(GL_QUADS
);
2140 gl_info
->gl_ops
.gl
.p_glTexCoord2f(left
, bottom
);
2141 gl_info
->gl_ops
.gl
.p_glVertex2i(0, 0);
2144 gl_info
->gl_ops
.gl
.p_glTexCoord2f(left
, top
);
2145 gl_info
->gl_ops
.gl
.p_glVertex2i(0, dst_rect
.bottom
- dst_rect
.top
);
2148 gl_info
->gl_ops
.gl
.p_glTexCoord2f(right
, top
);
2149 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
.right
- dst_rect
.left
, dst_rect
.bottom
- dst_rect
.top
);
2152 gl_info
->gl_ops
.gl
.p_glTexCoord2f(right
, bottom
);
2153 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
.right
- dst_rect
.left
, 0);
2154 gl_info
->gl_ops
.gl
.p_glEnd();
2155 checkGLcall("glEnd and previous");
2157 if (texture_target
!= dst_surface
->texture_target
)
2159 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
2160 gl_info
->gl_ops
.gl
.p_glEnable(dst_surface
->texture_target
);
2161 texture_target
= dst_surface
->texture_target
;
2164 /* Now read the stretched and upside down image into the destination texture */
2165 context_bind_texture(context
, texture_target
, dst_texture
->texture_rgb
.name
);
2166 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(texture_target
,
2168 dst_rect
.left
, dst_rect
.top
, /* xoffset, yoffset */
2169 0, 0, /* We blitted the image to the origin */
2170 dst_rect
.right
- dst_rect
.left
, dst_rect
.bottom
- dst_rect
.top
);
2171 checkGLcall("glCopyTexSubImage2D");
2173 if (drawBuffer
== GL_BACK
)
2175 /* Write the back buffer backup back. */
2178 if (texture_target
!= GL_TEXTURE_2D
)
2180 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
2181 gl_info
->gl_ops
.gl
.p_glEnable(GL_TEXTURE_2D
);
2182 texture_target
= GL_TEXTURE_2D
;
2184 context_bind_texture(context
, GL_TEXTURE_2D
, backup
);
2188 if (texture_target
!= src_surface
->texture_target
)
2190 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
2191 gl_info
->gl_ops
.gl
.p_glEnable(src_surface
->texture_target
);
2192 texture_target
= src_surface
->texture_target
;
2194 context_bind_texture(context
, src_surface
->texture_target
, src_texture
->texture_rgb
.name
);
2197 gl_info
->gl_ops
.gl
.p_glBegin(GL_QUADS
);
2199 gl_info
->gl_ops
.gl
.p_glTexCoord2f(0.0f
, 0.0f
);
2200 gl_info
->gl_ops
.gl
.p_glVertex2i(0, src_height
);
2203 gl_info
->gl_ops
.gl
.p_glTexCoord2f(0.0f
, (float)src_height
/ (float)src_pow2_height
);
2204 gl_info
->gl_ops
.gl
.p_glVertex2i(0, 0);
2207 gl_info
->gl_ops
.gl
.p_glTexCoord2f((float)src_width
/ (float)src_pow2_width
,
2208 (float)src_height
/ (float)src_pow2_height
);
2209 gl_info
->gl_ops
.gl
.p_glVertex2i(src_width
, 0);
2212 gl_info
->gl_ops
.gl
.p_glTexCoord2f((float)src_width
/ (float)src_pow2_width
, 0.0f
);
2213 gl_info
->gl_ops
.gl
.p_glVertex2i(src_width
, src_height
);
2214 gl_info
->gl_ops
.gl
.p_glEnd();
2216 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
2217 checkGLcall("glDisable(texture_target)");
2220 if (src
!= src_texture
->texture_rgb
.name
&& src
!= backup
)
2222 gl_info
->gl_ops
.gl
.p_glDeleteTextures(1, &src
);
2223 checkGLcall("glDeleteTextures(1, &src)");
2227 gl_info
->gl_ops
.gl
.p_glDeleteTextures(1, &backup
);
2228 checkGLcall("glDeleteTextures(1, &backup)");
2231 if (wined3d_settings
.strict_draw_ordering
)
2232 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
2234 context_release(context
);
2236 /* The texture is now most up to date - If the surface is a render target
2237 * and has a drawable, this path is never entered. */
2238 wined3d_texture_validate_location(dst_texture
, dst_sub_resource_idx
, WINED3D_LOCATION_TEXTURE_RGB
);
2239 wined3d_texture_invalidate_location(dst_texture
, dst_sub_resource_idx
, ~WINED3D_LOCATION_TEXTURE_RGB
);
2242 /* Front buffer coordinates are always full screen coordinates, but our GL
2243 * drawable is limited to the window's client area. The sysmem and texture
2244 * copies do have the full screen size. Note that GL has a bottom-left
2245 * origin, while D3D has a top-left origin. */
2246 void surface_translate_drawable_coords(const struct wined3d_surface
*surface
, HWND window
, RECT
*rect
)
2248 struct wined3d_texture
*texture
= surface
->container
;
2249 UINT drawable_height
;
2251 if (texture
->swapchain
&& texture
== texture
->swapchain
->front_buffer
)
2253 POINT offset
= {0, 0};
2256 ScreenToClient(window
, &offset
);
2257 OffsetRect(rect
, offset
.x
, offset
.y
);
2259 GetClientRect(window
, &windowsize
);
2260 drawable_height
= windowsize
.bottom
- windowsize
.top
;
2264 drawable_height
= wined3d_texture_get_level_height(texture
, surface
->texture_level
);
2267 rect
->top
= drawable_height
- rect
->top
;
2268 rect
->bottom
= drawable_height
- rect
->bottom
;
2271 /* Context activation is done by the caller. */
2272 static void surface_blt_to_drawable(const struct wined3d_device
*device
,
2273 struct wined3d_context
*old_ctx
,
2274 enum wined3d_texture_filter_type filter
, BOOL alpha_test
,
2275 struct wined3d_surface
*src_surface
, const RECT
*src_rect_in
,
2276 struct wined3d_surface
*dst_surface
, const RECT
*dst_rect_in
)
2278 struct wined3d_texture
*src_texture
= src_surface
->container
;
2279 struct wined3d_texture
*dst_texture
= dst_surface
->container
;
2280 const struct wined3d_gl_info
*gl_info
;
2281 struct wined3d_context
*context
= old_ctx
;
2282 struct wined3d_surface
*restore_rt
= NULL
;
2283 RECT src_rect
, dst_rect
;
2285 src_rect
= *src_rect_in
;
2286 dst_rect
= *dst_rect_in
;
2288 restore_rt
= context_get_rt_surface(old_ctx
);
2289 if (restore_rt
!= dst_surface
)
2290 context
= context_acquire(device
, dst_surface
);
2294 gl_info
= context
->gl_info
;
2296 /* Make sure the surface is up-to-date. This should probably use
2297 * surface_load_location() and worry about the destination surface too,
2298 * unless we're overwriting it completely. */
2299 wined3d_texture_load(src_texture
, context
, FALSE
);
2301 /* Activate the destination context, set it up for blitting */
2302 context_apply_blit_state(context
, device
);
2304 if (!wined3d_resource_is_offscreen(&dst_texture
->resource
))
2305 surface_translate_drawable_coords(dst_surface
, context
->win_handle
, &dst_rect
);
2307 device
->blitter
->set_shader(device
->blit_priv
, context
, src_surface
, NULL
);
2311 gl_info
->gl_ops
.gl
.p_glEnable(GL_ALPHA_TEST
);
2312 checkGLcall("glEnable(GL_ALPHA_TEST)");
2314 /* For P8 surfaces, the alpha component contains the palette index.
2315 * Which means that the colorkey is one of the palette entries. In
2316 * other cases pixels that should be masked away have alpha set to 0. */
2317 if (src_texture
->resource
.format
->id
== WINED3DFMT_P8_UINT
)
2318 gl_info
->gl_ops
.gl
.p_glAlphaFunc(GL_NOTEQUAL
,
2319 (float)src_texture
->async
.src_blt_color_key
.color_space_low_value
/ 255.0f
);
2321 gl_info
->gl_ops
.gl
.p_glAlphaFunc(GL_NOTEQUAL
, 0.0f
);
2322 checkGLcall("glAlphaFunc");
2326 gl_info
->gl_ops
.gl
.p_glDisable(GL_ALPHA_TEST
);
2327 checkGLcall("glDisable(GL_ALPHA_TEST)");
2330 draw_textured_quad(src_surface
, context
, &src_rect
, &dst_rect
, filter
);
2334 gl_info
->gl_ops
.gl
.p_glDisable(GL_ALPHA_TEST
);
2335 checkGLcall("glDisable(GL_ALPHA_TEST)");
2338 /* Leave the opengl state valid for blitting */
2339 device
->blitter
->unset_shader(context
->gl_info
);
2341 if (wined3d_settings
.strict_draw_ordering
2342 || (dst_texture
->swapchain
&& dst_texture
->swapchain
->front_buffer
== dst_texture
))
2343 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
2346 context_restore(context
, restore_rt
);
2349 HRESULT
surface_color_fill(struct wined3d_surface
*s
, const RECT
*rect
, const struct wined3d_color
*color
)
2351 struct wined3d_resource
*resource
= &s
->container
->resource
;
2352 struct wined3d_device
*device
= resource
->device
;
2353 struct wined3d_rendertarget_view_desc view_desc
;
2354 struct wined3d_rendertarget_view
*view
;
2355 const struct blit_shader
*blitter
;
2358 if (!(blitter
= wined3d_select_blitter(&device
->adapter
->gl_info
, &device
->adapter
->d3d_info
,
2359 WINED3D_BLIT_OP_COLOR_FILL
, NULL
, 0, 0, NULL
, rect
, resource
->usage
, resource
->pool
, resource
->format
)))
2361 FIXME("No blitter is capable of performing the requested color fill operation.\n");
2362 return WINED3DERR_INVALIDCALL
;
2365 view_desc
.format_id
= resource
->format
->id
;
2366 view_desc
.u
.texture
.level_idx
= s
->texture_level
;
2367 view_desc
.u
.texture
.layer_idx
= s
->texture_layer
;
2368 view_desc
.u
.texture
.layer_count
= 1;
2369 if (FAILED(hr
= wined3d_rendertarget_view_create(&view_desc
,
2370 resource
, NULL
, &wined3d_null_parent_ops
, &view
)))
2372 ERR("Failed to create rendertarget view, hr %#x.\n", hr
);
2376 hr
= blitter
->color_fill(device
, view
, rect
, color
);
2377 wined3d_rendertarget_view_decref(view
);
2382 static HRESULT
surface_blt_special(struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
,
2383 struct wined3d_surface
*src_surface
, const RECT
*src_rect
, DWORD flags
,
2384 const struct wined3d_blt_fx
*fx
, enum wined3d_texture_filter_type filter
)
2386 struct wined3d_texture
*dst_texture
= dst_surface
->container
;
2387 struct wined3d_device
*device
= dst_texture
->resource
.device
;
2388 const struct wined3d_surface
*rt
= wined3d_rendertarget_view_get_surface(device
->fb
.render_targets
[0]);
2389 struct wined3d_swapchain
*src_swapchain
, *dst_swapchain
;
2390 struct wined3d_texture
*src_texture
;
2392 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
2393 dst_surface
, wine_dbgstr_rect(dst_rect
), src_surface
, wine_dbgstr_rect(src_rect
),
2394 flags
, fx
, debug_d3dtexturefiltertype(filter
));
2396 /* Get the swapchain. One of the surfaces has to be a primary surface */
2397 if (dst_texture
->resource
.pool
== WINED3D_POOL_SYSTEM_MEM
)
2399 WARN("Destination is in sysmem, rejecting gl blt\n");
2400 return WINED3DERR_INVALIDCALL
;
2403 dst_swapchain
= dst_texture
->swapchain
;
2407 src_texture
= src_surface
->container
;
2408 if (src_texture
->resource
.pool
== WINED3D_POOL_SYSTEM_MEM
)
2410 WARN("Src is in sysmem, rejecting gl blt\n");
2411 return WINED3DERR_INVALIDCALL
;
2414 src_swapchain
= src_texture
->swapchain
;
2419 src_swapchain
= NULL
;
2422 /* Early sort out of cases where no render target is used */
2423 if (!dst_swapchain
&& !src_swapchain
&& src_surface
!= rt
&& dst_surface
!= rt
)
2425 TRACE("No surface is render target, not using hardware blit.\n");
2426 return WINED3DERR_INVALIDCALL
;
2429 /* No destination color keying supported */
2430 if (flags
& (WINED3D_BLT_DST_CKEY
| WINED3D_BLT_DST_CKEY_OVERRIDE
))
2432 /* Can we support that with glBlendFunc if blitting to the frame buffer? */
2433 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
2434 return WINED3DERR_INVALIDCALL
;
2437 if (dst_swapchain
&& dst_swapchain
== src_swapchain
)
2439 FIXME("Implement hardware blit between two surfaces on the same swapchain\n");
2440 return WINED3DERR_INVALIDCALL
;
2443 if (dst_swapchain
&& src_swapchain
)
2445 FIXME("Implement hardware blit between two different swapchains\n");
2446 return WINED3DERR_INVALIDCALL
;
2451 /* Handled with regular texture -> swapchain blit */
2452 if (src_surface
== rt
)
2453 TRACE("Blit from active render target to a swapchain\n");
2455 else if (src_swapchain
&& dst_surface
== rt
)
2457 FIXME("Implement blit from a swapchain to the active render target\n");
2458 return WINED3DERR_INVALIDCALL
;
2461 if ((src_swapchain
|| src_surface
== rt
) && !dst_swapchain
)
2463 unsigned int src_width
, src_height
;
2464 /* Blit from render target to texture */
2467 /* P8 read back is not implemented */
2468 if (src_texture
->resource
.format
->id
== WINED3DFMT_P8_UINT
2469 || dst_texture
->resource
.format
->id
== WINED3DFMT_P8_UINT
)
2471 TRACE("P8 read back not supported by frame buffer to texture blit\n");
2472 return WINED3DERR_INVALIDCALL
;
2475 if (flags
& (WINED3D_BLT_SRC_CKEY
| WINED3D_BLT_SRC_CKEY_OVERRIDE
))
2477 TRACE("Color keying not supported by frame buffer to texture blit\n");
2478 return WINED3DERR_INVALIDCALL
;
2479 /* Destination color key is checked above */
2482 if (dst_rect
->right
- dst_rect
->left
!= src_rect
->right
- src_rect
->left
)
2487 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
2488 * flip the image nor scale it.
2490 * -> If the app asks for an unscaled, upside down copy, just perform one glCopyTexSubImage2D call
2491 * -> If the app wants an image width an unscaled width, copy it line per line
2492 * -> If the app wants an image that is scaled on the x axis, and the destination rectangle is smaller
2493 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
2494 * back buffer. This is slower than reading line per line, thus not used for flipping
2495 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
2496 * pixel by pixel. */
2497 src_width
= wined3d_texture_get_level_width(src_texture
, src_surface
->texture_level
);
2498 src_height
= wined3d_texture_get_level_height(src_texture
, src_surface
->texture_level
);
2499 if (!stretchx
|| dst_rect
->right
- dst_rect
->left
> src_width
2500 || dst_rect
->bottom
- dst_rect
->top
> src_height
)
2502 TRACE("No stretching in x direction, using direct framebuffer -> texture copy.\n");
2503 fb_copy_to_texture_direct(dst_surface
, src_surface
, src_rect
, dst_rect
, filter
);
2507 TRACE("Using hardware stretching to flip / stretch the texture.\n");
2508 fb_copy_to_texture_hwstretch(dst_surface
, src_surface
, src_rect
, dst_rect
, filter
);
2514 /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
2515 TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
2516 return WINED3DERR_INVALIDCALL
;
2519 /* Context activation is done by the caller. */
2520 static void surface_depth_blt(const struct wined3d_surface
*surface
, struct wined3d_context
*context
,
2521 GLuint texture
, GLint x
, GLint y
, GLsizei w
, GLsizei h
, GLenum target
)
2523 struct wined3d_device
*device
= surface
->container
->resource
.device
;
2524 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
2525 GLint compare_mode
= GL_NONE
;
2526 struct blt_info info
;
2527 GLint old_binding
= 0;
2530 gl_info
->gl_ops
.gl
.p_glPushAttrib(GL_ENABLE_BIT
| GL_DEPTH_BUFFER_BIT
| GL_COLOR_BUFFER_BIT
| GL_VIEWPORT_BIT
);
2532 gl_info
->gl_ops
.gl
.p_glDisable(GL_CULL_FACE
);
2533 gl_info
->gl_ops
.gl
.p_glDisable(GL_BLEND
);
2534 gl_info
->gl_ops
.gl
.p_glDisable(GL_ALPHA_TEST
);
2535 gl_info
->gl_ops
.gl
.p_glDisable(GL_SCISSOR_TEST
);
2536 gl_info
->gl_ops
.gl
.p_glDisable(GL_STENCIL_TEST
);
2537 gl_info
->gl_ops
.gl
.p_glEnable(GL_DEPTH_TEST
);
2538 gl_info
->gl_ops
.gl
.p_glDepthFunc(GL_ALWAYS
);
2539 gl_info
->gl_ops
.gl
.p_glDepthMask(GL_TRUE
);
2540 gl_info
->gl_ops
.gl
.p_glColorMask(GL_FALSE
, GL_FALSE
, GL_FALSE
, GL_FALSE
);
2541 gl_info
->gl_ops
.gl
.p_glViewport(x
, y
, w
, h
);
2542 gl_info
->gl_ops
.gl
.p_glDepthRange(0.0, 1.0);
2544 SetRect(&rect
, 0, h
, w
, 0);
2545 surface_get_blt_info(target
, &rect
,
2546 wined3d_texture_get_level_pow2_width(surface
->container
, surface
->texture_level
),
2547 wined3d_texture_get_level_pow2_height(surface
->container
, surface
->texture_level
), &info
);
2548 context_active_texture(context
, context
->gl_info
, 0);
2549 gl_info
->gl_ops
.gl
.p_glGetIntegerv(info
.binding
, &old_binding
);
2550 gl_info
->gl_ops
.gl
.p_glBindTexture(info
.bind_target
, texture
);
2551 if (gl_info
->supported
[ARB_SHADOW
])
2553 gl_info
->gl_ops
.gl
.p_glGetTexParameteriv(info
.bind_target
, GL_TEXTURE_COMPARE_MODE_ARB
, &compare_mode
);
2554 if (compare_mode
!= GL_NONE
)
2555 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_COMPARE_MODE_ARB
, GL_NONE
);
2558 device
->shader_backend
->shader_select_depth_blt(device
->shader_priv
,
2559 gl_info
, info
.tex_type
, &surface
->ds_current_size
);
2561 gl_info
->gl_ops
.gl
.p_glBegin(GL_TRIANGLE_STRIP
);
2562 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[0]);
2563 gl_info
->gl_ops
.gl
.p_glVertex2f(-1.0f
, -1.0f
);
2564 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[1]);
2565 gl_info
->gl_ops
.gl
.p_glVertex2f(1.0f
, -1.0f
);
2566 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[2]);
2567 gl_info
->gl_ops
.gl
.p_glVertex2f(-1.0f
, 1.0f
);
2568 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[3]);
2569 gl_info
->gl_ops
.gl
.p_glVertex2f(1.0f
, 1.0f
);
2570 gl_info
->gl_ops
.gl
.p_glEnd();
2572 if (compare_mode
!= GL_NONE
)
2573 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_COMPARE_MODE_ARB
, compare_mode
);
2574 gl_info
->gl_ops
.gl
.p_glBindTexture(info
.bind_target
, old_binding
);
2576 gl_info
->gl_ops
.gl
.p_glPopAttrib();
2578 device
->shader_backend
->shader_deselect_depth_blt(device
->shader_priv
, gl_info
);
2581 void surface_modify_ds_location(struct wined3d_surface
*surface
,
2582 DWORD location
, UINT w
, UINT h
)
2584 struct wined3d_texture
*texture
= surface
->container
;
2585 unsigned int sub_resource_idx
;
2587 TRACE("surface %p, new location %#x, w %u, h %u.\n", surface
, location
, w
, h
);
2589 sub_resource_idx
= surface_get_sub_resource_idx(surface
);
2590 surface
->ds_current_size
.cx
= w
;
2591 surface
->ds_current_size
.cy
= h
;
2592 wined3d_texture_validate_location(texture
, sub_resource_idx
, location
);
2593 wined3d_texture_invalidate_location(texture
, sub_resource_idx
, ~location
);
2596 /* Context activation is done by the caller. */
2597 static void surface_load_ds_location(struct wined3d_surface
*surface
, struct wined3d_context
*context
, DWORD location
)
2599 unsigned int sub_resource_idx
= surface_get_sub_resource_idx(surface
);
2600 struct wined3d_texture
*texture
= surface
->container
;
2601 struct wined3d_device
*device
= texture
->resource
.device
;
2602 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
2605 TRACE("surface %p, context %p, new location %#x.\n", surface
, context
, location
);
2607 /* TODO: Make this work for modes other than FBO */
2608 if (wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
) return;
2610 if (!(texture
->sub_resources
[sub_resource_idx
].locations
& location
))
2612 w
= surface
->ds_current_size
.cx
;
2613 h
= surface
->ds_current_size
.cy
;
2614 surface
->ds_current_size
.cx
= 0;
2615 surface
->ds_current_size
.cy
= 0;
2619 w
= wined3d_texture_get_level_width(texture
, surface
->texture_level
);
2620 h
= wined3d_texture_get_level_height(texture
, surface
->texture_level
);
2623 if (surface
->current_renderbuffer
)
2625 FIXME("Not supported with fixed up depth stencil.\n");
2629 wined3d_texture_prepare_location(texture
, sub_resource_idx
, context
, location
);
2631 if (location
== WINED3D_LOCATION_TEXTURE_RGB
)
2633 GLint old_binding
= 0;
2636 /* The render target is allowed to be smaller than the depth/stencil
2637 * buffer, so the onscreen depth/stencil buffer is potentially smaller
2638 * than the offscreen surface. Don't overwrite the offscreen surface
2639 * with undefined data. */
2640 w
= min(w
, context
->swapchain
->desc
.backbuffer_width
);
2641 h
= min(h
, context
->swapchain
->desc
.backbuffer_height
);
2643 TRACE("Copying onscreen depth buffer to depth texture.\n");
2645 if (!device
->depth_blt_texture
)
2646 gl_info
->gl_ops
.gl
.p_glGenTextures(1, &device
->depth_blt_texture
);
2648 /* Note that we use depth_blt here as well, rather than glCopyTexImage2D
2649 * directly on the FBO texture. That's because we need to flip. */
2650 context_apply_fbo_state_blit(context
, GL_FRAMEBUFFER
,
2651 context
->swapchain
->front_buffer
->sub_resources
[0].u
.surface
,
2652 NULL
, WINED3D_LOCATION_DRAWABLE
);
2653 if (surface
->texture_target
== GL_TEXTURE_RECTANGLE_ARB
)
2655 gl_info
->gl_ops
.gl
.p_glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB
, &old_binding
);
2656 bind_target
= GL_TEXTURE_RECTANGLE_ARB
;
2660 gl_info
->gl_ops
.gl
.p_glGetIntegerv(GL_TEXTURE_BINDING_2D
, &old_binding
);
2661 bind_target
= GL_TEXTURE_2D
;
2663 gl_info
->gl_ops
.gl
.p_glBindTexture(bind_target
, device
->depth_blt_texture
);
2664 /* We use GL_DEPTH_COMPONENT instead of the surface's specific
2665 * internal format, because the internal format might include stencil
2666 * data. In principle we should copy stencil data as well, but unless
2667 * the driver supports stencil export it's hard to do, and doesn't
2668 * seem to be needed in practice. If the hardware doesn't support
2669 * writing stencil data, the glCopyTexImage2D() call might trigger
2670 * software fallbacks. */
2671 gl_info
->gl_ops
.gl
.p_glCopyTexImage2D(bind_target
, 0, GL_DEPTH_COMPONENT
, 0, 0, w
, h
, 0);
2672 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
2673 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
2674 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
2675 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
2676 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_TEXTURE_WRAP_R
, GL_CLAMP_TO_EDGE
);
2677 gl_info
->gl_ops
.gl
.p_glBindTexture(bind_target
, old_binding
);
2679 context_apply_fbo_state_blit(context
, GL_FRAMEBUFFER
,
2680 NULL
, surface
, WINED3D_LOCATION_TEXTURE_RGB
);
2681 context_set_draw_buffer(context
, GL_NONE
);
2683 /* Do the actual blit */
2684 surface_depth_blt(surface
, context
, device
->depth_blt_texture
, 0, 0, w
, h
, bind_target
);
2685 checkGLcall("depth_blt");
2687 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
2689 if (wined3d_settings
.strict_draw_ordering
)
2690 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
2692 else if (location
== WINED3D_LOCATION_DRAWABLE
)
2694 TRACE("Copying depth texture to onscreen depth buffer.\n");
2696 context_apply_fbo_state_blit(context
, GL_FRAMEBUFFER
,
2697 context
->swapchain
->front_buffer
->sub_resources
[0].u
.surface
,
2698 NULL
, WINED3D_LOCATION_DRAWABLE
);
2699 surface_depth_blt(surface
, context
, texture
->texture_rgb
.name
, 0,
2700 wined3d_texture_get_level_pow2_height(texture
, surface
->texture_level
) - h
,
2701 w
, h
, surface
->texture_target
);
2702 checkGLcall("depth_blt");
2704 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
2706 if (wined3d_settings
.strict_draw_ordering
)
2707 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
2711 ERR("Invalid location (%#x) specified.\n", location
);
2715 static DWORD
resource_access_from_location(DWORD location
)
2719 case WINED3D_LOCATION_SYSMEM
:
2720 case WINED3D_LOCATION_USER_MEMORY
:
2721 case WINED3D_LOCATION_BUFFER
:
2722 return WINED3D_RESOURCE_ACCESS_CPU
;
2724 case WINED3D_LOCATION_DRAWABLE
:
2725 case WINED3D_LOCATION_TEXTURE_SRGB
:
2726 case WINED3D_LOCATION_TEXTURE_RGB
:
2727 case WINED3D_LOCATION_RB_MULTISAMPLE
:
2728 case WINED3D_LOCATION_RB_RESOLVED
:
2729 return WINED3D_RESOURCE_ACCESS_GPU
;
2732 FIXME("Unhandled location %#x.\n", location
);
2737 static void surface_copy_simple_location(struct wined3d_surface
*surface
, DWORD location
)
2739 unsigned int sub_resource_idx
= surface_get_sub_resource_idx(surface
);
2740 struct wined3d_texture
*texture
= surface
->container
;
2741 struct wined3d_device
*device
= texture
->resource
.device
;
2742 struct wined3d_texture_sub_resource
*sub_resource
;
2743 struct wined3d_context
*context
;
2744 const struct wined3d_gl_info
*gl_info
;
2745 struct wined3d_bo_address dst
, src
;
2747 sub_resource
= &texture
->sub_resources
[sub_resource_idx
];
2748 wined3d_texture_get_memory(texture
, sub_resource_idx
, &dst
, location
);
2749 wined3d_texture_get_memory(texture
, sub_resource_idx
, &src
, sub_resource
->locations
);
2751 if (dst
.buffer_object
)
2753 context
= context_acquire(device
, NULL
);
2754 gl_info
= context
->gl_info
;
2755 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER
, dst
.buffer_object
));
2756 GL_EXTCALL(glBufferSubData(GL_PIXEL_UNPACK_BUFFER
, 0, sub_resource
->size
, src
.addr
));
2757 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER
, 0));
2758 checkGLcall("Upload PBO");
2759 context_release(context
);
2762 if (src
.buffer_object
)
2764 context
= context_acquire(device
, NULL
);
2765 gl_info
= context
->gl_info
;
2766 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, src
.buffer_object
));
2767 GL_EXTCALL(glGetBufferSubData(GL_PIXEL_PACK_BUFFER
, 0, sub_resource
->size
, dst
.addr
));
2768 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, 0));
2769 checkGLcall("Download PBO");
2770 context_release(context
);
2773 memcpy(dst
.addr
, src
.addr
, sub_resource
->size
);
2776 /* Context activation is done by the caller. */
2777 static void surface_load_sysmem(struct wined3d_surface
*surface
,
2778 struct wined3d_context
*context
, DWORD dst_location
)
2780 unsigned int sub_resource_idx
= surface_get_sub_resource_idx(surface
);
2781 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
2782 struct wined3d_texture
*texture
= surface
->container
;
2783 struct wined3d_texture_sub_resource
*sub_resource
;
2785 wined3d_texture_prepare_location(texture
, sub_resource_idx
, context
, dst_location
);
2787 sub_resource
= &texture
->sub_resources
[sub_resource_idx
];
2788 if (sub_resource
->locations
& surface_simple_locations
)
2790 surface_copy_simple_location(surface
, dst_location
);
2794 if (sub_resource
->locations
& (WINED3D_LOCATION_RB_MULTISAMPLE
| WINED3D_LOCATION_RB_RESOLVED
))
2795 wined3d_texture_load_location(texture
, sub_resource_idx
, context
, WINED3D_LOCATION_TEXTURE_RGB
);
2797 /* Download the surface to system memory. */
2798 if (sub_resource
->locations
& (WINED3D_LOCATION_TEXTURE_RGB
| WINED3D_LOCATION_TEXTURE_SRGB
))
2800 wined3d_texture_bind_and_dirtify(texture
, context
,
2801 !(sub_resource
->locations
& WINED3D_LOCATION_TEXTURE_RGB
));
2802 surface_download_data(surface
, gl_info
, dst_location
);
2803 ++texture
->download_count
;
2808 if (sub_resource
->locations
& WINED3D_LOCATION_DRAWABLE
)
2810 read_from_framebuffer(surface
, context
, dst_location
);
2814 FIXME("Can't load surface %p with location flags %s into sysmem.\n",
2815 surface
, wined3d_debug_location(sub_resource
->locations
));
2818 /* Context activation is done by the caller. */
2819 static HRESULT
surface_load_drawable(struct wined3d_surface
*surface
,
2820 struct wined3d_context
*context
)
2822 unsigned int sub_resource_idx
= surface_get_sub_resource_idx(surface
);
2823 struct wined3d_texture
*texture
= surface
->container
;
2826 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
2827 && wined3d_resource_is_offscreen(&texture
->resource
))
2829 ERR("Trying to load offscreen surface into WINED3D_LOCATION_DRAWABLE.\n");
2830 return WINED3DERR_INVALIDCALL
;
2833 surface_get_rect(surface
, NULL
, &r
);
2834 wined3d_texture_load_location(texture
, sub_resource_idx
, context
, WINED3D_LOCATION_TEXTURE_RGB
);
2835 surface_blt_to_drawable(texture
->resource
.device
, context
,
2836 WINED3D_TEXF_POINT
, FALSE
, surface
, &r
, surface
, &r
);
2841 static HRESULT
surface_load_texture(struct wined3d_surface
*surface
,
2842 struct wined3d_context
*context
, BOOL srgb
)
2844 unsigned int width
, height
, src_row_pitch
, src_slice_pitch
, dst_row_pitch
, dst_slice_pitch
;
2845 unsigned int sub_resource_idx
= surface_get_sub_resource_idx(surface
);
2846 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
2847 struct wined3d_texture
*texture
= surface
->container
;
2848 struct wined3d_device
*device
= texture
->resource
.device
;
2849 const struct wined3d_color_key_conversion
*conversion
;
2850 struct wined3d_texture_sub_resource
*sub_resource
;
2851 struct wined3d_bo_address data
;
2852 BYTE
*src_mem
, *dst_mem
= NULL
;
2853 struct wined3d_format format
;
2854 POINT dst_point
= {0, 0};
2857 sub_resource
= surface_get_sub_resource(surface
);
2858 if (wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
2859 && wined3d_resource_is_offscreen(&texture
->resource
)
2860 && (sub_resource
->locations
& WINED3D_LOCATION_DRAWABLE
))
2862 surface_load_fb_texture(surface
, srgb
, context
);
2867 width
= wined3d_texture_get_level_width(texture
, surface
->texture_level
);
2868 height
= wined3d_texture_get_level_height(texture
, surface
->texture_level
);
2869 SetRect(&src_rect
, 0, 0, width
, height
);
2871 if (sub_resource
->locations
& (WINED3D_LOCATION_TEXTURE_SRGB
| WINED3D_LOCATION_TEXTURE_RGB
)
2872 && (texture
->resource
.format_flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB
)
2873 && fbo_blit_supported(gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
2874 NULL
, texture
->resource
.usage
, texture
->resource
.pool
, texture
->resource
.format
,
2875 NULL
, texture
->resource
.usage
, texture
->resource
.pool
, texture
->resource
.format
))
2878 surface_blt_fbo(device
, context
, WINED3D_TEXF_POINT
, surface
, WINED3D_LOCATION_TEXTURE_RGB
,
2879 &src_rect
, surface
, WINED3D_LOCATION_TEXTURE_SRGB
, &src_rect
);
2881 surface_blt_fbo(device
, context
, WINED3D_TEXF_POINT
, surface
, WINED3D_LOCATION_TEXTURE_SRGB
,
2882 &src_rect
, surface
, WINED3D_LOCATION_TEXTURE_RGB
, &src_rect
);
2887 if (sub_resource
->locations
& (WINED3D_LOCATION_RB_MULTISAMPLE
| WINED3D_LOCATION_RB_RESOLVED
)
2888 && (!srgb
|| (texture
->resource
.format_flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB
))
2889 && fbo_blit_supported(gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
2890 NULL
, texture
->resource
.usage
, texture
->resource
.pool
, texture
->resource
.format
,
2891 NULL
, texture
->resource
.usage
, texture
->resource
.pool
, texture
->resource
.format
))
2893 DWORD src_location
= sub_resource
->locations
& WINED3D_LOCATION_RB_RESOLVED
?
2894 WINED3D_LOCATION_RB_RESOLVED
: WINED3D_LOCATION_RB_MULTISAMPLE
;
2895 DWORD dst_location
= srgb
? WINED3D_LOCATION_TEXTURE_SRGB
: WINED3D_LOCATION_TEXTURE_RGB
;
2897 surface_blt_fbo(device
, context
, WINED3D_TEXF_POINT
, surface
, src_location
,
2898 &src_rect
, surface
, dst_location
, &src_rect
);
2903 /* Upload from system memory */
2907 if ((sub_resource
->locations
& (WINED3D_LOCATION_TEXTURE_RGB
| texture
->resource
.map_binding
))
2908 == WINED3D_LOCATION_TEXTURE_RGB
)
2910 FIXME_(d3d_perf
)("Downloading RGB surface %p to reload it as sRGB.\n", surface
);
2911 wined3d_texture_load_location(texture
, sub_resource_idx
, context
, texture
->resource
.map_binding
);
2916 if ((sub_resource
->locations
& (WINED3D_LOCATION_TEXTURE_SRGB
| texture
->resource
.map_binding
))
2917 == WINED3D_LOCATION_TEXTURE_SRGB
)
2919 FIXME_(d3d_perf
)("Downloading sRGB surface %p to reload it as RGB.\n", surface
);
2920 wined3d_texture_load_location(texture
, sub_resource_idx
, context
, texture
->resource
.map_binding
);
2924 if (!(sub_resource
->locations
& surface_simple_locations
))
2926 WARN("Trying to load a texture from sysmem, but no simple location is valid.\n");
2927 /* Lets hope we get it from somewhere... */
2928 wined3d_texture_load_location(texture
, sub_resource_idx
, context
, WINED3D_LOCATION_SYSMEM
);
2931 wined3d_texture_prepare_texture(texture
, context
, srgb
);
2932 wined3d_texture_bind_and_dirtify(texture
, context
, srgb
);
2933 wined3d_texture_get_pitch(texture
, surface
->texture_level
, &src_row_pitch
, &src_slice_pitch
);
2935 format
= *texture
->resource
.format
;
2936 if ((conversion
= wined3d_format_get_color_key_conversion(texture
, TRUE
)))
2937 format
= *wined3d_get_format(gl_info
, conversion
->dst_format
);
2939 /* Don't use PBOs for converted surfaces. During PBO conversion we look at
2940 * WINED3D_TEXTURE_CONVERTED but it isn't set (yet) in all cases it is
2941 * getting called. */
2942 if ((format
.convert
|| conversion
) && texture
->sub_resources
[sub_resource_idx
].buffer_object
)
2944 TRACE("Removing the pbo attached to surface %p.\n", surface
);
2946 wined3d_texture_load_location(texture
, sub_resource_idx
, context
, WINED3D_LOCATION_SYSMEM
);
2947 wined3d_texture_set_map_binding(texture
, WINED3D_LOCATION_SYSMEM
);
2950 wined3d_texture_get_memory(texture
, sub_resource_idx
, &data
, sub_resource
->locations
);
2953 /* This code is entered for texture formats which need a fixup. */
2954 format
.byte_count
= format
.conv_byte_count
;
2955 wined3d_format_calculate_pitch(&format
, 1, width
, height
, &dst_row_pitch
, &dst_slice_pitch
);
2957 src_mem
= wined3d_texture_map_bo_address(&data
, src_slice_pitch
,
2958 gl_info
, GL_PIXEL_UNPACK_BUFFER
, WINED3D_MAP_READONLY
);
2959 if (!(dst_mem
= HeapAlloc(GetProcessHeap(), 0, dst_slice_pitch
)))
2961 ERR("Out of memory (%u).\n", dst_slice_pitch
);
2962 context_release(context
);
2963 return E_OUTOFMEMORY
;
2965 format
.convert(src_mem
, dst_mem
, src_row_pitch
, src_slice_pitch
,
2966 dst_row_pitch
, dst_slice_pitch
, width
, height
, 1);
2967 src_row_pitch
= dst_row_pitch
;
2968 wined3d_texture_unmap_bo_address(&data
, gl_info
, GL_PIXEL_UNPACK_BUFFER
);
2970 data
.buffer_object
= 0;
2971 data
.addr
= dst_mem
;
2973 else if (conversion
)
2975 /* This code is only entered for color keying fixups */
2976 struct wined3d_palette
*palette
= NULL
;
2978 wined3d_format_calculate_pitch(&format
, device
->surface_alignment
,
2979 width
, height
, &dst_row_pitch
, &dst_slice_pitch
);
2981 src_mem
= wined3d_texture_map_bo_address(&data
, src_slice_pitch
,
2982 gl_info
, GL_PIXEL_UNPACK_BUFFER
, WINED3D_MAP_READONLY
);
2983 if (!(dst_mem
= HeapAlloc(GetProcessHeap(), 0, dst_slice_pitch
)))
2985 ERR("Out of memory (%u).\n", dst_slice_pitch
);
2986 context_release(context
);
2987 return E_OUTOFMEMORY
;
2989 if (texture
->swapchain
&& texture
->swapchain
->palette
)
2990 palette
= texture
->swapchain
->palette
;
2991 conversion
->convert(src_mem
, src_row_pitch
, dst_mem
, dst_row_pitch
,
2992 width
, height
, palette
, &texture
->async
.gl_color_key
);
2993 src_row_pitch
= dst_row_pitch
;
2994 wined3d_texture_unmap_bo_address(&data
, gl_info
, GL_PIXEL_UNPACK_BUFFER
);
2996 data
.buffer_object
= 0;
2997 data
.addr
= dst_mem
;
3000 wined3d_surface_upload_data(surface
, gl_info
, &format
, &src_rect
,
3001 src_row_pitch
, &dst_point
, srgb
, wined3d_const_bo_address(&data
));
3003 HeapFree(GetProcessHeap(), 0, dst_mem
);
3008 /* Context activation is done by the caller. */
3009 static void surface_load_renderbuffer(struct wined3d_surface
*surface
, struct wined3d_context
*context
,
3012 struct wined3d_texture
*texture
= surface
->container
;
3013 const RECT rect
= {0, 0,
3014 wined3d_texture_get_level_width(texture
, surface
->texture_level
),
3015 wined3d_texture_get_level_height(texture
, surface
->texture_level
)};
3016 DWORD locations
= surface_get_sub_resource(surface
)->locations
;
3019 if (locations
& WINED3D_LOCATION_RB_MULTISAMPLE
)
3020 src_location
= WINED3D_LOCATION_RB_MULTISAMPLE
;
3021 else if (locations
& WINED3D_LOCATION_RB_RESOLVED
)
3022 src_location
= WINED3D_LOCATION_RB_RESOLVED
;
3023 else if (locations
& WINED3D_LOCATION_TEXTURE_SRGB
)
3024 src_location
= WINED3D_LOCATION_TEXTURE_SRGB
;
3025 else /* surface_blt_fbo will load the source location if necessary. */
3026 src_location
= WINED3D_LOCATION_TEXTURE_RGB
;
3028 surface_blt_fbo(texture
->resource
.device
, context
, WINED3D_TEXF_POINT
,
3029 surface
, src_location
, &rect
, surface
, dst_location
, &rect
);
3032 /* Context activation is done by the caller. Context may be NULL in ddraw-only mode. */
3033 HRESULT
surface_load_location(struct wined3d_surface
*surface
, struct wined3d_context
*context
, DWORD location
)
3035 unsigned int sub_resource_idx
= surface_get_sub_resource_idx(surface
);
3036 struct wined3d_texture
*texture
= surface
->container
;
3037 struct wined3d_texture_sub_resource
*sub_resource
;
3038 unsigned int surface_w
, surface_h
;
3041 TRACE("surface %p, location %s.\n", surface
, wined3d_debug_location(location
));
3043 surface_w
= wined3d_texture_get_level_width(texture
, surface
->texture_level
);
3044 surface_h
= wined3d_texture_get_level_height(texture
, surface
->texture_level
);
3046 sub_resource
= &texture
->sub_resources
[sub_resource_idx
];
3047 if (sub_resource
->locations
& location
&& (!(texture
->resource
.usage
& WINED3DUSAGE_DEPTHSTENCIL
)
3048 || (surface
->ds_current_size
.cx
== surface_w
&& surface
->ds_current_size
.cy
== surface_h
)))
3050 TRACE("Location (%#x) is already up to date.\n", location
);
3056 DWORD required_access
= resource_access_from_location(location
);
3057 if ((texture
->resource
.access_flags
& required_access
) != required_access
)
3058 WARN("Operation requires %#x access, but surface only has %#x.\n",
3059 required_access
, texture
->resource
.access_flags
);
3062 if (sub_resource
->locations
& WINED3D_LOCATION_DISCARDED
)
3064 TRACE("Surface previously discarded, nothing to do.\n");
3065 wined3d_texture_prepare_location(texture
, sub_resource_idx
, context
, location
);
3066 wined3d_texture_validate_location(texture
, sub_resource_idx
, location
);
3067 wined3d_texture_invalidate_location(texture
, sub_resource_idx
, WINED3D_LOCATION_DISCARDED
);
3071 if (!sub_resource
->locations
)
3073 ERR("Surface %p does not have any up to date location.\n", surface
);
3074 wined3d_texture_validate_location(texture
, sub_resource_idx
, WINED3D_LOCATION_DISCARDED
);
3075 return surface_load_location(surface
, context
, location
);
3078 if (texture
->resource
.usage
& WINED3DUSAGE_DEPTHSTENCIL
)
3080 if ((location
== WINED3D_LOCATION_TEXTURE_RGB
&& sub_resource
->locations
& WINED3D_LOCATION_DRAWABLE
)
3081 || (location
== WINED3D_LOCATION_DRAWABLE
&& sub_resource
->locations
& WINED3D_LOCATION_TEXTURE_RGB
))
3083 surface_load_ds_location(surface
, context
, location
);
3087 FIXME("Unimplemented copy from %s to %s for depth/stencil buffers.\n",
3088 wined3d_debug_location(sub_resource
->locations
), wined3d_debug_location(location
));
3089 return WINED3DERR_INVALIDCALL
;
3094 case WINED3D_LOCATION_USER_MEMORY
:
3095 case WINED3D_LOCATION_SYSMEM
:
3096 case WINED3D_LOCATION_BUFFER
:
3097 surface_load_sysmem(surface
, context
, location
);
3100 case WINED3D_LOCATION_DRAWABLE
:
3101 if (FAILED(hr
= surface_load_drawable(surface
, context
)))
3105 case WINED3D_LOCATION_RB_RESOLVED
:
3106 case WINED3D_LOCATION_RB_MULTISAMPLE
:
3107 surface_load_renderbuffer(surface
, context
, location
);
3110 case WINED3D_LOCATION_TEXTURE_RGB
:
3111 case WINED3D_LOCATION_TEXTURE_SRGB
:
3112 if (FAILED(hr
= surface_load_texture(surface
, context
,
3113 location
== WINED3D_LOCATION_TEXTURE_SRGB
)))
3118 ERR("Don't know how to handle location %#x.\n", location
);
3123 wined3d_texture_validate_location(texture
, sub_resource_idx
, location
);
3125 if (texture
->resource
.usage
& WINED3DUSAGE_DEPTHSTENCIL
)
3127 surface
->ds_current_size
.cx
= surface_w
;
3128 surface
->ds_current_size
.cy
= surface_h
;
3134 static HRESULT
ffp_blit_alloc(struct wined3d_device
*device
) { return WINED3D_OK
; }
3135 /* Context activation is done by the caller. */
3136 static void ffp_blit_free(struct wined3d_device
*device
) { }
3138 /* Context activation is done by the caller. */
3139 static HRESULT
ffp_blit_set(void *blit_priv
, struct wined3d_context
*context
, const struct wined3d_surface
*surface
,
3140 const struct wined3d_color_key
*color_key
)
3142 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
3144 gl_info
->gl_ops
.gl
.p_glEnable(surface
->container
->target
);
3145 checkGLcall("glEnable(target)");
3150 /* Context activation is done by the caller. */
3151 static void ffp_blit_unset(const struct wined3d_gl_info
*gl_info
)
3153 gl_info
->gl_ops
.gl
.p_glDisable(GL_TEXTURE_2D
);
3154 checkGLcall("glDisable(GL_TEXTURE_2D)");
3155 if (gl_info
->supported
[ARB_TEXTURE_CUBE_MAP
])
3157 gl_info
->gl_ops
.gl
.p_glDisable(GL_TEXTURE_CUBE_MAP_ARB
);
3158 checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
3160 if (gl_info
->supported
[ARB_TEXTURE_RECTANGLE
])
3162 gl_info
->gl_ops
.gl
.p_glDisable(GL_TEXTURE_RECTANGLE_ARB
);
3163 checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)");
3167 static BOOL
ffp_blit_supported(const struct wined3d_gl_info
*gl_info
,
3168 const struct wined3d_d3d_info
*d3d_info
, enum wined3d_blit_op blit_op
,
3169 const RECT
*src_rect
, DWORD src_usage
, enum wined3d_pool src_pool
, const struct wined3d_format
*src_format
,
3170 const RECT
*dst_rect
, DWORD dst_usage
, enum wined3d_pool dst_pool
, const struct wined3d_format
*dst_format
)
3172 if (src_pool
== WINED3D_POOL_SYSTEM_MEM
|| dst_pool
== WINED3D_POOL_SYSTEM_MEM
)
3174 TRACE("Source or destination is in system memory.\n");
3180 case WINED3D_BLIT_OP_COLOR_BLIT_CKEY
:
3181 if (d3d_info
->shader_color_key
)
3183 TRACE("Color keying requires converted textures.\n");
3186 case WINED3D_BLIT_OP_COLOR_BLIT
:
3187 case WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST
:
3190 TRACE("Checking support for fixup:\n");
3191 dump_color_fixup_desc(src_format
->color_fixup
);
3194 /* We only support identity conversions. */
3195 if (!is_identity_fixup(src_format
->color_fixup
)
3196 || !is_identity_fixup(dst_format
->color_fixup
))
3198 TRACE("Fixups are not supported.\n");
3202 if (!(dst_usage
& WINED3DUSAGE_RENDERTARGET
))
3204 TRACE("Can only blit to render targets.\n");
3209 case WINED3D_BLIT_OP_COLOR_FILL
:
3210 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
)
3212 if (!((dst_format
->flags
[WINED3D_GL_RES_TYPE_TEX_2D
] & WINED3DFMT_FLAG_FBO_ATTACHABLE
)
3213 || (dst_usage
& WINED3DUSAGE_RENDERTARGET
)))
3216 else if (!(dst_usage
& WINED3DUSAGE_RENDERTARGET
))
3218 TRACE("Color fill not supported\n");
3222 /* FIXME: We should reject color fills on formats with fixups,
3223 * but this would break P8 color fills for example. */
3227 case WINED3D_BLIT_OP_DEPTH_FILL
:
3231 TRACE("Unsupported blit_op=%d\n", blit_op
);
3236 static HRESULT
ffp_blit_color_fill(struct wined3d_device
*device
, struct wined3d_rendertarget_view
*view
,
3237 const RECT
*rect
, const struct wined3d_color
*color
)
3239 const RECT draw_rect
= {0, 0, view
->width
, view
->height
};
3240 struct wined3d_fb_state fb
= {&view
, NULL
};
3242 device_clear_render_targets(device
, 1, &fb
, 1, rect
, &draw_rect
, WINED3DCLEAR_TARGET
, color
, 0.0f
, 0);
3247 static HRESULT
ffp_blit_depth_fill(struct wined3d_device
*device
,
3248 struct wined3d_rendertarget_view
*view
, const RECT
*rect
, DWORD clear_flags
,
3249 float depth
, DWORD stencil
)
3251 const RECT draw_rect
= {0, 0, view
->width
, view
->height
};
3252 struct wined3d_fb_state fb
= {NULL
, view
};
3254 device_clear_render_targets(device
, 0, &fb
, 1, rect
, &draw_rect
, clear_flags
, NULL
, depth
, stencil
);
3259 static void ffp_blit_blit_surface(struct wined3d_device
*device
, enum wined3d_blit_op op
, DWORD filter
,
3260 struct wined3d_surface
*src_surface
, const RECT
*src_rect
,
3261 struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
,
3262 const struct wined3d_color_key
*color_key
)
3264 unsigned int dst_sub_resource_idx
= surface_get_sub_resource_idx(dst_surface
);
3265 struct wined3d_texture
*dst_texture
= dst_surface
->container
;
3266 struct wined3d_texture
*src_texture
= src_surface
->container
;
3267 struct wined3d_context
*context
;
3269 /* Blit from offscreen surface to render target */
3270 struct wined3d_color_key old_blt_key
= src_texture
->async
.src_blt_color_key
;
3271 DWORD old_color_key_flags
= src_texture
->async
.color_key_flags
;
3273 TRACE("Blt from surface %p to rendertarget %p\n", src_surface
, dst_surface
);
3275 wined3d_texture_set_color_key(src_texture
, WINED3D_CKEY_SRC_BLT
, color_key
);
3277 context
= context_acquire(device
, dst_surface
);
3279 if (op
== WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST
)
3280 glEnable(GL_ALPHA_TEST
);
3282 surface_blt_to_drawable(device
, context
, filter
,
3283 !!color_key
, src_surface
, src_rect
, dst_surface
, dst_rect
);
3285 if (op
== WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST
)
3286 glDisable(GL_ALPHA_TEST
);
3288 context_release(context
);
3290 /* Restore the color key parameters */
3291 wined3d_texture_set_color_key(src_texture
, WINED3D_CKEY_SRC_BLT
,
3292 (old_color_key_flags
& WINED3D_CKEY_SRC_BLT
) ? &old_blt_key
: NULL
);
3294 wined3d_texture_validate_location(dst_texture
, dst_sub_resource_idx
, dst_texture
->resource
.draw_binding
);
3295 wined3d_texture_invalidate_location(dst_texture
, dst_sub_resource_idx
, ~dst_texture
->resource
.draw_binding
);
3298 const struct blit_shader ffp_blit
= {
3304 ffp_blit_color_fill
,
3305 ffp_blit_depth_fill
,
3306 ffp_blit_blit_surface
,
3309 static HRESULT
cpu_blit_alloc(struct wined3d_device
*device
)
3314 /* Context activation is done by the caller. */
3315 static void cpu_blit_free(struct wined3d_device
*device
)
3319 /* Context activation is done by the caller. */
3320 static HRESULT
cpu_blit_set(void *blit_priv
, struct wined3d_context
*context
, const struct wined3d_surface
*surface
,
3321 const struct wined3d_color_key
*color_key
)
3326 /* Context activation is done by the caller. */
3327 static void cpu_blit_unset(const struct wined3d_gl_info
*gl_info
)
3331 static BOOL
cpu_blit_supported(const struct wined3d_gl_info
*gl_info
,
3332 const struct wined3d_d3d_info
*d3d_info
, enum wined3d_blit_op blit_op
,
3333 const RECT
*src_rect
, DWORD src_usage
, enum wined3d_pool src_pool
, const struct wined3d_format
*src_format
,
3334 const RECT
*dst_rect
, DWORD dst_usage
, enum wined3d_pool dst_pool
, const struct wined3d_format
*dst_format
)
3336 if (blit_op
== WINED3D_BLIT_OP_COLOR_FILL
)
3344 static HRESULT
surface_cpu_blt_compressed(const BYTE
*src_data
, BYTE
*dst_data
,
3345 UINT src_pitch
, UINT dst_pitch
, UINT update_w
, UINT update_h
,
3346 const struct wined3d_format
*format
, DWORD flags
, const struct wined3d_blt_fx
*fx
)
3348 UINT row_block_count
;
3349 const BYTE
*src_row
;
3356 row_block_count
= (update_w
+ format
->block_width
- 1) / format
->block_width
;
3360 for (y
= 0; y
< update_h
; y
+= format
->block_height
)
3362 memcpy(dst_row
, src_row
, row_block_count
* format
->block_byte_count
);
3363 src_row
+= src_pitch
;
3364 dst_row
+= dst_pitch
;
3370 if (flags
== WINED3D_BLT_FX
&& fx
->fx
== WINEDDBLTFX_MIRRORUPDOWN
)
3372 src_row
+= (((update_h
/ format
->block_height
) - 1) * src_pitch
);
3376 case WINED3DFMT_DXT1
:
3377 for (y
= 0; y
< update_h
; y
+= format
->block_height
)
3382 BYTE control_row
[4];
3385 const struct block
*s
= (const struct block
*)src_row
;
3386 struct block
*d
= (struct block
*)dst_row
;
3388 for (x
= 0; x
< row_block_count
; ++x
)
3390 d
[x
].color
[0] = s
[x
].color
[0];
3391 d
[x
].color
[1] = s
[x
].color
[1];
3392 d
[x
].control_row
[0] = s
[x
].control_row
[3];
3393 d
[x
].control_row
[1] = s
[x
].control_row
[2];
3394 d
[x
].control_row
[2] = s
[x
].control_row
[1];
3395 d
[x
].control_row
[3] = s
[x
].control_row
[0];
3397 src_row
-= src_pitch
;
3398 dst_row
+= dst_pitch
;
3402 case WINED3DFMT_DXT2
:
3403 case WINED3DFMT_DXT3
:
3404 for (y
= 0; y
< update_h
; y
+= format
->block_height
)
3410 BYTE control_row
[4];
3413 const struct block
*s
= (const struct block
*)src_row
;
3414 struct block
*d
= (struct block
*)dst_row
;
3416 for (x
= 0; x
< row_block_count
; ++x
)
3418 d
[x
].alpha_row
[0] = s
[x
].alpha_row
[3];
3419 d
[x
].alpha_row
[1] = s
[x
].alpha_row
[2];
3420 d
[x
].alpha_row
[2] = s
[x
].alpha_row
[1];
3421 d
[x
].alpha_row
[3] = s
[x
].alpha_row
[0];
3422 d
[x
].color
[0] = s
[x
].color
[0];
3423 d
[x
].color
[1] = s
[x
].color
[1];
3424 d
[x
].control_row
[0] = s
[x
].control_row
[3];
3425 d
[x
].control_row
[1] = s
[x
].control_row
[2];
3426 d
[x
].control_row
[2] = s
[x
].control_row
[1];
3427 d
[x
].control_row
[3] = s
[x
].control_row
[0];
3429 src_row
-= src_pitch
;
3430 dst_row
+= dst_pitch
;
3435 FIXME("Compressed flip not implemented for format %s.\n",
3436 debug_d3dformat(format
->id
));
3441 FIXME("Unsupported blit on compressed surface (format %s, flags %#x, DDFX %#x).\n",
3442 debug_d3dformat(format
->id
), flags
, flags
& WINED3D_BLT_FX
? fx
->fx
: 0);
3447 static HRESULT
surface_cpu_blt(struct wined3d_texture
*dst_texture
, unsigned int dst_sub_resource_idx
,
3448 const struct wined3d_box
*dst_box
, struct wined3d_texture
*src_texture
, unsigned int src_sub_resource_idx
,
3449 const struct wined3d_box
*src_box
, DWORD flags
, const struct wined3d_blt_fx
*fx
,
3450 enum wined3d_texture_filter_type filter
)
3452 unsigned int bpp
, src_height
, src_width
, dst_height
, dst_width
, row_byte_count
;
3453 const struct wined3d_format
*src_format
, *dst_format
;
3454 struct wined3d_texture
*converted_texture
= NULL
;
3455 unsigned int src_fmt_flags
, dst_fmt_flags
;
3456 struct wined3d_map_desc dst_map
, src_map
;
3457 const BYTE
*sbase
= NULL
;
3458 HRESULT hr
= WINED3D_OK
;
3459 BOOL same_sub_resource
;
3464 TRACE("dst_texture %p, dst_sub_resource_idx %u, dst_box %s, src_texture %p, "
3465 "src_sub_resource_idx %u, src_box %s, flags %#x, fx %p, filter %s.\n",
3466 dst_texture
, dst_sub_resource_idx
, debug_box(dst_box
), src_texture
,
3467 src_sub_resource_idx
, debug_box(src_box
), flags
, fx
, debug_d3dtexturefiltertype(filter
));
3469 if (src_texture
== dst_texture
&& src_sub_resource_idx
== dst_sub_resource_idx
)
3471 same_sub_resource
= TRUE
;
3472 wined3d_resource_map(&dst_texture
->resource
, dst_sub_resource_idx
, &dst_map
, NULL
, 0);
3474 src_format
= dst_texture
->resource
.format
;
3475 dst_format
= src_format
;
3476 dst_fmt_flags
= dst_texture
->resource
.format_flags
;
3477 src_fmt_flags
= dst_fmt_flags
;
3481 same_sub_resource
= FALSE
;
3482 dst_format
= dst_texture
->resource
.format
;
3483 dst_fmt_flags
= dst_texture
->resource
.format_flags
;
3486 if (dst_texture
->resource
.format
->id
!= src_texture
->resource
.format
->id
)
3488 if (!(converted_texture
= surface_convert_format(src_texture
, src_sub_resource_idx
, dst_format
)))
3490 FIXME("Cannot convert %s to %s.\n", debug_d3dformat(src_texture
->resource
.format
->id
),
3491 debug_d3dformat(dst_texture
->resource
.format
->id
));
3492 return WINED3DERR_NOTAVAILABLE
;
3494 src_texture
= converted_texture
;
3495 src_sub_resource_idx
= 0;
3497 wined3d_resource_map(&src_texture
->resource
, src_sub_resource_idx
, &src_map
, NULL
, WINED3D_MAP_READONLY
);
3498 src_format
= src_texture
->resource
.format
;
3499 src_fmt_flags
= src_texture
->resource
.format_flags
;
3503 src_format
= dst_format
;
3504 src_fmt_flags
= dst_fmt_flags
;
3507 wined3d_resource_map(&dst_texture
->resource
, dst_sub_resource_idx
, &dst_map
, dst_box
, 0);
3510 bpp
= dst_format
->byte_count
;
3511 src_height
= src_box
->bottom
- src_box
->top
;
3512 src_width
= src_box
->right
- src_box
->left
;
3513 dst_height
= dst_box
->bottom
- dst_box
->top
;
3514 dst_width
= dst_box
->right
- dst_box
->left
;
3515 row_byte_count
= dst_width
* bpp
;
3518 sbase
= (BYTE
*)src_map
.data
3519 + ((src_box
->top
/ src_format
->block_height
) * src_map
.row_pitch
)
3520 + ((src_box
->left
/ src_format
->block_width
) * src_format
->block_byte_count
);
3521 if (same_sub_resource
)
3522 dbuf
= (BYTE
*)dst_map
.data
3523 + ((dst_box
->top
/ dst_format
->block_height
) * dst_map
.row_pitch
)
3524 + ((dst_box
->left
/ dst_format
->block_width
) * dst_format
->block_byte_count
);
3526 dbuf
= dst_map
.data
;
3528 if (src_fmt_flags
& dst_fmt_flags
& WINED3DFMT_FLAG_BLOCKS
)
3530 TRACE("%s -> %s copy.\n", debug_d3dformat(src_format
->id
), debug_d3dformat(dst_format
->id
));
3532 if (same_sub_resource
)
3534 FIXME("Only plain blits supported on compressed surfaces.\n");
3539 if (src_height
!= dst_height
|| src_width
!= dst_width
)
3541 WARN("Stretching not supported on compressed surfaces.\n");
3542 hr
= WINED3DERR_INVALIDCALL
;
3546 if (!wined3d_texture_check_block_align(src_texture
,
3547 src_sub_resource_idx
% src_texture
->level_count
, src_box
))
3549 WARN("Source rectangle not block-aligned.\n");
3550 hr
= WINED3DERR_INVALIDCALL
;
3554 if (!wined3d_texture_check_block_align(dst_texture
,
3555 dst_sub_resource_idx
% dst_texture
->level_count
, dst_box
))
3557 WARN("Destination rectangle not block-aligned.\n");
3558 hr
= WINED3DERR_INVALIDCALL
;
3562 hr
= surface_cpu_blt_compressed(sbase
, dbuf
,
3563 src_map
.row_pitch
, dst_map
.row_pitch
, dst_width
, dst_height
,
3564 src_format
, flags
, fx
);
3568 /* First, all the 'source-less' blits */
3569 if (flags
& WINED3D_BLT_COLOR_FILL
)
3571 hr
= _Blt_ColorFill(dbuf
, dst_width
, dst_height
, bpp
, dst_map
.row_pitch
, fx
->fill_color
);
3572 flags
&= ~WINED3D_BLT_COLOR_FILL
;
3575 if (flags
& WINED3D_BLT_DEPTH_FILL
)
3576 FIXME("WINED3D_BLT_DEPTH_FILL needs to be implemented!\n");
3578 /* Now the 'with source' blits. */
3581 int sx
, xinc
, sy
, yinc
;
3583 if (!dst_width
|| !dst_height
) /* Hmm... stupid program? */
3586 if (filter
!= WINED3D_TEXF_NONE
&& filter
!= WINED3D_TEXF_POINT
3587 && (src_width
!= dst_width
|| src_height
!= dst_height
))
3589 /* Can happen when d3d9 apps do a StretchRect() call which isn't handled in GL. */
3590 FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(filter
));
3593 xinc
= (src_width
<< 16) / dst_width
;
3594 yinc
= (src_height
<< 16) / dst_height
;
3598 /* No effects, we can cheat here. */
3599 if (dst_width
== src_width
)
3601 if (dst_height
== src_height
)
3603 /* No stretching in either direction. This needs to be as
3604 * fast as possible. */
3607 /* Check for overlapping surfaces. */
3608 if (!same_sub_resource
|| dst_box
->top
< src_box
->top
3609 || dst_box
->right
<= src_box
->left
|| src_box
->right
<= dst_box
->left
)
3611 /* No overlap, or dst above src, so copy from top downwards. */
3612 for (y
= 0; y
< dst_height
; ++y
)
3614 memcpy(dbuf
, sbuf
, row_byte_count
);
3615 sbuf
+= src_map
.row_pitch
;
3616 dbuf
+= dst_map
.row_pitch
;
3619 else if (dst_box
->top
> src_box
->top
)
3621 /* Copy from bottom upwards. */
3622 sbuf
+= src_map
.row_pitch
* dst_height
;
3623 dbuf
+= dst_map
.row_pitch
* dst_height
;
3624 for (y
= 0; y
< dst_height
; ++y
)
3626 sbuf
-= src_map
.row_pitch
;
3627 dbuf
-= dst_map
.row_pitch
;
3628 memcpy(dbuf
, sbuf
, row_byte_count
);
3633 /* Src and dst overlapping on the same line, use memmove. */
3634 for (y
= 0; y
< dst_height
; ++y
)
3636 memmove(dbuf
, sbuf
, row_byte_count
);
3637 sbuf
+= src_map
.row_pitch
;
3638 dbuf
+= dst_map
.row_pitch
;
3644 /* Stretching in y direction only. */
3645 for (y
= sy
= 0; y
< dst_height
; ++y
, sy
+= yinc
)
3647 sbuf
= sbase
+ (sy
>> 16) * src_map
.row_pitch
;
3648 memcpy(dbuf
, sbuf
, row_byte_count
);
3649 dbuf
+= dst_map
.row_pitch
;
3655 /* Stretching in X direction. */
3657 for (y
= sy
= 0; y
< dst_height
; ++y
, sy
+= yinc
)
3659 sbuf
= sbase
+ (sy
>> 16) * src_map
.row_pitch
;
3661 if ((sy
>> 16) == (last_sy
>> 16))
3663 /* This source row is the same as last source row -
3664 * Copy the already stretched row. */
3665 memcpy(dbuf
, dbuf
- dst_map
.row_pitch
, row_byte_count
);
3669 #define STRETCH_ROW(type) \
3671 const type *s = (const type *)sbuf; \
3672 type *d = (type *)dbuf; \
3673 for (x = sx = 0; x < dst_width; ++x, sx += xinc) \
3674 d[x] = s[sx >> 16]; \
3692 for (x
= sx
= 0; x
< dst_width
; x
++, sx
+= xinc
)
3696 s
= sbuf
+ 3 * (sx
>> 16);
3697 pixel
= s
[0] | (s
[1] << 8) | (s
[2] << 16);
3698 d
[0] = (pixel
) & 0xff;
3699 d
[1] = (pixel
>> 8) & 0xff;
3700 d
[2] = (pixel
>> 16) & 0xff;
3706 FIXME("Stretched blit not implemented for bpp %u!\n", bpp
* 8);
3707 hr
= WINED3DERR_NOTAVAILABLE
;
3712 dbuf
+= dst_map
.row_pitch
;
3719 LONG dstyinc
= dst_map
.row_pitch
, dstxinc
= bpp
;
3720 DWORD keylow
= 0xffffffff, keyhigh
= 0, keymask
= 0xffffffff;
3721 DWORD destkeylow
= 0x0, destkeyhigh
= 0xffffffff, destkeymask
= 0xffffffff;
3722 if (flags
& (WINED3D_BLT_SRC_CKEY
| WINED3D_BLT_DST_CKEY
3723 | WINED3D_BLT_SRC_CKEY_OVERRIDE
| WINED3D_BLT_DST_CKEY_OVERRIDE
))
3725 /* The color keying flags are checked for correctness in ddraw */
3726 if (flags
& WINED3D_BLT_SRC_CKEY
)
3728 keylow
= src_texture
->async
.src_blt_color_key
.color_space_low_value
;
3729 keyhigh
= src_texture
->async
.src_blt_color_key
.color_space_high_value
;
3731 else if (flags
& WINED3D_BLT_SRC_CKEY_OVERRIDE
)
3733 keylow
= fx
->src_color_key
.color_space_low_value
;
3734 keyhigh
= fx
->src_color_key
.color_space_high_value
;
3737 if (flags
& WINED3D_BLT_DST_CKEY
)
3739 /* Destination color keys are taken from the source surface! */
3740 destkeylow
= src_texture
->async
.dst_blt_color_key
.color_space_low_value
;
3741 destkeyhigh
= src_texture
->async
.dst_blt_color_key
.color_space_high_value
;
3743 else if (flags
& WINED3D_BLT_DST_CKEY_OVERRIDE
)
3745 destkeylow
= fx
->dst_color_key
.color_space_low_value
;
3746 destkeyhigh
= fx
->dst_color_key
.color_space_high_value
;
3756 get_color_masks(src_format
, masks
);
3761 flags
&= ~(WINED3D_BLT_SRC_CKEY
| WINED3D_BLT_DST_CKEY
3762 | WINED3D_BLT_SRC_CKEY_OVERRIDE
| WINED3D_BLT_DST_CKEY_OVERRIDE
);
3765 if (flags
& WINED3D_BLT_FX
)
3767 BYTE
*dTopLeft
, *dTopRight
, *dBottomLeft
, *dBottomRight
, *tmp
;
3770 dTopRight
= dbuf
+ ((dst_width
- 1) * bpp
);
3771 dBottomLeft
= dTopLeft
+ ((dst_height
- 1) * dst_map
.row_pitch
);
3772 dBottomRight
= dBottomLeft
+ ((dst_width
- 1) * bpp
);
3774 if (fx
->fx
& WINEDDBLTFX_ARITHSTRETCHY
)
3776 /* I don't think we need to do anything about this flag */
3777 WARN("Nothing done for WINEDDBLTFX_ARITHSTRETCHY.\n");
3779 if (fx
->fx
& WINEDDBLTFX_MIRRORLEFTRIGHT
)
3782 dTopRight
= dTopLeft
;
3785 dBottomRight
= dBottomLeft
;
3787 dstxinc
= dstxinc
* -1;
3789 if (fx
->fx
& WINEDDBLTFX_MIRRORUPDOWN
)
3792 dTopLeft
= dBottomLeft
;
3795 dTopRight
= dBottomRight
;
3797 dstyinc
= dstyinc
* -1;
3799 if (fx
->fx
& WINEDDBLTFX_NOTEARING
)
3801 /* I don't think we need to do anything about this flag */
3802 WARN("Nothing done for WINEDDBLTFX_NOTEARING.\n");
3804 if (fx
->fx
& WINEDDBLTFX_ROTATE180
)
3807 dBottomRight
= dTopLeft
;
3810 dBottomLeft
= dTopRight
;
3812 dstxinc
= dstxinc
* -1;
3813 dstyinc
= dstyinc
* -1;
3815 if (fx
->fx
& WINEDDBLTFX_ROTATE270
)
3818 dTopLeft
= dBottomLeft
;
3819 dBottomLeft
= dBottomRight
;
3820 dBottomRight
= dTopRight
;
3825 dstxinc
= dstxinc
* -1;
3827 if (fx
->fx
& WINEDDBLTFX_ROTATE90
)
3830 dTopLeft
= dTopRight
;
3831 dTopRight
= dBottomRight
;
3832 dBottomRight
= dBottomLeft
;
3837 dstyinc
= dstyinc
* -1;
3839 if (fx
->fx
& WINEDDBLTFX_ZBUFFERBASEDEST
)
3841 /* I don't think we need to do anything about this flag */
3842 WARN("Nothing done for WINEDDBLTFX_ZBUFFERBASEDEST.\n");
3845 flags
&= ~(WINED3D_BLT_FX
);
3848 #define COPY_COLORKEY_FX(type) \
3851 type *d = (type *)dbuf, *dx, tmp; \
3852 for (y = sy = 0; y < dst_height; ++y, sy += yinc) \
3854 s = (const type *)(sbase + (sy >> 16) * src_map.row_pitch); \
3856 for (x = sx = 0; x < dst_width; ++x, sx += xinc) \
3858 tmp = s[sx >> 16]; \
3859 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) \
3860 && ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) \
3864 dx = (type *)(((BYTE *)dx) + dstxinc); \
3866 d = (type *)(((BYTE *)d) + dstyinc); \
3873 COPY_COLORKEY_FX(BYTE
);
3876 COPY_COLORKEY_FX(WORD
);
3879 COPY_COLORKEY_FX(DWORD
);
3884 BYTE
*d
= dbuf
, *dx
;
3885 for (y
= sy
= 0; y
< dst_height
; ++y
, sy
+= yinc
)
3887 sbuf
= sbase
+ (sy
>> 16) * src_map
.row_pitch
;
3889 for (x
= sx
= 0; x
< dst_width
; ++x
, sx
+= xinc
)
3891 DWORD pixel
, dpixel
= 0;
3892 s
= sbuf
+ 3 * (sx
>>16);
3893 pixel
= s
[0] | (s
[1] << 8) | (s
[2] << 16);
3894 dpixel
= dx
[0] | (dx
[1] << 8 ) | (dx
[2] << 16);
3895 if (((pixel
& keymask
) < keylow
|| (pixel
& keymask
) > keyhigh
)
3896 && ((dpixel
& keymask
) >= destkeylow
|| (dpixel
& keymask
) <= keyhigh
))
3898 dx
[0] = (pixel
) & 0xff;
3899 dx
[1] = (pixel
>> 8) & 0xff;
3900 dx
[2] = (pixel
>> 16) & 0xff;
3909 FIXME("%s color-keyed blit not implemented for bpp %u!\n",
3910 (flags
& WINED3D_BLT_SRC_CKEY
) ? "Source" : "Destination", bpp
* 8);
3911 hr
= WINED3DERR_NOTAVAILABLE
;
3913 #undef COPY_COLORKEY_FX
3920 FIXME(" Unsupported flags %#x.\n", flags
);
3923 wined3d_resource_unmap(&dst_texture
->resource
, dst_sub_resource_idx
);
3924 if (src_texture
&& !same_sub_resource
)
3925 wined3d_resource_unmap(&src_texture
->resource
, src_sub_resource_idx
);
3926 if (converted_texture
)
3927 wined3d_texture_decref(converted_texture
);
3932 static HRESULT
cpu_blit_color_fill(struct wined3d_device
*device
, struct wined3d_rendertarget_view
*view
,
3933 const RECT
*rect
, const struct wined3d_color
*color
)
3935 const struct wined3d_box box
= {rect
->left
, rect
->top
, rect
->right
, rect
->bottom
, 0, 1};
3936 static const struct wined3d_box src_box
;
3937 struct wined3d_blt_fx fx
;
3939 fx
.fill_color
= wined3d_format_convert_from_float(view
->format
, color
);
3940 return surface_cpu_blt(texture_from_resource(view
->resource
), view
->sub_resource_idx
,
3941 &box
, NULL
, 0, &src_box
, WINED3D_BLT_COLOR_FILL
, &fx
, WINED3D_TEXF_POINT
);
3944 static HRESULT
cpu_blit_depth_fill(struct wined3d_device
*device
,
3945 struct wined3d_rendertarget_view
*view
, const RECT
*rect
, DWORD clear_flags
,
3946 float depth
, DWORD stencil
)
3948 FIXME("Depth/stencil filling not implemented by cpu_blit.\n");
3949 return WINED3DERR_INVALIDCALL
;
3952 static void cpu_blit_blit_surface(struct wined3d_device
*device
, enum wined3d_blit_op op
, DWORD filter
,
3953 struct wined3d_surface
*src_surface
, const RECT
*src_rect
,
3954 struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
,
3955 const struct wined3d_color_key
*color_key
)
3957 /* FIXME: Remove error returns from surface_blt_cpu. */
3958 ERR("Blit method not implemented by cpu_blit.\n");
3961 const struct blit_shader cpu_blit
= {
3967 cpu_blit_color_fill
,
3968 cpu_blit_depth_fill
,
3969 cpu_blit_blit_surface
,
3972 HRESULT
wined3d_surface_blt(struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
,
3973 struct wined3d_surface
*src_surface
, const RECT
*src_rect
, DWORD flags
,
3974 const struct wined3d_blt_fx
*fx
, enum wined3d_texture_filter_type filter
)
3976 struct wined3d_box dst_box
= {dst_rect
->left
, dst_rect
->top
, dst_rect
->right
, dst_rect
->bottom
, 0, 1};
3977 struct wined3d_box src_box
= {src_rect
->left
, src_rect
->top
, src_rect
->right
, src_rect
->bottom
, 0, 1};
3978 unsigned int dst_sub_resource_idx
= surface_get_sub_resource_idx(dst_surface
);
3979 struct wined3d_texture
*dst_texture
= dst_surface
->container
;
3980 struct wined3d_device
*device
= dst_texture
->resource
.device
;
3981 struct wined3d_swapchain
*src_swapchain
, *dst_swapchain
;
3982 struct wined3d_texture
*src_texture
= NULL
;
3983 unsigned int dst_w
, dst_h
, src_w
, src_h
;
3984 unsigned int src_sub_resource_idx
= 0;
3985 DWORD src_ds_flags
, dst_ds_flags
;
3986 BOOL scale
, convert
;
3988 static const DWORD simple_blit
= WINED3D_BLT_ASYNC
3989 | WINED3D_BLT_COLOR_FILL
3990 | WINED3D_BLT_SRC_CKEY
3991 | WINED3D_BLT_SRC_CKEY_OVERRIDE
3993 | WINED3D_BLT_DEPTH_FILL
3994 | WINED3D_BLT_DO_NOT_WAIT
3995 | WINED3D_BLT_ALPHA_TEST
;
3997 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
3998 dst_surface
, wine_dbgstr_rect(dst_rect
), src_surface
, wine_dbgstr_rect(src_rect
),
3999 flags
, fx
, debug_d3dtexturefiltertype(filter
));
4000 TRACE("Usage is %s.\n", debug_d3dusage(dst_texture
->resource
.usage
));
4004 TRACE("fx %#x.\n", fx
->fx
);
4005 TRACE("fill_color 0x%08x.\n", fx
->fill_color
);
4006 TRACE("dst_color_key {0x%08x, 0x%08x}.\n",
4007 fx
->dst_color_key
.color_space_low_value
,
4008 fx
->dst_color_key
.color_space_high_value
);
4009 TRACE("src_color_key {0x%08x, 0x%08x}.\n",
4010 fx
->src_color_key
.color_space_low_value
,
4011 fx
->src_color_key
.color_space_high_value
);
4016 src_texture
= src_surface
->container
;
4017 src_sub_resource_idx
= surface_get_sub_resource_idx(src_surface
);
4020 if (dst_texture
->sub_resources
[dst_sub_resource_idx
].map_count
4021 || (src_texture
&& src_texture
->sub_resources
[src_sub_resource_idx
].map_count
))
4023 WARN("Surface is busy, returning WINEDDERR_SURFACEBUSY.\n");
4024 return WINEDDERR_SURFACEBUSY
;
4027 dst_w
= wined3d_texture_get_level_width(dst_texture
, dst_surface
->texture_level
);
4028 dst_h
= wined3d_texture_get_level_height(dst_texture
, dst_surface
->texture_level
);
4029 if (IsRectEmpty(dst_rect
) || dst_rect
->left
> dst_w
|| dst_rect
->left
< 0
4030 || dst_rect
->top
> dst_h
|| dst_rect
->top
< 0
4031 || dst_rect
->right
> dst_w
|| dst_rect
->right
< 0
4032 || dst_rect
->bottom
> dst_h
|| dst_rect
->bottom
< 0)
4034 WARN("The application gave us a bad destination rectangle.\n");
4035 return WINEDDERR_INVALIDRECT
;
4040 src_w
= wined3d_texture_get_level_width(src_texture
, src_surface
->texture_level
);
4041 src_h
= wined3d_texture_get_level_height(src_texture
, src_surface
->texture_level
);
4042 if (IsRectEmpty(src_rect
) || src_rect
->left
> src_w
|| src_rect
->left
< 0
4043 || src_rect
->top
> src_h
|| src_rect
->top
< 0
4044 || src_rect
->right
> src_w
|| src_rect
->right
< 0
4045 || src_rect
->bottom
> src_h
|| src_rect
->bottom
< 0)
4047 WARN("The application gave us a bad source rectangle.\n");
4048 return WINEDDERR_INVALIDRECT
;
4052 if (!fx
|| !(fx
->fx
))
4053 flags
&= ~WINED3D_BLT_FX
;
4055 if (flags
& WINED3D_BLT_WAIT
)
4056 flags
&= ~WINED3D_BLT_WAIT
;
4058 if (flags
& WINED3D_BLT_ASYNC
)
4060 static unsigned int once
;
4063 FIXME("Can't handle WINED3D_BLT_ASYNC flag.\n");
4064 flags
&= ~WINED3D_BLT_ASYNC
;
4067 /* WINED3D_BLT_DO_NOT_WAIT appeared in DX7. */
4068 if (flags
& WINED3D_BLT_DO_NOT_WAIT
)
4070 static unsigned int once
;
4073 FIXME("Can't handle WINED3D_BLT_DO_NOT_WAIT flag.\n");
4074 flags
&= ~WINED3D_BLT_DO_NOT_WAIT
;
4077 if (!device
->d3d_initialized
)
4079 WARN("D3D not initialized, using fallback.\n");
4083 /* We want to avoid invalidating the sysmem location for converted
4084 * surfaces, since otherwise we'd have to convert the data back when
4086 if (dst_texture
->flags
& WINED3D_TEXTURE_CONVERTED
|| dst_texture
->resource
.format
->convert
4087 || wined3d_format_get_color_key_conversion(dst_texture
, TRUE
))
4089 WARN_(d3d_perf
)("Converted surface, using CPU blit.\n");
4093 if (flags
& ~simple_blit
)
4095 WARN_(d3d_perf
)("Using fallback for complex blit (%#x).\n", flags
);
4100 src_swapchain
= src_texture
->swapchain
;
4102 src_swapchain
= NULL
;
4104 dst_swapchain
= dst_texture
->swapchain
;
4106 /* This isn't strictly needed. FBO blits for example could deal with
4107 * cross-swapchain blits by first downloading the source to a texture
4108 * before switching to the destination context. We just have this here to
4109 * not have to deal with the issue, since cross-swapchain blits should be
4111 if (src_swapchain
&& dst_swapchain
&& src_swapchain
!= dst_swapchain
)
4113 FIXME("Using fallback for cross-swapchain blit.\n");
4118 && (src_rect
->right
- src_rect
->left
!= dst_rect
->right
- dst_rect
->left
4119 || src_rect
->bottom
- src_rect
->top
!= dst_rect
->bottom
- dst_rect
->top
);
4120 convert
= src_texture
&& src_texture
->resource
.format
->id
!= dst_texture
->resource
.format
->id
;
4122 dst_ds_flags
= dst_texture
->resource
.format_flags
4123 & (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
4125 src_ds_flags
= src_texture
->resource
.format_flags
4126 & (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
4130 if (src_ds_flags
|| dst_ds_flags
)
4132 if (flags
& WINED3D_BLT_DEPTH_FILL
)
4136 TRACE("Depth fill.\n");
4138 if (!surface_convert_depth_to_float(dst_surface
, fx
->fill_color
, &depth
))
4139 return WINED3DERR_INVALIDCALL
;
4141 if (SUCCEEDED(wined3d_surface_depth_fill(dst_surface
, dst_rect
, depth
)))
4146 if (src_ds_flags
!= dst_ds_flags
)
4148 WARN("Rejecting depth / stencil blit between incompatible formats.\n");
4149 return WINED3DERR_INVALIDCALL
;
4152 if (SUCCEEDED(wined3d_surface_depth_blt(src_surface
, src_texture
->resource
.draw_binding
,
4153 src_rect
, dst_surface
, dst_texture
->resource
.draw_binding
, dst_rect
)))
4159 struct wined3d_texture_sub_resource
*src_sub_resource
, *dst_sub_resource
;
4160 const struct blit_shader
*blitter
;
4162 dst_sub_resource
= surface_get_sub_resource(dst_surface
);
4163 src_sub_resource
= src_texture
? &src_texture
->sub_resources
[src_sub_resource_idx
] : NULL
;
4165 /* In principle this would apply to depth blits as well, but we don't
4166 * implement those in the CPU blitter at the moment. */
4167 if ((dst_sub_resource
->locations
& dst_texture
->resource
.map_binding
)
4168 && (!src_texture
|| (src_sub_resource
->locations
& src_texture
->resource
.map_binding
)))
4171 TRACE("Not doing sysmem blit because of scaling.\n");
4173 TRACE("Not doing sysmem blit because of format conversion.\n");
4178 if (flags
& WINED3D_BLT_COLOR_FILL
)
4180 struct wined3d_color color
;
4181 const struct wined3d_palette
*palette
= dst_swapchain
? dst_swapchain
->palette
: NULL
;
4183 TRACE("Color fill.\n");
4185 if (!wined3d_format_convert_color_to_float(dst_texture
->resource
.format
,
4186 palette
, fx
->fill_color
, &color
))
4189 if (SUCCEEDED(surface_color_fill(dst_surface
, dst_rect
, &color
)))
4194 enum wined3d_blit_op blit_op
= WINED3D_BLIT_OP_COLOR_BLIT
;
4195 const struct wined3d_color_key
*color_key
= NULL
;
4197 TRACE("Color blit.\n");
4198 if (flags
& WINED3D_BLT_SRC_CKEY_OVERRIDE
)
4200 color_key
= &fx
->src_color_key
;
4201 blit_op
= WINED3D_BLIT_OP_COLOR_BLIT_CKEY
;
4203 else if (flags
& WINED3D_BLT_SRC_CKEY
)
4205 color_key
= &src_texture
->async
.src_blt_color_key
;
4206 blit_op
= WINED3D_BLIT_OP_COLOR_BLIT_CKEY
;
4208 else if (flags
& WINED3D_BLT_ALPHA_TEST
)
4210 blit_op
= WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST
;
4212 else if ((src_sub_resource
->locations
& WINED3D_LOCATION_SYSMEM
)
4213 && !(dst_sub_resource
->locations
& WINED3D_LOCATION_SYSMEM
))
4217 TRACE("Not doing upload because of scaling.\n");
4219 TRACE("Not doing upload because of format conversion.\n");
4222 POINT dst_point
= {dst_rect
->left
, dst_rect
->top
};
4224 if (SUCCEEDED(surface_upload_from_surface(dst_surface
, &dst_point
, src_surface
, src_rect
)))
4226 if (!wined3d_resource_is_offscreen(&dst_texture
->resource
))
4228 struct wined3d_context
*context
= context_acquire(device
, dst_surface
);
4229 wined3d_texture_load_location(dst_texture
, dst_sub_resource_idx
,
4230 context
, dst_texture
->resource
.draw_binding
);
4231 context_release(context
);
4237 else if (dst_swapchain
&& dst_swapchain
->back_buffers
4238 && dst_texture
== dst_swapchain
->front_buffer
4239 && src_texture
== dst_swapchain
->back_buffers
[0])
4241 /* Use present for back -> front blits. The idea behind this is
4242 * that present is potentially faster than a blit, in particular
4243 * when FBO blits aren't available. Some ddraw applications like
4244 * Half-Life and Prince of Persia 3D use Blt() from the backbuffer
4245 * to the frontbuffer instead of doing a Flip(). D3D8 and D3D9
4246 * applications can't blit directly to the frontbuffer. */
4247 enum wined3d_swap_effect swap_effect
= dst_swapchain
->desc
.swap_effect
;
4249 TRACE("Using present for backbuffer -> frontbuffer blit.\n");
4251 /* Set the swap effect to COPY, we don't want the backbuffer
4252 * to become undefined. */
4253 dst_swapchain
->desc
.swap_effect
= WINED3D_SWAP_EFFECT_COPY
;
4254 wined3d_swapchain_present(dst_swapchain
, NULL
, NULL
, dst_swapchain
->win_handle
, 0);
4255 dst_swapchain
->desc
.swap_effect
= swap_effect
;
4260 if (fbo_blit_supported(&device
->adapter
->gl_info
, blit_op
,
4261 src_rect
, src_texture
->resource
.usage
, src_texture
->resource
.pool
, src_texture
->resource
.format
,
4262 dst_rect
, dst_texture
->resource
.usage
, dst_texture
->resource
.pool
, dst_texture
->resource
.format
))
4264 struct wined3d_context
*context
;
4265 TRACE("Using FBO blit.\n");
4267 context
= context_acquire(device
, NULL
);
4268 surface_blt_fbo(device
, context
, filter
,
4269 src_surface
, src_texture
->resource
.draw_binding
, src_rect
,
4270 dst_surface
, dst_texture
->resource
.draw_binding
, dst_rect
);
4271 context_release(context
);
4273 wined3d_texture_validate_location(dst_texture
, dst_sub_resource_idx
,
4274 dst_texture
->resource
.draw_binding
);
4275 wined3d_texture_invalidate_location(dst_texture
, dst_sub_resource_idx
,
4276 ~dst_texture
->resource
.draw_binding
);
4281 blitter
= wined3d_select_blitter(&device
->adapter
->gl_info
, &device
->adapter
->d3d_info
, blit_op
,
4282 src_rect
, src_texture
->resource
.usage
, src_texture
->resource
.pool
, src_texture
->resource
.format
,
4283 dst_rect
, dst_texture
->resource
.usage
, dst_texture
->resource
.pool
, dst_texture
->resource
.format
);
4286 blitter
->blit_surface(device
, blit_op
, filter
, src_surface
,
4287 src_rect
, dst_surface
, dst_rect
, color_key
);
4294 /* Special cases for render targets. */
4295 if (SUCCEEDED(surface_blt_special(dst_surface
, dst_rect
, src_surface
, src_rect
, flags
, fx
, filter
)))
4299 return surface_cpu_blt(dst_texture
, dst_sub_resource_idx
, &dst_box
,
4300 src_texture
, src_sub_resource_idx
, &src_box
, flags
, fx
, filter
);