wined3d: Merge common code between texture3d_load_location() and surface_load_location().
[wine.git] / dlls / wined3d / surface.c
blob84f1c2fd02a22f611d0764369b707703dd518577
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
1525 || (src_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_COMPRESSED)))
1527 FIXME("Cannot find a conversion function from format %s to %s.\n",
1528 debug_d3dformat(src_format->id), debug_d3dformat(dst_format->id));
1529 return NULL;
1532 /* FIXME: Multisampled conversion? */
1533 desc.resource_type = WINED3D_RTYPE_TEXTURE_2D;
1534 desc.format = dst_format->id;
1535 desc.multisample_type = WINED3D_MULTISAMPLE_NONE;
1536 desc.multisample_quality = 0;
1537 desc.usage = 0;
1538 desc.pool = WINED3D_POOL_SCRATCH;
1539 desc.width = wined3d_texture_get_level_width(src_texture, texture_level);
1540 desc.height = wined3d_texture_get_level_height(src_texture, texture_level);
1541 desc.depth = 1;
1542 desc.size = 0;
1543 if (FAILED(wined3d_texture_create(device, &desc, 1, 1,
1544 WINED3D_TEXTURE_CREATE_MAPPABLE | WINED3D_TEXTURE_CREATE_DISCARD,
1545 NULL, NULL, &wined3d_null_parent_ops, &dst_texture)))
1547 ERR("Failed to create a destination texture for conversion.\n");
1548 return NULL;
1551 memset(&src_map, 0, sizeof(src_map));
1552 if (FAILED(wined3d_resource_map(&src_texture->resource, sub_resource_idx,
1553 &src_map, NULL, WINED3D_MAP_READONLY)))
1555 ERR("Failed to map the source texture.\n");
1556 wined3d_texture_decref(dst_texture);
1557 return NULL;
1559 if (conv)
1561 struct wined3d_map_desc dst_map;
1563 memset(&dst_map, 0, sizeof(dst_map));
1564 if (FAILED(wined3d_resource_map(&dst_texture->resource, 0, &dst_map, NULL, 0)))
1566 ERR("Failed to map the destination texture.\n");
1567 wined3d_resource_unmap(&src_texture->resource, sub_resource_idx);
1568 wined3d_texture_decref(dst_texture);
1569 return NULL;
1572 conv->convert(src_map.data, dst_map.data, src_map.row_pitch, dst_map.row_pitch, desc.width, desc.height);
1574 wined3d_resource_unmap(&dst_texture->resource, 0);
1576 else
1578 struct wined3d_bo_address data = {0, src_map.data};
1579 RECT src_rect = {0, 0, desc.width, desc.height};
1580 const struct wined3d_gl_info *gl_info;
1581 struct wined3d_context *context;
1582 POINT dst_point = {0, 0};
1584 TRACE("Using upload conversion.\n");
1585 context = context_acquire(device, NULL);
1586 gl_info = context->gl_info;
1588 wined3d_texture_prepare_texture(dst_texture, context, FALSE);
1589 wined3d_texture_bind_and_dirtify(dst_texture, context, FALSE);
1590 wined3d_surface_upload_data(dst_texture->sub_resources[0].u.surface, gl_info, src_format,
1591 &src_rect, src_map.row_pitch, &dst_point, FALSE, wined3d_const_bo_address(&data));
1593 context_release(context);
1595 wined3d_texture_validate_location(dst_texture, 0, WINED3D_LOCATION_TEXTURE_RGB);
1596 wined3d_texture_invalidate_location(dst_texture, 0, ~WINED3D_LOCATION_TEXTURE_RGB);
1598 wined3d_resource_unmap(&src_texture->resource, sub_resource_idx);
1600 return dst_texture;
1603 static HRESULT _Blt_ColorFill(BYTE *buf, unsigned int width, unsigned int height,
1604 unsigned int bpp, UINT pitch, DWORD color)
1606 BYTE *first;
1607 unsigned int x, y;
1609 /* Do first row */
1611 #define COLORFILL_ROW(type) \
1612 do { \
1613 type *d = (type *)buf; \
1614 for (x = 0; x < width; ++x) \
1615 d[x] = (type)color; \
1616 } while(0)
1618 switch (bpp)
1620 case 1:
1621 COLORFILL_ROW(BYTE);
1622 break;
1624 case 2:
1625 COLORFILL_ROW(WORD);
1626 break;
1628 case 3:
1630 BYTE *d = buf;
1631 for (x = 0; x < width; ++x, d += 3)
1633 d[0] = (color ) & 0xff;
1634 d[1] = (color >> 8) & 0xff;
1635 d[2] = (color >> 16) & 0xff;
1637 break;
1639 case 4:
1640 COLORFILL_ROW(DWORD);
1641 break;
1643 default:
1644 FIXME("Color fill not implemented for bpp %u!\n", bpp * 8);
1645 return WINED3DERR_NOTAVAILABLE;
1648 #undef COLORFILL_ROW
1650 /* Now copy first row. */
1651 first = buf;
1652 for (y = 1; y < height; ++y)
1654 buf += pitch;
1655 memcpy(buf, first, width * bpp);
1658 return WINED3D_OK;
1661 static void read_from_framebuffer(struct wined3d_surface *surface,
1662 struct wined3d_context *old_ctx, DWORD dst_location)
1664 unsigned int sub_resource_idx = surface_get_sub_resource_idx(surface);
1665 struct wined3d_texture *texture = surface->container;
1666 struct wined3d_device *device = texture->resource.device;
1667 const struct wined3d_gl_info *gl_info;
1668 struct wined3d_context *context = old_ctx;
1669 struct wined3d_surface *restore_rt = NULL;
1670 unsigned int row_pitch, slice_pitch;
1671 unsigned int width, height;
1672 BYTE *mem;
1673 BYTE *row, *top, *bottom;
1674 int i;
1675 BOOL srcIsUpsideDown;
1676 struct wined3d_bo_address data;
1678 wined3d_texture_get_memory(texture, sub_resource_idx, &data, dst_location);
1680 restore_rt = context_get_rt_surface(old_ctx);
1681 if (restore_rt != surface)
1682 context = context_acquire(device, surface);
1683 else
1684 restore_rt = NULL;
1686 context_apply_blit_state(context, device);
1687 gl_info = context->gl_info;
1689 /* Select the correct read buffer, and give some debug output.
1690 * There is no need to keep track of the current read buffer or reset it, every part of the code
1691 * that reads sets the read buffer as desired.
1693 if (wined3d_resource_is_offscreen(&texture->resource))
1695 /* Mapping the primary render target which is not on a swapchain.
1696 * Read from the back buffer. */
1697 TRACE("Mapping offscreen render target.\n");
1698 gl_info->gl_ops.gl.p_glReadBuffer(context_get_offscreen_gl_buffer(context));
1699 srcIsUpsideDown = TRUE;
1701 else
1703 /* Onscreen surfaces are always part of a swapchain */
1704 GLenum buffer = wined3d_texture_get_gl_buffer(texture);
1705 TRACE("Mapping %#x buffer.\n", buffer);
1706 gl_info->gl_ops.gl.p_glReadBuffer(buffer);
1707 checkGLcall("glReadBuffer");
1708 srcIsUpsideDown = FALSE;
1711 if (data.buffer_object)
1713 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, data.buffer_object));
1714 checkGLcall("glBindBuffer");
1717 wined3d_texture_get_pitch(texture, surface->texture_level, &row_pitch, &slice_pitch);
1719 /* Setup pixel store pack state -- to glReadPixels into the correct place */
1720 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_ROW_LENGTH, row_pitch / texture->resource.format->byte_count);
1721 checkGLcall("glPixelStorei");
1723 width = wined3d_texture_get_level_width(texture, surface->texture_level);
1724 height = wined3d_texture_get_level_height(texture, surface->texture_level);
1725 gl_info->gl_ops.gl.p_glReadPixels(0, 0, width, height,
1726 texture->resource.format->glFormat,
1727 texture->resource.format->glType, data.addr);
1728 checkGLcall("glReadPixels");
1730 /* Reset previous pixel store pack state */
1731 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_ROW_LENGTH, 0);
1732 checkGLcall("glPixelStorei");
1734 if (!srcIsUpsideDown)
1736 /* glReadPixels returns the image upside down, and there is no way to
1737 * prevent this. Flip the lines in software. */
1739 if (!(row = HeapAlloc(GetProcessHeap(), 0, row_pitch)))
1740 goto error;
1742 if (data.buffer_object)
1744 mem = GL_EXTCALL(glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_WRITE));
1745 checkGLcall("glMapBuffer");
1747 else
1748 mem = data.addr;
1750 top = mem;
1751 bottom = mem + row_pitch * (height - 1);
1752 for (i = 0; i < height / 2; i++)
1754 memcpy(row, top, row_pitch);
1755 memcpy(top, bottom, row_pitch);
1756 memcpy(bottom, row, row_pitch);
1757 top += row_pitch;
1758 bottom -= row_pitch;
1760 HeapFree(GetProcessHeap(), 0, row);
1762 if (data.buffer_object)
1763 GL_EXTCALL(glUnmapBuffer(GL_PIXEL_PACK_BUFFER));
1766 error:
1767 if (data.buffer_object)
1769 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));
1770 checkGLcall("glBindBuffer");
1773 if (restore_rt)
1774 context_restore(context, restore_rt);
1777 /* Read the framebuffer contents into a texture. Note that this function
1778 * doesn't do any kind of flipping. Using this on an onscreen surface will
1779 * result in a flipped D3D texture.
1781 * Context activation is done by the caller. This function may temporarily
1782 * switch to a different context and restore the original one before return. */
1783 void surface_load_fb_texture(struct wined3d_surface *surface, BOOL srgb, struct wined3d_context *old_ctx)
1785 struct wined3d_texture *texture = surface->container;
1786 struct wined3d_device *device = texture->resource.device;
1787 const struct wined3d_gl_info *gl_info;
1788 struct wined3d_context *context = old_ctx;
1789 struct wined3d_surface *restore_rt = NULL;
1791 restore_rt = context_get_rt_surface(old_ctx);
1792 if (restore_rt != surface)
1793 context = context_acquire(device, surface);
1794 else
1795 restore_rt = NULL;
1797 gl_info = context->gl_info;
1798 device_invalidate_state(device, STATE_FRAMEBUFFER);
1800 wined3d_texture_prepare_texture(texture, context, srgb);
1801 wined3d_texture_bind_and_dirtify(texture, context, srgb);
1803 TRACE("Reading back offscreen render target %p.\n", surface);
1805 if (wined3d_resource_is_offscreen(&texture->resource))
1806 gl_info->gl_ops.gl.p_glReadBuffer(context_get_offscreen_gl_buffer(context));
1807 else
1808 gl_info->gl_ops.gl.p_glReadBuffer(wined3d_texture_get_gl_buffer(texture));
1809 checkGLcall("glReadBuffer");
1811 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(surface->texture_target, surface->texture_level,
1812 0, 0, 0, 0, wined3d_texture_get_level_width(texture, surface->texture_level),
1813 wined3d_texture_get_level_height(texture, surface->texture_level));
1814 checkGLcall("glCopyTexSubImage2D");
1816 if (restore_rt)
1817 context_restore(context, restore_rt);
1820 /* Does a direct frame buffer -> texture copy. Stretching is done with single
1821 * pixel copy calls. */
1822 static void fb_copy_to_texture_direct(struct wined3d_surface *dst_surface, struct wined3d_surface *src_surface,
1823 const RECT *src_rect, const RECT *dst_rect_in, enum wined3d_texture_filter_type filter)
1825 unsigned int dst_sub_resource_idx = surface_get_sub_resource_idx(dst_surface);
1826 struct wined3d_texture *src_texture = src_surface->container;
1827 struct wined3d_texture *dst_texture = dst_surface->container;
1828 struct wined3d_device *device = dst_texture->resource.device;
1829 const struct wined3d_gl_info *gl_info;
1830 float xrel, yrel;
1831 struct wined3d_context *context;
1832 BOOL upsidedown = FALSE;
1833 RECT dst_rect = *dst_rect_in;
1834 unsigned int src_height;
1836 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
1837 * glCopyTexSubImage is a bit picky about the parameters we pass to it
1839 if(dst_rect.top > dst_rect.bottom) {
1840 UINT tmp = dst_rect.bottom;
1841 dst_rect.bottom = dst_rect.top;
1842 dst_rect.top = tmp;
1843 upsidedown = TRUE;
1846 context = context_acquire(device, src_surface);
1847 gl_info = context->gl_info;
1848 context_apply_blit_state(context, device);
1849 wined3d_texture_load(dst_texture, context, FALSE);
1851 /* Bind the target texture */
1852 context_bind_texture(context, dst_texture->target, dst_texture->texture_rgb.name);
1853 if (wined3d_resource_is_offscreen(&src_texture->resource))
1855 TRACE("Reading from an offscreen target\n");
1856 upsidedown = !upsidedown;
1857 gl_info->gl_ops.gl.p_glReadBuffer(context_get_offscreen_gl_buffer(context));
1859 else
1861 gl_info->gl_ops.gl.p_glReadBuffer(wined3d_texture_get_gl_buffer(src_texture));
1863 checkGLcall("glReadBuffer");
1865 xrel = (float) (src_rect->right - src_rect->left) / (float) (dst_rect.right - dst_rect.left);
1866 yrel = (float) (src_rect->bottom - src_rect->top) / (float) (dst_rect.bottom - dst_rect.top);
1868 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
1870 FIXME_(d3d_perf)("Doing a pixel by pixel copy from the framebuffer to a texture.\n");
1872 if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT)
1873 ERR("Texture filtering not supported in direct blit.\n");
1875 else if ((filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT)
1876 && ((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
1878 ERR("Texture filtering not supported in direct blit\n");
1881 src_height = wined3d_texture_get_level_height(src_texture, src_surface->texture_level);
1882 if (upsidedown
1883 && !((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
1884 && !((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
1886 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do. */
1887 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
1888 dst_rect.left /*xoffset */, dst_rect.top /* y offset */,
1889 src_rect->left, src_height - src_rect->bottom,
1890 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
1892 else
1894 LONG row;
1895 UINT yoffset = src_height - src_rect->top + dst_rect.top - 1;
1896 /* I have to process this row by row to swap the image,
1897 * otherwise it would be upside down, so stretching in y direction
1898 * doesn't cost extra time
1900 * However, stretching in x direction can be avoided if not necessary
1902 for(row = dst_rect.top; row < dst_rect.bottom; row++) {
1903 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
1905 /* Well, that stuff works, but it's very slow.
1906 * find a better way instead
1908 LONG col;
1910 for (col = dst_rect.left; col < dst_rect.right; ++col)
1912 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
1913 dst_rect.left + col /* x offset */, row /* y offset */,
1914 src_rect->left + col * xrel, yoffset - (int) (row * yrel), 1, 1);
1917 else
1919 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
1920 dst_rect.left /* x offset */, row /* y offset */,
1921 src_rect->left, yoffset - (int) (row * yrel), dst_rect.right - dst_rect.left, 1);
1925 checkGLcall("glCopyTexSubImage2D");
1927 context_release(context);
1929 /* The texture is now most up to date - If the surface is a render target
1930 * and has a drawable, this path is never entered. */
1931 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB);
1932 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB);
1935 /* Uses the hardware to stretch and flip the image */
1936 static void fb_copy_to_texture_hwstretch(struct wined3d_surface *dst_surface, struct wined3d_surface *src_surface,
1937 const RECT *src_rect, const RECT *dst_rect_in, enum wined3d_texture_filter_type filter)
1939 unsigned int dst_sub_resource_idx = surface_get_sub_resource_idx(dst_surface);
1940 unsigned int src_width, src_height, src_pow2_width, src_pow2_height;
1941 struct wined3d_texture *src_texture = src_surface->container;
1942 struct wined3d_texture *dst_texture = dst_surface->container;
1943 struct wined3d_device *device = dst_texture->resource.device;
1944 GLuint src, backup = 0;
1945 float left, right, top, bottom; /* Texture coordinates */
1946 const struct wined3d_gl_info *gl_info;
1947 struct wined3d_context *context;
1948 GLenum drawBuffer = GL_BACK;
1949 GLenum offscreen_buffer;
1950 GLenum texture_target;
1951 BOOL noBackBufferBackup;
1952 BOOL src_offscreen;
1953 BOOL upsidedown = FALSE;
1954 RECT dst_rect = *dst_rect_in;
1956 TRACE("Using hwstretch blit\n");
1957 /* Activate the Proper context for reading from the source surface, set it up for blitting */
1958 context = context_acquire(device, src_surface);
1959 gl_info = context->gl_info;
1960 context_apply_blit_state(context, device);
1961 wined3d_texture_load(dst_texture, context, FALSE);
1963 offscreen_buffer = context_get_offscreen_gl_buffer(context);
1964 src_width = wined3d_texture_get_level_width(src_texture, src_surface->texture_level);
1965 src_height = wined3d_texture_get_level_height(src_texture, src_surface->texture_level);
1966 src_pow2_width = wined3d_texture_get_level_pow2_width(src_texture, src_surface->texture_level);
1967 src_pow2_height = wined3d_texture_get_level_pow2_height(src_texture, src_surface->texture_level);
1969 src_offscreen = wined3d_resource_is_offscreen(&src_texture->resource);
1970 noBackBufferBackup = src_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO;
1971 if (!noBackBufferBackup && !src_texture->texture_rgb.name)
1973 /* Get it a description */
1974 wined3d_texture_load(src_texture, context, FALSE);
1977 /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
1978 * This way we don't have to wait for the 2nd readback to finish to leave this function.
1980 if (context->aux_buffers >= 2)
1982 /* Got more than one aux buffer? Use the 2nd aux buffer */
1983 drawBuffer = GL_AUX1;
1985 else if ((!src_offscreen || offscreen_buffer == GL_BACK) && context->aux_buffers >= 1)
1987 /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
1988 drawBuffer = GL_AUX0;
1991 if (noBackBufferBackup)
1993 gl_info->gl_ops.gl.p_glGenTextures(1, &backup);
1994 checkGLcall("glGenTextures");
1995 context_bind_texture(context, GL_TEXTURE_2D, backup);
1996 texture_target = GL_TEXTURE_2D;
1998 else
2000 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
2001 * we are reading from the back buffer, the backup can be used as source texture
2003 texture_target = src_surface->texture_target;
2004 context_bind_texture(context, texture_target, src_texture->texture_rgb.name);
2005 gl_info->gl_ops.gl.p_glEnable(texture_target);
2006 checkGLcall("glEnable(texture_target)");
2008 /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
2009 surface_get_sub_resource(src_surface)->locations &= ~WINED3D_LOCATION_TEXTURE_RGB;
2012 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
2013 * glCopyTexSubImage is a bit picky about the parameters we pass to it
2015 if(dst_rect.top > dst_rect.bottom) {
2016 UINT tmp = dst_rect.bottom;
2017 dst_rect.bottom = dst_rect.top;
2018 dst_rect.top = tmp;
2019 upsidedown = TRUE;
2022 if (src_offscreen)
2024 TRACE("Reading from an offscreen target\n");
2025 upsidedown = !upsidedown;
2026 gl_info->gl_ops.gl.p_glReadBuffer(offscreen_buffer);
2028 else
2030 gl_info->gl_ops.gl.p_glReadBuffer(wined3d_texture_get_gl_buffer(src_texture));
2033 /* TODO: Only back up the part that will be overwritten */
2034 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(texture_target, 0, 0, 0, 0, 0, src_width, src_height);
2036 checkGLcall("glCopyTexSubImage2D");
2038 /* No issue with overriding these - the sampler is dirty due to blit usage */
2039 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, wined3d_gl_mag_filter(filter));
2040 checkGLcall("glTexParameteri");
2041 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER,
2042 wined3d_gl_min_mip_filter(filter, WINED3D_TEXF_NONE));
2043 checkGLcall("glTexParameteri");
2045 if (!src_texture->swapchain || src_texture == src_texture->swapchain->back_buffers[0])
2047 src = backup ? backup : src_texture->texture_rgb.name;
2049 else
2051 gl_info->gl_ops.gl.p_glReadBuffer(GL_FRONT);
2052 checkGLcall("glReadBuffer(GL_FRONT)");
2054 gl_info->gl_ops.gl.p_glGenTextures(1, &src);
2055 checkGLcall("glGenTextures(1, &src)");
2056 context_bind_texture(context, GL_TEXTURE_2D, src);
2058 /* TODO: Only copy the part that will be read. Use src_rect->left,
2059 * src_rect->bottom as origin, but with the width watch out for power
2060 * of 2 sizes. */
2061 gl_info->gl_ops.gl.p_glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, src_pow2_width,
2062 src_pow2_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
2063 checkGLcall("glTexImage2D");
2064 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, src_width, src_height);
2066 gl_info->gl_ops.gl.p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2067 checkGLcall("glTexParameteri");
2068 gl_info->gl_ops.gl.p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2069 checkGLcall("glTexParameteri");
2071 gl_info->gl_ops.gl.p_glReadBuffer(GL_BACK);
2072 checkGLcall("glReadBuffer(GL_BACK)");
2074 if (texture_target != GL_TEXTURE_2D)
2076 gl_info->gl_ops.gl.p_glDisable(texture_target);
2077 gl_info->gl_ops.gl.p_glEnable(GL_TEXTURE_2D);
2078 texture_target = GL_TEXTURE_2D;
2081 checkGLcall("glEnd and previous");
2083 left = src_rect->left;
2084 right = src_rect->right;
2086 if (!upsidedown)
2088 top = src_height - src_rect->top;
2089 bottom = src_height - src_rect->bottom;
2091 else
2093 top = src_height - src_rect->bottom;
2094 bottom = src_height - src_rect->top;
2097 if (src_texture->flags & WINED3D_TEXTURE_NORMALIZED_COORDS)
2099 left /= src_pow2_width;
2100 right /= src_pow2_width;
2101 top /= src_pow2_height;
2102 bottom /= src_pow2_height;
2105 /* draw the source texture stretched and upside down. The correct surface is bound already */
2106 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2107 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2109 context_set_draw_buffer(context, drawBuffer);
2110 gl_info->gl_ops.gl.p_glReadBuffer(drawBuffer);
2112 gl_info->gl_ops.gl.p_glBegin(GL_QUADS);
2113 /* bottom left */
2114 gl_info->gl_ops.gl.p_glTexCoord2f(left, bottom);
2115 gl_info->gl_ops.gl.p_glVertex2i(0, 0);
2117 /* top left */
2118 gl_info->gl_ops.gl.p_glTexCoord2f(left, top);
2119 gl_info->gl_ops.gl.p_glVertex2i(0, dst_rect.bottom - dst_rect.top);
2121 /* top right */
2122 gl_info->gl_ops.gl.p_glTexCoord2f(right, top);
2123 gl_info->gl_ops.gl.p_glVertex2i(dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
2125 /* bottom right */
2126 gl_info->gl_ops.gl.p_glTexCoord2f(right, bottom);
2127 gl_info->gl_ops.gl.p_glVertex2i(dst_rect.right - dst_rect.left, 0);
2128 gl_info->gl_ops.gl.p_glEnd();
2129 checkGLcall("glEnd and previous");
2131 if (texture_target != dst_surface->texture_target)
2133 gl_info->gl_ops.gl.p_glDisable(texture_target);
2134 gl_info->gl_ops.gl.p_glEnable(dst_surface->texture_target);
2135 texture_target = dst_surface->texture_target;
2138 /* Now read the stretched and upside down image into the destination texture */
2139 context_bind_texture(context, texture_target, dst_texture->texture_rgb.name);
2140 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(texture_target,
2142 dst_rect.left, dst_rect.top, /* xoffset, yoffset */
2143 0, 0, /* We blitted the image to the origin */
2144 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
2145 checkGLcall("glCopyTexSubImage2D");
2147 if (drawBuffer == GL_BACK)
2149 /* Write the back buffer backup back. */
2150 if (backup)
2152 if (texture_target != GL_TEXTURE_2D)
2154 gl_info->gl_ops.gl.p_glDisable(texture_target);
2155 gl_info->gl_ops.gl.p_glEnable(GL_TEXTURE_2D);
2156 texture_target = GL_TEXTURE_2D;
2158 context_bind_texture(context, GL_TEXTURE_2D, backup);
2160 else
2162 if (texture_target != src_surface->texture_target)
2164 gl_info->gl_ops.gl.p_glDisable(texture_target);
2165 gl_info->gl_ops.gl.p_glEnable(src_surface->texture_target);
2166 texture_target = src_surface->texture_target;
2168 context_bind_texture(context, src_surface->texture_target, src_texture->texture_rgb.name);
2171 gl_info->gl_ops.gl.p_glBegin(GL_QUADS);
2172 /* top left */
2173 gl_info->gl_ops.gl.p_glTexCoord2f(0.0f, 0.0f);
2174 gl_info->gl_ops.gl.p_glVertex2i(0, src_height);
2176 /* bottom left */
2177 gl_info->gl_ops.gl.p_glTexCoord2f(0.0f, (float)src_height / (float)src_pow2_height);
2178 gl_info->gl_ops.gl.p_glVertex2i(0, 0);
2180 /* bottom right */
2181 gl_info->gl_ops.gl.p_glTexCoord2f((float)src_width / (float)src_pow2_width,
2182 (float)src_height / (float)src_pow2_height);
2183 gl_info->gl_ops.gl.p_glVertex2i(src_width, 0);
2185 /* top right */
2186 gl_info->gl_ops.gl.p_glTexCoord2f((float)src_width / (float)src_pow2_width, 0.0f);
2187 gl_info->gl_ops.gl.p_glVertex2i(src_width, src_height);
2188 gl_info->gl_ops.gl.p_glEnd();
2190 gl_info->gl_ops.gl.p_glDisable(texture_target);
2191 checkGLcall("glDisable(texture_target)");
2193 /* Cleanup */
2194 if (src != src_texture->texture_rgb.name && src != backup)
2196 gl_info->gl_ops.gl.p_glDeleteTextures(1, &src);
2197 checkGLcall("glDeleteTextures(1, &src)");
2199 if (backup)
2201 gl_info->gl_ops.gl.p_glDeleteTextures(1, &backup);
2202 checkGLcall("glDeleteTextures(1, &backup)");
2205 if (wined3d_settings.strict_draw_ordering)
2206 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
2208 context_release(context);
2210 /* The texture is now most up to date - If the surface is a render target
2211 * and has a drawable, this path is never entered. */
2212 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB);
2213 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB);
2216 /* Front buffer coordinates are always full screen coordinates, but our GL
2217 * drawable is limited to the window's client area. The sysmem and texture
2218 * copies do have the full screen size. Note that GL has a bottom-left
2219 * origin, while D3D has a top-left origin. */
2220 void surface_translate_drawable_coords(const struct wined3d_surface *surface, HWND window, RECT *rect)
2222 struct wined3d_texture *texture = surface->container;
2223 UINT drawable_height;
2225 if (texture->swapchain && texture == texture->swapchain->front_buffer)
2227 POINT offset = {0, 0};
2228 RECT windowsize;
2230 ScreenToClient(window, &offset);
2231 OffsetRect(rect, offset.x, offset.y);
2233 GetClientRect(window, &windowsize);
2234 drawable_height = windowsize.bottom - windowsize.top;
2236 else
2238 drawable_height = wined3d_texture_get_level_height(texture, surface->texture_level);
2241 rect->top = drawable_height - rect->top;
2242 rect->bottom = drawable_height - rect->bottom;
2245 /* Context activation is done by the caller. */
2246 static void surface_blt_to_drawable(const struct wined3d_device *device,
2247 struct wined3d_context *old_ctx,
2248 enum wined3d_texture_filter_type filter, BOOL alpha_test,
2249 struct wined3d_surface *src_surface, const RECT *src_rect_in,
2250 struct wined3d_surface *dst_surface, const RECT *dst_rect_in)
2252 struct wined3d_texture *src_texture = src_surface->container;
2253 struct wined3d_texture *dst_texture = dst_surface->container;
2254 const struct wined3d_gl_info *gl_info;
2255 struct wined3d_context *context = old_ctx;
2256 struct wined3d_surface *restore_rt = NULL;
2257 RECT src_rect, dst_rect;
2259 src_rect = *src_rect_in;
2260 dst_rect = *dst_rect_in;
2262 restore_rt = context_get_rt_surface(old_ctx);
2263 if (restore_rt != dst_surface)
2264 context = context_acquire(device, dst_surface);
2265 else
2266 restore_rt = NULL;
2268 gl_info = context->gl_info;
2270 /* Make sure the surface is up-to-date. This should probably use
2271 * surface_load_location() and worry about the destination surface too,
2272 * unless we're overwriting it completely. */
2273 wined3d_texture_load(src_texture, context, FALSE);
2275 /* Activate the destination context, set it up for blitting */
2276 context_apply_blit_state(context, device);
2278 if (!wined3d_resource_is_offscreen(&dst_texture->resource))
2279 surface_translate_drawable_coords(dst_surface, context->win_handle, &dst_rect);
2281 device->blitter->set_shader(device->blit_priv, context, src_surface, NULL);
2283 if (alpha_test)
2285 gl_info->gl_ops.gl.p_glEnable(GL_ALPHA_TEST);
2286 checkGLcall("glEnable(GL_ALPHA_TEST)");
2288 /* For P8 surfaces, the alpha component contains the palette index.
2289 * Which means that the colorkey is one of the palette entries. In
2290 * other cases pixels that should be masked away have alpha set to 0. */
2291 if (src_texture->resource.format->id == WINED3DFMT_P8_UINT)
2292 gl_info->gl_ops.gl.p_glAlphaFunc(GL_NOTEQUAL,
2293 (float)src_texture->async.src_blt_color_key.color_space_low_value / 255.0f);
2294 else
2295 gl_info->gl_ops.gl.p_glAlphaFunc(GL_NOTEQUAL, 0.0f);
2296 checkGLcall("glAlphaFunc");
2298 else
2300 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
2301 checkGLcall("glDisable(GL_ALPHA_TEST)");
2304 draw_textured_quad(src_surface, context, &src_rect, &dst_rect, filter);
2306 if (alpha_test)
2308 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
2309 checkGLcall("glDisable(GL_ALPHA_TEST)");
2312 /* Leave the opengl state valid for blitting */
2313 device->blitter->unset_shader(context->gl_info);
2315 if (wined3d_settings.strict_draw_ordering
2316 || (dst_texture->swapchain && dst_texture->swapchain->front_buffer == dst_texture))
2317 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
2319 if (restore_rt)
2320 context_restore(context, restore_rt);
2323 HRESULT surface_color_fill(struct wined3d_surface *s, const RECT *rect, const struct wined3d_color *color)
2325 struct wined3d_resource *resource = &s->container->resource;
2326 struct wined3d_device *device = resource->device;
2327 struct wined3d_rendertarget_view *view;
2328 struct wined3d_view_desc view_desc;
2329 const struct blit_shader *blitter;
2330 HRESULT hr;
2332 if (!(blitter = wined3d_select_blitter(&device->adapter->gl_info, &device->adapter->d3d_info,
2333 WINED3D_BLIT_OP_COLOR_FILL, NULL, 0, 0, NULL, rect, resource->usage, resource->pool, resource->format)))
2335 FIXME("No blitter is capable of performing the requested color fill operation.\n");
2336 return WINED3DERR_INVALIDCALL;
2339 view_desc.format_id = resource->format->id;
2340 view_desc.flags = 0;
2341 view_desc.u.texture.level_idx = s->texture_level;
2342 view_desc.u.texture.level_count = 1;
2343 view_desc.u.texture.layer_idx = s->texture_layer;
2344 view_desc.u.texture.layer_count = 1;
2345 if (FAILED(hr = wined3d_rendertarget_view_create(&view_desc,
2346 resource, NULL, &wined3d_null_parent_ops, &view)))
2348 ERR("Failed to create rendertarget view, hr %#x.\n", hr);
2349 return hr;
2352 hr = blitter->color_fill(device, view, rect, color);
2353 wined3d_rendertarget_view_decref(view);
2355 return hr;
2358 static HRESULT surface_blt_special(struct wined3d_surface *dst_surface, const RECT *dst_rect,
2359 struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags,
2360 const struct wined3d_blt_fx *fx, enum wined3d_texture_filter_type filter)
2362 struct wined3d_texture *dst_texture = dst_surface->container;
2363 struct wined3d_device *device = dst_texture->resource.device;
2364 const struct wined3d_surface *rt = wined3d_rendertarget_view_get_surface(device->fb.render_targets[0]);
2365 struct wined3d_swapchain *src_swapchain, *dst_swapchain;
2366 struct wined3d_texture *src_texture;
2368 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
2369 dst_surface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect),
2370 flags, fx, debug_d3dtexturefiltertype(filter));
2372 /* Get the swapchain. One of the surfaces has to be a primary surface */
2373 if (dst_texture->resource.pool == WINED3D_POOL_SYSTEM_MEM)
2375 WARN("Destination is in sysmem, rejecting gl blt\n");
2376 return WINED3DERR_INVALIDCALL;
2379 dst_swapchain = dst_texture->swapchain;
2381 if (src_surface)
2383 src_texture = src_surface->container;
2384 if (src_texture->resource.pool == WINED3D_POOL_SYSTEM_MEM)
2386 WARN("Src is in sysmem, rejecting gl blt\n");
2387 return WINED3DERR_INVALIDCALL;
2390 src_swapchain = src_texture->swapchain;
2392 else
2394 src_texture = NULL;
2395 src_swapchain = NULL;
2398 /* Early sort out of cases where no render target is used */
2399 if (!dst_swapchain && !src_swapchain && src_surface != rt && dst_surface != rt)
2401 TRACE("No surface is render target, not using hardware blit.\n");
2402 return WINED3DERR_INVALIDCALL;
2405 /* No destination color keying supported */
2406 if (flags & (WINED3D_BLT_DST_CKEY | WINED3D_BLT_DST_CKEY_OVERRIDE))
2408 /* Can we support that with glBlendFunc if blitting to the frame buffer? */
2409 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
2410 return WINED3DERR_INVALIDCALL;
2413 if (dst_swapchain && dst_swapchain == src_swapchain)
2415 FIXME("Implement hardware blit between two surfaces on the same swapchain\n");
2416 return WINED3DERR_INVALIDCALL;
2419 if (dst_swapchain && src_swapchain)
2421 FIXME("Implement hardware blit between two different swapchains\n");
2422 return WINED3DERR_INVALIDCALL;
2425 if (dst_swapchain)
2427 /* Handled with regular texture -> swapchain blit */
2428 if (src_surface == rt)
2429 TRACE("Blit from active render target to a swapchain\n");
2431 else if (src_swapchain && dst_surface == rt)
2433 FIXME("Implement blit from a swapchain to the active render target\n");
2434 return WINED3DERR_INVALIDCALL;
2437 if ((src_swapchain || src_surface == rt) && !dst_swapchain)
2439 unsigned int src_width, src_height;
2440 /* Blit from render target to texture */
2441 BOOL stretchx;
2443 /* P8 read back is not implemented */
2444 if (src_texture->resource.format->id == WINED3DFMT_P8_UINT
2445 || dst_texture->resource.format->id == WINED3DFMT_P8_UINT)
2447 TRACE("P8 read back not supported by frame buffer to texture blit\n");
2448 return WINED3DERR_INVALIDCALL;
2451 if (flags & (WINED3D_BLT_SRC_CKEY | WINED3D_BLT_SRC_CKEY_OVERRIDE))
2453 TRACE("Color keying not supported by frame buffer to texture blit\n");
2454 return WINED3DERR_INVALIDCALL;
2455 /* Destination color key is checked above */
2458 if (dst_rect->right - dst_rect->left != src_rect->right - src_rect->left)
2459 stretchx = TRUE;
2460 else
2461 stretchx = FALSE;
2463 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
2464 * flip the image nor scale it.
2466 * -> If the app asks for an unscaled, upside down copy, just perform one glCopyTexSubImage2D call
2467 * -> If the app wants an image width an unscaled width, copy it line per line
2468 * -> If the app wants an image that is scaled on the x axis, and the destination rectangle is smaller
2469 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
2470 * back buffer. This is slower than reading line per line, thus not used for flipping
2471 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
2472 * pixel by pixel. */
2473 src_width = wined3d_texture_get_level_width(src_texture, src_surface->texture_level);
2474 src_height = wined3d_texture_get_level_height(src_texture, src_surface->texture_level);
2475 if (!stretchx || dst_rect->right - dst_rect->left > src_width
2476 || dst_rect->bottom - dst_rect->top > src_height)
2478 TRACE("No stretching in x direction, using direct framebuffer -> texture copy.\n");
2479 fb_copy_to_texture_direct(dst_surface, src_surface, src_rect, dst_rect, filter);
2481 else
2483 TRACE("Using hardware stretching to flip / stretch the texture.\n");
2484 fb_copy_to_texture_hwstretch(dst_surface, src_surface, src_rect, dst_rect, filter);
2487 return WINED3D_OK;
2490 /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
2491 TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
2492 return WINED3DERR_INVALIDCALL;
2495 static void surface_copy_simple_location(struct wined3d_surface *surface, DWORD location)
2497 unsigned int sub_resource_idx = surface_get_sub_resource_idx(surface);
2498 struct wined3d_texture *texture = surface->container;
2499 struct wined3d_device *device = texture->resource.device;
2500 struct wined3d_texture_sub_resource *sub_resource;
2501 struct wined3d_context *context;
2502 const struct wined3d_gl_info *gl_info;
2503 struct wined3d_bo_address dst, src;
2505 sub_resource = &texture->sub_resources[sub_resource_idx];
2506 wined3d_texture_get_memory(texture, sub_resource_idx, &dst, location);
2507 wined3d_texture_get_memory(texture, sub_resource_idx, &src, sub_resource->locations);
2509 if (dst.buffer_object)
2511 context = context_acquire(device, NULL);
2512 gl_info = context->gl_info;
2513 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, dst.buffer_object));
2514 GL_EXTCALL(glBufferSubData(GL_PIXEL_UNPACK_BUFFER, 0, sub_resource->size, src.addr));
2515 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));
2516 checkGLcall("Upload PBO");
2517 context_release(context);
2518 return;
2520 if (src.buffer_object)
2522 context = context_acquire(device, NULL);
2523 gl_info = context->gl_info;
2524 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, src.buffer_object));
2525 GL_EXTCALL(glGetBufferSubData(GL_PIXEL_PACK_BUFFER, 0, sub_resource->size, dst.addr));
2526 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));
2527 checkGLcall("Download PBO");
2528 context_release(context);
2529 return;
2531 memcpy(dst.addr, src.addr, sub_resource->size);
2534 /* Context activation is done by the caller. */
2535 static void surface_load_sysmem(struct wined3d_surface *surface,
2536 struct wined3d_context *context, DWORD dst_location)
2538 unsigned int sub_resource_idx = surface_get_sub_resource_idx(surface);
2539 const struct wined3d_gl_info *gl_info = context->gl_info;
2540 struct wined3d_texture *texture = surface->container;
2541 struct wined3d_texture_sub_resource *sub_resource;
2543 wined3d_texture_prepare_location(texture, sub_resource_idx, context, dst_location);
2545 sub_resource = &texture->sub_resources[sub_resource_idx];
2546 if (sub_resource->locations & surface_simple_locations)
2548 surface_copy_simple_location(surface, dst_location);
2549 return;
2552 if (sub_resource->locations & (WINED3D_LOCATION_RB_MULTISAMPLE | WINED3D_LOCATION_RB_RESOLVED))
2553 wined3d_texture_load_location(texture, sub_resource_idx, context, WINED3D_LOCATION_TEXTURE_RGB);
2555 /* Download the surface to system memory. */
2556 if (sub_resource->locations & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB))
2558 wined3d_texture_bind_and_dirtify(texture, context,
2559 !(sub_resource->locations & WINED3D_LOCATION_TEXTURE_RGB));
2560 surface_download_data(surface, gl_info, dst_location);
2561 ++texture->download_count;
2563 return;
2566 if (sub_resource->locations & WINED3D_LOCATION_DRAWABLE)
2568 read_from_framebuffer(surface, context, dst_location);
2569 return;
2572 FIXME("Can't load surface %p with location flags %s into sysmem.\n",
2573 surface, wined3d_debug_location(sub_resource->locations));
2576 /* Context activation is done by the caller. */
2577 static HRESULT surface_load_drawable(struct wined3d_surface *surface,
2578 struct wined3d_context *context)
2580 unsigned int sub_resource_idx = surface_get_sub_resource_idx(surface);
2581 struct wined3d_texture *texture = surface->container;
2582 RECT r;
2584 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO
2585 && wined3d_resource_is_offscreen(&texture->resource))
2587 ERR("Trying to load offscreen surface into WINED3D_LOCATION_DRAWABLE.\n");
2588 return WINED3DERR_INVALIDCALL;
2591 surface_get_rect(surface, NULL, &r);
2592 wined3d_texture_load_location(texture, sub_resource_idx, context, WINED3D_LOCATION_TEXTURE_RGB);
2593 surface_blt_to_drawable(texture->resource.device, context,
2594 WINED3D_TEXF_POINT, FALSE, surface, &r, surface, &r);
2596 return WINED3D_OK;
2599 static HRESULT surface_load_texture(struct wined3d_surface *surface,
2600 struct wined3d_context *context, BOOL srgb)
2602 unsigned int width, height, src_row_pitch, src_slice_pitch, dst_row_pitch, dst_slice_pitch;
2603 unsigned int sub_resource_idx = surface_get_sub_resource_idx(surface);
2604 const struct wined3d_gl_info *gl_info = context->gl_info;
2605 struct wined3d_texture *texture = surface->container;
2606 struct wined3d_device *device = texture->resource.device;
2607 const struct wined3d_color_key_conversion *conversion;
2608 struct wined3d_texture_sub_resource *sub_resource;
2609 struct wined3d_bo_address data;
2610 BYTE *src_mem, *dst_mem = NULL;
2611 struct wined3d_format format;
2612 POINT dst_point = {0, 0};
2613 RECT src_rect;
2615 sub_resource = surface_get_sub_resource(surface);
2616 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO
2617 && wined3d_resource_is_offscreen(&texture->resource)
2618 && (sub_resource->locations & WINED3D_LOCATION_DRAWABLE))
2620 surface_load_fb_texture(surface, srgb, context);
2622 return WINED3D_OK;
2625 width = wined3d_texture_get_level_width(texture, surface->texture_level);
2626 height = wined3d_texture_get_level_height(texture, surface->texture_level);
2627 SetRect(&src_rect, 0, 0, width, height);
2629 if (sub_resource->locations & (WINED3D_LOCATION_TEXTURE_SRGB | WINED3D_LOCATION_TEXTURE_RGB)
2630 && (texture->resource.format_flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB)
2631 && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
2632 NULL, texture->resource.usage, texture->resource.pool, texture->resource.format,
2633 NULL, texture->resource.usage, texture->resource.pool, texture->resource.format))
2635 if (srgb)
2636 surface_blt_fbo(device, context, WINED3D_TEXF_POINT, surface, WINED3D_LOCATION_TEXTURE_RGB,
2637 &src_rect, surface, WINED3D_LOCATION_TEXTURE_SRGB, &src_rect);
2638 else
2639 surface_blt_fbo(device, context, WINED3D_TEXF_POINT, surface, WINED3D_LOCATION_TEXTURE_SRGB,
2640 &src_rect, surface, WINED3D_LOCATION_TEXTURE_RGB, &src_rect);
2642 return WINED3D_OK;
2645 if (sub_resource->locations & (WINED3D_LOCATION_RB_MULTISAMPLE | WINED3D_LOCATION_RB_RESOLVED)
2646 && (!srgb || (texture->resource.format_flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB))
2647 && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
2648 NULL, texture->resource.usage, texture->resource.pool, texture->resource.format,
2649 NULL, texture->resource.usage, texture->resource.pool, texture->resource.format))
2651 DWORD src_location = sub_resource->locations & WINED3D_LOCATION_RB_RESOLVED ?
2652 WINED3D_LOCATION_RB_RESOLVED : WINED3D_LOCATION_RB_MULTISAMPLE;
2653 DWORD dst_location = srgb ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB;
2655 surface_blt_fbo(device, context, WINED3D_TEXF_POINT, surface, src_location,
2656 &src_rect, surface, dst_location, &src_rect);
2658 return WINED3D_OK;
2661 /* Upload from system memory */
2663 if (srgb)
2665 if ((sub_resource->locations & (WINED3D_LOCATION_TEXTURE_RGB | texture->resource.map_binding))
2666 == WINED3D_LOCATION_TEXTURE_RGB)
2668 FIXME_(d3d_perf)("Downloading RGB surface %p to reload it as sRGB.\n", surface);
2669 wined3d_texture_load_location(texture, sub_resource_idx, context, texture->resource.map_binding);
2672 else
2674 if ((sub_resource->locations & (WINED3D_LOCATION_TEXTURE_SRGB | texture->resource.map_binding))
2675 == WINED3D_LOCATION_TEXTURE_SRGB)
2677 FIXME_(d3d_perf)("Downloading sRGB surface %p to reload it as RGB.\n", surface);
2678 wined3d_texture_load_location(texture, sub_resource_idx, context, texture->resource.map_binding);
2682 if (!(sub_resource->locations & surface_simple_locations))
2684 WARN("Trying to load a texture from sysmem, but no simple location is valid.\n");
2685 /* Lets hope we get it from somewhere... */
2686 wined3d_texture_load_location(texture, sub_resource_idx, context, WINED3D_LOCATION_SYSMEM);
2689 wined3d_texture_prepare_texture(texture, context, srgb);
2690 wined3d_texture_bind_and_dirtify(texture, context, srgb);
2691 wined3d_texture_get_pitch(texture, surface->texture_level, &src_row_pitch, &src_slice_pitch);
2693 format = *texture->resource.format;
2694 if ((conversion = wined3d_format_get_color_key_conversion(texture, TRUE)))
2695 format = *wined3d_get_format(gl_info, conversion->dst_format, texture->resource.usage);
2697 /* Don't use PBOs for converted surfaces. During PBO conversion we look at
2698 * WINED3D_TEXTURE_CONVERTED but it isn't set (yet) in all cases it is
2699 * getting called. */
2700 if ((format.convert || conversion) && texture->sub_resources[sub_resource_idx].buffer_object)
2702 TRACE("Removing the pbo attached to surface %p.\n", surface);
2704 wined3d_texture_load_location(texture, sub_resource_idx, context, WINED3D_LOCATION_SYSMEM);
2705 wined3d_texture_set_map_binding(texture, WINED3D_LOCATION_SYSMEM);
2708 wined3d_texture_get_memory(texture, sub_resource_idx, &data, sub_resource->locations);
2709 if (format.convert)
2711 /* This code is entered for texture formats which need a fixup. */
2712 format.byte_count = format.conv_byte_count;
2713 wined3d_format_calculate_pitch(&format, 1, width, height, &dst_row_pitch, &dst_slice_pitch);
2715 src_mem = wined3d_texture_map_bo_address(&data, src_slice_pitch,
2716 gl_info, GL_PIXEL_UNPACK_BUFFER, WINED3D_MAP_READONLY);
2717 if (!(dst_mem = HeapAlloc(GetProcessHeap(), 0, dst_slice_pitch)))
2719 ERR("Out of memory (%u).\n", dst_slice_pitch);
2720 context_release(context);
2721 return E_OUTOFMEMORY;
2723 format.convert(src_mem, dst_mem, src_row_pitch, src_slice_pitch,
2724 dst_row_pitch, dst_slice_pitch, width, height, 1);
2725 src_row_pitch = dst_row_pitch;
2726 wined3d_texture_unmap_bo_address(&data, gl_info, GL_PIXEL_UNPACK_BUFFER);
2728 data.buffer_object = 0;
2729 data.addr = dst_mem;
2731 else if (conversion)
2733 /* This code is only entered for color keying fixups */
2734 struct wined3d_palette *palette = NULL;
2736 wined3d_format_calculate_pitch(&format, device->surface_alignment,
2737 width, height, &dst_row_pitch, &dst_slice_pitch);
2739 src_mem = wined3d_texture_map_bo_address(&data, src_slice_pitch,
2740 gl_info, GL_PIXEL_UNPACK_BUFFER, WINED3D_MAP_READONLY);
2741 if (!(dst_mem = HeapAlloc(GetProcessHeap(), 0, dst_slice_pitch)))
2743 ERR("Out of memory (%u).\n", dst_slice_pitch);
2744 context_release(context);
2745 return E_OUTOFMEMORY;
2747 if (texture->swapchain && texture->swapchain->palette)
2748 palette = texture->swapchain->palette;
2749 conversion->convert(src_mem, src_row_pitch, dst_mem, dst_row_pitch,
2750 width, height, palette, &texture->async.gl_color_key);
2751 src_row_pitch = dst_row_pitch;
2752 wined3d_texture_unmap_bo_address(&data, gl_info, GL_PIXEL_UNPACK_BUFFER);
2754 data.buffer_object = 0;
2755 data.addr = dst_mem;
2758 wined3d_surface_upload_data(surface, gl_info, &format, &src_rect,
2759 src_row_pitch, &dst_point, srgb, wined3d_const_bo_address(&data));
2761 HeapFree(GetProcessHeap(), 0, dst_mem);
2763 return WINED3D_OK;
2766 /* Context activation is done by the caller. */
2767 static void surface_load_renderbuffer(struct wined3d_surface *surface, struct wined3d_context *context,
2768 DWORD dst_location)
2770 struct wined3d_texture *texture = surface->container;
2771 const RECT rect = {0, 0,
2772 wined3d_texture_get_level_width(texture, surface->texture_level),
2773 wined3d_texture_get_level_height(texture, surface->texture_level)};
2774 DWORD locations = surface_get_sub_resource(surface)->locations;
2775 DWORD src_location;
2777 if (locations & WINED3D_LOCATION_RB_MULTISAMPLE)
2778 src_location = WINED3D_LOCATION_RB_MULTISAMPLE;
2779 else if (locations & WINED3D_LOCATION_RB_RESOLVED)
2780 src_location = WINED3D_LOCATION_RB_RESOLVED;
2781 else if (locations & WINED3D_LOCATION_TEXTURE_SRGB)
2782 src_location = WINED3D_LOCATION_TEXTURE_SRGB;
2783 else /* surface_blt_fbo will load the source location if necessary. */
2784 src_location = WINED3D_LOCATION_TEXTURE_RGB;
2786 surface_blt_fbo(texture->resource.device, context, WINED3D_TEXF_POINT,
2787 surface, src_location, &rect, surface, dst_location, &rect);
2790 /* Context activation is done by the caller. Context may be NULL in ddraw-only mode. */
2791 HRESULT surface_load_location(struct wined3d_surface *surface, struct wined3d_context *context, DWORD location)
2793 unsigned int sub_resource_idx = surface_get_sub_resource_idx(surface);
2794 struct wined3d_texture *texture = surface->container;
2795 HRESULT hr;
2797 TRACE("surface %p, location %s.\n", surface, wined3d_debug_location(location));
2799 if (texture->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
2801 DWORD current = texture->sub_resources[sub_resource_idx].locations;
2802 FIXME("Unimplemented copy from %s to %s for depth/stencil buffers.\n",
2803 wined3d_debug_location(current), wined3d_debug_location(location));
2804 return WINED3DERR_INVALIDCALL;
2807 switch (location)
2809 case WINED3D_LOCATION_USER_MEMORY:
2810 case WINED3D_LOCATION_SYSMEM:
2811 case WINED3D_LOCATION_BUFFER:
2812 surface_load_sysmem(surface, context, location);
2813 break;
2815 case WINED3D_LOCATION_DRAWABLE:
2816 if (FAILED(hr = surface_load_drawable(surface, context)))
2817 return hr;
2818 break;
2820 case WINED3D_LOCATION_RB_RESOLVED:
2821 case WINED3D_LOCATION_RB_MULTISAMPLE:
2822 surface_load_renderbuffer(surface, context, location);
2823 break;
2825 case WINED3D_LOCATION_TEXTURE_RGB:
2826 case WINED3D_LOCATION_TEXTURE_SRGB:
2827 if (FAILED(hr = surface_load_texture(surface, context,
2828 location == WINED3D_LOCATION_TEXTURE_SRGB)))
2829 return hr;
2830 break;
2832 default:
2833 ERR("Don't know how to handle location %#x.\n", location);
2834 break;
2837 return WINED3D_OK;
2840 static HRESULT ffp_blit_alloc(struct wined3d_device *device) { return WINED3D_OK; }
2841 /* Context activation is done by the caller. */
2842 static void ffp_blit_free(struct wined3d_device *device) { }
2844 /* Context activation is done by the caller. */
2845 static HRESULT ffp_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface,
2846 const struct wined3d_color_key *color_key)
2848 const struct wined3d_gl_info *gl_info = context->gl_info;
2850 gl_info->gl_ops.gl.p_glEnable(surface->container->target);
2851 checkGLcall("glEnable(target)");
2853 return WINED3D_OK;
2856 /* Context activation is done by the caller. */
2857 static void ffp_blit_unset(const struct wined3d_gl_info *gl_info)
2859 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_2D);
2860 checkGLcall("glDisable(GL_TEXTURE_2D)");
2861 if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
2863 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_CUBE_MAP_ARB);
2864 checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
2866 if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
2868 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_RECTANGLE_ARB);
2869 checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)");
2873 static BOOL ffp_blit_supported(const struct wined3d_gl_info *gl_info,
2874 const struct wined3d_d3d_info *d3d_info, enum wined3d_blit_op blit_op,
2875 const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
2876 const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
2878 BOOL decompress;
2880 decompress = src_format && (src_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_COMPRESSED)
2881 && !(dst_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_COMPRESSED);
2882 if (!decompress && (src_pool == WINED3D_POOL_SYSTEM_MEM || dst_pool == WINED3D_POOL_SYSTEM_MEM))
2884 TRACE("Source or destination is in system memory.\n");
2885 return FALSE;
2888 switch (blit_op)
2890 case WINED3D_BLIT_OP_COLOR_BLIT_CKEY:
2891 if (d3d_info->shader_color_key)
2893 TRACE("Color keying requires converted textures.\n");
2894 return FALSE;
2896 case WINED3D_BLIT_OP_COLOR_BLIT:
2897 case WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST:
2898 if (TRACE_ON(d3d))
2900 TRACE("Checking support for fixup:\n");
2901 dump_color_fixup_desc(src_format->color_fixup);
2904 /* We only support identity conversions. */
2905 if (!is_identity_fixup(src_format->color_fixup)
2906 || !is_identity_fixup(dst_format->color_fixup))
2908 TRACE("Fixups are not supported.\n");
2909 return FALSE;
2912 if (!(dst_usage & WINED3DUSAGE_RENDERTARGET))
2914 TRACE("Can only blit to render targets.\n");
2915 return FALSE;
2917 return TRUE;
2919 case WINED3D_BLIT_OP_COLOR_FILL:
2920 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
2922 if (!((dst_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_FBO_ATTACHABLE)
2923 || (dst_usage & WINED3DUSAGE_RENDERTARGET)))
2924 return FALSE;
2926 else if (!(dst_usage & WINED3DUSAGE_RENDERTARGET))
2928 TRACE("Color fill not supported\n");
2929 return FALSE;
2932 /* FIXME: We should reject color fills on formats with fixups,
2933 * but this would break P8 color fills for example. */
2935 return TRUE;
2937 case WINED3D_BLIT_OP_DEPTH_FILL:
2938 return TRUE;
2940 default:
2941 TRACE("Unsupported blit_op=%d\n", blit_op);
2942 return FALSE;
2946 static HRESULT ffp_blit_color_fill(struct wined3d_device *device, struct wined3d_rendertarget_view *view,
2947 const RECT *rect, const struct wined3d_color *color)
2949 const RECT draw_rect = {0, 0, view->width, view->height};
2950 struct wined3d_fb_state fb = {&view, NULL};
2952 device_clear_render_targets(device, 1, &fb, 1, rect, &draw_rect, WINED3DCLEAR_TARGET, color, 0.0f, 0);
2954 return WINED3D_OK;
2957 static HRESULT ffp_blit_depth_fill(struct wined3d_device *device,
2958 struct wined3d_rendertarget_view *view, const RECT *rect, DWORD clear_flags,
2959 float depth, DWORD stencil)
2961 const RECT draw_rect = {0, 0, view->width, view->height};
2962 struct wined3d_fb_state fb = {NULL, view};
2964 device_clear_render_targets(device, 0, &fb, 1, rect, &draw_rect, clear_flags, NULL, depth, stencil);
2966 return WINED3D_OK;
2969 static void ffp_blit_blit_surface(struct wined3d_device *device, enum wined3d_blit_op op, DWORD filter,
2970 struct wined3d_surface *src_surface, const RECT *src_rect,
2971 struct wined3d_surface *dst_surface, const RECT *dst_rect,
2972 const struct wined3d_color_key *color_key)
2974 unsigned int dst_sub_resource_idx = surface_get_sub_resource_idx(dst_surface);
2975 struct wined3d_texture *dst_texture = dst_surface->container;
2976 struct wined3d_texture *src_texture = src_surface->container;
2977 const struct wined3d_gl_info *gl_info;
2978 struct wined3d_context *context;
2980 /* Blit from offscreen surface to render target */
2981 struct wined3d_color_key old_blt_key = src_texture->async.src_blt_color_key;
2982 DWORD old_color_key_flags = src_texture->async.color_key_flags;
2984 TRACE("Blt from surface %p to rendertarget %p\n", src_surface, dst_surface);
2986 wined3d_texture_set_color_key(src_texture, WINED3D_CKEY_SRC_BLT, color_key);
2988 context = context_acquire(device, dst_surface);
2989 gl_info = context->gl_info;
2991 if (op == WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST)
2992 gl_info->gl_ops.gl.p_glEnable(GL_ALPHA_TEST);
2994 surface_blt_to_drawable(device, context, filter,
2995 !!color_key, src_surface, src_rect, dst_surface, dst_rect);
2997 if (op == WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST)
2998 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
3000 context_release(context);
3002 /* Restore the color key parameters */
3003 wined3d_texture_set_color_key(src_texture, WINED3D_CKEY_SRC_BLT,
3004 (old_color_key_flags & WINED3D_CKEY_SRC_BLT) ? &old_blt_key : NULL);
3006 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, dst_texture->resource.draw_binding);
3007 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~dst_texture->resource.draw_binding);
3010 const struct blit_shader ffp_blit = {
3011 ffp_blit_alloc,
3012 ffp_blit_free,
3013 ffp_blit_set,
3014 ffp_blit_unset,
3015 ffp_blit_supported,
3016 ffp_blit_color_fill,
3017 ffp_blit_depth_fill,
3018 ffp_blit_blit_surface,
3021 static HRESULT cpu_blit_alloc(struct wined3d_device *device)
3023 return WINED3D_OK;
3026 /* Context activation is done by the caller. */
3027 static void cpu_blit_free(struct wined3d_device *device)
3031 /* Context activation is done by the caller. */
3032 static HRESULT cpu_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface,
3033 const struct wined3d_color_key *color_key)
3035 return WINED3D_OK;
3038 /* Context activation is done by the caller. */
3039 static void cpu_blit_unset(const struct wined3d_gl_info *gl_info)
3043 static BOOL cpu_blit_supported(const struct wined3d_gl_info *gl_info,
3044 const struct wined3d_d3d_info *d3d_info, enum wined3d_blit_op blit_op,
3045 const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
3046 const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
3048 if (blit_op == WINED3D_BLIT_OP_COLOR_FILL)
3050 return TRUE;
3053 return FALSE;
3056 static HRESULT surface_cpu_blt_compressed(const BYTE *src_data, BYTE *dst_data,
3057 UINT src_pitch, UINT dst_pitch, UINT update_w, UINT update_h,
3058 const struct wined3d_format *format, DWORD flags, const struct wined3d_blt_fx *fx)
3060 UINT row_block_count;
3061 const BYTE *src_row;
3062 BYTE *dst_row;
3063 UINT x, y;
3065 src_row = src_data;
3066 dst_row = dst_data;
3068 row_block_count = (update_w + format->block_width - 1) / format->block_width;
3070 if (!flags)
3072 for (y = 0; y < update_h; y += format->block_height)
3074 memcpy(dst_row, src_row, row_block_count * format->block_byte_count);
3075 src_row += src_pitch;
3076 dst_row += dst_pitch;
3079 return WINED3D_OK;
3082 if (flags == WINED3D_BLT_FX && fx->fx == WINEDDBLTFX_MIRRORUPDOWN)
3084 src_row += (((update_h / format->block_height) - 1) * src_pitch);
3086 switch (format->id)
3088 case WINED3DFMT_DXT1:
3089 for (y = 0; y < update_h; y += format->block_height)
3091 struct block
3093 WORD color[2];
3094 BYTE control_row[4];
3097 const struct block *s = (const struct block *)src_row;
3098 struct block *d = (struct block *)dst_row;
3100 for (x = 0; x < row_block_count; ++x)
3102 d[x].color[0] = s[x].color[0];
3103 d[x].color[1] = s[x].color[1];
3104 d[x].control_row[0] = s[x].control_row[3];
3105 d[x].control_row[1] = s[x].control_row[2];
3106 d[x].control_row[2] = s[x].control_row[1];
3107 d[x].control_row[3] = s[x].control_row[0];
3109 src_row -= src_pitch;
3110 dst_row += dst_pitch;
3112 return WINED3D_OK;
3114 case WINED3DFMT_DXT2:
3115 case WINED3DFMT_DXT3:
3116 for (y = 0; y < update_h; y += format->block_height)
3118 struct block
3120 WORD alpha_row[4];
3121 WORD color[2];
3122 BYTE control_row[4];
3125 const struct block *s = (const struct block *)src_row;
3126 struct block *d = (struct block *)dst_row;
3128 for (x = 0; x < row_block_count; ++x)
3130 d[x].alpha_row[0] = s[x].alpha_row[3];
3131 d[x].alpha_row[1] = s[x].alpha_row[2];
3132 d[x].alpha_row[2] = s[x].alpha_row[1];
3133 d[x].alpha_row[3] = s[x].alpha_row[0];
3134 d[x].color[0] = s[x].color[0];
3135 d[x].color[1] = s[x].color[1];
3136 d[x].control_row[0] = s[x].control_row[3];
3137 d[x].control_row[1] = s[x].control_row[2];
3138 d[x].control_row[2] = s[x].control_row[1];
3139 d[x].control_row[3] = s[x].control_row[0];
3141 src_row -= src_pitch;
3142 dst_row += dst_pitch;
3144 return WINED3D_OK;
3146 default:
3147 FIXME("Compressed flip not implemented for format %s.\n",
3148 debug_d3dformat(format->id));
3149 return E_NOTIMPL;
3153 FIXME("Unsupported blit on compressed surface (format %s, flags %#x, DDFX %#x).\n",
3154 debug_d3dformat(format->id), flags, flags & WINED3D_BLT_FX ? fx->fx : 0);
3156 return E_NOTIMPL;
3159 static HRESULT surface_cpu_blt(struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx,
3160 const struct wined3d_box *dst_box, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx,
3161 const struct wined3d_box *src_box, DWORD flags, const struct wined3d_blt_fx *fx,
3162 enum wined3d_texture_filter_type filter)
3164 unsigned int bpp, src_height, src_width, dst_height, dst_width, row_byte_count;
3165 const struct wined3d_format *src_format, *dst_format;
3166 struct wined3d_texture *converted_texture = NULL;
3167 unsigned int src_fmt_flags, dst_fmt_flags;
3168 struct wined3d_map_desc dst_map, src_map;
3169 const BYTE *sbase = NULL;
3170 HRESULT hr = WINED3D_OK;
3171 BOOL same_sub_resource;
3172 const BYTE *sbuf;
3173 BYTE *dbuf;
3174 int x, y;
3176 TRACE("dst_texture %p, dst_sub_resource_idx %u, dst_box %s, src_texture %p, "
3177 "src_sub_resource_idx %u, src_box %s, flags %#x, fx %p, filter %s.\n",
3178 dst_texture, dst_sub_resource_idx, debug_box(dst_box), src_texture,
3179 src_sub_resource_idx, debug_box(src_box), flags, fx, debug_d3dtexturefiltertype(filter));
3181 if (src_texture == dst_texture && src_sub_resource_idx == dst_sub_resource_idx)
3183 same_sub_resource = TRUE;
3184 wined3d_resource_map(&dst_texture->resource, dst_sub_resource_idx, &dst_map, NULL, 0);
3185 src_map = dst_map;
3186 src_format = dst_texture->resource.format;
3187 dst_format = src_format;
3188 dst_fmt_flags = dst_texture->resource.format_flags;
3189 src_fmt_flags = dst_fmt_flags;
3191 else
3193 same_sub_resource = FALSE;
3194 dst_format = dst_texture->resource.format;
3195 dst_fmt_flags = dst_texture->resource.format_flags;
3196 if (src_texture)
3198 if (dst_texture->resource.format->id != src_texture->resource.format->id)
3200 if (!(converted_texture = surface_convert_format(src_texture, src_sub_resource_idx, dst_format)))
3202 FIXME("Cannot convert %s to %s.\n", debug_d3dformat(src_texture->resource.format->id),
3203 debug_d3dformat(dst_texture->resource.format->id));
3204 return WINED3DERR_NOTAVAILABLE;
3206 src_texture = converted_texture;
3207 src_sub_resource_idx = 0;
3209 wined3d_resource_map(&src_texture->resource, src_sub_resource_idx, &src_map, NULL, WINED3D_MAP_READONLY);
3210 src_format = src_texture->resource.format;
3211 src_fmt_flags = src_texture->resource.format_flags;
3213 else
3215 src_format = dst_format;
3216 src_fmt_flags = dst_fmt_flags;
3219 wined3d_resource_map(&dst_texture->resource, dst_sub_resource_idx, &dst_map, dst_box, 0);
3222 bpp = dst_format->byte_count;
3223 src_height = src_box->bottom - src_box->top;
3224 src_width = src_box->right - src_box->left;
3225 dst_height = dst_box->bottom - dst_box->top;
3226 dst_width = dst_box->right - dst_box->left;
3227 row_byte_count = dst_width * bpp;
3229 if (src_texture)
3230 sbase = (BYTE *)src_map.data
3231 + ((src_box->top / src_format->block_height) * src_map.row_pitch)
3232 + ((src_box->left / src_format->block_width) * src_format->block_byte_count);
3233 if (same_sub_resource)
3234 dbuf = (BYTE *)dst_map.data
3235 + ((dst_box->top / dst_format->block_height) * dst_map.row_pitch)
3236 + ((dst_box->left / dst_format->block_width) * dst_format->block_byte_count);
3237 else
3238 dbuf = dst_map.data;
3240 if (src_fmt_flags & dst_fmt_flags & WINED3DFMT_FLAG_BLOCKS)
3242 TRACE("%s -> %s copy.\n", debug_d3dformat(src_format->id), debug_d3dformat(dst_format->id));
3244 if (same_sub_resource)
3246 FIXME("Only plain blits supported on compressed surfaces.\n");
3247 hr = E_NOTIMPL;
3248 goto release;
3251 if (src_height != dst_height || src_width != dst_width)
3253 WARN("Stretching not supported on compressed surfaces.\n");
3254 hr = WINED3DERR_INVALIDCALL;
3255 goto release;
3258 if (!wined3d_texture_check_block_align(src_texture,
3259 src_sub_resource_idx % src_texture->level_count, src_box))
3261 WARN("Source rectangle not block-aligned.\n");
3262 hr = WINED3DERR_INVALIDCALL;
3263 goto release;
3266 if (!wined3d_texture_check_block_align(dst_texture,
3267 dst_sub_resource_idx % dst_texture->level_count, dst_box))
3269 WARN("Destination rectangle not block-aligned.\n");
3270 hr = WINED3DERR_INVALIDCALL;
3271 goto release;
3274 hr = surface_cpu_blt_compressed(sbase, dbuf,
3275 src_map.row_pitch, dst_map.row_pitch, dst_width, dst_height,
3276 src_format, flags, fx);
3277 goto release;
3280 /* First, all the 'source-less' blits */
3281 if (flags & WINED3D_BLT_COLOR_FILL)
3283 hr = _Blt_ColorFill(dbuf, dst_width, dst_height, bpp, dst_map.row_pitch, fx->fill_color);
3284 flags &= ~WINED3D_BLT_COLOR_FILL;
3287 if (flags & WINED3D_BLT_DEPTH_FILL)
3288 FIXME("WINED3D_BLT_DEPTH_FILL needs to be implemented!\n");
3290 /* Now the 'with source' blits. */
3291 if (src_texture)
3293 int sx, xinc, sy, yinc;
3295 if (!dst_width || !dst_height) /* Hmm... stupid program? */
3296 goto release;
3298 if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT
3299 && (src_width != dst_width || src_height != dst_height))
3301 /* Can happen when d3d9 apps do a StretchRect() call which isn't handled in GL. */
3302 FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(filter));
3305 xinc = (src_width << 16) / dst_width;
3306 yinc = (src_height << 16) / dst_height;
3308 if (!flags)
3310 /* No effects, we can cheat here. */
3311 if (dst_width == src_width)
3313 if (dst_height == src_height)
3315 /* No stretching in either direction. This needs to be as
3316 * fast as possible. */
3317 sbuf = sbase;
3319 /* Check for overlapping surfaces. */
3320 if (!same_sub_resource || dst_box->top < src_box->top
3321 || dst_box->right <= src_box->left || src_box->right <= dst_box->left)
3323 /* No overlap, or dst above src, so copy from top downwards. */
3324 for (y = 0; y < dst_height; ++y)
3326 memcpy(dbuf, sbuf, row_byte_count);
3327 sbuf += src_map.row_pitch;
3328 dbuf += dst_map.row_pitch;
3331 else if (dst_box->top > src_box->top)
3333 /* Copy from bottom upwards. */
3334 sbuf += src_map.row_pitch * dst_height;
3335 dbuf += dst_map.row_pitch * dst_height;
3336 for (y = 0; y < dst_height; ++y)
3338 sbuf -= src_map.row_pitch;
3339 dbuf -= dst_map.row_pitch;
3340 memcpy(dbuf, sbuf, row_byte_count);
3343 else
3345 /* Src and dst overlapping on the same line, use memmove. */
3346 for (y = 0; y < dst_height; ++y)
3348 memmove(dbuf, sbuf, row_byte_count);
3349 sbuf += src_map.row_pitch;
3350 dbuf += dst_map.row_pitch;
3354 else
3356 /* Stretching in y direction only. */
3357 for (y = sy = 0; y < dst_height; ++y, sy += yinc)
3359 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
3360 memcpy(dbuf, sbuf, row_byte_count);
3361 dbuf += dst_map.row_pitch;
3365 else
3367 /* Stretching in X direction. */
3368 int last_sy = -1;
3369 for (y = sy = 0; y < dst_height; ++y, sy += yinc)
3371 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
3373 if ((sy >> 16) == (last_sy >> 16))
3375 /* This source row is the same as last source row -
3376 * Copy the already stretched row. */
3377 memcpy(dbuf, dbuf - dst_map.row_pitch, row_byte_count);
3379 else
3381 #define STRETCH_ROW(type) \
3382 do { \
3383 const type *s = (const type *)sbuf; \
3384 type *d = (type *)dbuf; \
3385 for (x = sx = 0; x < dst_width; ++x, sx += xinc) \
3386 d[x] = s[sx >> 16]; \
3387 } while(0)
3389 switch(bpp)
3391 case 1:
3392 STRETCH_ROW(BYTE);
3393 break;
3394 case 2:
3395 STRETCH_ROW(WORD);
3396 break;
3397 case 4:
3398 STRETCH_ROW(DWORD);
3399 break;
3400 case 3:
3402 const BYTE *s;
3403 BYTE *d = dbuf;
3404 for (x = sx = 0; x < dst_width; x++, sx+= xinc)
3406 DWORD pixel;
3408 s = sbuf + 3 * (sx >> 16);
3409 pixel = s[0] | (s[1] << 8) | (s[2] << 16);
3410 d[0] = (pixel ) & 0xff;
3411 d[1] = (pixel >> 8) & 0xff;
3412 d[2] = (pixel >> 16) & 0xff;
3413 d += 3;
3415 break;
3417 default:
3418 FIXME("Stretched blit not implemented for bpp %u!\n", bpp * 8);
3419 hr = WINED3DERR_NOTAVAILABLE;
3420 goto error;
3422 #undef STRETCH_ROW
3424 dbuf += dst_map.row_pitch;
3425 last_sy = sy;
3429 else
3431 LONG dstyinc = dst_map.row_pitch, dstxinc = bpp;
3432 DWORD keylow = 0xffffffff, keyhigh = 0, keymask = 0xffffffff;
3433 DWORD destkeylow = 0x0, destkeyhigh = 0xffffffff, destkeymask = 0xffffffff;
3434 if (flags & (WINED3D_BLT_SRC_CKEY | WINED3D_BLT_DST_CKEY
3435 | WINED3D_BLT_SRC_CKEY_OVERRIDE | WINED3D_BLT_DST_CKEY_OVERRIDE))
3437 /* The color keying flags are checked for correctness in ddraw */
3438 if (flags & WINED3D_BLT_SRC_CKEY)
3440 keylow = src_texture->async.src_blt_color_key.color_space_low_value;
3441 keyhigh = src_texture->async.src_blt_color_key.color_space_high_value;
3443 else if (flags & WINED3D_BLT_SRC_CKEY_OVERRIDE)
3445 keylow = fx->src_color_key.color_space_low_value;
3446 keyhigh = fx->src_color_key.color_space_high_value;
3449 if (flags & WINED3D_BLT_DST_CKEY)
3451 /* Destination color keys are taken from the source surface! */
3452 destkeylow = src_texture->async.dst_blt_color_key.color_space_low_value;
3453 destkeyhigh = src_texture->async.dst_blt_color_key.color_space_high_value;
3455 else if (flags & WINED3D_BLT_DST_CKEY_OVERRIDE)
3457 destkeylow = fx->dst_color_key.color_space_low_value;
3458 destkeyhigh = fx->dst_color_key.color_space_high_value;
3461 if (bpp == 1)
3463 keymask = 0xff;
3465 else
3467 DWORD masks[3];
3468 get_color_masks(src_format, masks);
3469 keymask = masks[0]
3470 | masks[1]
3471 | masks[2];
3473 flags &= ~(WINED3D_BLT_SRC_CKEY | WINED3D_BLT_DST_CKEY
3474 | WINED3D_BLT_SRC_CKEY_OVERRIDE | WINED3D_BLT_DST_CKEY_OVERRIDE);
3477 if (flags & WINED3D_BLT_FX)
3479 BYTE *dTopLeft, *dTopRight, *dBottomLeft, *dBottomRight, *tmp;
3480 LONG tmpxy;
3481 dTopLeft = dbuf;
3482 dTopRight = dbuf + ((dst_width - 1) * bpp);
3483 dBottomLeft = dTopLeft + ((dst_height - 1) * dst_map.row_pitch);
3484 dBottomRight = dBottomLeft + ((dst_width - 1) * bpp);
3486 if (fx->fx & WINEDDBLTFX_ARITHSTRETCHY)
3488 /* I don't think we need to do anything about this flag */
3489 WARN("Nothing done for WINEDDBLTFX_ARITHSTRETCHY.\n");
3491 if (fx->fx & WINEDDBLTFX_MIRRORLEFTRIGHT)
3493 tmp = dTopRight;
3494 dTopRight = dTopLeft;
3495 dTopLeft = tmp;
3496 tmp = dBottomRight;
3497 dBottomRight = dBottomLeft;
3498 dBottomLeft = tmp;
3499 dstxinc = dstxinc * -1;
3501 if (fx->fx & WINEDDBLTFX_MIRRORUPDOWN)
3503 tmp = dTopLeft;
3504 dTopLeft = dBottomLeft;
3505 dBottomLeft = tmp;
3506 tmp = dTopRight;
3507 dTopRight = dBottomRight;
3508 dBottomRight = tmp;
3509 dstyinc = dstyinc * -1;
3511 if (fx->fx & WINEDDBLTFX_NOTEARING)
3513 /* I don't think we need to do anything about this flag */
3514 WARN("Nothing done for WINEDDBLTFX_NOTEARING.\n");
3516 if (fx->fx & WINEDDBLTFX_ROTATE180)
3518 tmp = dBottomRight;
3519 dBottomRight = dTopLeft;
3520 dTopLeft = tmp;
3521 tmp = dBottomLeft;
3522 dBottomLeft = dTopRight;
3523 dTopRight = tmp;
3524 dstxinc = dstxinc * -1;
3525 dstyinc = dstyinc * -1;
3527 if (fx->fx & WINEDDBLTFX_ROTATE270)
3529 tmp = dTopLeft;
3530 dTopLeft = dBottomLeft;
3531 dBottomLeft = dBottomRight;
3532 dBottomRight = dTopRight;
3533 dTopRight = tmp;
3534 tmpxy = dstxinc;
3535 dstxinc = dstyinc;
3536 dstyinc = tmpxy;
3537 dstxinc = dstxinc * -1;
3539 if (fx->fx & WINEDDBLTFX_ROTATE90)
3541 tmp = dTopLeft;
3542 dTopLeft = dTopRight;
3543 dTopRight = dBottomRight;
3544 dBottomRight = dBottomLeft;
3545 dBottomLeft = tmp;
3546 tmpxy = dstxinc;
3547 dstxinc = dstyinc;
3548 dstyinc = tmpxy;
3549 dstyinc = dstyinc * -1;
3551 if (fx->fx & WINEDDBLTFX_ZBUFFERBASEDEST)
3553 /* I don't think we need to do anything about this flag */
3554 WARN("Nothing done for WINEDDBLTFX_ZBUFFERBASEDEST.\n");
3556 dbuf = dTopLeft;
3557 flags &= ~(WINED3D_BLT_FX);
3560 #define COPY_COLORKEY_FX(type) \
3561 do { \
3562 const type *s; \
3563 type *d = (type *)dbuf, *dx, tmp; \
3564 for (y = sy = 0; y < dst_height; ++y, sy += yinc) \
3566 s = (const type *)(sbase + (sy >> 16) * src_map.row_pitch); \
3567 dx = d; \
3568 for (x = sx = 0; x < dst_width; ++x, sx += xinc) \
3570 tmp = s[sx >> 16]; \
3571 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) \
3572 && ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) \
3574 dx[0] = tmp; \
3576 dx = (type *)(((BYTE *)dx) + dstxinc); \
3578 d = (type *)(((BYTE *)d) + dstyinc); \
3580 } while(0)
3582 switch (bpp)
3584 case 1:
3585 COPY_COLORKEY_FX(BYTE);
3586 break;
3587 case 2:
3588 COPY_COLORKEY_FX(WORD);
3589 break;
3590 case 4:
3591 COPY_COLORKEY_FX(DWORD);
3592 break;
3593 case 3:
3595 const BYTE *s;
3596 BYTE *d = dbuf, *dx;
3597 for (y = sy = 0; y < dst_height; ++y, sy += yinc)
3599 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
3600 dx = d;
3601 for (x = sx = 0; x < dst_width; ++x, sx+= xinc)
3603 DWORD pixel, dpixel = 0;
3604 s = sbuf + 3 * (sx>>16);
3605 pixel = s[0] | (s[1] << 8) | (s[2] << 16);
3606 dpixel = dx[0] | (dx[1] << 8 ) | (dx[2] << 16);
3607 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh)
3608 && ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
3610 dx[0] = (pixel ) & 0xff;
3611 dx[1] = (pixel >> 8) & 0xff;
3612 dx[2] = (pixel >> 16) & 0xff;
3614 dx += dstxinc;
3616 d += dstyinc;
3618 break;
3620 default:
3621 FIXME("%s color-keyed blit not implemented for bpp %u!\n",
3622 (flags & WINED3D_BLT_SRC_CKEY) ? "Source" : "Destination", bpp * 8);
3623 hr = WINED3DERR_NOTAVAILABLE;
3624 goto error;
3625 #undef COPY_COLORKEY_FX
3630 error:
3631 if (flags)
3632 FIXME(" Unsupported flags %#x.\n", flags);
3634 release:
3635 wined3d_resource_unmap(&dst_texture->resource, dst_sub_resource_idx);
3636 if (src_texture && !same_sub_resource)
3637 wined3d_resource_unmap(&src_texture->resource, src_sub_resource_idx);
3638 if (converted_texture)
3639 wined3d_texture_decref(converted_texture);
3641 return hr;
3644 static HRESULT cpu_blit_color_fill(struct wined3d_device *device, struct wined3d_rendertarget_view *view,
3645 const RECT *rect, const struct wined3d_color *color)
3647 const struct wined3d_box box = {rect->left, rect->top, rect->right, rect->bottom, 0, 1};
3648 static const struct wined3d_box src_box;
3649 struct wined3d_blt_fx fx;
3651 fx.fill_color = wined3d_format_convert_from_float(view->format, color);
3652 return surface_cpu_blt(texture_from_resource(view->resource), view->sub_resource_idx,
3653 &box, NULL, 0, &src_box, WINED3D_BLT_COLOR_FILL, &fx, WINED3D_TEXF_POINT);
3656 static HRESULT cpu_blit_depth_fill(struct wined3d_device *device,
3657 struct wined3d_rendertarget_view *view, const RECT *rect, DWORD clear_flags,
3658 float depth, DWORD stencil)
3660 FIXME("Depth/stencil filling not implemented by cpu_blit.\n");
3661 return WINED3DERR_INVALIDCALL;
3664 static void cpu_blit_blit_surface(struct wined3d_device *device, enum wined3d_blit_op op, DWORD filter,
3665 struct wined3d_surface *src_surface, const RECT *src_rect,
3666 struct wined3d_surface *dst_surface, const RECT *dst_rect,
3667 const struct wined3d_color_key *color_key)
3669 /* FIXME: Remove error returns from surface_blt_cpu. */
3670 ERR("Blit method not implemented by cpu_blit.\n");
3673 const struct blit_shader cpu_blit = {
3674 cpu_blit_alloc,
3675 cpu_blit_free,
3676 cpu_blit_set,
3677 cpu_blit_unset,
3678 cpu_blit_supported,
3679 cpu_blit_color_fill,
3680 cpu_blit_depth_fill,
3681 cpu_blit_blit_surface,
3684 HRESULT wined3d_surface_blt(struct wined3d_surface *dst_surface, const RECT *dst_rect,
3685 struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags,
3686 const struct wined3d_blt_fx *fx, enum wined3d_texture_filter_type filter)
3688 struct wined3d_box dst_box = {dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, 0, 1};
3689 struct wined3d_box src_box = {src_rect->left, src_rect->top, src_rect->right, src_rect->bottom, 0, 1};
3690 unsigned int dst_sub_resource_idx = surface_get_sub_resource_idx(dst_surface);
3691 struct wined3d_texture *dst_texture = dst_surface->container;
3692 struct wined3d_device *device = dst_texture->resource.device;
3693 struct wined3d_swapchain *src_swapchain, *dst_swapchain;
3694 struct wined3d_texture *src_texture = NULL;
3695 unsigned int dst_w, dst_h, src_w, src_h;
3696 unsigned int src_sub_resource_idx = 0;
3697 DWORD src_ds_flags, dst_ds_flags;
3698 BOOL scale, convert;
3700 static const DWORD simple_blit = WINED3D_BLT_ASYNC
3701 | WINED3D_BLT_COLOR_FILL
3702 | WINED3D_BLT_SRC_CKEY
3703 | WINED3D_BLT_SRC_CKEY_OVERRIDE
3704 | WINED3D_BLT_WAIT
3705 | WINED3D_BLT_DEPTH_FILL
3706 | WINED3D_BLT_DO_NOT_WAIT
3707 | WINED3D_BLT_ALPHA_TEST;
3709 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
3710 dst_surface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect),
3711 flags, fx, debug_d3dtexturefiltertype(filter));
3712 TRACE("Usage is %s.\n", debug_d3dusage(dst_texture->resource.usage));
3714 if (fx)
3716 TRACE("fx %#x.\n", fx->fx);
3717 TRACE("fill_color 0x%08x.\n", fx->fill_color);
3718 TRACE("dst_color_key {0x%08x, 0x%08x}.\n",
3719 fx->dst_color_key.color_space_low_value,
3720 fx->dst_color_key.color_space_high_value);
3721 TRACE("src_color_key {0x%08x, 0x%08x}.\n",
3722 fx->src_color_key.color_space_low_value,
3723 fx->src_color_key.color_space_high_value);
3726 if (src_surface)
3728 src_texture = src_surface->container;
3729 src_sub_resource_idx = surface_get_sub_resource_idx(src_surface);
3732 if (dst_texture->sub_resources[dst_sub_resource_idx].map_count
3733 || (src_texture && src_texture->sub_resources[src_sub_resource_idx].map_count))
3735 WARN("Surface is busy, returning WINEDDERR_SURFACEBUSY.\n");
3736 return WINEDDERR_SURFACEBUSY;
3739 dst_w = wined3d_texture_get_level_width(dst_texture, dst_surface->texture_level);
3740 dst_h = wined3d_texture_get_level_height(dst_texture, dst_surface->texture_level);
3741 if (IsRectEmpty(dst_rect) || dst_rect->left > dst_w || dst_rect->left < 0
3742 || dst_rect->top > dst_h || dst_rect->top < 0
3743 || dst_rect->right > dst_w || dst_rect->right < 0
3744 || dst_rect->bottom > dst_h || dst_rect->bottom < 0)
3746 WARN("The application gave us a bad destination rectangle.\n");
3747 return WINEDDERR_INVALIDRECT;
3750 if (src_texture)
3752 src_w = wined3d_texture_get_level_width(src_texture, src_surface->texture_level);
3753 src_h = wined3d_texture_get_level_height(src_texture, src_surface->texture_level);
3754 if (IsRectEmpty(src_rect) || src_rect->left > src_w || src_rect->left < 0
3755 || src_rect->top > src_h || src_rect->top < 0
3756 || src_rect->right > src_w || src_rect->right < 0
3757 || src_rect->bottom > src_h || src_rect->bottom < 0)
3759 WARN("The application gave us a bad source rectangle.\n");
3760 return WINEDDERR_INVALIDRECT;
3764 if (!fx || !(fx->fx))
3765 flags &= ~WINED3D_BLT_FX;
3767 if (flags & WINED3D_BLT_WAIT)
3768 flags &= ~WINED3D_BLT_WAIT;
3770 if (flags & WINED3D_BLT_ASYNC)
3772 static unsigned int once;
3774 if (!once++)
3775 FIXME("Can't handle WINED3D_BLT_ASYNC flag.\n");
3776 flags &= ~WINED3D_BLT_ASYNC;
3779 /* WINED3D_BLT_DO_NOT_WAIT appeared in DX7. */
3780 if (flags & WINED3D_BLT_DO_NOT_WAIT)
3782 static unsigned int once;
3784 if (!once++)
3785 FIXME("Can't handle WINED3D_BLT_DO_NOT_WAIT flag.\n");
3786 flags &= ~WINED3D_BLT_DO_NOT_WAIT;
3789 if (!device->d3d_initialized)
3791 WARN("D3D not initialized, using fallback.\n");
3792 goto cpu;
3795 /* We want to avoid invalidating the sysmem location for converted
3796 * surfaces, since otherwise we'd have to convert the data back when
3797 * locking them. */
3798 if (dst_texture->flags & WINED3D_TEXTURE_CONVERTED || dst_texture->resource.format->convert
3799 || wined3d_format_get_color_key_conversion(dst_texture, TRUE))
3801 WARN_(d3d_perf)("Converted surface, using CPU blit.\n");
3802 goto cpu;
3805 if (flags & ~simple_blit)
3807 WARN_(d3d_perf)("Using fallback for complex blit (%#x).\n", flags);
3808 goto fallback;
3811 if (src_texture)
3812 src_swapchain = src_texture->swapchain;
3813 else
3814 src_swapchain = NULL;
3816 dst_swapchain = dst_texture->swapchain;
3818 /* This isn't strictly needed. FBO blits for example could deal with
3819 * cross-swapchain blits by first downloading the source to a texture
3820 * before switching to the destination context. We just have this here to
3821 * not have to deal with the issue, since cross-swapchain blits should be
3822 * rare. */
3823 if (src_swapchain && dst_swapchain && src_swapchain != dst_swapchain)
3825 FIXME("Using fallback for cross-swapchain blit.\n");
3826 goto fallback;
3829 scale = src_texture
3830 && (src_rect->right - src_rect->left != dst_rect->right - dst_rect->left
3831 || src_rect->bottom - src_rect->top != dst_rect->bottom - dst_rect->top);
3832 convert = src_texture && src_texture->resource.format->id != dst_texture->resource.format->id;
3834 dst_ds_flags = dst_texture->resource.format_flags
3835 & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
3836 if (src_texture)
3837 src_ds_flags = src_texture->resource.format_flags
3838 & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
3839 else
3840 src_ds_flags = 0;
3842 if (src_ds_flags || dst_ds_flags)
3844 if (flags & WINED3D_BLT_DEPTH_FILL)
3846 float depth;
3848 TRACE("Depth fill.\n");
3850 if (!surface_convert_depth_to_float(dst_surface, fx->fill_color, &depth))
3851 return WINED3DERR_INVALIDCALL;
3853 if (SUCCEEDED(wined3d_surface_depth_fill(dst_surface, dst_rect, depth)))
3854 return WINED3D_OK;
3856 else
3858 if (src_ds_flags != dst_ds_flags)
3860 WARN("Rejecting depth / stencil blit between incompatible formats.\n");
3861 return WINED3DERR_INVALIDCALL;
3864 if (SUCCEEDED(wined3d_surface_depth_blt(src_surface, src_texture->resource.draw_binding,
3865 src_rect, dst_surface, dst_texture->resource.draw_binding, dst_rect)))
3866 return WINED3D_OK;
3869 else
3871 struct wined3d_texture_sub_resource *src_sub_resource, *dst_sub_resource;
3872 const struct blit_shader *blitter;
3874 dst_sub_resource = surface_get_sub_resource(dst_surface);
3875 src_sub_resource = src_texture ? &src_texture->sub_resources[src_sub_resource_idx] : NULL;
3877 /* In principle this would apply to depth blits as well, but we don't
3878 * implement those in the CPU blitter at the moment. */
3879 if ((dst_sub_resource->locations & dst_texture->resource.map_binding)
3880 && (!src_texture || (src_sub_resource->locations & src_texture->resource.map_binding)))
3882 if (scale)
3883 TRACE("Not doing sysmem blit because of scaling.\n");
3884 else if (convert)
3885 TRACE("Not doing sysmem blit because of format conversion.\n");
3886 else
3887 goto cpu;
3890 if (flags & WINED3D_BLT_COLOR_FILL)
3892 struct wined3d_color color;
3893 const struct wined3d_palette *palette = dst_swapchain ? dst_swapchain->palette : NULL;
3895 TRACE("Color fill.\n");
3897 if (!wined3d_format_convert_color_to_float(dst_texture->resource.format,
3898 palette, fx->fill_color, &color))
3899 goto fallback;
3901 if (SUCCEEDED(surface_color_fill(dst_surface, dst_rect, &color)))
3902 return WINED3D_OK;
3904 else
3906 enum wined3d_blit_op blit_op = WINED3D_BLIT_OP_COLOR_BLIT;
3907 const struct wined3d_color_key *color_key = NULL;
3909 TRACE("Color blit.\n");
3910 if (flags & WINED3D_BLT_SRC_CKEY_OVERRIDE)
3912 color_key = &fx->src_color_key;
3913 blit_op = WINED3D_BLIT_OP_COLOR_BLIT_CKEY;
3915 else if (flags & WINED3D_BLT_SRC_CKEY)
3917 color_key = &src_texture->async.src_blt_color_key;
3918 blit_op = WINED3D_BLIT_OP_COLOR_BLIT_CKEY;
3920 else if (flags & WINED3D_BLT_ALPHA_TEST)
3922 blit_op = WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST;
3924 else if ((src_sub_resource->locations & WINED3D_LOCATION_SYSMEM)
3925 && !(dst_sub_resource->locations & WINED3D_LOCATION_SYSMEM))
3927 /* Upload */
3928 if (scale)
3929 TRACE("Not doing upload because of scaling.\n");
3930 else if (convert)
3931 TRACE("Not doing upload because of format conversion.\n");
3932 else
3934 POINT dst_point = {dst_rect->left, dst_rect->top};
3936 if (SUCCEEDED(surface_upload_from_surface(dst_surface, &dst_point, src_surface, src_rect)))
3938 if (!wined3d_resource_is_offscreen(&dst_texture->resource))
3940 struct wined3d_context *context = context_acquire(device, dst_surface);
3941 wined3d_texture_load_location(dst_texture, dst_sub_resource_idx,
3942 context, dst_texture->resource.draw_binding);
3943 context_release(context);
3945 return WINED3D_OK;
3949 else if (dst_swapchain && dst_swapchain->back_buffers
3950 && dst_texture == dst_swapchain->front_buffer
3951 && src_texture == dst_swapchain->back_buffers[0])
3953 /* Use present for back -> front blits. The idea behind this is
3954 * that present is potentially faster than a blit, in particular
3955 * when FBO blits aren't available. Some ddraw applications like
3956 * Half-Life and Prince of Persia 3D use Blt() from the backbuffer
3957 * to the frontbuffer instead of doing a Flip(). D3D8 and D3D9
3958 * applications can't blit directly to the frontbuffer. */
3959 enum wined3d_swap_effect swap_effect = dst_swapchain->desc.swap_effect;
3961 TRACE("Using present for backbuffer -> frontbuffer blit.\n");
3963 /* Set the swap effect to COPY, we don't want the backbuffer
3964 * to become undefined. */
3965 dst_swapchain->desc.swap_effect = WINED3D_SWAP_EFFECT_COPY;
3966 wined3d_swapchain_present(dst_swapchain, NULL, NULL, dst_swapchain->win_handle, 0);
3967 dst_swapchain->desc.swap_effect = swap_effect;
3969 return WINED3D_OK;
3972 if (fbo_blit_supported(&device->adapter->gl_info, blit_op,
3973 src_rect, src_texture->resource.usage, src_texture->resource.pool, src_texture->resource.format,
3974 dst_rect, dst_texture->resource.usage, dst_texture->resource.pool, dst_texture->resource.format))
3976 struct wined3d_context *context;
3977 TRACE("Using FBO blit.\n");
3979 context = context_acquire(device, NULL);
3980 surface_blt_fbo(device, context, filter,
3981 src_surface, src_texture->resource.draw_binding, src_rect,
3982 dst_surface, dst_texture->resource.draw_binding, dst_rect);
3983 context_release(context);
3985 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx,
3986 dst_texture->resource.draw_binding);
3987 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx,
3988 ~dst_texture->resource.draw_binding);
3990 return WINED3D_OK;
3993 blitter = wined3d_select_blitter(&device->adapter->gl_info, &device->adapter->d3d_info, blit_op,
3994 src_rect, src_texture->resource.usage, src_texture->resource.pool, src_texture->resource.format,
3995 dst_rect, dst_texture->resource.usage, dst_texture->resource.pool, dst_texture->resource.format);
3996 if (blitter)
3998 blitter->blit_surface(device, blit_op, filter, src_surface,
3999 src_rect, dst_surface, dst_rect, color_key);
4000 return WINED3D_OK;
4005 fallback:
4006 /* Special cases for render targets. */
4007 if (SUCCEEDED(surface_blt_special(dst_surface, dst_rect, src_surface, src_rect, flags, fx, filter)))
4008 return WINED3D_OK;
4010 cpu:
4011 return surface_cpu_blt(dst_texture, dst_sub_resource_idx, &dst_box,
4012 src_texture, src_sub_resource_idx, &src_box, flags, fx, filter);