ddraw: Don't crash if writing out a new ddraw4 surface segfaults.
[wine.git] / dlls / wined3d / surface.c
blobb4e2025659cf2438c137fa242911375fbd950c81
1 /*
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
29 #include "config.h"
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 struct blt_info
41 GLenum binding;
42 GLenum bind_target;
43 enum wined3d_gl_resource_type tex_type;
44 struct wined3d_vec3 texcoords[4];
47 struct float_rect
49 float l;
50 float t;
51 float r;
52 float b;
55 static inline void cube_coords_float(const RECT *r, UINT w, UINT h, struct float_rect *f)
57 f->l = ((r->left * 2.0f) / w) - 1.0f;
58 f->t = ((r->top * 2.0f) / h) - 1.0f;
59 f->r = ((r->right * 2.0f) / w) - 1.0f;
60 f->b = ((r->bottom * 2.0f) / h) - 1.0f;
63 static void surface_get_blt_info(GLenum target, const RECT *rect, GLsizei w, GLsizei h, struct blt_info *info)
65 struct wined3d_vec3 *coords = info->texcoords;
66 struct float_rect f;
68 switch (target)
70 default:
71 FIXME("Unsupported texture target %#x.\n", target);
72 /* Fall back to GL_TEXTURE_2D */
73 case GL_TEXTURE_2D:
74 info->binding = GL_TEXTURE_BINDING_2D;
75 info->bind_target = GL_TEXTURE_2D;
76 info->tex_type = WINED3D_GL_RES_TYPE_TEX_2D;
77 coords[0].x = (float)rect->left / w;
78 coords[0].y = (float)rect->top / h;
79 coords[0].z = 0.0f;
81 coords[1].x = (float)rect->right / w;
82 coords[1].y = (float)rect->top / h;
83 coords[1].z = 0.0f;
85 coords[2].x = (float)rect->left / w;
86 coords[2].y = (float)rect->bottom / h;
87 coords[2].z = 0.0f;
89 coords[3].x = (float)rect->right / w;
90 coords[3].y = (float)rect->bottom / h;
91 coords[3].z = 0.0f;
92 break;
94 case GL_TEXTURE_RECTANGLE_ARB:
95 info->binding = GL_TEXTURE_BINDING_RECTANGLE_ARB;
96 info->bind_target = GL_TEXTURE_RECTANGLE_ARB;
97 info->tex_type = WINED3D_GL_RES_TYPE_TEX_RECT;
98 coords[0].x = rect->left; coords[0].y = rect->top; coords[0].z = 0.0f;
99 coords[1].x = rect->right; coords[1].y = rect->top; coords[1].z = 0.0f;
100 coords[2].x = rect->left; coords[2].y = rect->bottom; coords[2].z = 0.0f;
101 coords[3].x = rect->right; coords[3].y = rect->bottom; coords[3].z = 0.0f;
102 break;
104 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
105 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
106 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
107 info->tex_type = WINED3D_GL_RES_TYPE_TEX_CUBE;
108 cube_coords_float(rect, w, h, &f);
110 coords[0].x = 1.0f; coords[0].y = -f.t; coords[0].z = -f.l;
111 coords[1].x = 1.0f; coords[1].y = -f.t; coords[1].z = -f.r;
112 coords[2].x = 1.0f; coords[2].y = -f.b; coords[2].z = -f.l;
113 coords[3].x = 1.0f; coords[3].y = -f.b; coords[3].z = -f.r;
114 break;
116 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
117 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
118 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
119 info->tex_type = WINED3D_GL_RES_TYPE_TEX_CUBE;
120 cube_coords_float(rect, w, h, &f);
122 coords[0].x = -1.0f; coords[0].y = -f.t; coords[0].z = f.l;
123 coords[1].x = -1.0f; coords[1].y = -f.t; coords[1].z = f.r;
124 coords[2].x = -1.0f; coords[2].y = -f.b; coords[2].z = f.l;
125 coords[3].x = -1.0f; coords[3].y = -f.b; coords[3].z = f.r;
126 break;
128 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
129 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
130 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
131 info->tex_type = WINED3D_GL_RES_TYPE_TEX_CUBE;
132 cube_coords_float(rect, w, h, &f);
134 coords[0].x = f.l; coords[0].y = 1.0f; coords[0].z = f.t;
135 coords[1].x = f.r; coords[1].y = 1.0f; coords[1].z = f.t;
136 coords[2].x = f.l; coords[2].y = 1.0f; coords[2].z = f.b;
137 coords[3].x = f.r; coords[3].y = 1.0f; coords[3].z = f.b;
138 break;
140 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
141 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
142 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
143 info->tex_type = WINED3D_GL_RES_TYPE_TEX_CUBE;
144 cube_coords_float(rect, w, h, &f);
146 coords[0].x = f.l; coords[0].y = -1.0f; coords[0].z = -f.t;
147 coords[1].x = f.r; coords[1].y = -1.0f; coords[1].z = -f.t;
148 coords[2].x = f.l; coords[2].y = -1.0f; coords[2].z = -f.b;
149 coords[3].x = f.r; coords[3].y = -1.0f; coords[3].z = -f.b;
150 break;
152 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
153 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
154 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
155 info->tex_type = WINED3D_GL_RES_TYPE_TEX_CUBE;
156 cube_coords_float(rect, w, h, &f);
158 coords[0].x = f.l; coords[0].y = -f.t; coords[0].z = 1.0f;
159 coords[1].x = f.r; coords[1].y = -f.t; coords[1].z = 1.0f;
160 coords[2].x = f.l; coords[2].y = -f.b; coords[2].z = 1.0f;
161 coords[3].x = f.r; coords[3].y = -f.b; coords[3].z = 1.0f;
162 break;
164 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
165 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
166 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
167 info->tex_type = WINED3D_GL_RES_TYPE_TEX_CUBE;
168 cube_coords_float(rect, w, h, &f);
170 coords[0].x = -f.l; coords[0].y = -f.t; coords[0].z = -1.0f;
171 coords[1].x = -f.r; coords[1].y = -f.t; coords[1].z = -1.0f;
172 coords[2].x = -f.l; coords[2].y = -f.b; coords[2].z = -1.0f;
173 coords[3].x = -f.r; coords[3].y = -f.b; coords[3].z = -1.0f;
174 break;
178 static void surface_get_rect(const struct wined3d_surface *surface, const RECT *rect_in, RECT *rect_out)
180 if (rect_in)
181 *rect_out = *rect_in;
182 else
184 const struct wined3d_texture *texture = surface->container;
186 SetRect(rect_out, 0, 0, wined3d_texture_get_level_width(texture, surface->texture_level),
187 wined3d_texture_get_level_height(texture, surface->texture_level));
191 /* Context activation is done by the caller. */
192 void draw_textured_quad(const struct wined3d_surface *src_surface, struct wined3d_context *context,
193 const RECT *src_rect, const RECT *dst_rect, enum wined3d_texture_filter_type filter)
195 const struct wined3d_gl_info *gl_info = context->gl_info;
196 struct wined3d_texture *texture = src_surface->container;
197 struct blt_info info;
199 surface_get_blt_info(src_surface->texture_target, src_rect,
200 wined3d_texture_get_level_pow2_width(texture, src_surface->texture_level),
201 wined3d_texture_get_level_pow2_height(texture, src_surface->texture_level), &info);
203 gl_info->gl_ops.gl.p_glEnable(info.bind_target);
204 checkGLcall("glEnable(bind_target)");
206 context_bind_texture(context, info.bind_target, texture->texture_rgb.name);
208 /* Filtering for StretchRect */
209 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_MAG_FILTER, wined3d_gl_mag_filter(filter));
210 checkGLcall("glTexParameteri");
211 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_MIN_FILTER,
212 wined3d_gl_min_mip_filter(filter, WINED3D_TEXF_NONE));
213 checkGLcall("glTexParameteri");
214 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
215 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
216 if (context->gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
217 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT);
218 gl_info->gl_ops.gl.p_glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
219 checkGLcall("glTexEnvi");
221 /* Draw a quad */
222 gl_info->gl_ops.gl.p_glBegin(GL_TRIANGLE_STRIP);
223 gl_info->gl_ops.gl.p_glTexCoord3fv(&info.texcoords[0].x);
224 gl_info->gl_ops.gl.p_glVertex2i(dst_rect->left, dst_rect->top);
226 gl_info->gl_ops.gl.p_glTexCoord3fv(&info.texcoords[1].x);
227 gl_info->gl_ops.gl.p_glVertex2i(dst_rect->right, dst_rect->top);
229 gl_info->gl_ops.gl.p_glTexCoord3fv(&info.texcoords[2].x);
230 gl_info->gl_ops.gl.p_glVertex2i(dst_rect->left, dst_rect->bottom);
232 gl_info->gl_ops.gl.p_glTexCoord3fv(&info.texcoords[3].x);
233 gl_info->gl_ops.gl.p_glVertex2i(dst_rect->right, dst_rect->bottom);
234 gl_info->gl_ops.gl.p_glEnd();
236 /* Unbind the texture */
237 context_bind_texture(context, info.bind_target, 0);
239 /* We changed the filtering settings on the texture. Inform the
240 * container about this to get the filters reset properly next draw. */
241 texture->texture_rgb.sampler_desc.mag_filter = WINED3D_TEXF_POINT;
242 texture->texture_rgb.sampler_desc.min_filter = WINED3D_TEXF_POINT;
243 texture->texture_rgb.sampler_desc.mip_filter = WINED3D_TEXF_NONE;
244 texture->texture_rgb.sampler_desc.srgb_decode = FALSE;
247 /* Works correctly only for <= 4 bpp formats. */
248 static void get_color_masks(const struct wined3d_format *format, DWORD *masks)
250 masks[0] = ((1u << format->red_size) - 1) << format->red_offset;
251 masks[1] = ((1u << format->green_size) - 1) << format->green_offset;
252 masks[2] = ((1u << format->blue_size) - 1) << format->blue_offset;
255 void wined3d_surface_destroy_dc(struct wined3d_surface *surface)
257 unsigned int sub_resource_idx = surface_get_sub_resource_idx(surface);
258 struct wined3d_texture *texture = surface->container;
259 struct wined3d_device *device = texture->resource.device;
260 const struct wined3d_gl_info *gl_info = NULL;
261 D3DKMT_DESTROYDCFROMMEMORY destroy_desc;
262 struct wined3d_context *context = NULL;
263 struct wined3d_bo_address data;
264 NTSTATUS status;
266 if (!surface->dc)
268 ERR("Surface %p has no DC.\n", surface);
269 return;
272 TRACE("dc %p, bitmap %p.\n", surface->dc, surface->bitmap);
274 destroy_desc.hDc = surface->dc;
275 destroy_desc.hBitmap = surface->bitmap;
276 if ((status = D3DKMTDestroyDCFromMemory(&destroy_desc)))
277 ERR("Failed to destroy dc, status %#x.\n", status);
278 surface->dc = NULL;
279 surface->bitmap = NULL;
281 if (device->d3d_initialized)
283 context = context_acquire(device, NULL);
284 gl_info = context->gl_info;
287 wined3d_texture_get_memory(texture, sub_resource_idx, &data, texture->resource.map_binding);
288 wined3d_texture_unmap_bo_address(&data, gl_info, GL_PIXEL_UNPACK_BUFFER);
290 if (context)
291 context_release(context);
294 HRESULT wined3d_surface_create_dc(struct wined3d_surface *surface)
296 unsigned int sub_resource_idx = surface_get_sub_resource_idx(surface);
297 struct wined3d_texture *texture = surface->container;
298 const struct wined3d_format *format = texture->resource.format;
299 struct wined3d_device *device = texture->resource.device;
300 const struct wined3d_gl_info *gl_info = NULL;
301 struct wined3d_context *context = NULL;
302 unsigned int row_pitch, slice_pitch;
303 struct wined3d_bo_address data;
304 D3DKMT_CREATEDCFROMMEMORY desc;
305 NTSTATUS status;
307 TRACE("surface %p.\n", surface);
309 if (!format->ddi_format)
311 WARN("Cannot create a DC for format %s.\n", debug_d3dformat(format->id));
312 return WINED3DERR_INVALIDCALL;
315 wined3d_texture_get_pitch(texture, surface->texture_level, &row_pitch, &slice_pitch);
317 if (device->d3d_initialized)
319 context = context_acquire(device, NULL);
320 gl_info = context->gl_info;
323 wined3d_texture_get_memory(texture, sub_resource_idx, &data, texture->resource.map_binding);
324 desc.pMemory = wined3d_texture_map_bo_address(&data, texture->sub_resources[sub_resource_idx].size,
325 gl_info, GL_PIXEL_UNPACK_BUFFER, 0);
327 if (context)
328 context_release(context);
330 desc.Format = format->ddi_format;
331 desc.Width = wined3d_texture_get_level_width(texture, surface->texture_level);
332 desc.Height = wined3d_texture_get_level_height(texture, surface->texture_level);
333 desc.Pitch = row_pitch;
334 desc.hDeviceDc = CreateCompatibleDC(NULL);
335 desc.pColorTable = NULL;
337 status = D3DKMTCreateDCFromMemory(&desc);
338 DeleteDC(desc.hDeviceDc);
339 if (status)
341 WARN("Failed to create DC, status %#x.\n", status);
342 return WINED3DERR_INVALIDCALL;
345 surface->dc = desc.hDc;
346 surface->bitmap = desc.hBitmap;
348 TRACE("Created DC %p, bitmap %p for surface %p.\n", surface->dc, surface->bitmap, surface);
350 return WINED3D_OK;
353 static BOOL surface_is_full_rect(const struct wined3d_surface *surface, const RECT *r)
355 unsigned int t;
357 t = wined3d_texture_get_level_width(surface->container, surface->texture_level);
358 if ((r->left && r->right) || abs(r->right - r->left) != t)
359 return FALSE;
360 t = wined3d_texture_get_level_height(surface->container, surface->texture_level);
361 if ((r->top && r->bottom) || abs(r->bottom - r->top) != t)
362 return FALSE;
363 return TRUE;
366 static void surface_depth_blt_fbo(const struct wined3d_device *device,
367 struct wined3d_surface *src_surface, DWORD src_location, const RECT *src_rect,
368 struct wined3d_surface *dst_surface, DWORD dst_location, const RECT *dst_rect)
370 unsigned int dst_sub_resource_idx = surface_get_sub_resource_idx(dst_surface);
371 unsigned int src_sub_resource_idx = surface_get_sub_resource_idx(src_surface);
372 struct wined3d_texture *dst_texture = dst_surface->container;
373 struct wined3d_texture *src_texture = src_surface->container;
374 const struct wined3d_gl_info *gl_info;
375 struct wined3d_context *context;
376 DWORD src_mask, dst_mask;
377 GLbitfield gl_mask;
379 TRACE("device %p\n", device);
380 TRACE("src_surface %p, src_location %s, src_rect %s,\n",
381 src_surface, wined3d_debug_location(src_location), wine_dbgstr_rect(src_rect));
382 TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n",
383 dst_surface, wined3d_debug_location(dst_location), wine_dbgstr_rect(dst_rect));
385 src_mask = src_texture->resource.format_flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
386 dst_mask = dst_texture->resource.format_flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
388 if (src_mask != dst_mask)
390 ERR("Incompatible formats %s and %s.\n",
391 debug_d3dformat(src_texture->resource.format->id),
392 debug_d3dformat(dst_texture->resource.format->id));
393 return;
396 if (!src_mask)
398 ERR("Not a depth / stencil format: %s.\n",
399 debug_d3dformat(src_texture->resource.format->id));
400 return;
403 gl_mask = 0;
404 if (src_mask & WINED3DFMT_FLAG_DEPTH)
405 gl_mask |= GL_DEPTH_BUFFER_BIT;
406 if (src_mask & WINED3DFMT_FLAG_STENCIL)
407 gl_mask |= GL_STENCIL_BUFFER_BIT;
409 context = context_acquire(device, NULL);
410 if (!context->valid)
412 context_release(context);
413 WARN("Invalid context, skipping blit.\n");
414 return;
417 /* Make sure the locations are up-to-date. Loading the destination
418 * surface isn't required if the entire surface is overwritten. */
419 wined3d_texture_load_location(src_texture, src_sub_resource_idx, context, src_location);
420 if (!surface_is_full_rect(dst_surface, dst_rect))
421 wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, dst_location);
422 else
423 wined3d_texture_prepare_location(dst_texture, dst_sub_resource_idx, context, dst_location);
425 gl_info = context->gl_info;
427 context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER, NULL, src_surface, src_location);
428 context_check_fbo_status(context, GL_READ_FRAMEBUFFER);
430 context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER, NULL, dst_surface, dst_location);
431 context_set_draw_buffer(context, GL_NONE);
432 context_check_fbo_status(context, GL_DRAW_FRAMEBUFFER);
433 context_invalidate_state(context, STATE_FRAMEBUFFER);
435 if (gl_mask & GL_DEPTH_BUFFER_BIT)
437 gl_info->gl_ops.gl.p_glDepthMask(GL_TRUE);
438 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_ZWRITEENABLE));
440 if (gl_mask & GL_STENCIL_BUFFER_BIT)
442 if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
444 gl_info->gl_ops.gl.p_glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
445 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_TWOSIDEDSTENCILMODE));
447 gl_info->gl_ops.gl.p_glStencilMask(~0U);
448 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_STENCILWRITEMASK));
451 gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
452 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE));
454 gl_info->fbo_ops.glBlitFramebuffer(src_rect->left, src_rect->top, src_rect->right, src_rect->bottom,
455 dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, gl_mask, GL_NEAREST);
456 checkGLcall("glBlitFramebuffer()");
458 if (wined3d_settings.strict_draw_ordering)
459 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
461 context_release(context);
464 /* Blit between surface locations. Onscreen on different swapchains is not supported.
465 * Depth / stencil is not supported. Context activation is done by the caller. */
466 static void surface_blt_fbo(const struct wined3d_device *device,
467 struct wined3d_context *old_ctx, enum wined3d_texture_filter_type filter,
468 struct wined3d_surface *src_surface, DWORD src_location, const RECT *src_rect_in,
469 struct wined3d_surface *dst_surface, DWORD dst_location, const RECT *dst_rect_in)
471 unsigned int dst_sub_resource_idx = surface_get_sub_resource_idx(dst_surface);
472 unsigned int src_sub_resource_idx = surface_get_sub_resource_idx(src_surface);
473 struct wined3d_texture *dst_texture = dst_surface->container;
474 struct wined3d_texture *src_texture = src_surface->container;
475 const struct wined3d_gl_info *gl_info;
476 struct wined3d_context *context = old_ctx;
477 struct wined3d_surface *required_rt, *restore_rt = NULL;
478 RECT src_rect, dst_rect;
479 GLenum gl_filter;
480 GLenum buffer;
482 TRACE("device %p, filter %s,\n", device, debug_d3dtexturefiltertype(filter));
483 TRACE("src_surface %p, src_location %s, src_rect %s,\n",
484 src_surface, wined3d_debug_location(src_location), wine_dbgstr_rect(src_rect_in));
485 TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n",
486 dst_surface, wined3d_debug_location(dst_location), wine_dbgstr_rect(dst_rect_in));
488 src_rect = *src_rect_in;
489 dst_rect = *dst_rect_in;
491 switch (filter)
493 case WINED3D_TEXF_LINEAR:
494 gl_filter = GL_LINEAR;
495 break;
497 default:
498 FIXME("Unsupported filter mode %s (%#x).\n", debug_d3dtexturefiltertype(filter), filter);
499 case WINED3D_TEXF_NONE:
500 case WINED3D_TEXF_POINT:
501 gl_filter = GL_NEAREST;
502 break;
505 /* Resolve the source surface first if needed. */
506 if (src_location == WINED3D_LOCATION_RB_MULTISAMPLE
507 && (src_texture->resource.format->id != dst_texture->resource.format->id
508 || abs(src_rect.bottom - src_rect.top) != abs(dst_rect.bottom - dst_rect.top)
509 || abs(src_rect.right - src_rect.left) != abs(dst_rect.right - dst_rect.left)))
510 src_location = WINED3D_LOCATION_RB_RESOLVED;
512 /* Make sure the locations are up-to-date. Loading the destination
513 * surface isn't required if the entire surface is overwritten. (And is
514 * in fact harmful if we're being called by surface_load_location() with
515 * the purpose of loading the destination surface.) */
516 wined3d_texture_load_location(src_texture, src_sub_resource_idx, old_ctx, src_location);
517 if (!surface_is_full_rect(dst_surface, &dst_rect))
518 wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, old_ctx, dst_location);
519 else
520 wined3d_texture_prepare_location(dst_texture, dst_sub_resource_idx, old_ctx, dst_location);
523 if (src_location == WINED3D_LOCATION_DRAWABLE) required_rt = src_surface;
524 else if (dst_location == WINED3D_LOCATION_DRAWABLE) required_rt = dst_surface;
525 else required_rt = NULL;
527 restore_rt = context_get_rt_surface(old_ctx);
528 if (restore_rt != required_rt)
529 context = context_acquire(device, required_rt);
530 else
531 restore_rt = NULL;
533 if (!context->valid)
535 context_release(context);
536 WARN("Invalid context, skipping blit.\n");
537 return;
540 gl_info = context->gl_info;
542 if (src_location == WINED3D_LOCATION_DRAWABLE)
544 TRACE("Source surface %p is onscreen.\n", src_surface);
545 buffer = wined3d_texture_get_gl_buffer(src_texture);
546 surface_translate_drawable_coords(src_surface, context->win_handle, &src_rect);
548 else
550 TRACE("Source surface %p is offscreen.\n", src_surface);
551 buffer = GL_COLOR_ATTACHMENT0;
554 context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER, src_surface, NULL, src_location);
555 gl_info->gl_ops.gl.p_glReadBuffer(buffer);
556 checkGLcall("glReadBuffer()");
557 context_check_fbo_status(context, GL_READ_FRAMEBUFFER);
559 if (dst_location == WINED3D_LOCATION_DRAWABLE)
561 TRACE("Destination surface %p is onscreen.\n", dst_surface);
562 buffer = wined3d_texture_get_gl_buffer(dst_texture);
563 surface_translate_drawable_coords(dst_surface, context->win_handle, &dst_rect);
565 else
567 TRACE("Destination surface %p is offscreen.\n", dst_surface);
568 buffer = GL_COLOR_ATTACHMENT0;
571 context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER, dst_surface, NULL, dst_location);
572 context_set_draw_buffer(context, buffer);
573 context_check_fbo_status(context, GL_DRAW_FRAMEBUFFER);
574 context_invalidate_state(context, STATE_FRAMEBUFFER);
576 gl_info->gl_ops.gl.p_glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
577 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE));
578 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE1));
579 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE2));
580 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE3));
582 gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
583 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE));
585 gl_info->fbo_ops.glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom,
586 dst_rect.left, dst_rect.top, dst_rect.right, dst_rect.bottom, GL_COLOR_BUFFER_BIT, gl_filter);
587 checkGLcall("glBlitFramebuffer()");
589 if (wined3d_settings.strict_draw_ordering || (dst_location == WINED3D_LOCATION_DRAWABLE
590 && dst_texture->swapchain->front_buffer == dst_texture))
591 gl_info->gl_ops.gl.p_glFlush();
593 if (restore_rt)
594 context_restore(context, restore_rt);
597 static BOOL fbo_blit_supported(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op,
598 const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
599 const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
601 if ((wined3d_settings.offscreen_rendering_mode != ORM_FBO) || !gl_info->fbo_ops.glBlitFramebuffer)
602 return FALSE;
604 /* Source and/or destination need to be on the GL side */
605 if (src_pool == WINED3D_POOL_SYSTEM_MEM || dst_pool == WINED3D_POOL_SYSTEM_MEM)
606 return FALSE;
608 switch (blit_op)
610 case WINED3D_BLIT_OP_COLOR_BLIT:
611 if (!((src_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_FBO_ATTACHABLE)
612 || (src_usage & WINED3DUSAGE_RENDERTARGET)))
613 return FALSE;
614 if (!((dst_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_FBO_ATTACHABLE)
615 || (dst_usage & WINED3DUSAGE_RENDERTARGET)))
616 return FALSE;
617 if (!(src_format->id == dst_format->id
618 || (is_identity_fixup(src_format->color_fixup)
619 && is_identity_fixup(dst_format->color_fixup))))
620 return FALSE;
621 break;
623 case WINED3D_BLIT_OP_DEPTH_BLIT:
624 if (!(src_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL)))
625 return FALSE;
626 if (!(dst_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL)))
627 return FALSE;
628 /* Accept pure swizzle fixups for depth formats. In general we
629 * ignore the stencil component (if present) at the moment and the
630 * swizzle is not relevant with just the depth component. */
631 if (is_complex_fixup(src_format->color_fixup) || is_complex_fixup(dst_format->color_fixup)
632 || is_scaling_fixup(src_format->color_fixup) || is_scaling_fixup(dst_format->color_fixup))
633 return FALSE;
634 break;
636 default:
637 return FALSE;
640 return TRUE;
643 static BOOL surface_convert_depth_to_float(const struct wined3d_surface *surface, DWORD depth, float *float_depth)
645 const struct wined3d_format *format = surface->container->resource.format;
647 switch (format->id)
649 case WINED3DFMT_S1_UINT_D15_UNORM:
650 *float_depth = depth / (float)0x00007fff;
651 break;
653 case WINED3DFMT_D16_UNORM:
654 *float_depth = depth / (float)0x0000ffff;
655 break;
657 case WINED3DFMT_D24_UNORM_S8_UINT:
658 case WINED3DFMT_X8D24_UNORM:
659 *float_depth = depth / (float)0x00ffffff;
660 break;
662 case WINED3DFMT_D32_UNORM:
663 *float_depth = depth / (float)0xffffffff;
664 break;
666 default:
667 ERR("Unhandled conversion from %s to floating point.\n", debug_d3dformat(format->id));
668 return FALSE;
671 return TRUE;
674 static HRESULT wined3d_surface_depth_fill(struct wined3d_surface *surface, const RECT *rect, float depth)
676 struct wined3d_resource *resource = &surface->container->resource;
677 struct wined3d_device *device = resource->device;
678 struct wined3d_rendertarget_view *view;
679 struct wined3d_view_desc view_desc;
680 const struct blit_shader *blitter;
681 HRESULT hr;
683 if (!(blitter = wined3d_select_blitter(&device->adapter->gl_info, &device->adapter->d3d_info,
684 WINED3D_BLIT_OP_DEPTH_FILL, NULL, 0, 0, NULL, rect, resource->usage, resource->pool, resource->format)))
686 FIXME("No blitter is capable of performing the requested depth fill operation.\n");
687 return WINED3DERR_INVALIDCALL;
690 view_desc.format_id = resource->format->id;
691 view_desc.flags = 0;
692 view_desc.u.texture.level_idx = surface->texture_level;
693 view_desc.u.texture.level_count = 1;
694 view_desc.u.texture.layer_idx = surface->texture_layer;
695 view_desc.u.texture.layer_count = 1;
696 if (FAILED(hr = wined3d_rendertarget_view_create(&view_desc,
697 resource, NULL, &wined3d_null_parent_ops, &view)))
699 ERR("Failed to create rendertarget view, hr %#x.\n", hr);
700 return hr;
703 hr = blitter->depth_fill(device, view, rect, WINED3DCLEAR_ZBUFFER, depth, 0);
704 wined3d_rendertarget_view_decref(view);
706 return hr;
709 static HRESULT wined3d_surface_depth_blt(struct wined3d_surface *src_surface, DWORD src_location, const RECT *src_rect,
710 struct wined3d_surface *dst_surface, DWORD dst_location, const RECT *dst_rect)
712 struct wined3d_texture *src_texture = src_surface->container;
713 struct wined3d_texture *dst_texture = dst_surface->container;
714 struct wined3d_device *device = src_texture->resource.device;
715 unsigned int dst_sub_resource_idx;
717 if (!fbo_blit_supported(&device->adapter->gl_info, WINED3D_BLIT_OP_DEPTH_BLIT,
718 src_rect, src_texture->resource.usage, src_texture->resource.pool, src_texture->resource.format,
719 dst_rect, dst_texture->resource.usage, dst_texture->resource.pool, dst_texture->resource.format))
720 return WINED3DERR_INVALIDCALL;
722 surface_depth_blt_fbo(device, src_surface, src_location, src_rect, dst_surface, dst_location, dst_rect);
724 dst_sub_resource_idx = surface_get_sub_resource_idx(dst_surface);
725 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, dst_location);
726 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~dst_location);
728 return WINED3D_OK;
731 /* This call just downloads data, the caller is responsible for binding the
732 * correct texture. */
733 /* Context activation is done by the caller. */
734 static void surface_download_data(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info,
735 DWORD dst_location)
737 unsigned int sub_resource_idx = surface_get_sub_resource_idx(surface);
738 struct wined3d_texture *texture = surface->container;
739 const struct wined3d_format *format = texture->resource.format;
740 struct wined3d_texture_sub_resource *sub_resource;
741 unsigned int dst_row_pitch, dst_slice_pitch;
742 unsigned int src_row_pitch, src_slice_pitch;
743 struct wined3d_bo_address data;
744 BYTE *temporary_mem = NULL;
745 void *mem;
747 /* Only support read back of converted P8 surfaces. */
748 if (texture->flags & WINED3D_TEXTURE_CONVERTED && format->id != WINED3DFMT_P8_UINT)
750 ERR("Trying to read back converted surface %p with format %s.\n", surface, debug_d3dformat(format->id));
751 return;
754 sub_resource = &texture->sub_resources[sub_resource_idx];
756 if (surface->texture_target == GL_TEXTURE_2D_ARRAY)
758 /* NP2 emulation is not allowed on array textures. */
759 if (texture->flags & WINED3D_TEXTURE_COND_NP2_EMULATED)
760 ERR("Array texture %p uses NP2 emulation.\n", texture);
762 WARN_(d3d_perf)("Downloading all miplevel layers to get the surface data for a single sub-resource.\n");
764 if (!(temporary_mem = wined3d_calloc(texture->layer_count, sub_resource->size)))
766 ERR("Out of memory.\n");
767 return;
771 wined3d_texture_get_memory(texture, sub_resource_idx, &data, dst_location);
773 if (texture->flags & WINED3D_TEXTURE_COND_NP2_EMULATED)
775 wined3d_texture_get_pitch(texture, surface->texture_level, &dst_row_pitch, &dst_slice_pitch);
776 wined3d_format_calculate_pitch(format, texture->resource.device->surface_alignment,
777 wined3d_texture_get_level_pow2_width(texture, surface->texture_level),
778 wined3d_texture_get_level_pow2_height(texture, surface->texture_level),
779 &src_row_pitch, &src_slice_pitch);
780 if (!(temporary_mem = HeapAlloc(GetProcessHeap(), 0, src_slice_pitch)))
782 ERR("Out of memory.\n");
783 return;
786 if (data.buffer_object)
787 ERR("NP2 emulated texture uses PBO unexpectedly.\n");
788 if (texture->resource.format_flags & WINED3DFMT_FLAG_COMPRESSED)
789 ERR("Unexpected compressed format for NP2 emulated texture.\n");
792 if (temporary_mem)
794 mem = temporary_mem;
796 else if (data.buffer_object)
798 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, data.buffer_object));
799 checkGLcall("glBindBuffer");
800 mem = data.addr;
802 else
804 mem = data.addr;
807 if (texture->resource.format_flags & WINED3DFMT_FLAG_COMPRESSED)
809 TRACE("Downloading compressed surface %p, level %u, format %#x, type %#x, data %p.\n",
810 surface, surface->texture_level, format->glFormat, format->glType, mem);
812 GL_EXTCALL(glGetCompressedTexImage(surface->texture_target, surface->texture_level, mem));
813 checkGLcall("glGetCompressedTexImage");
815 else
817 TRACE("Downloading surface %p, level %u, format %#x, type %#x, data %p.\n",
818 surface, surface->texture_level, format->glFormat, format->glType, mem);
820 gl_info->gl_ops.gl.p_glGetTexImage(surface->texture_target, surface->texture_level,
821 format->glFormat, format->glType, mem);
822 checkGLcall("glGetTexImage");
825 if (texture->flags & WINED3D_TEXTURE_COND_NP2_EMULATED)
827 const BYTE *src_data;
828 unsigned int h, y;
829 BYTE *dst_data;
831 * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing
832 * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
833 * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width.
835 * We're doing this...
837 * instead of boxing the texture :
838 * |<-texture width ->| -->pow2width| /\
839 * |111111111111111111| | |
840 * |222 Texture 222222| boxed empty | texture height
841 * |3333 Data 33333333| | |
842 * |444444444444444444| | \/
843 * ----------------------------------- |
844 * | boxed empty | boxed empty | pow2height
845 * | | | \/
846 * -----------------------------------
849 * we're repacking the data to the expected texture width
851 * |<-texture width ->| -->pow2width| /\
852 * |111111111111111111222222222222222| |
853 * |222333333333333333333444444444444| texture height
854 * |444444 | |
855 * | | \/
856 * | | |
857 * | empty | pow2height
858 * | | \/
859 * -----------------------------------
861 * == is the same as
863 * |<-texture width ->| /\
864 * |111111111111111111|
865 * |222222222222222222|texture height
866 * |333333333333333333|
867 * |444444444444444444| \/
868 * --------------------
870 * This also means that any references to surface memory should work with the data as if it were a
871 * standard texture with a non-power2 width instead of a texture boxed up to be a power2 texture.
873 * internally the texture is still stored in a boxed format so any references to textureName will
874 * get a boxed texture with width pow2width and not a texture of width resource.width. */
875 src_data = mem;
876 dst_data = data.addr;
877 TRACE("Repacking the surface data from pitch %u to pitch %u.\n", src_row_pitch, dst_row_pitch);
878 h = wined3d_texture_get_level_height(texture, surface->texture_level);
879 for (y = 0; y < h; ++y)
881 memcpy(dst_data, src_data, dst_row_pitch);
882 src_data += src_row_pitch;
883 dst_data += dst_row_pitch;
886 else if (temporary_mem)
888 void *src_data = temporary_mem + surface->texture_layer * sub_resource->size;
889 if (data.buffer_object)
891 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, data.buffer_object));
892 checkGLcall("glBindBuffer");
893 GL_EXTCALL(glBufferSubData(GL_PIXEL_PACK_BUFFER, 0, sub_resource->size, src_data));
894 checkGLcall("glBufferSubData");
896 else
898 memcpy(data.addr, src_data, sub_resource->size);
902 if (data.buffer_object)
904 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));
905 checkGLcall("glBindBuffer");
908 HeapFree(GetProcessHeap(), 0, temporary_mem);
911 /* This call just uploads data, the caller is responsible for binding the
912 * correct texture. */
913 /* Context activation is done by the caller. */
914 void wined3d_surface_upload_data(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info,
915 const struct wined3d_format *format, const RECT *src_rect, UINT src_pitch, const POINT *dst_point,
916 BOOL srgb, const struct wined3d_const_bo_address *data)
918 unsigned int sub_resource_idx = surface_get_sub_resource_idx(surface);
919 struct wined3d_texture *texture = surface->container;
920 UINT update_w = src_rect->right - src_rect->left;
921 UINT update_h = src_rect->bottom - src_rect->top;
923 TRACE("surface %p, gl_info %p, format %s, src_rect %s, src_pitch %u, dst_point %s, srgb %#x, data {%#x:%p}.\n",
924 surface, gl_info, debug_d3dformat(format->id), wine_dbgstr_rect(src_rect), src_pitch,
925 wine_dbgstr_point(dst_point), srgb, data->buffer_object, data->addr);
927 if (texture->sub_resources[sub_resource_idx].map_count)
929 WARN("Uploading a surface that is currently mapped, setting WINED3D_TEXTURE_PIN_SYSMEM.\n");
930 texture->flags |= WINED3D_TEXTURE_PIN_SYSMEM;
933 if (format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_HEIGHT_SCALE)
935 update_h *= format->height_scale.numerator;
936 update_h /= format->height_scale.denominator;
939 if (data->buffer_object)
941 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, data->buffer_object));
942 checkGLcall("glBindBuffer");
945 if (format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_COMPRESSED)
947 unsigned int dst_row_pitch, dst_slice_pitch;
948 const BYTE *addr = data->addr;
949 GLenum internal;
951 addr += (src_rect->top / format->block_height) * src_pitch;
952 addr += (src_rect->left / format->block_width) * format->block_byte_count;
954 if (srgb)
955 internal = format->glGammaInternal;
956 else if (texture->resource.usage & WINED3DUSAGE_RENDERTARGET
957 && wined3d_resource_is_offscreen(&texture->resource))
958 internal = format->rtInternal;
959 else
960 internal = format->glInternal;
962 wined3d_format_calculate_pitch(format, 1, update_w, update_h, &dst_row_pitch, &dst_slice_pitch);
964 TRACE("Uploading compressed data, target %#x, level %u, layer %u, x %d, y %d, w %u, h %u, "
965 "format %#x, image_size %#x, addr %p.\n",
966 surface->texture_target, surface->texture_level, surface->texture_layer,
967 dst_point->x, dst_point->y, update_w, update_h, internal, dst_slice_pitch, addr);
969 if (dst_row_pitch == src_pitch)
971 if (surface->texture_target == GL_TEXTURE_2D_ARRAY)
973 GL_EXTCALL(glCompressedTexSubImage3D(surface->texture_target, surface->texture_level,
974 dst_point->x, dst_point->y, surface->texture_layer, update_w, update_h, 1,
975 internal, dst_slice_pitch, addr));
977 else
979 GL_EXTCALL(glCompressedTexSubImage2D(surface->texture_target, surface->texture_level,
980 dst_point->x, dst_point->y, update_w, update_h,
981 internal, dst_slice_pitch, addr));
984 else
986 UINT row_count = (update_h + format->block_height - 1) / format->block_height;
987 UINT row, y;
989 /* glCompressedTexSubImage2D() ignores pixel store state, so we
990 * can't use the unpack row length like for glTexSubImage2D. */
991 for (row = 0, y = dst_point->y; row < row_count; ++row)
993 if (surface->texture_target == GL_TEXTURE_2D_ARRAY)
995 GL_EXTCALL(glCompressedTexSubImage3D(surface->texture_target, surface->texture_level,
996 dst_point->x, y, surface->texture_layer, update_w, format->block_height, 1,
997 internal, dst_row_pitch, addr));
999 else
1001 GL_EXTCALL(glCompressedTexSubImage2D(surface->texture_target, surface->texture_level,
1002 dst_point->x, y, update_w, format->block_height, internal, dst_row_pitch, addr));
1005 y += format->block_height;
1006 addr += src_pitch;
1009 checkGLcall("Upload compressed surface data");
1011 else
1013 const BYTE *addr = data->addr;
1015 addr += src_rect->top * src_pitch;
1016 addr += src_rect->left * format->byte_count;
1018 TRACE("Uploading data, target %#x, level %u, layer %u, x %d, y %d, w %u, h %u, "
1019 "format %#x, type %#x, addr %p.\n",
1020 surface->texture_target, surface->texture_level, surface->texture_layer,
1021 dst_point->x, dst_point->y, update_w, update_h, format->glFormat, format->glType, addr);
1023 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, src_pitch / format->byte_count);
1024 if (surface->texture_target == GL_TEXTURE_2D_ARRAY)
1026 GL_EXTCALL(glTexSubImage3D(surface->texture_target, surface->texture_level,
1027 dst_point->x, dst_point->y, surface->texture_layer, update_w, update_h, 1,
1028 format->glFormat, format->glType, addr));
1030 else
1032 gl_info->gl_ops.gl.p_glTexSubImage2D(surface->texture_target, surface->texture_level,
1033 dst_point->x, dst_point->y, update_w, update_h, format->glFormat, format->glType, addr);
1035 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1036 checkGLcall("Upload surface data");
1039 if (data->buffer_object)
1041 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));
1042 checkGLcall("glBindBuffer");
1045 if (wined3d_settings.strict_draw_ordering)
1046 gl_info->gl_ops.gl.p_glFlush();
1048 if (gl_info->quirks & WINED3D_QUIRK_FBO_TEX_UPDATE)
1050 struct wined3d_device *device = texture->resource.device;
1051 unsigned int i;
1053 for (i = 0; i < device->context_count; ++i)
1055 context_surface_update(device->contexts[i], surface);
1060 static BOOL surface_check_block_align_rect(struct wined3d_surface *surface, const RECT *rect)
1062 struct wined3d_box box = {rect->left, rect->top, rect->right, rect->bottom, 0, 1};
1064 return wined3d_texture_check_block_align(surface->container, surface->texture_level, &box);
1067 HRESULT surface_upload_from_surface(struct wined3d_surface *dst_surface, const POINT *dst_point,
1068 struct wined3d_surface *src_surface, const RECT *src_rect)
1070 unsigned int src_sub_resource_idx = surface_get_sub_resource_idx(src_surface);
1071 unsigned int dst_sub_resource_idx = surface_get_sub_resource_idx(dst_surface);
1072 struct wined3d_texture *src_texture = src_surface->container;
1073 struct wined3d_texture *dst_texture = dst_surface->container;
1074 unsigned int src_row_pitch, src_slice_pitch;
1075 const struct wined3d_format *src_format;
1076 const struct wined3d_format *dst_format;
1077 unsigned int src_fmt_flags, dst_fmt_flags;
1078 const struct wined3d_gl_info *gl_info;
1079 struct wined3d_context *context;
1080 struct wined3d_bo_address data;
1081 UINT update_w, update_h;
1082 UINT dst_w, dst_h;
1083 RECT r, dst_rect;
1084 POINT p;
1086 TRACE("dst_surface %p, dst_point %s, src_surface %p, src_rect %s.\n",
1087 dst_surface, wine_dbgstr_point(dst_point),
1088 src_surface, wine_dbgstr_rect(src_rect));
1090 src_format = src_texture->resource.format;
1091 dst_format = dst_texture->resource.format;
1092 src_fmt_flags = src_texture->resource.format_flags;
1093 dst_fmt_flags = dst_texture->resource.format_flags;
1095 if (src_format->id != dst_format->id)
1097 WARN("Source and destination surfaces should have the same format.\n");
1098 return WINED3DERR_INVALIDCALL;
1101 if (!dst_point)
1103 p.x = 0;
1104 p.y = 0;
1105 dst_point = &p;
1107 else if (dst_point->x < 0 || dst_point->y < 0)
1109 WARN("Invalid destination point.\n");
1110 return WINED3DERR_INVALIDCALL;
1113 if (!src_rect)
1115 SetRect(&r, 0, 0, wined3d_texture_get_level_width(src_texture, src_surface->texture_level),
1116 wined3d_texture_get_level_height(src_texture, src_surface->texture_level));
1117 src_rect = &r;
1119 else if (src_rect->left < 0 || src_rect->top < 0 || IsRectEmpty(src_rect))
1121 WARN("Invalid source rectangle.\n");
1122 return WINED3DERR_INVALIDCALL;
1125 dst_w = wined3d_texture_get_level_width(dst_texture, dst_surface->texture_level);
1126 dst_h = wined3d_texture_get_level_height(dst_texture, dst_surface->texture_level);
1128 update_w = src_rect->right - src_rect->left;
1129 update_h = src_rect->bottom - src_rect->top;
1131 if (update_w > dst_w || dst_point->x > dst_w - update_w
1132 || update_h > dst_h || dst_point->y > dst_h - update_h)
1134 WARN("Destination out of bounds.\n");
1135 return WINED3DERR_INVALIDCALL;
1138 if ((src_fmt_flags & WINED3DFMT_FLAG_BLOCKS) && !surface_check_block_align_rect(src_surface, src_rect))
1140 WARN("Source rectangle not block-aligned.\n");
1141 return WINED3DERR_INVALIDCALL;
1144 SetRect(&dst_rect, dst_point->x, dst_point->y, dst_point->x + update_w, dst_point->y + update_h);
1145 if ((dst_fmt_flags & WINED3DFMT_FLAG_BLOCKS) && !surface_check_block_align_rect(dst_surface, &dst_rect))
1147 WARN("Destination rectangle not block-aligned.\n");
1148 return WINED3DERR_INVALIDCALL;
1151 /* Use wined3d_surface_blt() instead of uploading directly if we need conversion. */
1152 if (dst_format->convert || wined3d_format_get_color_key_conversion(dst_texture, FALSE))
1153 return wined3d_surface_blt(dst_surface, &dst_rect, src_surface, src_rect, 0, NULL, WINED3D_TEXF_POINT);
1155 context = context_acquire(dst_texture->resource.device, NULL);
1156 gl_info = context->gl_info;
1158 /* Only load the surface for partial updates. For newly allocated texture
1159 * the texture wouldn't be the current location, and we'd upload zeroes
1160 * just to overwrite them again. */
1161 if (update_w == dst_w && update_h == dst_h)
1162 wined3d_texture_prepare_texture(dst_texture, context, FALSE);
1163 else
1164 wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, WINED3D_LOCATION_TEXTURE_RGB);
1165 wined3d_texture_bind_and_dirtify(dst_texture, context, FALSE);
1167 wined3d_texture_get_memory(src_texture, src_sub_resource_idx, &data,
1168 src_texture->sub_resources[src_sub_resource_idx].locations);
1169 wined3d_texture_get_pitch(src_texture, src_surface->texture_level, &src_row_pitch, &src_slice_pitch);
1171 wined3d_surface_upload_data(dst_surface, gl_info, src_format, src_rect,
1172 src_row_pitch, dst_point, FALSE, wined3d_const_bo_address(&data));
1174 context_release(context);
1176 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB);
1177 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB);
1179 return WINED3D_OK;
1182 /* In D3D the depth stencil dimensions have to be greater than or equal to the
1183 * render target dimensions. With FBOs, the dimensions have to be an exact match. */
1184 /* TODO: We should synchronize the renderbuffer's content with the texture's content. */
1185 /* Context activation is done by the caller. */
1186 void surface_set_compatible_renderbuffer(struct wined3d_surface *surface, const struct wined3d_surface *rt)
1188 const struct wined3d_gl_info *gl_info = &surface->container->resource.device->adapter->gl_info;
1189 struct wined3d_renderbuffer_entry *entry;
1190 GLuint renderbuffer = 0;
1191 unsigned int src_width, src_height;
1192 unsigned int width, height;
1194 if (rt && rt->container->resource.format->id != WINED3DFMT_NULL)
1196 width = wined3d_texture_get_level_pow2_width(rt->container, rt->texture_level);
1197 height = wined3d_texture_get_level_pow2_height(rt->container, rt->texture_level);
1199 else
1201 width = wined3d_texture_get_level_pow2_width(surface->container, surface->texture_level);
1202 height = wined3d_texture_get_level_pow2_height(surface->container, surface->texture_level);
1205 src_width = wined3d_texture_get_level_pow2_width(surface->container, surface->texture_level);
1206 src_height = wined3d_texture_get_level_pow2_height(surface->container, surface->texture_level);
1208 /* A depth stencil smaller than the render target is not valid */
1209 if (width > src_width || height > src_height) return;
1211 /* Remove any renderbuffer set if the sizes match */
1212 if (gl_info->supported[ARB_FRAMEBUFFER_OBJECT]
1213 || (width == src_width && height == src_height))
1215 surface->current_renderbuffer = NULL;
1216 return;
1219 /* Look if we've already got a renderbuffer of the correct dimensions */
1220 LIST_FOR_EACH_ENTRY(entry, &surface->renderbuffers, struct wined3d_renderbuffer_entry, entry)
1222 if (entry->width == width && entry->height == height)
1224 renderbuffer = entry->id;
1225 surface->current_renderbuffer = entry;
1226 break;
1230 if (!renderbuffer)
1232 gl_info->fbo_ops.glGenRenderbuffers(1, &renderbuffer);
1233 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
1234 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER,
1235 surface->container->resource.format->glInternal, width, height);
1237 entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry));
1238 entry->width = width;
1239 entry->height = height;
1240 entry->id = renderbuffer;
1241 list_add_head(&surface->renderbuffers, &entry->entry);
1243 surface->current_renderbuffer = entry;
1246 checkGLcall("set_compatible_renderbuffer");
1249 /* See also float_16_to_32() in wined3d_private.h */
1250 static inline unsigned short float_32_to_16(const float *in)
1252 int exp = 0;
1253 float tmp = fabsf(*in);
1254 unsigned int mantissa;
1255 unsigned short ret;
1257 /* Deal with special numbers */
1258 if (*in == 0.0f)
1259 return 0x0000;
1260 if (isnan(*in))
1261 return 0x7c01;
1262 if (isinf(*in))
1263 return (*in < 0.0f ? 0xfc00 : 0x7c00);
1265 if (tmp < (float)(1u << 10))
1269 tmp = tmp * 2.0f;
1270 exp--;
1271 } while (tmp < (float)(1u << 10));
1273 else if (tmp >= (float)(1u << 11))
1277 tmp /= 2.0f;
1278 exp++;
1279 } while (tmp >= (float)(1u << 11));
1282 mantissa = (unsigned int)tmp;
1283 if (tmp - mantissa >= 0.5f)
1284 ++mantissa; /* Round to nearest, away from zero. */
1286 exp += 10; /* Normalize the mantissa. */
1287 exp += 15; /* Exponent is encoded with excess 15. */
1289 if (exp > 30) /* too big */
1291 ret = 0x7c00; /* INF */
1293 else if (exp <= 0)
1295 /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers. */
1296 while (exp <= 0)
1298 mantissa = mantissa >> 1;
1299 ++exp;
1301 ret = mantissa & 0x3ff;
1303 else
1305 ret = (exp << 10) | (mantissa & 0x3ff);
1308 ret |= ((*in < 0.0f ? 1 : 0) << 15); /* Add the sign */
1309 return ret;
1312 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst,
1313 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
1315 unsigned short *dst_s;
1316 const float *src_f;
1317 unsigned int x, y;
1319 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
1321 for (y = 0; y < h; ++y)
1323 src_f = (const float *)(src + y * pitch_in);
1324 dst_s = (unsigned short *) (dst + y * pitch_out);
1325 for (x = 0; x < w; ++x)
1327 dst_s[x] = float_32_to_16(src_f + x);
1332 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
1333 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
1335 static const unsigned char convert_5to8[] =
1337 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
1338 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
1339 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
1340 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
1342 static const unsigned char convert_6to8[] =
1344 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
1345 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
1346 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
1347 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
1348 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
1349 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
1350 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
1351 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
1353 unsigned int x, y;
1355 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
1357 for (y = 0; y < h; ++y)
1359 const WORD *src_line = (const WORD *)(src + y * pitch_in);
1360 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
1361 for (x = 0; x < w; ++x)
1363 WORD pixel = src_line[x];
1364 dst_line[x] = 0xff000000u
1365 | convert_5to8[(pixel & 0xf800u) >> 11] << 16
1366 | convert_6to8[(pixel & 0x07e0u) >> 5] << 8
1367 | convert_5to8[(pixel & 0x001fu)];
1372 /* We use this for both B8G8R8A8 -> B8G8R8X8 and B8G8R8X8 -> B8G8R8A8, since
1373 * in both cases we're just setting the X / Alpha channel to 0xff. */
1374 static void convert_a8r8g8b8_x8r8g8b8(const BYTE *src, BYTE *dst,
1375 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
1377 unsigned int x, y;
1379 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
1381 for (y = 0; y < h; ++y)
1383 const DWORD *src_line = (const DWORD *)(src + y * pitch_in);
1384 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
1386 for (x = 0; x < w; ++x)
1388 dst_line[x] = 0xff000000 | (src_line[x] & 0xffffff);
1393 static inline BYTE cliptobyte(int x)
1395 return (BYTE)((x < 0) ? 0 : ((x > 255) ? 255 : x));
1398 static void convert_yuy2_x8r8g8b8(const BYTE *src, BYTE *dst,
1399 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
1401 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
1402 unsigned int x, y;
1404 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
1406 for (y = 0; y < h; ++y)
1408 const BYTE *src_line = src + y * pitch_in;
1409 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
1410 for (x = 0; x < w; ++x)
1412 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
1413 * C = Y - 16; D = U - 128; E = V - 128;
1414 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
1415 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
1416 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
1417 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
1418 * U and V are shared between the pixels. */
1419 if (!(x & 1)) /* For every even pixel, read new U and V. */
1421 d = (int) src_line[1] - 128;
1422 e = (int) src_line[3] - 128;
1423 r2 = 409 * e + 128;
1424 g2 = - 100 * d - 208 * e + 128;
1425 b2 = 516 * d + 128;
1427 c2 = 298 * ((int) src_line[0] - 16);
1428 dst_line[x] = 0xff000000
1429 | cliptobyte((c2 + r2) >> 8) << 16 /* red */
1430 | cliptobyte((c2 + g2) >> 8) << 8 /* green */
1431 | cliptobyte((c2 + b2) >> 8); /* blue */
1432 /* Scale RGB values to 0..255 range,
1433 * then clip them if still not in range (may be negative),
1434 * then shift them within DWORD if necessary. */
1435 src_line += 2;
1440 static void convert_yuy2_r5g6b5(const BYTE *src, BYTE *dst,
1441 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
1443 unsigned int x, y;
1444 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
1446 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
1448 for (y = 0; y < h; ++y)
1450 const BYTE *src_line = src + y * pitch_in;
1451 WORD *dst_line = (WORD *)(dst + y * pitch_out);
1452 for (x = 0; x < w; ++x)
1454 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
1455 * C = Y - 16; D = U - 128; E = V - 128;
1456 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
1457 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
1458 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
1459 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
1460 * U and V are shared between the pixels. */
1461 if (!(x & 1)) /* For every even pixel, read new U and V. */
1463 d = (int) src_line[1] - 128;
1464 e = (int) src_line[3] - 128;
1465 r2 = 409 * e + 128;
1466 g2 = - 100 * d - 208 * e + 128;
1467 b2 = 516 * d + 128;
1469 c2 = 298 * ((int) src_line[0] - 16);
1470 dst_line[x] = (cliptobyte((c2 + r2) >> 8) >> 3) << 11 /* red */
1471 | (cliptobyte((c2 + g2) >> 8) >> 2) << 5 /* green */
1472 | (cliptobyte((c2 + b2) >> 8) >> 3); /* blue */
1473 /* Scale RGB values to 0..255 range,
1474 * then clip them if still not in range (may be negative),
1475 * then shift them within DWORD if necessary. */
1476 src_line += 2;
1481 struct d3dfmt_converter_desc
1483 enum wined3d_format_id from, to;
1484 void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
1487 static const struct d3dfmt_converter_desc converters[] =
1489 {WINED3DFMT_R32_FLOAT, WINED3DFMT_R16_FLOAT, convert_r32_float_r16_float},
1490 {WINED3DFMT_B5G6R5_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_r5g6b5_x8r8g8b8},
1491 {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_a8r8g8b8_x8r8g8b8},
1492 {WINED3DFMT_B8G8R8X8_UNORM, WINED3DFMT_B8G8R8A8_UNORM, convert_a8r8g8b8_x8r8g8b8},
1493 {WINED3DFMT_YUY2, WINED3DFMT_B8G8R8X8_UNORM, convert_yuy2_x8r8g8b8},
1494 {WINED3DFMT_YUY2, WINED3DFMT_B5G6R5_UNORM, convert_yuy2_r5g6b5},
1497 static inline const struct d3dfmt_converter_desc *find_converter(enum wined3d_format_id from,
1498 enum wined3d_format_id to)
1500 unsigned int i;
1502 for (i = 0; i < (sizeof(converters) / sizeof(*converters)); ++i)
1504 if (converters[i].from == from && converters[i].to == to)
1505 return &converters[i];
1508 return NULL;
1511 static struct wined3d_texture *surface_convert_format(struct wined3d_texture *src_texture,
1512 unsigned int sub_resource_idx, const struct wined3d_format *dst_format)
1514 unsigned int texture_level = sub_resource_idx % src_texture->level_count;
1515 const struct wined3d_format *src_format = src_texture->resource.format;
1516 struct wined3d_device *device = src_texture->resource.device;
1517 const struct d3dfmt_converter_desc *conv = NULL;
1518 struct wined3d_texture *dst_texture;
1519 struct wined3d_resource_desc desc;
1520 struct wined3d_map_desc src_map;
1522 if (!(conv = find_converter(src_format->id, dst_format->id)) && (!device->d3d_initialized
1523 || !is_identity_fixup(src_format->color_fixup) || src_format->convert
1524 || !is_identity_fixup(dst_format->color_fixup) || dst_format->convert))
1526 FIXME("Cannot find a conversion function from format %s to %s.\n",
1527 debug_d3dformat(src_format->id), debug_d3dformat(dst_format->id));
1528 return NULL;
1531 /* FIXME: Multisampled conversion? */
1532 desc.resource_type = WINED3D_RTYPE_TEXTURE_2D;
1533 desc.format = dst_format->id;
1534 desc.multisample_type = WINED3D_MULTISAMPLE_NONE;
1535 desc.multisample_quality = 0;
1536 desc.usage = 0;
1537 desc.pool = WINED3D_POOL_SCRATCH;
1538 desc.width = wined3d_texture_get_level_width(src_texture, texture_level);
1539 desc.height = wined3d_texture_get_level_height(src_texture, texture_level);
1540 desc.depth = 1;
1541 desc.size = 0;
1542 if (FAILED(wined3d_texture_create(device, &desc, 1, 1,
1543 WINED3D_TEXTURE_CREATE_MAPPABLE | WINED3D_TEXTURE_CREATE_DISCARD,
1544 NULL, NULL, &wined3d_null_parent_ops, &dst_texture)))
1546 ERR("Failed to create a destination texture for conversion.\n");
1547 return NULL;
1550 memset(&src_map, 0, sizeof(src_map));
1551 if (FAILED(wined3d_resource_map(&src_texture->resource, sub_resource_idx,
1552 &src_map, NULL, WINED3D_MAP_READONLY)))
1554 ERR("Failed to map the source texture.\n");
1555 wined3d_texture_decref(dst_texture);
1556 return NULL;
1558 if (conv)
1560 struct wined3d_map_desc dst_map;
1562 memset(&dst_map, 0, sizeof(dst_map));
1563 if (FAILED(wined3d_resource_map(&dst_texture->resource, 0, &dst_map, NULL, 0)))
1565 ERR("Failed to map the destination texture.\n");
1566 wined3d_resource_unmap(&src_texture->resource, sub_resource_idx);
1567 wined3d_texture_decref(dst_texture);
1568 return NULL;
1571 conv->convert(src_map.data, dst_map.data, src_map.row_pitch, dst_map.row_pitch, desc.width, desc.height);
1573 wined3d_resource_unmap(&dst_texture->resource, 0);
1575 else
1577 struct wined3d_bo_address data = {0, src_map.data};
1578 RECT src_rect = {0, 0, desc.width, desc.height};
1579 const struct wined3d_gl_info *gl_info;
1580 struct wined3d_context *context;
1581 POINT dst_point = {0, 0};
1583 TRACE("Using upload conversion.\n");
1584 context = context_acquire(device, NULL);
1585 gl_info = context->gl_info;
1587 wined3d_texture_prepare_texture(dst_texture, context, FALSE);
1588 wined3d_texture_bind_and_dirtify(dst_texture, context, FALSE);
1589 wined3d_surface_upload_data(dst_texture->sub_resources[0].u.surface, gl_info, src_format,
1590 &src_rect, src_map.row_pitch, &dst_point, FALSE, wined3d_const_bo_address(&data));
1592 context_release(context);
1594 wined3d_texture_validate_location(dst_texture, 0, WINED3D_LOCATION_TEXTURE_RGB);
1595 wined3d_texture_invalidate_location(dst_texture, 0, ~WINED3D_LOCATION_TEXTURE_RGB);
1597 wined3d_resource_unmap(&src_texture->resource, sub_resource_idx);
1599 return dst_texture;
1602 static HRESULT _Blt_ColorFill(BYTE *buf, unsigned int width, unsigned int height,
1603 unsigned int bpp, UINT pitch, DWORD color)
1605 BYTE *first;
1606 unsigned int x, y;
1608 /* Do first row */
1610 #define COLORFILL_ROW(type) \
1611 do { \
1612 type *d = (type *)buf; \
1613 for (x = 0; x < width; ++x) \
1614 d[x] = (type)color; \
1615 } while(0)
1617 switch (bpp)
1619 case 1:
1620 COLORFILL_ROW(BYTE);
1621 break;
1623 case 2:
1624 COLORFILL_ROW(WORD);
1625 break;
1627 case 3:
1629 BYTE *d = buf;
1630 for (x = 0; x < width; ++x, d += 3)
1632 d[0] = (color ) & 0xff;
1633 d[1] = (color >> 8) & 0xff;
1634 d[2] = (color >> 16) & 0xff;
1636 break;
1638 case 4:
1639 COLORFILL_ROW(DWORD);
1640 break;
1642 default:
1643 FIXME("Color fill not implemented for bpp %u!\n", bpp * 8);
1644 return WINED3DERR_NOTAVAILABLE;
1647 #undef COLORFILL_ROW
1649 /* Now copy first row. */
1650 first = buf;
1651 for (y = 1; y < height; ++y)
1653 buf += pitch;
1654 memcpy(buf, first, width * bpp);
1657 return WINED3D_OK;
1660 static void read_from_framebuffer(struct wined3d_surface *surface,
1661 struct wined3d_context *old_ctx, DWORD dst_location)
1663 unsigned int sub_resource_idx = surface_get_sub_resource_idx(surface);
1664 struct wined3d_texture *texture = surface->container;
1665 struct wined3d_device *device = texture->resource.device;
1666 const struct wined3d_gl_info *gl_info;
1667 struct wined3d_context *context = old_ctx;
1668 struct wined3d_surface *restore_rt = NULL;
1669 unsigned int row_pitch, slice_pitch;
1670 unsigned int width, height;
1671 BYTE *mem;
1672 BYTE *row, *top, *bottom;
1673 int i;
1674 BOOL srcIsUpsideDown;
1675 struct wined3d_bo_address data;
1677 wined3d_texture_get_memory(texture, sub_resource_idx, &data, dst_location);
1679 restore_rt = context_get_rt_surface(old_ctx);
1680 if (restore_rt != surface)
1681 context = context_acquire(device, surface);
1682 else
1683 restore_rt = NULL;
1685 context_apply_blit_state(context, device);
1686 gl_info = context->gl_info;
1688 /* Select the correct read buffer, and give some debug output.
1689 * There is no need to keep track of the current read buffer or reset it, every part of the code
1690 * that reads sets the read buffer as desired.
1692 if (wined3d_resource_is_offscreen(&texture->resource))
1694 /* Mapping the primary render target which is not on a swapchain.
1695 * Read from the back buffer. */
1696 TRACE("Mapping offscreen render target.\n");
1697 gl_info->gl_ops.gl.p_glReadBuffer(context_get_offscreen_gl_buffer(context));
1698 srcIsUpsideDown = TRUE;
1700 else
1702 /* Onscreen surfaces are always part of a swapchain */
1703 GLenum buffer = wined3d_texture_get_gl_buffer(texture);
1704 TRACE("Mapping %#x buffer.\n", buffer);
1705 gl_info->gl_ops.gl.p_glReadBuffer(buffer);
1706 checkGLcall("glReadBuffer");
1707 srcIsUpsideDown = FALSE;
1710 if (data.buffer_object)
1712 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, data.buffer_object));
1713 checkGLcall("glBindBuffer");
1716 wined3d_texture_get_pitch(texture, surface->texture_level, &row_pitch, &slice_pitch);
1718 /* Setup pixel store pack state -- to glReadPixels into the correct place */
1719 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_ROW_LENGTH, row_pitch / texture->resource.format->byte_count);
1720 checkGLcall("glPixelStorei");
1722 width = wined3d_texture_get_level_width(texture, surface->texture_level);
1723 height = wined3d_texture_get_level_height(texture, surface->texture_level);
1724 gl_info->gl_ops.gl.p_glReadPixels(0, 0, width, height,
1725 texture->resource.format->glFormat,
1726 texture->resource.format->glType, data.addr);
1727 checkGLcall("glReadPixels");
1729 /* Reset previous pixel store pack state */
1730 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_ROW_LENGTH, 0);
1731 checkGLcall("glPixelStorei");
1733 if (!srcIsUpsideDown)
1735 /* glReadPixels returns the image upside down, and there is no way to
1736 * prevent this. Flip the lines in software. */
1738 if (!(row = HeapAlloc(GetProcessHeap(), 0, row_pitch)))
1739 goto error;
1741 if (data.buffer_object)
1743 mem = GL_EXTCALL(glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_WRITE));
1744 checkGLcall("glMapBuffer");
1746 else
1747 mem = data.addr;
1749 top = mem;
1750 bottom = mem + row_pitch * (height - 1);
1751 for (i = 0; i < height / 2; i++)
1753 memcpy(row, top, row_pitch);
1754 memcpy(top, bottom, row_pitch);
1755 memcpy(bottom, row, row_pitch);
1756 top += row_pitch;
1757 bottom -= row_pitch;
1759 HeapFree(GetProcessHeap(), 0, row);
1761 if (data.buffer_object)
1762 GL_EXTCALL(glUnmapBuffer(GL_PIXEL_PACK_BUFFER));
1765 error:
1766 if (data.buffer_object)
1768 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));
1769 checkGLcall("glBindBuffer");
1772 if (restore_rt)
1773 context_restore(context, restore_rt);
1776 /* Read the framebuffer contents into a texture. Note that this function
1777 * doesn't do any kind of flipping. Using this on an onscreen surface will
1778 * result in a flipped D3D texture.
1780 * Context activation is done by the caller. This function may temporarily
1781 * switch to a different context and restore the original one before return. */
1782 void surface_load_fb_texture(struct wined3d_surface *surface, BOOL srgb, struct wined3d_context *old_ctx)
1784 struct wined3d_texture *texture = surface->container;
1785 struct wined3d_device *device = texture->resource.device;
1786 const struct wined3d_gl_info *gl_info;
1787 struct wined3d_context *context = old_ctx;
1788 struct wined3d_surface *restore_rt = NULL;
1790 restore_rt = context_get_rt_surface(old_ctx);
1791 if (restore_rt != surface)
1792 context = context_acquire(device, surface);
1793 else
1794 restore_rt = NULL;
1796 gl_info = context->gl_info;
1797 device_invalidate_state(device, STATE_FRAMEBUFFER);
1799 wined3d_texture_prepare_texture(texture, context, srgb);
1800 wined3d_texture_bind_and_dirtify(texture, context, srgb);
1802 TRACE("Reading back offscreen render target %p.\n", surface);
1804 if (wined3d_resource_is_offscreen(&texture->resource))
1805 gl_info->gl_ops.gl.p_glReadBuffer(context_get_offscreen_gl_buffer(context));
1806 else
1807 gl_info->gl_ops.gl.p_glReadBuffer(wined3d_texture_get_gl_buffer(texture));
1808 checkGLcall("glReadBuffer");
1810 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(surface->texture_target, surface->texture_level,
1811 0, 0, 0, 0, wined3d_texture_get_level_width(texture, surface->texture_level),
1812 wined3d_texture_get_level_height(texture, surface->texture_level));
1813 checkGLcall("glCopyTexSubImage2D");
1815 if (restore_rt)
1816 context_restore(context, restore_rt);
1819 /* Does a direct frame buffer -> texture copy. Stretching is done with single
1820 * pixel copy calls. */
1821 static void fb_copy_to_texture_direct(struct wined3d_surface *dst_surface, struct wined3d_surface *src_surface,
1822 const RECT *src_rect, const RECT *dst_rect_in, enum wined3d_texture_filter_type filter)
1824 unsigned int dst_sub_resource_idx = surface_get_sub_resource_idx(dst_surface);
1825 struct wined3d_texture *src_texture = src_surface->container;
1826 struct wined3d_texture *dst_texture = dst_surface->container;
1827 struct wined3d_device *device = dst_texture->resource.device;
1828 const struct wined3d_gl_info *gl_info;
1829 float xrel, yrel;
1830 struct wined3d_context *context;
1831 BOOL upsidedown = FALSE;
1832 RECT dst_rect = *dst_rect_in;
1833 unsigned int src_height;
1835 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
1836 * glCopyTexSubImage is a bit picky about the parameters we pass to it
1838 if(dst_rect.top > dst_rect.bottom) {
1839 UINT tmp = dst_rect.bottom;
1840 dst_rect.bottom = dst_rect.top;
1841 dst_rect.top = tmp;
1842 upsidedown = TRUE;
1845 context = context_acquire(device, src_surface);
1846 gl_info = context->gl_info;
1847 context_apply_blit_state(context, device);
1848 wined3d_texture_load(dst_texture, context, FALSE);
1850 /* Bind the target texture */
1851 context_bind_texture(context, dst_texture->target, dst_texture->texture_rgb.name);
1852 if (wined3d_resource_is_offscreen(&src_texture->resource))
1854 TRACE("Reading from an offscreen target\n");
1855 upsidedown = !upsidedown;
1856 gl_info->gl_ops.gl.p_glReadBuffer(context_get_offscreen_gl_buffer(context));
1858 else
1860 gl_info->gl_ops.gl.p_glReadBuffer(wined3d_texture_get_gl_buffer(src_texture));
1862 checkGLcall("glReadBuffer");
1864 xrel = (float) (src_rect->right - src_rect->left) / (float) (dst_rect.right - dst_rect.left);
1865 yrel = (float) (src_rect->bottom - src_rect->top) / (float) (dst_rect.bottom - dst_rect.top);
1867 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
1869 FIXME_(d3d_perf)("Doing a pixel by pixel copy from the framebuffer to a texture.\n");
1871 if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT)
1872 ERR("Texture filtering not supported in direct blit.\n");
1874 else if ((filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT)
1875 && ((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
1877 ERR("Texture filtering not supported in direct blit\n");
1880 src_height = wined3d_texture_get_level_height(src_texture, src_surface->texture_level);
1881 if (upsidedown
1882 && !((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
1883 && !((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
1885 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do. */
1886 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
1887 dst_rect.left /*xoffset */, dst_rect.top /* y offset */,
1888 src_rect->left, src_height - src_rect->bottom,
1889 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
1891 else
1893 LONG row;
1894 UINT yoffset = src_height - src_rect->top + dst_rect.top - 1;
1895 /* I have to process this row by row to swap the image,
1896 * otherwise it would be upside down, so stretching in y direction
1897 * doesn't cost extra time
1899 * However, stretching in x direction can be avoided if not necessary
1901 for(row = dst_rect.top; row < dst_rect.bottom; row++) {
1902 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
1904 /* Well, that stuff works, but it's very slow.
1905 * find a better way instead
1907 LONG col;
1909 for (col = dst_rect.left; col < dst_rect.right; ++col)
1911 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
1912 dst_rect.left + col /* x offset */, row /* y offset */,
1913 src_rect->left + col * xrel, yoffset - (int) (row * yrel), 1, 1);
1916 else
1918 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
1919 dst_rect.left /* x offset */, row /* y offset */,
1920 src_rect->left, yoffset - (int) (row * yrel), dst_rect.right - dst_rect.left, 1);
1924 checkGLcall("glCopyTexSubImage2D");
1926 context_release(context);
1928 /* The texture is now most up to date - If the surface is a render target
1929 * and has a drawable, this path is never entered. */
1930 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB);
1931 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB);
1934 /* Uses the hardware to stretch and flip the image */
1935 static void fb_copy_to_texture_hwstretch(struct wined3d_surface *dst_surface, struct wined3d_surface *src_surface,
1936 const RECT *src_rect, const RECT *dst_rect_in, enum wined3d_texture_filter_type filter)
1938 unsigned int dst_sub_resource_idx = surface_get_sub_resource_idx(dst_surface);
1939 unsigned int src_width, src_height, src_pow2_width, src_pow2_height;
1940 struct wined3d_texture *src_texture = src_surface->container;
1941 struct wined3d_texture *dst_texture = dst_surface->container;
1942 struct wined3d_device *device = dst_texture->resource.device;
1943 GLuint src, backup = 0;
1944 float left, right, top, bottom; /* Texture coordinates */
1945 const struct wined3d_gl_info *gl_info;
1946 struct wined3d_context *context;
1947 GLenum drawBuffer = GL_BACK;
1948 GLenum offscreen_buffer;
1949 GLenum texture_target;
1950 BOOL noBackBufferBackup;
1951 BOOL src_offscreen;
1952 BOOL upsidedown = FALSE;
1953 RECT dst_rect = *dst_rect_in;
1955 TRACE("Using hwstretch blit\n");
1956 /* Activate the Proper context for reading from the source surface, set it up for blitting */
1957 context = context_acquire(device, src_surface);
1958 gl_info = context->gl_info;
1959 context_apply_blit_state(context, device);
1960 wined3d_texture_load(dst_texture, context, FALSE);
1962 offscreen_buffer = context_get_offscreen_gl_buffer(context);
1963 src_width = wined3d_texture_get_level_width(src_texture, src_surface->texture_level);
1964 src_height = wined3d_texture_get_level_height(src_texture, src_surface->texture_level);
1965 src_pow2_width = wined3d_texture_get_level_pow2_width(src_texture, src_surface->texture_level);
1966 src_pow2_height = wined3d_texture_get_level_pow2_height(src_texture, src_surface->texture_level);
1968 src_offscreen = wined3d_resource_is_offscreen(&src_texture->resource);
1969 noBackBufferBackup = src_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO;
1970 if (!noBackBufferBackup && !src_texture->texture_rgb.name)
1972 /* Get it a description */
1973 wined3d_texture_load(src_texture, context, FALSE);
1976 /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
1977 * This way we don't have to wait for the 2nd readback to finish to leave this function.
1979 if (context->aux_buffers >= 2)
1981 /* Got more than one aux buffer? Use the 2nd aux buffer */
1982 drawBuffer = GL_AUX1;
1984 else if ((!src_offscreen || offscreen_buffer == GL_BACK) && context->aux_buffers >= 1)
1986 /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
1987 drawBuffer = GL_AUX0;
1990 if (noBackBufferBackup)
1992 gl_info->gl_ops.gl.p_glGenTextures(1, &backup);
1993 checkGLcall("glGenTextures");
1994 context_bind_texture(context, GL_TEXTURE_2D, backup);
1995 texture_target = GL_TEXTURE_2D;
1997 else
1999 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
2000 * we are reading from the back buffer, the backup can be used as source texture
2002 texture_target = src_surface->texture_target;
2003 context_bind_texture(context, texture_target, src_texture->texture_rgb.name);
2004 gl_info->gl_ops.gl.p_glEnable(texture_target);
2005 checkGLcall("glEnable(texture_target)");
2007 /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
2008 surface_get_sub_resource(src_surface)->locations &= ~WINED3D_LOCATION_TEXTURE_RGB;
2011 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
2012 * glCopyTexSubImage is a bit picky about the parameters we pass to it
2014 if(dst_rect.top > dst_rect.bottom) {
2015 UINT tmp = dst_rect.bottom;
2016 dst_rect.bottom = dst_rect.top;
2017 dst_rect.top = tmp;
2018 upsidedown = TRUE;
2021 if (src_offscreen)
2023 TRACE("Reading from an offscreen target\n");
2024 upsidedown = !upsidedown;
2025 gl_info->gl_ops.gl.p_glReadBuffer(offscreen_buffer);
2027 else
2029 gl_info->gl_ops.gl.p_glReadBuffer(wined3d_texture_get_gl_buffer(src_texture));
2032 /* TODO: Only back up the part that will be overwritten */
2033 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(texture_target, 0, 0, 0, 0, 0, src_width, src_height);
2035 checkGLcall("glCopyTexSubImage2D");
2037 /* No issue with overriding these - the sampler is dirty due to blit usage */
2038 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, wined3d_gl_mag_filter(filter));
2039 checkGLcall("glTexParameteri");
2040 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER,
2041 wined3d_gl_min_mip_filter(filter, WINED3D_TEXF_NONE));
2042 checkGLcall("glTexParameteri");
2044 if (!src_texture->swapchain || src_texture == src_texture->swapchain->back_buffers[0])
2046 src = backup ? backup : src_texture->texture_rgb.name;
2048 else
2050 gl_info->gl_ops.gl.p_glReadBuffer(GL_FRONT);
2051 checkGLcall("glReadBuffer(GL_FRONT)");
2053 gl_info->gl_ops.gl.p_glGenTextures(1, &src);
2054 checkGLcall("glGenTextures(1, &src)");
2055 context_bind_texture(context, GL_TEXTURE_2D, src);
2057 /* TODO: Only copy the part that will be read. Use src_rect->left,
2058 * src_rect->bottom as origin, but with the width watch out for power
2059 * of 2 sizes. */
2060 gl_info->gl_ops.gl.p_glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, src_pow2_width,
2061 src_pow2_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
2062 checkGLcall("glTexImage2D");
2063 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, src_width, src_height);
2065 gl_info->gl_ops.gl.p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2066 checkGLcall("glTexParameteri");
2067 gl_info->gl_ops.gl.p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2068 checkGLcall("glTexParameteri");
2070 gl_info->gl_ops.gl.p_glReadBuffer(GL_BACK);
2071 checkGLcall("glReadBuffer(GL_BACK)");
2073 if (texture_target != GL_TEXTURE_2D)
2075 gl_info->gl_ops.gl.p_glDisable(texture_target);
2076 gl_info->gl_ops.gl.p_glEnable(GL_TEXTURE_2D);
2077 texture_target = GL_TEXTURE_2D;
2080 checkGLcall("glEnd and previous");
2082 left = src_rect->left;
2083 right = src_rect->right;
2085 if (!upsidedown)
2087 top = src_height - src_rect->top;
2088 bottom = src_height - src_rect->bottom;
2090 else
2092 top = src_height - src_rect->bottom;
2093 bottom = src_height - src_rect->top;
2096 if (src_texture->flags & WINED3D_TEXTURE_NORMALIZED_COORDS)
2098 left /= src_pow2_width;
2099 right /= src_pow2_width;
2100 top /= src_pow2_height;
2101 bottom /= src_pow2_height;
2104 /* draw the source texture stretched and upside down. The correct surface is bound already */
2105 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2106 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2108 context_set_draw_buffer(context, drawBuffer);
2109 gl_info->gl_ops.gl.p_glReadBuffer(drawBuffer);
2111 gl_info->gl_ops.gl.p_glBegin(GL_QUADS);
2112 /* bottom left */
2113 gl_info->gl_ops.gl.p_glTexCoord2f(left, bottom);
2114 gl_info->gl_ops.gl.p_glVertex2i(0, 0);
2116 /* top left */
2117 gl_info->gl_ops.gl.p_glTexCoord2f(left, top);
2118 gl_info->gl_ops.gl.p_glVertex2i(0, dst_rect.bottom - dst_rect.top);
2120 /* top right */
2121 gl_info->gl_ops.gl.p_glTexCoord2f(right, top);
2122 gl_info->gl_ops.gl.p_glVertex2i(dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
2124 /* bottom right */
2125 gl_info->gl_ops.gl.p_glTexCoord2f(right, bottom);
2126 gl_info->gl_ops.gl.p_glVertex2i(dst_rect.right - dst_rect.left, 0);
2127 gl_info->gl_ops.gl.p_glEnd();
2128 checkGLcall("glEnd and previous");
2130 if (texture_target != dst_surface->texture_target)
2132 gl_info->gl_ops.gl.p_glDisable(texture_target);
2133 gl_info->gl_ops.gl.p_glEnable(dst_surface->texture_target);
2134 texture_target = dst_surface->texture_target;
2137 /* Now read the stretched and upside down image into the destination texture */
2138 context_bind_texture(context, texture_target, dst_texture->texture_rgb.name);
2139 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(texture_target,
2141 dst_rect.left, dst_rect.top, /* xoffset, yoffset */
2142 0, 0, /* We blitted the image to the origin */
2143 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
2144 checkGLcall("glCopyTexSubImage2D");
2146 if (drawBuffer == GL_BACK)
2148 /* Write the back buffer backup back. */
2149 if (backup)
2151 if (texture_target != GL_TEXTURE_2D)
2153 gl_info->gl_ops.gl.p_glDisable(texture_target);
2154 gl_info->gl_ops.gl.p_glEnable(GL_TEXTURE_2D);
2155 texture_target = GL_TEXTURE_2D;
2157 context_bind_texture(context, GL_TEXTURE_2D, backup);
2159 else
2161 if (texture_target != src_surface->texture_target)
2163 gl_info->gl_ops.gl.p_glDisable(texture_target);
2164 gl_info->gl_ops.gl.p_glEnable(src_surface->texture_target);
2165 texture_target = src_surface->texture_target;
2167 context_bind_texture(context, src_surface->texture_target, src_texture->texture_rgb.name);
2170 gl_info->gl_ops.gl.p_glBegin(GL_QUADS);
2171 /* top left */
2172 gl_info->gl_ops.gl.p_glTexCoord2f(0.0f, 0.0f);
2173 gl_info->gl_ops.gl.p_glVertex2i(0, src_height);
2175 /* bottom left */
2176 gl_info->gl_ops.gl.p_glTexCoord2f(0.0f, (float)src_height / (float)src_pow2_height);
2177 gl_info->gl_ops.gl.p_glVertex2i(0, 0);
2179 /* bottom right */
2180 gl_info->gl_ops.gl.p_glTexCoord2f((float)src_width / (float)src_pow2_width,
2181 (float)src_height / (float)src_pow2_height);
2182 gl_info->gl_ops.gl.p_glVertex2i(src_width, 0);
2184 /* top right */
2185 gl_info->gl_ops.gl.p_glTexCoord2f((float)src_width / (float)src_pow2_width, 0.0f);
2186 gl_info->gl_ops.gl.p_glVertex2i(src_width, src_height);
2187 gl_info->gl_ops.gl.p_glEnd();
2189 gl_info->gl_ops.gl.p_glDisable(texture_target);
2190 checkGLcall("glDisable(texture_target)");
2192 /* Cleanup */
2193 if (src != src_texture->texture_rgb.name && src != backup)
2195 gl_info->gl_ops.gl.p_glDeleteTextures(1, &src);
2196 checkGLcall("glDeleteTextures(1, &src)");
2198 if (backup)
2200 gl_info->gl_ops.gl.p_glDeleteTextures(1, &backup);
2201 checkGLcall("glDeleteTextures(1, &backup)");
2204 if (wined3d_settings.strict_draw_ordering)
2205 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
2207 context_release(context);
2209 /* The texture is now most up to date - If the surface is a render target
2210 * and has a drawable, this path is never entered. */
2211 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB);
2212 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB);
2215 /* Front buffer coordinates are always full screen coordinates, but our GL
2216 * drawable is limited to the window's client area. The sysmem and texture
2217 * copies do have the full screen size. Note that GL has a bottom-left
2218 * origin, while D3D has a top-left origin. */
2219 void surface_translate_drawable_coords(const struct wined3d_surface *surface, HWND window, RECT *rect)
2221 struct wined3d_texture *texture = surface->container;
2222 UINT drawable_height;
2224 if (texture->swapchain && texture == texture->swapchain->front_buffer)
2226 POINT offset = {0, 0};
2227 RECT windowsize;
2229 ScreenToClient(window, &offset);
2230 OffsetRect(rect, offset.x, offset.y);
2232 GetClientRect(window, &windowsize);
2233 drawable_height = windowsize.bottom - windowsize.top;
2235 else
2237 drawable_height = wined3d_texture_get_level_height(texture, surface->texture_level);
2240 rect->top = drawable_height - rect->top;
2241 rect->bottom = drawable_height - rect->bottom;
2244 /* Context activation is done by the caller. */
2245 static void surface_blt_to_drawable(const struct wined3d_device *device,
2246 struct wined3d_context *old_ctx,
2247 enum wined3d_texture_filter_type filter, BOOL alpha_test,
2248 struct wined3d_surface *src_surface, const RECT *src_rect_in,
2249 struct wined3d_surface *dst_surface, const RECT *dst_rect_in)
2251 struct wined3d_texture *src_texture = src_surface->container;
2252 struct wined3d_texture *dst_texture = dst_surface->container;
2253 const struct wined3d_gl_info *gl_info;
2254 struct wined3d_context *context = old_ctx;
2255 struct wined3d_surface *restore_rt = NULL;
2256 RECT src_rect, dst_rect;
2258 src_rect = *src_rect_in;
2259 dst_rect = *dst_rect_in;
2261 restore_rt = context_get_rt_surface(old_ctx);
2262 if (restore_rt != dst_surface)
2263 context = context_acquire(device, dst_surface);
2264 else
2265 restore_rt = NULL;
2267 gl_info = context->gl_info;
2269 /* Make sure the surface is up-to-date. This should probably use
2270 * surface_load_location() and worry about the destination surface too,
2271 * unless we're overwriting it completely. */
2272 wined3d_texture_load(src_texture, context, FALSE);
2274 /* Activate the destination context, set it up for blitting */
2275 context_apply_blit_state(context, device);
2277 if (!wined3d_resource_is_offscreen(&dst_texture->resource))
2278 surface_translate_drawable_coords(dst_surface, context->win_handle, &dst_rect);
2280 device->blitter->set_shader(device->blit_priv, context, src_surface, NULL);
2282 if (alpha_test)
2284 gl_info->gl_ops.gl.p_glEnable(GL_ALPHA_TEST);
2285 checkGLcall("glEnable(GL_ALPHA_TEST)");
2287 /* For P8 surfaces, the alpha component contains the palette index.
2288 * Which means that the colorkey is one of the palette entries. In
2289 * other cases pixels that should be masked away have alpha set to 0. */
2290 if (src_texture->resource.format->id == WINED3DFMT_P8_UINT)
2291 gl_info->gl_ops.gl.p_glAlphaFunc(GL_NOTEQUAL,
2292 (float)src_texture->async.src_blt_color_key.color_space_low_value / 255.0f);
2293 else
2294 gl_info->gl_ops.gl.p_glAlphaFunc(GL_NOTEQUAL, 0.0f);
2295 checkGLcall("glAlphaFunc");
2297 else
2299 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
2300 checkGLcall("glDisable(GL_ALPHA_TEST)");
2303 draw_textured_quad(src_surface, context, &src_rect, &dst_rect, filter);
2305 if (alpha_test)
2307 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
2308 checkGLcall("glDisable(GL_ALPHA_TEST)");
2311 /* Leave the opengl state valid for blitting */
2312 device->blitter->unset_shader(context->gl_info);
2314 if (wined3d_settings.strict_draw_ordering
2315 || (dst_texture->swapchain && dst_texture->swapchain->front_buffer == dst_texture))
2316 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
2318 if (restore_rt)
2319 context_restore(context, restore_rt);
2322 HRESULT surface_color_fill(struct wined3d_surface *s, const RECT *rect, const struct wined3d_color *color)
2324 struct wined3d_resource *resource = &s->container->resource;
2325 struct wined3d_device *device = resource->device;
2326 struct wined3d_rendertarget_view *view;
2327 struct wined3d_view_desc view_desc;
2328 const struct blit_shader *blitter;
2329 HRESULT hr;
2331 if (!(blitter = wined3d_select_blitter(&device->adapter->gl_info, &device->adapter->d3d_info,
2332 WINED3D_BLIT_OP_COLOR_FILL, NULL, 0, 0, NULL, rect, resource->usage, resource->pool, resource->format)))
2334 FIXME("No blitter is capable of performing the requested color fill operation.\n");
2335 return WINED3DERR_INVALIDCALL;
2338 view_desc.format_id = resource->format->id;
2339 view_desc.flags = 0;
2340 view_desc.u.texture.level_idx = s->texture_level;
2341 view_desc.u.texture.level_count = 1;
2342 view_desc.u.texture.layer_idx = s->texture_layer;
2343 view_desc.u.texture.layer_count = 1;
2344 if (FAILED(hr = wined3d_rendertarget_view_create(&view_desc,
2345 resource, NULL, &wined3d_null_parent_ops, &view)))
2347 ERR("Failed to create rendertarget view, hr %#x.\n", hr);
2348 return hr;
2351 hr = blitter->color_fill(device, view, rect, color);
2352 wined3d_rendertarget_view_decref(view);
2354 return hr;
2357 static HRESULT surface_blt_special(struct wined3d_surface *dst_surface, const RECT *dst_rect,
2358 struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags,
2359 const struct wined3d_blt_fx *fx, enum wined3d_texture_filter_type filter)
2361 struct wined3d_texture *dst_texture = dst_surface->container;
2362 struct wined3d_device *device = dst_texture->resource.device;
2363 const struct wined3d_surface *rt = wined3d_rendertarget_view_get_surface(device->fb.render_targets[0]);
2364 struct wined3d_swapchain *src_swapchain, *dst_swapchain;
2365 struct wined3d_texture *src_texture;
2367 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
2368 dst_surface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect),
2369 flags, fx, debug_d3dtexturefiltertype(filter));
2371 /* Get the swapchain. One of the surfaces has to be a primary surface */
2372 if (dst_texture->resource.pool == WINED3D_POOL_SYSTEM_MEM)
2374 WARN("Destination is in sysmem, rejecting gl blt\n");
2375 return WINED3DERR_INVALIDCALL;
2378 dst_swapchain = dst_texture->swapchain;
2380 if (src_surface)
2382 src_texture = src_surface->container;
2383 if (src_texture->resource.pool == WINED3D_POOL_SYSTEM_MEM)
2385 WARN("Src is in sysmem, rejecting gl blt\n");
2386 return WINED3DERR_INVALIDCALL;
2389 src_swapchain = src_texture->swapchain;
2391 else
2393 src_texture = NULL;
2394 src_swapchain = NULL;
2397 /* Early sort out of cases where no render target is used */
2398 if (!dst_swapchain && !src_swapchain && src_surface != rt && dst_surface != rt)
2400 TRACE("No surface is render target, not using hardware blit.\n");
2401 return WINED3DERR_INVALIDCALL;
2404 /* No destination color keying supported */
2405 if (flags & (WINED3D_BLT_DST_CKEY | WINED3D_BLT_DST_CKEY_OVERRIDE))
2407 /* Can we support that with glBlendFunc if blitting to the frame buffer? */
2408 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
2409 return WINED3DERR_INVALIDCALL;
2412 if (dst_swapchain && dst_swapchain == src_swapchain)
2414 FIXME("Implement hardware blit between two surfaces on the same swapchain\n");
2415 return WINED3DERR_INVALIDCALL;
2418 if (dst_swapchain && src_swapchain)
2420 FIXME("Implement hardware blit between two different swapchains\n");
2421 return WINED3DERR_INVALIDCALL;
2424 if (dst_swapchain)
2426 /* Handled with regular texture -> swapchain blit */
2427 if (src_surface == rt)
2428 TRACE("Blit from active render target to a swapchain\n");
2430 else if (src_swapchain && dst_surface == rt)
2432 FIXME("Implement blit from a swapchain to the active render target\n");
2433 return WINED3DERR_INVALIDCALL;
2436 if ((src_swapchain || src_surface == rt) && !dst_swapchain)
2438 unsigned int src_width, src_height;
2439 /* Blit from render target to texture */
2440 BOOL stretchx;
2442 /* P8 read back is not implemented */
2443 if (src_texture->resource.format->id == WINED3DFMT_P8_UINT
2444 || dst_texture->resource.format->id == WINED3DFMT_P8_UINT)
2446 TRACE("P8 read back not supported by frame buffer to texture blit\n");
2447 return WINED3DERR_INVALIDCALL;
2450 if (flags & (WINED3D_BLT_SRC_CKEY | WINED3D_BLT_SRC_CKEY_OVERRIDE))
2452 TRACE("Color keying not supported by frame buffer to texture blit\n");
2453 return WINED3DERR_INVALIDCALL;
2454 /* Destination color key is checked above */
2457 if (dst_rect->right - dst_rect->left != src_rect->right - src_rect->left)
2458 stretchx = TRUE;
2459 else
2460 stretchx = FALSE;
2462 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
2463 * flip the image nor scale it.
2465 * -> If the app asks for an unscaled, upside down copy, just perform one glCopyTexSubImage2D call
2466 * -> If the app wants an image width an unscaled width, copy it line per line
2467 * -> If the app wants an image that is scaled on the x axis, and the destination rectangle is smaller
2468 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
2469 * back buffer. This is slower than reading line per line, thus not used for flipping
2470 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
2471 * pixel by pixel. */
2472 src_width = wined3d_texture_get_level_width(src_texture, src_surface->texture_level);
2473 src_height = wined3d_texture_get_level_height(src_texture, src_surface->texture_level);
2474 if (!stretchx || dst_rect->right - dst_rect->left > src_width
2475 || dst_rect->bottom - dst_rect->top > src_height)
2477 TRACE("No stretching in x direction, using direct framebuffer -> texture copy.\n");
2478 fb_copy_to_texture_direct(dst_surface, src_surface, src_rect, dst_rect, filter);
2480 else
2482 TRACE("Using hardware stretching to flip / stretch the texture.\n");
2483 fb_copy_to_texture_hwstretch(dst_surface, src_surface, src_rect, dst_rect, filter);
2486 return WINED3D_OK;
2489 /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
2490 TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
2491 return WINED3DERR_INVALIDCALL;
2494 static DWORD resource_access_from_location(DWORD location)
2496 switch (location)
2498 case WINED3D_LOCATION_SYSMEM:
2499 case WINED3D_LOCATION_USER_MEMORY:
2500 case WINED3D_LOCATION_BUFFER:
2501 return WINED3D_RESOURCE_ACCESS_CPU;
2503 case WINED3D_LOCATION_DRAWABLE:
2504 case WINED3D_LOCATION_TEXTURE_SRGB:
2505 case WINED3D_LOCATION_TEXTURE_RGB:
2506 case WINED3D_LOCATION_RB_MULTISAMPLE:
2507 case WINED3D_LOCATION_RB_RESOLVED:
2508 return WINED3D_RESOURCE_ACCESS_GPU;
2510 default:
2511 FIXME("Unhandled location %#x.\n", location);
2512 return 0;
2516 static void surface_copy_simple_location(struct wined3d_surface *surface, DWORD location)
2518 unsigned int sub_resource_idx = surface_get_sub_resource_idx(surface);
2519 struct wined3d_texture *texture = surface->container;
2520 struct wined3d_device *device = texture->resource.device;
2521 struct wined3d_texture_sub_resource *sub_resource;
2522 struct wined3d_context *context;
2523 const struct wined3d_gl_info *gl_info;
2524 struct wined3d_bo_address dst, src;
2526 sub_resource = &texture->sub_resources[sub_resource_idx];
2527 wined3d_texture_get_memory(texture, sub_resource_idx, &dst, location);
2528 wined3d_texture_get_memory(texture, sub_resource_idx, &src, sub_resource->locations);
2530 if (dst.buffer_object)
2532 context = context_acquire(device, NULL);
2533 gl_info = context->gl_info;
2534 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, dst.buffer_object));
2535 GL_EXTCALL(glBufferSubData(GL_PIXEL_UNPACK_BUFFER, 0, sub_resource->size, src.addr));
2536 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));
2537 checkGLcall("Upload PBO");
2538 context_release(context);
2539 return;
2541 if (src.buffer_object)
2543 context = context_acquire(device, NULL);
2544 gl_info = context->gl_info;
2545 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, src.buffer_object));
2546 GL_EXTCALL(glGetBufferSubData(GL_PIXEL_PACK_BUFFER, 0, sub_resource->size, dst.addr));
2547 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));
2548 checkGLcall("Download PBO");
2549 context_release(context);
2550 return;
2552 memcpy(dst.addr, src.addr, sub_resource->size);
2555 /* Context activation is done by the caller. */
2556 static void surface_load_sysmem(struct wined3d_surface *surface,
2557 struct wined3d_context *context, DWORD dst_location)
2559 unsigned int sub_resource_idx = surface_get_sub_resource_idx(surface);
2560 const struct wined3d_gl_info *gl_info = context->gl_info;
2561 struct wined3d_texture *texture = surface->container;
2562 struct wined3d_texture_sub_resource *sub_resource;
2564 wined3d_texture_prepare_location(texture, sub_resource_idx, context, dst_location);
2566 sub_resource = &texture->sub_resources[sub_resource_idx];
2567 if (sub_resource->locations & surface_simple_locations)
2569 surface_copy_simple_location(surface, dst_location);
2570 return;
2573 if (sub_resource->locations & (WINED3D_LOCATION_RB_MULTISAMPLE | WINED3D_LOCATION_RB_RESOLVED))
2574 wined3d_texture_load_location(texture, sub_resource_idx, context, WINED3D_LOCATION_TEXTURE_RGB);
2576 /* Download the surface to system memory. */
2577 if (sub_resource->locations & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB))
2579 wined3d_texture_bind_and_dirtify(texture, context,
2580 !(sub_resource->locations & WINED3D_LOCATION_TEXTURE_RGB));
2581 surface_download_data(surface, gl_info, dst_location);
2582 ++texture->download_count;
2584 return;
2587 if (sub_resource->locations & WINED3D_LOCATION_DRAWABLE)
2589 read_from_framebuffer(surface, context, dst_location);
2590 return;
2593 FIXME("Can't load surface %p with location flags %s into sysmem.\n",
2594 surface, wined3d_debug_location(sub_resource->locations));
2597 /* Context activation is done by the caller. */
2598 static HRESULT surface_load_drawable(struct wined3d_surface *surface,
2599 struct wined3d_context *context)
2601 unsigned int sub_resource_idx = surface_get_sub_resource_idx(surface);
2602 struct wined3d_texture *texture = surface->container;
2603 RECT r;
2605 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO
2606 && wined3d_resource_is_offscreen(&texture->resource))
2608 ERR("Trying to load offscreen surface into WINED3D_LOCATION_DRAWABLE.\n");
2609 return WINED3DERR_INVALIDCALL;
2612 surface_get_rect(surface, NULL, &r);
2613 wined3d_texture_load_location(texture, sub_resource_idx, context, WINED3D_LOCATION_TEXTURE_RGB);
2614 surface_blt_to_drawable(texture->resource.device, context,
2615 WINED3D_TEXF_POINT, FALSE, surface, &r, surface, &r);
2617 return WINED3D_OK;
2620 static HRESULT surface_load_texture(struct wined3d_surface *surface,
2621 struct wined3d_context *context, BOOL srgb)
2623 unsigned int width, height, src_row_pitch, src_slice_pitch, dst_row_pitch, dst_slice_pitch;
2624 unsigned int sub_resource_idx = surface_get_sub_resource_idx(surface);
2625 const struct wined3d_gl_info *gl_info = context->gl_info;
2626 struct wined3d_texture *texture = surface->container;
2627 struct wined3d_device *device = texture->resource.device;
2628 const struct wined3d_color_key_conversion *conversion;
2629 struct wined3d_texture_sub_resource *sub_resource;
2630 struct wined3d_bo_address data;
2631 BYTE *src_mem, *dst_mem = NULL;
2632 struct wined3d_format format;
2633 POINT dst_point = {0, 0};
2634 RECT src_rect;
2636 sub_resource = surface_get_sub_resource(surface);
2637 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO
2638 && wined3d_resource_is_offscreen(&texture->resource)
2639 && (sub_resource->locations & WINED3D_LOCATION_DRAWABLE))
2641 surface_load_fb_texture(surface, srgb, context);
2643 return WINED3D_OK;
2646 width = wined3d_texture_get_level_width(texture, surface->texture_level);
2647 height = wined3d_texture_get_level_height(texture, surface->texture_level);
2648 SetRect(&src_rect, 0, 0, width, height);
2650 if (sub_resource->locations & (WINED3D_LOCATION_TEXTURE_SRGB | WINED3D_LOCATION_TEXTURE_RGB)
2651 && (texture->resource.format_flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB)
2652 && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
2653 NULL, texture->resource.usage, texture->resource.pool, texture->resource.format,
2654 NULL, texture->resource.usage, texture->resource.pool, texture->resource.format))
2656 if (srgb)
2657 surface_blt_fbo(device, context, WINED3D_TEXF_POINT, surface, WINED3D_LOCATION_TEXTURE_RGB,
2658 &src_rect, surface, WINED3D_LOCATION_TEXTURE_SRGB, &src_rect);
2659 else
2660 surface_blt_fbo(device, context, WINED3D_TEXF_POINT, surface, WINED3D_LOCATION_TEXTURE_SRGB,
2661 &src_rect, surface, WINED3D_LOCATION_TEXTURE_RGB, &src_rect);
2663 return WINED3D_OK;
2666 if (sub_resource->locations & (WINED3D_LOCATION_RB_MULTISAMPLE | WINED3D_LOCATION_RB_RESOLVED)
2667 && (!srgb || (texture->resource.format_flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB))
2668 && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
2669 NULL, texture->resource.usage, texture->resource.pool, texture->resource.format,
2670 NULL, texture->resource.usage, texture->resource.pool, texture->resource.format))
2672 DWORD src_location = sub_resource->locations & WINED3D_LOCATION_RB_RESOLVED ?
2673 WINED3D_LOCATION_RB_RESOLVED : WINED3D_LOCATION_RB_MULTISAMPLE;
2674 DWORD dst_location = srgb ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB;
2676 surface_blt_fbo(device, context, WINED3D_TEXF_POINT, surface, src_location,
2677 &src_rect, surface, dst_location, &src_rect);
2679 return WINED3D_OK;
2682 /* Upload from system memory */
2684 if (srgb)
2686 if ((sub_resource->locations & (WINED3D_LOCATION_TEXTURE_RGB | texture->resource.map_binding))
2687 == WINED3D_LOCATION_TEXTURE_RGB)
2689 FIXME_(d3d_perf)("Downloading RGB surface %p to reload it as sRGB.\n", surface);
2690 wined3d_texture_load_location(texture, sub_resource_idx, context, texture->resource.map_binding);
2693 else
2695 if ((sub_resource->locations & (WINED3D_LOCATION_TEXTURE_SRGB | texture->resource.map_binding))
2696 == WINED3D_LOCATION_TEXTURE_SRGB)
2698 FIXME_(d3d_perf)("Downloading sRGB surface %p to reload it as RGB.\n", surface);
2699 wined3d_texture_load_location(texture, sub_resource_idx, context, texture->resource.map_binding);
2703 if (!(sub_resource->locations & surface_simple_locations))
2705 WARN("Trying to load a texture from sysmem, but no simple location is valid.\n");
2706 /* Lets hope we get it from somewhere... */
2707 wined3d_texture_load_location(texture, sub_resource_idx, context, WINED3D_LOCATION_SYSMEM);
2710 wined3d_texture_prepare_texture(texture, context, srgb);
2711 wined3d_texture_bind_and_dirtify(texture, context, srgb);
2712 wined3d_texture_get_pitch(texture, surface->texture_level, &src_row_pitch, &src_slice_pitch);
2714 format = *texture->resource.format;
2715 if ((conversion = wined3d_format_get_color_key_conversion(texture, TRUE)))
2716 format = *wined3d_get_format(gl_info, conversion->dst_format, texture->resource.usage);
2718 /* Don't use PBOs for converted surfaces. During PBO conversion we look at
2719 * WINED3D_TEXTURE_CONVERTED but it isn't set (yet) in all cases it is
2720 * getting called. */
2721 if ((format.convert || conversion) && texture->sub_resources[sub_resource_idx].buffer_object)
2723 TRACE("Removing the pbo attached to surface %p.\n", surface);
2725 wined3d_texture_load_location(texture, sub_resource_idx, context, WINED3D_LOCATION_SYSMEM);
2726 wined3d_texture_set_map_binding(texture, WINED3D_LOCATION_SYSMEM);
2729 wined3d_texture_get_memory(texture, sub_resource_idx, &data, sub_resource->locations);
2730 if (format.convert)
2732 /* This code is entered for texture formats which need a fixup. */
2733 format.byte_count = format.conv_byte_count;
2734 wined3d_format_calculate_pitch(&format, 1, width, height, &dst_row_pitch, &dst_slice_pitch);
2736 src_mem = wined3d_texture_map_bo_address(&data, src_slice_pitch,
2737 gl_info, GL_PIXEL_UNPACK_BUFFER, WINED3D_MAP_READONLY);
2738 if (!(dst_mem = HeapAlloc(GetProcessHeap(), 0, dst_slice_pitch)))
2740 ERR("Out of memory (%u).\n", dst_slice_pitch);
2741 context_release(context);
2742 return E_OUTOFMEMORY;
2744 format.convert(src_mem, dst_mem, src_row_pitch, src_slice_pitch,
2745 dst_row_pitch, dst_slice_pitch, width, height, 1);
2746 src_row_pitch = dst_row_pitch;
2747 wined3d_texture_unmap_bo_address(&data, gl_info, GL_PIXEL_UNPACK_BUFFER);
2749 data.buffer_object = 0;
2750 data.addr = dst_mem;
2752 else if (conversion)
2754 /* This code is only entered for color keying fixups */
2755 struct wined3d_palette *palette = NULL;
2757 wined3d_format_calculate_pitch(&format, device->surface_alignment,
2758 width, height, &dst_row_pitch, &dst_slice_pitch);
2760 src_mem = wined3d_texture_map_bo_address(&data, src_slice_pitch,
2761 gl_info, GL_PIXEL_UNPACK_BUFFER, WINED3D_MAP_READONLY);
2762 if (!(dst_mem = HeapAlloc(GetProcessHeap(), 0, dst_slice_pitch)))
2764 ERR("Out of memory (%u).\n", dst_slice_pitch);
2765 context_release(context);
2766 return E_OUTOFMEMORY;
2768 if (texture->swapchain && texture->swapchain->palette)
2769 palette = texture->swapchain->palette;
2770 conversion->convert(src_mem, src_row_pitch, dst_mem, dst_row_pitch,
2771 width, height, palette, &texture->async.gl_color_key);
2772 src_row_pitch = dst_row_pitch;
2773 wined3d_texture_unmap_bo_address(&data, gl_info, GL_PIXEL_UNPACK_BUFFER);
2775 data.buffer_object = 0;
2776 data.addr = dst_mem;
2779 wined3d_surface_upload_data(surface, gl_info, &format, &src_rect,
2780 src_row_pitch, &dst_point, srgb, wined3d_const_bo_address(&data));
2782 HeapFree(GetProcessHeap(), 0, dst_mem);
2784 return WINED3D_OK;
2787 /* Context activation is done by the caller. */
2788 static void surface_load_renderbuffer(struct wined3d_surface *surface, struct wined3d_context *context,
2789 DWORD dst_location)
2791 struct wined3d_texture *texture = surface->container;
2792 const RECT rect = {0, 0,
2793 wined3d_texture_get_level_width(texture, surface->texture_level),
2794 wined3d_texture_get_level_height(texture, surface->texture_level)};
2795 DWORD locations = surface_get_sub_resource(surface)->locations;
2796 DWORD src_location;
2798 if (locations & WINED3D_LOCATION_RB_MULTISAMPLE)
2799 src_location = WINED3D_LOCATION_RB_MULTISAMPLE;
2800 else if (locations & WINED3D_LOCATION_RB_RESOLVED)
2801 src_location = WINED3D_LOCATION_RB_RESOLVED;
2802 else if (locations & WINED3D_LOCATION_TEXTURE_SRGB)
2803 src_location = WINED3D_LOCATION_TEXTURE_SRGB;
2804 else /* surface_blt_fbo will load the source location if necessary. */
2805 src_location = WINED3D_LOCATION_TEXTURE_RGB;
2807 surface_blt_fbo(texture->resource.device, context, WINED3D_TEXF_POINT,
2808 surface, src_location, &rect, surface, dst_location, &rect);
2811 /* Context activation is done by the caller. Context may be NULL in ddraw-only mode. */
2812 HRESULT surface_load_location(struct wined3d_surface *surface, struct wined3d_context *context, DWORD location)
2814 unsigned int sub_resource_idx = surface_get_sub_resource_idx(surface);
2815 struct wined3d_texture *texture = surface->container;
2816 struct wined3d_texture_sub_resource *sub_resource;
2817 HRESULT hr;
2819 TRACE("surface %p, location %s.\n", surface, wined3d_debug_location(location));
2821 sub_resource = &texture->sub_resources[sub_resource_idx];
2822 if (sub_resource->locations & location)
2824 TRACE("Location (%#x) is already up to date.\n", location);
2825 return WINED3D_OK;
2828 if (WARN_ON(d3d))
2830 DWORD required_access = resource_access_from_location(location);
2831 if ((texture->resource.access_flags & required_access) != required_access)
2832 WARN("Operation requires %#x access, but surface only has %#x.\n",
2833 required_access, texture->resource.access_flags);
2836 if (sub_resource->locations & WINED3D_LOCATION_DISCARDED)
2838 TRACE("Surface previously discarded, nothing to do.\n");
2839 wined3d_texture_prepare_location(texture, sub_resource_idx, context, location);
2840 wined3d_texture_validate_location(texture, sub_resource_idx, location);
2841 wined3d_texture_invalidate_location(texture, sub_resource_idx, WINED3D_LOCATION_DISCARDED);
2842 goto done;
2845 if (!sub_resource->locations)
2847 ERR("Surface %p does not have any up to date location.\n", surface);
2848 wined3d_texture_validate_location(texture, sub_resource_idx, WINED3D_LOCATION_DISCARDED);
2849 return surface_load_location(surface, context, location);
2852 if (texture->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
2854 FIXME("Unimplemented copy from %s to %s for depth/stencil buffers.\n",
2855 wined3d_debug_location(sub_resource->locations), wined3d_debug_location(location));
2856 return WINED3DERR_INVALIDCALL;
2859 switch (location)
2861 case WINED3D_LOCATION_USER_MEMORY:
2862 case WINED3D_LOCATION_SYSMEM:
2863 case WINED3D_LOCATION_BUFFER:
2864 surface_load_sysmem(surface, context, location);
2865 break;
2867 case WINED3D_LOCATION_DRAWABLE:
2868 if (FAILED(hr = surface_load_drawable(surface, context)))
2869 return hr;
2870 break;
2872 case WINED3D_LOCATION_RB_RESOLVED:
2873 case WINED3D_LOCATION_RB_MULTISAMPLE:
2874 surface_load_renderbuffer(surface, context, location);
2875 break;
2877 case WINED3D_LOCATION_TEXTURE_RGB:
2878 case WINED3D_LOCATION_TEXTURE_SRGB:
2879 if (FAILED(hr = surface_load_texture(surface, context,
2880 location == WINED3D_LOCATION_TEXTURE_SRGB)))
2881 return hr;
2882 break;
2884 default:
2885 ERR("Don't know how to handle location %#x.\n", location);
2886 break;
2889 done:
2890 wined3d_texture_validate_location(texture, sub_resource_idx, location);
2892 return WINED3D_OK;
2895 static HRESULT ffp_blit_alloc(struct wined3d_device *device) { return WINED3D_OK; }
2896 /* Context activation is done by the caller. */
2897 static void ffp_blit_free(struct wined3d_device *device) { }
2899 /* Context activation is done by the caller. */
2900 static HRESULT ffp_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface,
2901 const struct wined3d_color_key *color_key)
2903 const struct wined3d_gl_info *gl_info = context->gl_info;
2905 gl_info->gl_ops.gl.p_glEnable(surface->container->target);
2906 checkGLcall("glEnable(target)");
2908 return WINED3D_OK;
2911 /* Context activation is done by the caller. */
2912 static void ffp_blit_unset(const struct wined3d_gl_info *gl_info)
2914 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_2D);
2915 checkGLcall("glDisable(GL_TEXTURE_2D)");
2916 if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
2918 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_CUBE_MAP_ARB);
2919 checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
2921 if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
2923 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_RECTANGLE_ARB);
2924 checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)");
2928 static BOOL ffp_blit_supported(const struct wined3d_gl_info *gl_info,
2929 const struct wined3d_d3d_info *d3d_info, enum wined3d_blit_op blit_op,
2930 const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
2931 const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
2933 if (src_pool == WINED3D_POOL_SYSTEM_MEM || dst_pool == WINED3D_POOL_SYSTEM_MEM)
2935 TRACE("Source or destination is in system memory.\n");
2936 return FALSE;
2939 switch (blit_op)
2941 case WINED3D_BLIT_OP_COLOR_BLIT_CKEY:
2942 if (d3d_info->shader_color_key)
2944 TRACE("Color keying requires converted textures.\n");
2945 return FALSE;
2947 case WINED3D_BLIT_OP_COLOR_BLIT:
2948 case WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST:
2949 if (TRACE_ON(d3d))
2951 TRACE("Checking support for fixup:\n");
2952 dump_color_fixup_desc(src_format->color_fixup);
2955 /* We only support identity conversions. */
2956 if (!is_identity_fixup(src_format->color_fixup)
2957 || !is_identity_fixup(dst_format->color_fixup))
2959 TRACE("Fixups are not supported.\n");
2960 return FALSE;
2963 if (!(dst_usage & WINED3DUSAGE_RENDERTARGET))
2965 TRACE("Can only blit to render targets.\n");
2966 return FALSE;
2968 return TRUE;
2970 case WINED3D_BLIT_OP_COLOR_FILL:
2971 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
2973 if (!((dst_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_FBO_ATTACHABLE)
2974 || (dst_usage & WINED3DUSAGE_RENDERTARGET)))
2975 return FALSE;
2977 else if (!(dst_usage & WINED3DUSAGE_RENDERTARGET))
2979 TRACE("Color fill not supported\n");
2980 return FALSE;
2983 /* FIXME: We should reject color fills on formats with fixups,
2984 * but this would break P8 color fills for example. */
2986 return TRUE;
2988 case WINED3D_BLIT_OP_DEPTH_FILL:
2989 return TRUE;
2991 default:
2992 TRACE("Unsupported blit_op=%d\n", blit_op);
2993 return FALSE;
2997 static HRESULT ffp_blit_color_fill(struct wined3d_device *device, struct wined3d_rendertarget_view *view,
2998 const RECT *rect, const struct wined3d_color *color)
3000 const RECT draw_rect = {0, 0, view->width, view->height};
3001 struct wined3d_fb_state fb = {&view, NULL};
3003 device_clear_render_targets(device, 1, &fb, 1, rect, &draw_rect, WINED3DCLEAR_TARGET, color, 0.0f, 0);
3005 return WINED3D_OK;
3008 static HRESULT ffp_blit_depth_fill(struct wined3d_device *device,
3009 struct wined3d_rendertarget_view *view, const RECT *rect, DWORD clear_flags,
3010 float depth, DWORD stencil)
3012 const RECT draw_rect = {0, 0, view->width, view->height};
3013 struct wined3d_fb_state fb = {NULL, view};
3015 device_clear_render_targets(device, 0, &fb, 1, rect, &draw_rect, clear_flags, NULL, depth, stencil);
3017 return WINED3D_OK;
3020 static void ffp_blit_blit_surface(struct wined3d_device *device, enum wined3d_blit_op op, DWORD filter,
3021 struct wined3d_surface *src_surface, const RECT *src_rect,
3022 struct wined3d_surface *dst_surface, const RECT *dst_rect,
3023 const struct wined3d_color_key *color_key)
3025 unsigned int dst_sub_resource_idx = surface_get_sub_resource_idx(dst_surface);
3026 struct wined3d_texture *dst_texture = dst_surface->container;
3027 struct wined3d_texture *src_texture = src_surface->container;
3028 const struct wined3d_gl_info *gl_info;
3029 struct wined3d_context *context;
3031 /* Blit from offscreen surface to render target */
3032 struct wined3d_color_key old_blt_key = src_texture->async.src_blt_color_key;
3033 DWORD old_color_key_flags = src_texture->async.color_key_flags;
3035 TRACE("Blt from surface %p to rendertarget %p\n", src_surface, dst_surface);
3037 wined3d_texture_set_color_key(src_texture, WINED3D_CKEY_SRC_BLT, color_key);
3039 context = context_acquire(device, dst_surface);
3040 gl_info = context->gl_info;
3042 if (op == WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST)
3043 gl_info->gl_ops.gl.p_glEnable(GL_ALPHA_TEST);
3045 surface_blt_to_drawable(device, context, filter,
3046 !!color_key, src_surface, src_rect, dst_surface, dst_rect);
3048 if (op == WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST)
3049 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
3051 context_release(context);
3053 /* Restore the color key parameters */
3054 wined3d_texture_set_color_key(src_texture, WINED3D_CKEY_SRC_BLT,
3055 (old_color_key_flags & WINED3D_CKEY_SRC_BLT) ? &old_blt_key : NULL);
3057 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, dst_texture->resource.draw_binding);
3058 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~dst_texture->resource.draw_binding);
3061 const struct blit_shader ffp_blit = {
3062 ffp_blit_alloc,
3063 ffp_blit_free,
3064 ffp_blit_set,
3065 ffp_blit_unset,
3066 ffp_blit_supported,
3067 ffp_blit_color_fill,
3068 ffp_blit_depth_fill,
3069 ffp_blit_blit_surface,
3072 static HRESULT cpu_blit_alloc(struct wined3d_device *device)
3074 return WINED3D_OK;
3077 /* Context activation is done by the caller. */
3078 static void cpu_blit_free(struct wined3d_device *device)
3082 /* Context activation is done by the caller. */
3083 static HRESULT cpu_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface,
3084 const struct wined3d_color_key *color_key)
3086 return WINED3D_OK;
3089 /* Context activation is done by the caller. */
3090 static void cpu_blit_unset(const struct wined3d_gl_info *gl_info)
3094 static BOOL cpu_blit_supported(const struct wined3d_gl_info *gl_info,
3095 const struct wined3d_d3d_info *d3d_info, enum wined3d_blit_op blit_op,
3096 const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
3097 const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
3099 if (blit_op == WINED3D_BLIT_OP_COLOR_FILL)
3101 return TRUE;
3104 return FALSE;
3107 static HRESULT surface_cpu_blt_compressed(const BYTE *src_data, BYTE *dst_data,
3108 UINT src_pitch, UINT dst_pitch, UINT update_w, UINT update_h,
3109 const struct wined3d_format *format, DWORD flags, const struct wined3d_blt_fx *fx)
3111 UINT row_block_count;
3112 const BYTE *src_row;
3113 BYTE *dst_row;
3114 UINT x, y;
3116 src_row = src_data;
3117 dst_row = dst_data;
3119 row_block_count = (update_w + format->block_width - 1) / format->block_width;
3121 if (!flags)
3123 for (y = 0; y < update_h; y += format->block_height)
3125 memcpy(dst_row, src_row, row_block_count * format->block_byte_count);
3126 src_row += src_pitch;
3127 dst_row += dst_pitch;
3130 return WINED3D_OK;
3133 if (flags == WINED3D_BLT_FX && fx->fx == WINEDDBLTFX_MIRRORUPDOWN)
3135 src_row += (((update_h / format->block_height) - 1) * src_pitch);
3137 switch (format->id)
3139 case WINED3DFMT_DXT1:
3140 for (y = 0; y < update_h; y += format->block_height)
3142 struct block
3144 WORD color[2];
3145 BYTE control_row[4];
3148 const struct block *s = (const struct block *)src_row;
3149 struct block *d = (struct block *)dst_row;
3151 for (x = 0; x < row_block_count; ++x)
3153 d[x].color[0] = s[x].color[0];
3154 d[x].color[1] = s[x].color[1];
3155 d[x].control_row[0] = s[x].control_row[3];
3156 d[x].control_row[1] = s[x].control_row[2];
3157 d[x].control_row[2] = s[x].control_row[1];
3158 d[x].control_row[3] = s[x].control_row[0];
3160 src_row -= src_pitch;
3161 dst_row += dst_pitch;
3163 return WINED3D_OK;
3165 case WINED3DFMT_DXT2:
3166 case WINED3DFMT_DXT3:
3167 for (y = 0; y < update_h; y += format->block_height)
3169 struct block
3171 WORD alpha_row[4];
3172 WORD color[2];
3173 BYTE control_row[4];
3176 const struct block *s = (const struct block *)src_row;
3177 struct block *d = (struct block *)dst_row;
3179 for (x = 0; x < row_block_count; ++x)
3181 d[x].alpha_row[0] = s[x].alpha_row[3];
3182 d[x].alpha_row[1] = s[x].alpha_row[2];
3183 d[x].alpha_row[2] = s[x].alpha_row[1];
3184 d[x].alpha_row[3] = s[x].alpha_row[0];
3185 d[x].color[0] = s[x].color[0];
3186 d[x].color[1] = s[x].color[1];
3187 d[x].control_row[0] = s[x].control_row[3];
3188 d[x].control_row[1] = s[x].control_row[2];
3189 d[x].control_row[2] = s[x].control_row[1];
3190 d[x].control_row[3] = s[x].control_row[0];
3192 src_row -= src_pitch;
3193 dst_row += dst_pitch;
3195 return WINED3D_OK;
3197 default:
3198 FIXME("Compressed flip not implemented for format %s.\n",
3199 debug_d3dformat(format->id));
3200 return E_NOTIMPL;
3204 FIXME("Unsupported blit on compressed surface (format %s, flags %#x, DDFX %#x).\n",
3205 debug_d3dformat(format->id), flags, flags & WINED3D_BLT_FX ? fx->fx : 0);
3207 return E_NOTIMPL;
3210 static HRESULT surface_cpu_blt(struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx,
3211 const struct wined3d_box *dst_box, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx,
3212 const struct wined3d_box *src_box, DWORD flags, const struct wined3d_blt_fx *fx,
3213 enum wined3d_texture_filter_type filter)
3215 unsigned int bpp, src_height, src_width, dst_height, dst_width, row_byte_count;
3216 const struct wined3d_format *src_format, *dst_format;
3217 struct wined3d_texture *converted_texture = NULL;
3218 unsigned int src_fmt_flags, dst_fmt_flags;
3219 struct wined3d_map_desc dst_map, src_map;
3220 const BYTE *sbase = NULL;
3221 HRESULT hr = WINED3D_OK;
3222 BOOL same_sub_resource;
3223 const BYTE *sbuf;
3224 BYTE *dbuf;
3225 int x, y;
3227 TRACE("dst_texture %p, dst_sub_resource_idx %u, dst_box %s, src_texture %p, "
3228 "src_sub_resource_idx %u, src_box %s, flags %#x, fx %p, filter %s.\n",
3229 dst_texture, dst_sub_resource_idx, debug_box(dst_box), src_texture,
3230 src_sub_resource_idx, debug_box(src_box), flags, fx, debug_d3dtexturefiltertype(filter));
3232 if (src_texture == dst_texture && src_sub_resource_idx == dst_sub_resource_idx)
3234 same_sub_resource = TRUE;
3235 wined3d_resource_map(&dst_texture->resource, dst_sub_resource_idx, &dst_map, NULL, 0);
3236 src_map = dst_map;
3237 src_format = dst_texture->resource.format;
3238 dst_format = src_format;
3239 dst_fmt_flags = dst_texture->resource.format_flags;
3240 src_fmt_flags = dst_fmt_flags;
3242 else
3244 same_sub_resource = FALSE;
3245 dst_format = dst_texture->resource.format;
3246 dst_fmt_flags = dst_texture->resource.format_flags;
3247 if (src_texture)
3249 if (dst_texture->resource.format->id != src_texture->resource.format->id)
3251 if (!(converted_texture = surface_convert_format(src_texture, src_sub_resource_idx, dst_format)))
3253 FIXME("Cannot convert %s to %s.\n", debug_d3dformat(src_texture->resource.format->id),
3254 debug_d3dformat(dst_texture->resource.format->id));
3255 return WINED3DERR_NOTAVAILABLE;
3257 src_texture = converted_texture;
3258 src_sub_resource_idx = 0;
3260 wined3d_resource_map(&src_texture->resource, src_sub_resource_idx, &src_map, NULL, WINED3D_MAP_READONLY);
3261 src_format = src_texture->resource.format;
3262 src_fmt_flags = src_texture->resource.format_flags;
3264 else
3266 src_format = dst_format;
3267 src_fmt_flags = dst_fmt_flags;
3270 wined3d_resource_map(&dst_texture->resource, dst_sub_resource_idx, &dst_map, dst_box, 0);
3273 bpp = dst_format->byte_count;
3274 src_height = src_box->bottom - src_box->top;
3275 src_width = src_box->right - src_box->left;
3276 dst_height = dst_box->bottom - dst_box->top;
3277 dst_width = dst_box->right - dst_box->left;
3278 row_byte_count = dst_width * bpp;
3280 if (src_texture)
3281 sbase = (BYTE *)src_map.data
3282 + ((src_box->top / src_format->block_height) * src_map.row_pitch)
3283 + ((src_box->left / src_format->block_width) * src_format->block_byte_count);
3284 if (same_sub_resource)
3285 dbuf = (BYTE *)dst_map.data
3286 + ((dst_box->top / dst_format->block_height) * dst_map.row_pitch)
3287 + ((dst_box->left / dst_format->block_width) * dst_format->block_byte_count);
3288 else
3289 dbuf = dst_map.data;
3291 if (src_fmt_flags & dst_fmt_flags & WINED3DFMT_FLAG_BLOCKS)
3293 TRACE("%s -> %s copy.\n", debug_d3dformat(src_format->id), debug_d3dformat(dst_format->id));
3295 if (same_sub_resource)
3297 FIXME("Only plain blits supported on compressed surfaces.\n");
3298 hr = E_NOTIMPL;
3299 goto release;
3302 if (src_height != dst_height || src_width != dst_width)
3304 WARN("Stretching not supported on compressed surfaces.\n");
3305 hr = WINED3DERR_INVALIDCALL;
3306 goto release;
3309 if (!wined3d_texture_check_block_align(src_texture,
3310 src_sub_resource_idx % src_texture->level_count, src_box))
3312 WARN("Source rectangle not block-aligned.\n");
3313 hr = WINED3DERR_INVALIDCALL;
3314 goto release;
3317 if (!wined3d_texture_check_block_align(dst_texture,
3318 dst_sub_resource_idx % dst_texture->level_count, dst_box))
3320 WARN("Destination rectangle not block-aligned.\n");
3321 hr = WINED3DERR_INVALIDCALL;
3322 goto release;
3325 hr = surface_cpu_blt_compressed(sbase, dbuf,
3326 src_map.row_pitch, dst_map.row_pitch, dst_width, dst_height,
3327 src_format, flags, fx);
3328 goto release;
3331 /* First, all the 'source-less' blits */
3332 if (flags & WINED3D_BLT_COLOR_FILL)
3334 hr = _Blt_ColorFill(dbuf, dst_width, dst_height, bpp, dst_map.row_pitch, fx->fill_color);
3335 flags &= ~WINED3D_BLT_COLOR_FILL;
3338 if (flags & WINED3D_BLT_DEPTH_FILL)
3339 FIXME("WINED3D_BLT_DEPTH_FILL needs to be implemented!\n");
3341 /* Now the 'with source' blits. */
3342 if (src_texture)
3344 int sx, xinc, sy, yinc;
3346 if (!dst_width || !dst_height) /* Hmm... stupid program? */
3347 goto release;
3349 if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT
3350 && (src_width != dst_width || src_height != dst_height))
3352 /* Can happen when d3d9 apps do a StretchRect() call which isn't handled in GL. */
3353 FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(filter));
3356 xinc = (src_width << 16) / dst_width;
3357 yinc = (src_height << 16) / dst_height;
3359 if (!flags)
3361 /* No effects, we can cheat here. */
3362 if (dst_width == src_width)
3364 if (dst_height == src_height)
3366 /* No stretching in either direction. This needs to be as
3367 * fast as possible. */
3368 sbuf = sbase;
3370 /* Check for overlapping surfaces. */
3371 if (!same_sub_resource || dst_box->top < src_box->top
3372 || dst_box->right <= src_box->left || src_box->right <= dst_box->left)
3374 /* No overlap, or dst above src, so copy from top downwards. */
3375 for (y = 0; y < dst_height; ++y)
3377 memcpy(dbuf, sbuf, row_byte_count);
3378 sbuf += src_map.row_pitch;
3379 dbuf += dst_map.row_pitch;
3382 else if (dst_box->top > src_box->top)
3384 /* Copy from bottom upwards. */
3385 sbuf += src_map.row_pitch * dst_height;
3386 dbuf += dst_map.row_pitch * dst_height;
3387 for (y = 0; y < dst_height; ++y)
3389 sbuf -= src_map.row_pitch;
3390 dbuf -= dst_map.row_pitch;
3391 memcpy(dbuf, sbuf, row_byte_count);
3394 else
3396 /* Src and dst overlapping on the same line, use memmove. */
3397 for (y = 0; y < dst_height; ++y)
3399 memmove(dbuf, sbuf, row_byte_count);
3400 sbuf += src_map.row_pitch;
3401 dbuf += dst_map.row_pitch;
3405 else
3407 /* Stretching in y direction only. */
3408 for (y = sy = 0; y < dst_height; ++y, sy += yinc)
3410 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
3411 memcpy(dbuf, sbuf, row_byte_count);
3412 dbuf += dst_map.row_pitch;
3416 else
3418 /* Stretching in X direction. */
3419 int last_sy = -1;
3420 for (y = sy = 0; y < dst_height; ++y, sy += yinc)
3422 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
3424 if ((sy >> 16) == (last_sy >> 16))
3426 /* This source row is the same as last source row -
3427 * Copy the already stretched row. */
3428 memcpy(dbuf, dbuf - dst_map.row_pitch, row_byte_count);
3430 else
3432 #define STRETCH_ROW(type) \
3433 do { \
3434 const type *s = (const type *)sbuf; \
3435 type *d = (type *)dbuf; \
3436 for (x = sx = 0; x < dst_width; ++x, sx += xinc) \
3437 d[x] = s[sx >> 16]; \
3438 } while(0)
3440 switch(bpp)
3442 case 1:
3443 STRETCH_ROW(BYTE);
3444 break;
3445 case 2:
3446 STRETCH_ROW(WORD);
3447 break;
3448 case 4:
3449 STRETCH_ROW(DWORD);
3450 break;
3451 case 3:
3453 const BYTE *s;
3454 BYTE *d = dbuf;
3455 for (x = sx = 0; x < dst_width; x++, sx+= xinc)
3457 DWORD pixel;
3459 s = sbuf + 3 * (sx >> 16);
3460 pixel = s[0] | (s[1] << 8) | (s[2] << 16);
3461 d[0] = (pixel ) & 0xff;
3462 d[1] = (pixel >> 8) & 0xff;
3463 d[2] = (pixel >> 16) & 0xff;
3464 d += 3;
3466 break;
3468 default:
3469 FIXME("Stretched blit not implemented for bpp %u!\n", bpp * 8);
3470 hr = WINED3DERR_NOTAVAILABLE;
3471 goto error;
3473 #undef STRETCH_ROW
3475 dbuf += dst_map.row_pitch;
3476 last_sy = sy;
3480 else
3482 LONG dstyinc = dst_map.row_pitch, dstxinc = bpp;
3483 DWORD keylow = 0xffffffff, keyhigh = 0, keymask = 0xffffffff;
3484 DWORD destkeylow = 0x0, destkeyhigh = 0xffffffff, destkeymask = 0xffffffff;
3485 if (flags & (WINED3D_BLT_SRC_CKEY | WINED3D_BLT_DST_CKEY
3486 | WINED3D_BLT_SRC_CKEY_OVERRIDE | WINED3D_BLT_DST_CKEY_OVERRIDE))
3488 /* The color keying flags are checked for correctness in ddraw */
3489 if (flags & WINED3D_BLT_SRC_CKEY)
3491 keylow = src_texture->async.src_blt_color_key.color_space_low_value;
3492 keyhigh = src_texture->async.src_blt_color_key.color_space_high_value;
3494 else if (flags & WINED3D_BLT_SRC_CKEY_OVERRIDE)
3496 keylow = fx->src_color_key.color_space_low_value;
3497 keyhigh = fx->src_color_key.color_space_high_value;
3500 if (flags & WINED3D_BLT_DST_CKEY)
3502 /* Destination color keys are taken from the source surface! */
3503 destkeylow = src_texture->async.dst_blt_color_key.color_space_low_value;
3504 destkeyhigh = src_texture->async.dst_blt_color_key.color_space_high_value;
3506 else if (flags & WINED3D_BLT_DST_CKEY_OVERRIDE)
3508 destkeylow = fx->dst_color_key.color_space_low_value;
3509 destkeyhigh = fx->dst_color_key.color_space_high_value;
3512 if (bpp == 1)
3514 keymask = 0xff;
3516 else
3518 DWORD masks[3];
3519 get_color_masks(src_format, masks);
3520 keymask = masks[0]
3521 | masks[1]
3522 | masks[2];
3524 flags &= ~(WINED3D_BLT_SRC_CKEY | WINED3D_BLT_DST_CKEY
3525 | WINED3D_BLT_SRC_CKEY_OVERRIDE | WINED3D_BLT_DST_CKEY_OVERRIDE);
3528 if (flags & WINED3D_BLT_FX)
3530 BYTE *dTopLeft, *dTopRight, *dBottomLeft, *dBottomRight, *tmp;
3531 LONG tmpxy;
3532 dTopLeft = dbuf;
3533 dTopRight = dbuf + ((dst_width - 1) * bpp);
3534 dBottomLeft = dTopLeft + ((dst_height - 1) * dst_map.row_pitch);
3535 dBottomRight = dBottomLeft + ((dst_width - 1) * bpp);
3537 if (fx->fx & WINEDDBLTFX_ARITHSTRETCHY)
3539 /* I don't think we need to do anything about this flag */
3540 WARN("Nothing done for WINEDDBLTFX_ARITHSTRETCHY.\n");
3542 if (fx->fx & WINEDDBLTFX_MIRRORLEFTRIGHT)
3544 tmp = dTopRight;
3545 dTopRight = dTopLeft;
3546 dTopLeft = tmp;
3547 tmp = dBottomRight;
3548 dBottomRight = dBottomLeft;
3549 dBottomLeft = tmp;
3550 dstxinc = dstxinc * -1;
3552 if (fx->fx & WINEDDBLTFX_MIRRORUPDOWN)
3554 tmp = dTopLeft;
3555 dTopLeft = dBottomLeft;
3556 dBottomLeft = tmp;
3557 tmp = dTopRight;
3558 dTopRight = dBottomRight;
3559 dBottomRight = tmp;
3560 dstyinc = dstyinc * -1;
3562 if (fx->fx & WINEDDBLTFX_NOTEARING)
3564 /* I don't think we need to do anything about this flag */
3565 WARN("Nothing done for WINEDDBLTFX_NOTEARING.\n");
3567 if (fx->fx & WINEDDBLTFX_ROTATE180)
3569 tmp = dBottomRight;
3570 dBottomRight = dTopLeft;
3571 dTopLeft = tmp;
3572 tmp = dBottomLeft;
3573 dBottomLeft = dTopRight;
3574 dTopRight = tmp;
3575 dstxinc = dstxinc * -1;
3576 dstyinc = dstyinc * -1;
3578 if (fx->fx & WINEDDBLTFX_ROTATE270)
3580 tmp = dTopLeft;
3581 dTopLeft = dBottomLeft;
3582 dBottomLeft = dBottomRight;
3583 dBottomRight = dTopRight;
3584 dTopRight = tmp;
3585 tmpxy = dstxinc;
3586 dstxinc = dstyinc;
3587 dstyinc = tmpxy;
3588 dstxinc = dstxinc * -1;
3590 if (fx->fx & WINEDDBLTFX_ROTATE90)
3592 tmp = dTopLeft;
3593 dTopLeft = dTopRight;
3594 dTopRight = dBottomRight;
3595 dBottomRight = dBottomLeft;
3596 dBottomLeft = tmp;
3597 tmpxy = dstxinc;
3598 dstxinc = dstyinc;
3599 dstyinc = tmpxy;
3600 dstyinc = dstyinc * -1;
3602 if (fx->fx & WINEDDBLTFX_ZBUFFERBASEDEST)
3604 /* I don't think we need to do anything about this flag */
3605 WARN("Nothing done for WINEDDBLTFX_ZBUFFERBASEDEST.\n");
3607 dbuf = dTopLeft;
3608 flags &= ~(WINED3D_BLT_FX);
3611 #define COPY_COLORKEY_FX(type) \
3612 do { \
3613 const type *s; \
3614 type *d = (type *)dbuf, *dx, tmp; \
3615 for (y = sy = 0; y < dst_height; ++y, sy += yinc) \
3617 s = (const type *)(sbase + (sy >> 16) * src_map.row_pitch); \
3618 dx = d; \
3619 for (x = sx = 0; x < dst_width; ++x, sx += xinc) \
3621 tmp = s[sx >> 16]; \
3622 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) \
3623 && ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) \
3625 dx[0] = tmp; \
3627 dx = (type *)(((BYTE *)dx) + dstxinc); \
3629 d = (type *)(((BYTE *)d) + dstyinc); \
3631 } while(0)
3633 switch (bpp)
3635 case 1:
3636 COPY_COLORKEY_FX(BYTE);
3637 break;
3638 case 2:
3639 COPY_COLORKEY_FX(WORD);
3640 break;
3641 case 4:
3642 COPY_COLORKEY_FX(DWORD);
3643 break;
3644 case 3:
3646 const BYTE *s;
3647 BYTE *d = dbuf, *dx;
3648 for (y = sy = 0; y < dst_height; ++y, sy += yinc)
3650 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
3651 dx = d;
3652 for (x = sx = 0; x < dst_width; ++x, sx+= xinc)
3654 DWORD pixel, dpixel = 0;
3655 s = sbuf + 3 * (sx>>16);
3656 pixel = s[0] | (s[1] << 8) | (s[2] << 16);
3657 dpixel = dx[0] | (dx[1] << 8 ) | (dx[2] << 16);
3658 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh)
3659 && ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
3661 dx[0] = (pixel ) & 0xff;
3662 dx[1] = (pixel >> 8) & 0xff;
3663 dx[2] = (pixel >> 16) & 0xff;
3665 dx += dstxinc;
3667 d += dstyinc;
3669 break;
3671 default:
3672 FIXME("%s color-keyed blit not implemented for bpp %u!\n",
3673 (flags & WINED3D_BLT_SRC_CKEY) ? "Source" : "Destination", bpp * 8);
3674 hr = WINED3DERR_NOTAVAILABLE;
3675 goto error;
3676 #undef COPY_COLORKEY_FX
3681 error:
3682 if (flags)
3683 FIXME(" Unsupported flags %#x.\n", flags);
3685 release:
3686 wined3d_resource_unmap(&dst_texture->resource, dst_sub_resource_idx);
3687 if (src_texture && !same_sub_resource)
3688 wined3d_resource_unmap(&src_texture->resource, src_sub_resource_idx);
3689 if (converted_texture)
3690 wined3d_texture_decref(converted_texture);
3692 return hr;
3695 static HRESULT cpu_blit_color_fill(struct wined3d_device *device, struct wined3d_rendertarget_view *view,
3696 const RECT *rect, const struct wined3d_color *color)
3698 const struct wined3d_box box = {rect->left, rect->top, rect->right, rect->bottom, 0, 1};
3699 static const struct wined3d_box src_box;
3700 struct wined3d_blt_fx fx;
3702 fx.fill_color = wined3d_format_convert_from_float(view->format, color);
3703 return surface_cpu_blt(texture_from_resource(view->resource), view->sub_resource_idx,
3704 &box, NULL, 0, &src_box, WINED3D_BLT_COLOR_FILL, &fx, WINED3D_TEXF_POINT);
3707 static HRESULT cpu_blit_depth_fill(struct wined3d_device *device,
3708 struct wined3d_rendertarget_view *view, const RECT *rect, DWORD clear_flags,
3709 float depth, DWORD stencil)
3711 FIXME("Depth/stencil filling not implemented by cpu_blit.\n");
3712 return WINED3DERR_INVALIDCALL;
3715 static void cpu_blit_blit_surface(struct wined3d_device *device, enum wined3d_blit_op op, DWORD filter,
3716 struct wined3d_surface *src_surface, const RECT *src_rect,
3717 struct wined3d_surface *dst_surface, const RECT *dst_rect,
3718 const struct wined3d_color_key *color_key)
3720 /* FIXME: Remove error returns from surface_blt_cpu. */
3721 ERR("Blit method not implemented by cpu_blit.\n");
3724 const struct blit_shader cpu_blit = {
3725 cpu_blit_alloc,
3726 cpu_blit_free,
3727 cpu_blit_set,
3728 cpu_blit_unset,
3729 cpu_blit_supported,
3730 cpu_blit_color_fill,
3731 cpu_blit_depth_fill,
3732 cpu_blit_blit_surface,
3735 HRESULT wined3d_surface_blt(struct wined3d_surface *dst_surface, const RECT *dst_rect,
3736 struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags,
3737 const struct wined3d_blt_fx *fx, enum wined3d_texture_filter_type filter)
3739 struct wined3d_box dst_box = {dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, 0, 1};
3740 struct wined3d_box src_box = {src_rect->left, src_rect->top, src_rect->right, src_rect->bottom, 0, 1};
3741 unsigned int dst_sub_resource_idx = surface_get_sub_resource_idx(dst_surface);
3742 struct wined3d_texture *dst_texture = dst_surface->container;
3743 struct wined3d_device *device = dst_texture->resource.device;
3744 struct wined3d_swapchain *src_swapchain, *dst_swapchain;
3745 struct wined3d_texture *src_texture = NULL;
3746 unsigned int dst_w, dst_h, src_w, src_h;
3747 unsigned int src_sub_resource_idx = 0;
3748 DWORD src_ds_flags, dst_ds_flags;
3749 BOOL scale, convert;
3751 static const DWORD simple_blit = WINED3D_BLT_ASYNC
3752 | WINED3D_BLT_COLOR_FILL
3753 | WINED3D_BLT_SRC_CKEY
3754 | WINED3D_BLT_SRC_CKEY_OVERRIDE
3755 | WINED3D_BLT_WAIT
3756 | WINED3D_BLT_DEPTH_FILL
3757 | WINED3D_BLT_DO_NOT_WAIT
3758 | WINED3D_BLT_ALPHA_TEST;
3760 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
3761 dst_surface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect),
3762 flags, fx, debug_d3dtexturefiltertype(filter));
3763 TRACE("Usage is %s.\n", debug_d3dusage(dst_texture->resource.usage));
3765 if (fx)
3767 TRACE("fx %#x.\n", fx->fx);
3768 TRACE("fill_color 0x%08x.\n", fx->fill_color);
3769 TRACE("dst_color_key {0x%08x, 0x%08x}.\n",
3770 fx->dst_color_key.color_space_low_value,
3771 fx->dst_color_key.color_space_high_value);
3772 TRACE("src_color_key {0x%08x, 0x%08x}.\n",
3773 fx->src_color_key.color_space_low_value,
3774 fx->src_color_key.color_space_high_value);
3777 if (src_surface)
3779 src_texture = src_surface->container;
3780 src_sub_resource_idx = surface_get_sub_resource_idx(src_surface);
3783 if (dst_texture->sub_resources[dst_sub_resource_idx].map_count
3784 || (src_texture && src_texture->sub_resources[src_sub_resource_idx].map_count))
3786 WARN("Surface is busy, returning WINEDDERR_SURFACEBUSY.\n");
3787 return WINEDDERR_SURFACEBUSY;
3790 dst_w = wined3d_texture_get_level_width(dst_texture, dst_surface->texture_level);
3791 dst_h = wined3d_texture_get_level_height(dst_texture, dst_surface->texture_level);
3792 if (IsRectEmpty(dst_rect) || dst_rect->left > dst_w || dst_rect->left < 0
3793 || dst_rect->top > dst_h || dst_rect->top < 0
3794 || dst_rect->right > dst_w || dst_rect->right < 0
3795 || dst_rect->bottom > dst_h || dst_rect->bottom < 0)
3797 WARN("The application gave us a bad destination rectangle.\n");
3798 return WINEDDERR_INVALIDRECT;
3801 if (src_texture)
3803 src_w = wined3d_texture_get_level_width(src_texture, src_surface->texture_level);
3804 src_h = wined3d_texture_get_level_height(src_texture, src_surface->texture_level);
3805 if (IsRectEmpty(src_rect) || src_rect->left > src_w || src_rect->left < 0
3806 || src_rect->top > src_h || src_rect->top < 0
3807 || src_rect->right > src_w || src_rect->right < 0
3808 || src_rect->bottom > src_h || src_rect->bottom < 0)
3810 WARN("The application gave us a bad source rectangle.\n");
3811 return WINEDDERR_INVALIDRECT;
3815 if (!fx || !(fx->fx))
3816 flags &= ~WINED3D_BLT_FX;
3818 if (flags & WINED3D_BLT_WAIT)
3819 flags &= ~WINED3D_BLT_WAIT;
3821 if (flags & WINED3D_BLT_ASYNC)
3823 static unsigned int once;
3825 if (!once++)
3826 FIXME("Can't handle WINED3D_BLT_ASYNC flag.\n");
3827 flags &= ~WINED3D_BLT_ASYNC;
3830 /* WINED3D_BLT_DO_NOT_WAIT appeared in DX7. */
3831 if (flags & WINED3D_BLT_DO_NOT_WAIT)
3833 static unsigned int once;
3835 if (!once++)
3836 FIXME("Can't handle WINED3D_BLT_DO_NOT_WAIT flag.\n");
3837 flags &= ~WINED3D_BLT_DO_NOT_WAIT;
3840 if (!device->d3d_initialized)
3842 WARN("D3D not initialized, using fallback.\n");
3843 goto cpu;
3846 /* We want to avoid invalidating the sysmem location for converted
3847 * surfaces, since otherwise we'd have to convert the data back when
3848 * locking them. */
3849 if (dst_texture->flags & WINED3D_TEXTURE_CONVERTED || dst_texture->resource.format->convert
3850 || wined3d_format_get_color_key_conversion(dst_texture, TRUE))
3852 WARN_(d3d_perf)("Converted surface, using CPU blit.\n");
3853 goto cpu;
3856 if (flags & ~simple_blit)
3858 WARN_(d3d_perf)("Using fallback for complex blit (%#x).\n", flags);
3859 goto fallback;
3862 if (src_texture)
3863 src_swapchain = src_texture->swapchain;
3864 else
3865 src_swapchain = NULL;
3867 dst_swapchain = dst_texture->swapchain;
3869 /* This isn't strictly needed. FBO blits for example could deal with
3870 * cross-swapchain blits by first downloading the source to a texture
3871 * before switching to the destination context. We just have this here to
3872 * not have to deal with the issue, since cross-swapchain blits should be
3873 * rare. */
3874 if (src_swapchain && dst_swapchain && src_swapchain != dst_swapchain)
3876 FIXME("Using fallback for cross-swapchain blit.\n");
3877 goto fallback;
3880 scale = src_texture
3881 && (src_rect->right - src_rect->left != dst_rect->right - dst_rect->left
3882 || src_rect->bottom - src_rect->top != dst_rect->bottom - dst_rect->top);
3883 convert = src_texture && src_texture->resource.format->id != dst_texture->resource.format->id;
3885 dst_ds_flags = dst_texture->resource.format_flags
3886 & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
3887 if (src_texture)
3888 src_ds_flags = src_texture->resource.format_flags
3889 & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
3890 else
3891 src_ds_flags = 0;
3893 if (src_ds_flags || dst_ds_flags)
3895 if (flags & WINED3D_BLT_DEPTH_FILL)
3897 float depth;
3899 TRACE("Depth fill.\n");
3901 if (!surface_convert_depth_to_float(dst_surface, fx->fill_color, &depth))
3902 return WINED3DERR_INVALIDCALL;
3904 if (SUCCEEDED(wined3d_surface_depth_fill(dst_surface, dst_rect, depth)))
3905 return WINED3D_OK;
3907 else
3909 if (src_ds_flags != dst_ds_flags)
3911 WARN("Rejecting depth / stencil blit between incompatible formats.\n");
3912 return WINED3DERR_INVALIDCALL;
3915 if (SUCCEEDED(wined3d_surface_depth_blt(src_surface, src_texture->resource.draw_binding,
3916 src_rect, dst_surface, dst_texture->resource.draw_binding, dst_rect)))
3917 return WINED3D_OK;
3920 else
3922 struct wined3d_texture_sub_resource *src_sub_resource, *dst_sub_resource;
3923 const struct blit_shader *blitter;
3925 dst_sub_resource = surface_get_sub_resource(dst_surface);
3926 src_sub_resource = src_texture ? &src_texture->sub_resources[src_sub_resource_idx] : NULL;
3928 /* In principle this would apply to depth blits as well, but we don't
3929 * implement those in the CPU blitter at the moment. */
3930 if ((dst_sub_resource->locations & dst_texture->resource.map_binding)
3931 && (!src_texture || (src_sub_resource->locations & src_texture->resource.map_binding)))
3933 if (scale)
3934 TRACE("Not doing sysmem blit because of scaling.\n");
3935 else if (convert)
3936 TRACE("Not doing sysmem blit because of format conversion.\n");
3937 else
3938 goto cpu;
3941 if (flags & WINED3D_BLT_COLOR_FILL)
3943 struct wined3d_color color;
3944 const struct wined3d_palette *palette = dst_swapchain ? dst_swapchain->palette : NULL;
3946 TRACE("Color fill.\n");
3948 if (!wined3d_format_convert_color_to_float(dst_texture->resource.format,
3949 palette, fx->fill_color, &color))
3950 goto fallback;
3952 if (SUCCEEDED(surface_color_fill(dst_surface, dst_rect, &color)))
3953 return WINED3D_OK;
3955 else
3957 enum wined3d_blit_op blit_op = WINED3D_BLIT_OP_COLOR_BLIT;
3958 const struct wined3d_color_key *color_key = NULL;
3960 TRACE("Color blit.\n");
3961 if (flags & WINED3D_BLT_SRC_CKEY_OVERRIDE)
3963 color_key = &fx->src_color_key;
3964 blit_op = WINED3D_BLIT_OP_COLOR_BLIT_CKEY;
3966 else if (flags & WINED3D_BLT_SRC_CKEY)
3968 color_key = &src_texture->async.src_blt_color_key;
3969 blit_op = WINED3D_BLIT_OP_COLOR_BLIT_CKEY;
3971 else if (flags & WINED3D_BLT_ALPHA_TEST)
3973 blit_op = WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST;
3975 else if ((src_sub_resource->locations & WINED3D_LOCATION_SYSMEM)
3976 && !(dst_sub_resource->locations & WINED3D_LOCATION_SYSMEM))
3978 /* Upload */
3979 if (scale)
3980 TRACE("Not doing upload because of scaling.\n");
3981 else if (convert)
3982 TRACE("Not doing upload because of format conversion.\n");
3983 else
3985 POINT dst_point = {dst_rect->left, dst_rect->top};
3987 if (SUCCEEDED(surface_upload_from_surface(dst_surface, &dst_point, src_surface, src_rect)))
3989 if (!wined3d_resource_is_offscreen(&dst_texture->resource))
3991 struct wined3d_context *context = context_acquire(device, dst_surface);
3992 wined3d_texture_load_location(dst_texture, dst_sub_resource_idx,
3993 context, dst_texture->resource.draw_binding);
3994 context_release(context);
3996 return WINED3D_OK;
4000 else if (dst_swapchain && dst_swapchain->back_buffers
4001 && dst_texture == dst_swapchain->front_buffer
4002 && src_texture == dst_swapchain->back_buffers[0])
4004 /* Use present for back -> front blits. The idea behind this is
4005 * that present is potentially faster than a blit, in particular
4006 * when FBO blits aren't available. Some ddraw applications like
4007 * Half-Life and Prince of Persia 3D use Blt() from the backbuffer
4008 * to the frontbuffer instead of doing a Flip(). D3D8 and D3D9
4009 * applications can't blit directly to the frontbuffer. */
4010 enum wined3d_swap_effect swap_effect = dst_swapchain->desc.swap_effect;
4012 TRACE("Using present for backbuffer -> frontbuffer blit.\n");
4014 /* Set the swap effect to COPY, we don't want the backbuffer
4015 * to become undefined. */
4016 dst_swapchain->desc.swap_effect = WINED3D_SWAP_EFFECT_COPY;
4017 wined3d_swapchain_present(dst_swapchain, NULL, NULL, dst_swapchain->win_handle, 0);
4018 dst_swapchain->desc.swap_effect = swap_effect;
4020 return WINED3D_OK;
4023 if (fbo_blit_supported(&device->adapter->gl_info, blit_op,
4024 src_rect, src_texture->resource.usage, src_texture->resource.pool, src_texture->resource.format,
4025 dst_rect, dst_texture->resource.usage, dst_texture->resource.pool, dst_texture->resource.format))
4027 struct wined3d_context *context;
4028 TRACE("Using FBO blit.\n");
4030 context = context_acquire(device, NULL);
4031 surface_blt_fbo(device, context, filter,
4032 src_surface, src_texture->resource.draw_binding, src_rect,
4033 dst_surface, dst_texture->resource.draw_binding, dst_rect);
4034 context_release(context);
4036 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx,
4037 dst_texture->resource.draw_binding);
4038 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx,
4039 ~dst_texture->resource.draw_binding);
4041 return WINED3D_OK;
4044 blitter = wined3d_select_blitter(&device->adapter->gl_info, &device->adapter->d3d_info, blit_op,
4045 src_rect, src_texture->resource.usage, src_texture->resource.pool, src_texture->resource.format,
4046 dst_rect, dst_texture->resource.usage, dst_texture->resource.pool, dst_texture->resource.format);
4047 if (blitter)
4049 blitter->blit_surface(device, blit_op, filter, src_surface,
4050 src_rect, dst_surface, dst_rect, color_key);
4051 return WINED3D_OK;
4056 fallback:
4057 /* Special cases for render targets. */
4058 if (SUCCEEDED(surface_blt_special(dst_surface, dst_rect, src_surface, src_rect, flags, fx, filter)))
4059 return WINED3D_OK;
4061 cpu:
4062 return surface_cpu_blt(dst_texture, dst_sub_resource_idx, &dst_box,
4063 src_texture, src_sub_resource_idx, &src_box, flags, fx, filter);