xref: /reactos/dll/directx/wine/wined3d/surface.c (revision 4567e13e)
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
13  *
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.
18  *
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.
23  *
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
27  */
28 
29 #include "config.h"
30 #include "wine/port.h"
31 #include "wined3d_private.h"
32 
33 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
34 WINE_DECLARE_DEBUG_CHANNEL(d3d_perf);
35 
36 static const DWORD surface_simple_locations = WINED3D_LOCATION_SYSMEM
37         | WINED3D_LOCATION_USER_MEMORY | WINED3D_LOCATION_BUFFER;
38 
39 /* Works correctly only for <= 4 bpp formats. */
40 static void get_color_masks(const struct wined3d_format *format, DWORD *masks)
41 {
42     masks[0] = ((1u << format->red_size) - 1) << format->red_offset;
43     masks[1] = ((1u << format->green_size) - 1) << format->green_offset;
44     masks[2] = ((1u << format->blue_size) - 1) << format->blue_offset;
45 }
46 
47 static BOOL texture2d_is_full_rect(const struct wined3d_texture *texture, unsigned int level, const RECT *r)
48 {
49     unsigned int t;
50 
51     t = wined3d_texture_get_level_width(texture, level);
52     if ((r->left && r->right) || abs(r->right - r->left) != t)
53         return FALSE;
54     t = wined3d_texture_get_level_height(texture, level);
55     if ((r->top && r->bottom) || abs(r->bottom - r->top) != t)
56         return FALSE;
57     return TRUE;
58 }
59 
60 static void texture2d_depth_blt_fbo(const struct wined3d_device *device, struct wined3d_context *context,
61         struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx, DWORD src_location,
62         const RECT *src_rect, struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx,
63         DWORD dst_location, const RECT *dst_rect)
64 {
65     const struct wined3d_gl_info *gl_info = context->gl_info;
66     DWORD src_mask, dst_mask;
67     GLbitfield gl_mask;
68 
69     TRACE("device %p, src_texture %p, src_sub_resource_idx %u, src_location %s, src_rect %s, "
70             "dst_texture %p, dst_sub_resource_idx %u, dst_location %s, dst_rect %s.\n", device,
71             src_texture, src_sub_resource_idx, wined3d_debug_location(src_location), wine_dbgstr_rect(src_rect),
72             dst_texture, dst_sub_resource_idx, wined3d_debug_location(dst_location), wine_dbgstr_rect(dst_rect));
73 
74     src_mask = src_texture->resource.format_flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
75     dst_mask = dst_texture->resource.format_flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
76 
77     if (src_mask != dst_mask)
78     {
79         ERR("Incompatible formats %s and %s.\n",
80                 debug_d3dformat(src_texture->resource.format->id),
81                 debug_d3dformat(dst_texture->resource.format->id));
82         return;
83     }
84 
85     if (!src_mask)
86     {
87         ERR("Not a depth / stencil format: %s.\n",
88                 debug_d3dformat(src_texture->resource.format->id));
89         return;
90     }
91 
92     gl_mask = 0;
93     if (src_mask & WINED3DFMT_FLAG_DEPTH)
94         gl_mask |= GL_DEPTH_BUFFER_BIT;
95     if (src_mask & WINED3DFMT_FLAG_STENCIL)
96         gl_mask |= GL_STENCIL_BUFFER_BIT;
97 
98     /* Make sure the locations are up-to-date. Loading the destination
99      * surface isn't required if the entire surface is overwritten. */
100     wined3d_texture_load_location(src_texture, src_sub_resource_idx, context, src_location);
101     if (!texture2d_is_full_rect(dst_texture, dst_sub_resource_idx % dst_texture->level_count, dst_rect))
102         wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, dst_location);
103     else
104         wined3d_texture_prepare_location(dst_texture, dst_sub_resource_idx, context, dst_location);
105 
106     context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER, NULL, 0,
107             &src_texture->resource, src_sub_resource_idx, src_location);
108     context_check_fbo_status(context, GL_READ_FRAMEBUFFER);
109 
110     context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER, NULL, 0,
111             &dst_texture->resource, dst_sub_resource_idx, dst_location);
112     context_set_draw_buffer(context, GL_NONE);
113     context_check_fbo_status(context, GL_DRAW_FRAMEBUFFER);
114     context_invalidate_state(context, STATE_FRAMEBUFFER);
115 
116     if (gl_mask & GL_DEPTH_BUFFER_BIT)
117     {
118         gl_info->gl_ops.gl.p_glDepthMask(GL_TRUE);
119         context_invalidate_state(context, STATE_RENDER(WINED3D_RS_ZWRITEENABLE));
120     }
121     if (gl_mask & GL_STENCIL_BUFFER_BIT)
122     {
123         if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
124         {
125             gl_info->gl_ops.gl.p_glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
126             context_invalidate_state(context, STATE_RENDER(WINED3D_RS_TWOSIDEDSTENCILMODE));
127         }
128         gl_info->gl_ops.gl.p_glStencilMask(~0U);
129         context_invalidate_state(context, STATE_RENDER(WINED3D_RS_STENCILWRITEMASK));
130     }
131 
132     gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
133     context_invalidate_state(context, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE));
134 
135     gl_info->fbo_ops.glBlitFramebuffer(src_rect->left, src_rect->top, src_rect->right, src_rect->bottom,
136             dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, gl_mask, GL_NEAREST);
137     checkGLcall("glBlitFramebuffer()");
138 }
139 
140 static BOOL is_multisample_location(const struct wined3d_texture *texture, DWORD location)
141 {
142     if (location == WINED3D_LOCATION_RB_MULTISAMPLE)
143         return TRUE;
144     if (location != WINED3D_LOCATION_TEXTURE_RGB && location != WINED3D_LOCATION_TEXTURE_SRGB)
145         return FALSE;
146     return texture->target == GL_TEXTURE_2D_MULTISAMPLE || texture->target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY;
147 }
148 
149 /* Blit between surface locations. Onscreen on different swapchains is not supported.
150  * Depth / stencil is not supported. Context activation is done by the caller. */
151 static void texture2d_blt_fbo(const struct wined3d_device *device, struct wined3d_context *context,
152         enum wined3d_texture_filter_type filter, struct wined3d_texture *src_texture,
153         unsigned int src_sub_resource_idx, DWORD src_location, const RECT *src_rect,
154         struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx, DWORD dst_location,
155         const RECT *dst_rect)
156 {
157     struct wined3d_texture *required_texture, *restore_texture;
158     unsigned int required_idx, restore_idx;
159     const struct wined3d_gl_info *gl_info;
160     GLenum gl_filter;
161     GLenum buffer;
162     RECT s, d;
163     int i;
164 
165     TRACE("device %p, context %p, filter %s, src_texture %p, src_sub_resource_idx %u, src_location %s, "
166             "src_rect %s, dst_texture %p, dst_sub_resource_idx %u, dst_location %s, dst_rect %s.\n",
167             device, context, debug_d3dtexturefiltertype(filter), src_texture, src_sub_resource_idx,
168             wined3d_debug_location(src_location), wine_dbgstr_rect(src_rect), dst_texture,
169             dst_sub_resource_idx, wined3d_debug_location(dst_location), wine_dbgstr_rect(dst_rect));
170 
171     switch (filter)
172     {
173         case WINED3D_TEXF_LINEAR:
174             gl_filter = GL_LINEAR;
175             break;
176 
177         default:
178             FIXME("Unsupported filter mode %s (%#x).\n", debug_d3dtexturefiltertype(filter), filter);
179         case WINED3D_TEXF_NONE:
180         case WINED3D_TEXF_POINT:
181             gl_filter = GL_NEAREST;
182             break;
183     }
184 
185     /* Resolve the source surface first if needed. */
186     if (is_multisample_location(src_texture, src_location)
187             && (src_texture->resource.format->id != dst_texture->resource.format->id
188                 || abs(src_rect->bottom - src_rect->top) != abs(dst_rect->bottom - dst_rect->top)
189                 || abs(src_rect->right - src_rect->left) != abs(dst_rect->right - dst_rect->left)))
190         src_location = WINED3D_LOCATION_RB_RESOLVED;
191 
192     /* Make sure the locations are up-to-date. Loading the destination
193      * surface isn't required if the entire surface is overwritten. (And is
194      * in fact harmful if we're being called by surface_load_location() with
195      * the purpose of loading the destination surface.) */
196     wined3d_texture_load_location(src_texture, src_sub_resource_idx, context, src_location);
197     if (!texture2d_is_full_rect(dst_texture, dst_sub_resource_idx % dst_texture->level_count, dst_rect))
198         wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, dst_location);
199     else
200         wined3d_texture_prepare_location(dst_texture, dst_sub_resource_idx, context, dst_location);
201 
202 
203     if (src_location == WINED3D_LOCATION_DRAWABLE)
204     {
205         required_texture = src_texture;
206         required_idx = src_sub_resource_idx;
207     }
208     else if (dst_location == WINED3D_LOCATION_DRAWABLE)
209     {
210         required_texture = dst_texture;
211         required_idx = dst_sub_resource_idx;
212     }
213     else
214     {
215         required_texture = NULL;
216         required_idx = 0;
217     }
218 
219     restore_texture = context->current_rt.texture;
220     restore_idx = context->current_rt.sub_resource_idx;
221     if (restore_texture != required_texture || restore_idx != required_idx)
222         context = context_acquire(device, required_texture, required_idx);
223     else
224         restore_texture = NULL;
225 
226     if (!context->valid)
227     {
228         context_release(context);
229         WARN("Invalid context, skipping blit.\n");
230         return;
231     }
232 
233     gl_info = context->gl_info;
234 
235     if (src_location == WINED3D_LOCATION_DRAWABLE)
236     {
237         TRACE("Source texture %p is onscreen.\n", src_texture);
238         buffer = wined3d_texture_get_gl_buffer(src_texture);
239         s = *src_rect;
240         wined3d_texture_translate_drawable_coords(src_texture, context->win_handle, &s);
241         src_rect = &s;
242     }
243     else
244     {
245         TRACE("Source texture %p is offscreen.\n", src_texture);
246         buffer = GL_COLOR_ATTACHMENT0;
247     }
248 
249     context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER,
250             &src_texture->resource, src_sub_resource_idx, NULL, 0, src_location);
251     gl_info->gl_ops.gl.p_glReadBuffer(buffer);
252     checkGLcall("glReadBuffer()");
253     context_check_fbo_status(context, GL_READ_FRAMEBUFFER);
254 
255     if (dst_location == WINED3D_LOCATION_DRAWABLE)
256     {
257         TRACE("Destination texture %p is onscreen.\n", dst_texture);
258         buffer = wined3d_texture_get_gl_buffer(dst_texture);
259         d = *dst_rect;
260         wined3d_texture_translate_drawable_coords(dst_texture, context->win_handle, &d);
261         dst_rect = &d;
262     }
263     else
264     {
265         TRACE("Destination texture %p is offscreen.\n", dst_texture);
266         buffer = GL_COLOR_ATTACHMENT0;
267     }
268 
269     context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER,
270             &dst_texture->resource, dst_sub_resource_idx, NULL, 0, dst_location);
271     context_set_draw_buffer(context, buffer);
272     context_check_fbo_status(context, GL_DRAW_FRAMEBUFFER);
273     context_invalidate_state(context, STATE_FRAMEBUFFER);
274 
275     gl_info->gl_ops.gl.p_glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
276     for (i = 0; i < MAX_RENDER_TARGETS; ++i)
277         context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITE(i)));
278 
279     gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
280     context_invalidate_state(context, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE));
281 
282     gl_info->fbo_ops.glBlitFramebuffer(src_rect->left, src_rect->top, src_rect->right, src_rect->bottom,
283             dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, GL_COLOR_BUFFER_BIT, gl_filter);
284     checkGLcall("glBlitFramebuffer()");
285 
286     if (dst_location == WINED3D_LOCATION_DRAWABLE && dst_texture->swapchain->front_buffer == dst_texture)
287         gl_info->gl_ops.gl.p_glFlush();
288 
289     if (restore_texture)
290         context_restore(context, restore_texture, restore_idx);
291 }
292 
293 static BOOL fbo_blitter_supported(enum wined3d_blit_op blit_op, const struct wined3d_gl_info *gl_info,
294         const struct wined3d_resource *src_resource, DWORD src_location,
295         const struct wined3d_resource *dst_resource, DWORD dst_location)
296 {
297     const struct wined3d_format *src_format = src_resource->format;
298     const struct wined3d_format *dst_format = dst_resource->format;
299 
300     if ((wined3d_settings.offscreen_rendering_mode != ORM_FBO) || !gl_info->fbo_ops.glBlitFramebuffer)
301         return FALSE;
302 
303     /* Source and/or destination need to be on the GL side */
304     if (!(src_resource->access & dst_resource->access & WINED3D_RESOURCE_ACCESS_GPU))
305         return FALSE;
306 
307     if (src_resource->type != WINED3D_RTYPE_TEXTURE_2D)
308         return FALSE;
309 
310     switch (blit_op)
311     {
312         case WINED3D_BLIT_OP_COLOR_BLIT:
313             if (!((src_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_FBO_ATTACHABLE)
314                     || (src_resource->usage & WINED3DUSAGE_RENDERTARGET)))
315                 return FALSE;
316             if (!((dst_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_FBO_ATTACHABLE)
317                     || (dst_resource->usage & WINED3DUSAGE_RENDERTARGET)))
318                 return FALSE;
319             if ((src_format->id != dst_format->id || dst_location == WINED3D_LOCATION_DRAWABLE)
320                     && (!is_identity_fixup(src_format->color_fixup) || !is_identity_fixup(dst_format->color_fixup)))
321                 return FALSE;
322             break;
323 
324         case WINED3D_BLIT_OP_DEPTH_BLIT:
325             if (!(src_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL)))
326                 return FALSE;
327             if (!(dst_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL)))
328                 return FALSE;
329             /* Accept pure swizzle fixups for depth formats. In general we
330              * ignore the stencil component (if present) at the moment and the
331              * swizzle is not relevant with just the depth component. */
332             if (is_complex_fixup(src_format->color_fixup) || is_complex_fixup(dst_format->color_fixup)
333                     || is_scaling_fixup(src_format->color_fixup) || is_scaling_fixup(dst_format->color_fixup))
334                 return FALSE;
335             break;
336 
337         default:
338             return FALSE;
339     }
340 
341     return TRUE;
342 }
343 
344 /* This call just downloads data, the caller is responsible for binding the
345  * correct texture. */
346 /* Context activation is done by the caller. */
347 static void texture2d_download_data(struct wined3d_texture *texture, unsigned int sub_resource_idx,
348         const struct wined3d_context *context, DWORD dst_location)
349 {
350     const struct wined3d_format *format = texture->resource.format;
351     const struct wined3d_gl_info *gl_info = context->gl_info;
352     struct wined3d_texture_sub_resource *sub_resource;
353     unsigned int dst_row_pitch, dst_slice_pitch;
354     unsigned int src_row_pitch, src_slice_pitch;
355     struct wined3d_bo_address data;
356     BYTE *temporary_mem = NULL;
357     unsigned int level;
358     GLenum target;
359     void *mem;
360 
361     /* Only support read back of converted P8 textures. */
362     if (texture->flags & WINED3D_TEXTURE_CONVERTED && format->id != WINED3DFMT_P8_UINT && !format->download)
363     {
364         ERR("Trying to read back converted texture %p, %u with format %s.\n",
365                 texture, sub_resource_idx, debug_d3dformat(format->id));
366         return;
367     }
368 
369     sub_resource = &texture->sub_resources[sub_resource_idx];
370     target = wined3d_texture_get_sub_resource_target(texture, sub_resource_idx);
371     level = sub_resource_idx % texture->level_count;
372 
373     if (target == GL_TEXTURE_2D_ARRAY)
374     {
375         if (format->download)
376         {
377             FIXME("Reading back converted array texture %p is not supported.\n", texture);
378             return;
379         }
380 
381         /* NP2 emulation is not allowed on array textures. */
382         if (texture->flags & WINED3D_TEXTURE_COND_NP2_EMULATED)
383             ERR("Array texture %p uses NP2 emulation.\n", texture);
384 
385         WARN_(d3d_perf)("Downloading all miplevel layers to get the data for a single sub-resource.\n");
386 
387         if (!(temporary_mem = heap_calloc(texture->layer_count, sub_resource->size)))
388         {
389             ERR("Out of memory.\n");
390             return;
391         }
392     }
393 
394     wined3d_texture_get_memory(texture, sub_resource_idx, &data, dst_location);
395 
396     if (texture->flags & WINED3D_TEXTURE_COND_NP2_EMULATED)
397     {
398         if (format->download)
399         {
400             FIXME("Reading back converted texture %p with NP2 emulation is not supported.\n", texture);
401             return;
402         }
403 
404         wined3d_texture_get_pitch(texture, level, &dst_row_pitch, &dst_slice_pitch);
405         wined3d_format_calculate_pitch(format, texture->resource.device->surface_alignment,
406                 wined3d_texture_get_level_pow2_width(texture, level),
407                 wined3d_texture_get_level_pow2_height(texture, level),
408                 &src_row_pitch, &src_slice_pitch);
409         if (!(temporary_mem = heap_alloc(src_slice_pitch)))
410         {
411             ERR("Out of memory.\n");
412             return;
413         }
414 
415         if (data.buffer_object)
416             ERR("NP2 emulated texture uses PBO unexpectedly.\n");
417         if (texture->resource.format_flags & WINED3DFMT_FLAG_COMPRESSED)
418             ERR("Unexpected compressed format for NP2 emulated texture.\n");
419     }
420 
421     if (format->download)
422     {
423         struct wined3d_format f;
424 
425         if (data.buffer_object)
426             ERR("Converted texture %p uses PBO unexpectedly.\n", texture);
427 
428         WARN_(d3d_perf)("Downloading converted texture %p, %u with format %s.\n",
429                 texture, sub_resource_idx, debug_d3dformat(format->id));
430 
431         f = *format;
432         f.byte_count = format->conv_byte_count;
433         wined3d_texture_get_pitch(texture, level, &dst_row_pitch, &dst_slice_pitch);
434         wined3d_format_calculate_pitch(&f, texture->resource.device->surface_alignment,
435                 wined3d_texture_get_level_width(texture, level),
436                 wined3d_texture_get_level_height(texture, level),
437                 &src_row_pitch, &src_slice_pitch);
438 
439         if (!(temporary_mem = heap_alloc(src_slice_pitch)))
440         {
441             ERR("Failed to allocate memory.\n");
442             return;
443         }
444     }
445 
446     if (temporary_mem)
447     {
448         mem = temporary_mem;
449     }
450     else if (data.buffer_object)
451     {
452         GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, data.buffer_object));
453         checkGLcall("glBindBuffer");
454         mem = data.addr;
455     }
456     else
457     {
458         mem = data.addr;
459     }
460 
461     if (texture->resource.format_flags & WINED3DFMT_FLAG_COMPRESSED)
462     {
463         TRACE("Downloading compressed texture %p, %u, level %u, format %#x, type %#x, data %p.\n",
464                 texture, sub_resource_idx, level, format->glFormat, format->glType, mem);
465 
466         GL_EXTCALL(glGetCompressedTexImage(target, level, mem));
467         checkGLcall("glGetCompressedTexImage");
468     }
469     else
470     {
471         TRACE("Downloading texture %p, %u, level %u, format %#x, type %#x, data %p.\n",
472                 texture, sub_resource_idx, level, format->glFormat, format->glType, mem);
473 
474         gl_info->gl_ops.gl.p_glGetTexImage(target, level, format->glFormat, format->glType, mem);
475         checkGLcall("glGetTexImage");
476     }
477 
478     if (format->download)
479     {
480         format->download(mem, data.addr, src_row_pitch, src_slice_pitch, dst_row_pitch, dst_slice_pitch,
481                 wined3d_texture_get_level_width(texture, level),
482                 wined3d_texture_get_level_height(texture, level), 1);
483     }
484     else if (texture->flags & WINED3D_TEXTURE_COND_NP2_EMULATED)
485     {
486         const BYTE *src_data;
487         unsigned int h, y;
488         BYTE *dst_data;
489         /*
490          * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing
491          * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
492          * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width.
493          *
494          * We're doing this...
495          *
496          * instead of boxing the texture :
497          * |<-texture width ->|  -->pow2width|   /\
498          * |111111111111111111|              |   |
499          * |222 Texture 222222| boxed empty  | texture height
500          * |3333 Data 33333333|              |   |
501          * |444444444444444444|              |   \/
502          * -----------------------------------   |
503          * |     boxed  empty | boxed empty  | pow2height
504          * |                  |              |   \/
505          * -----------------------------------
506          *
507          *
508          * we're repacking the data to the expected texture width
509          *
510          * |<-texture width ->|  -->pow2width|   /\
511          * |111111111111111111222222222222222|   |
512          * |222333333333333333333444444444444| texture height
513          * |444444                           |   |
514          * |                                 |   \/
515          * |                                 |   |
516          * |            empty                | pow2height
517          * |                                 |   \/
518          * -----------------------------------
519          *
520          * == is the same as
521          *
522          * |<-texture width ->|    /\
523          * |111111111111111111|
524          * |222222222222222222|texture height
525          * |333333333333333333|
526          * |444444444444444444|    \/
527          * --------------------
528          *
529          * This also means that any references to surface memory should work with the data as if it were a
530          * standard texture with a non-power2 width instead of a texture boxed up to be a power2 texture.
531          *
532          * internally the texture is still stored in a boxed format so any references to textureName will
533          * get a boxed texture with width pow2width and not a texture of width resource.width. */
534         src_data = mem;
535         dst_data = data.addr;
536         TRACE("Repacking the surface data from pitch %u to pitch %u.\n", src_row_pitch, dst_row_pitch);
537         h = wined3d_texture_get_level_height(texture, level);
538         for (y = 0; y < h; ++y)
539         {
540             memcpy(dst_data, src_data, dst_row_pitch);
541             src_data += src_row_pitch;
542             dst_data += dst_row_pitch;
543         }
544     }
545     else if (temporary_mem)
546     {
547         unsigned int layer = sub_resource_idx / texture->level_count;
548         void *src_data = temporary_mem + layer * sub_resource->size;
549         if (data.buffer_object)
550         {
551             GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, data.buffer_object));
552             checkGLcall("glBindBuffer");
553             GL_EXTCALL(glBufferSubData(GL_PIXEL_PACK_BUFFER, 0, sub_resource->size, src_data));
554             checkGLcall("glBufferSubData");
555         }
556         else
557         {
558             memcpy(data.addr, src_data, sub_resource->size);
559         }
560     }
561 
562     if (data.buffer_object)
563     {
564         GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));
565         checkGLcall("glBindBuffer");
566     }
567 
568     heap_free(temporary_mem);
569 }
570 
571 /* See also float_16_to_32() in wined3d_private.h */
572 static inline unsigned short float_32_to_16(const float *in)
573 {
574     int exp = 0;
575     float tmp = fabsf(*in);
576     unsigned int mantissa;
577     unsigned short ret;
578 
579     /* Deal with special numbers */
580     if (*in == 0.0f)
581         return 0x0000;
582     if (isnan(*in))
583         return 0x7c01;
584     if (isinf(*in))
585         return (*in < 0.0f ? 0xfc00 : 0x7c00);
586 
587     if (tmp < (float)(1u << 10))
588     {
589         do
590         {
591             tmp = tmp * 2.0f;
592             exp--;
593         } while (tmp < (float)(1u << 10));
594     }
595     else if (tmp >= (float)(1u << 11))
596     {
597         do
598         {
599             tmp /= 2.0f;
600             exp++;
601         } while (tmp >= (float)(1u << 11));
602     }
603 
604     mantissa = (unsigned int)tmp;
605     if (tmp - mantissa >= 0.5f)
606         ++mantissa; /* Round to nearest, away from zero. */
607 
608     exp += 10;  /* Normalize the mantissa. */
609     exp += 15;  /* Exponent is encoded with excess 15. */
610 
611     if (exp > 30) /* too big */
612     {
613         ret = 0x7c00; /* INF */
614     }
615     else if (exp <= 0)
616     {
617         /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers. */
618         while (exp <= 0)
619         {
620             mantissa = mantissa >> 1;
621             ++exp;
622         }
623         ret = mantissa & 0x3ff;
624     }
625     else
626     {
627         ret = (exp << 10) | (mantissa & 0x3ff);
628     }
629 
630     ret |= ((*in < 0.0f ? 1 : 0) << 15); /* Add the sign */
631     return ret;
632 }
633 
634 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst,
635         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
636 {
637     unsigned short *dst_s;
638     const float *src_f;
639     unsigned int x, y;
640 
641     TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
642 
643     for (y = 0; y < h; ++y)
644     {
645         src_f = (const float *)(src + y * pitch_in);
646         dst_s = (unsigned short *) (dst + y * pitch_out);
647         for (x = 0; x < w; ++x)
648         {
649             dst_s[x] = float_32_to_16(src_f + x);
650         }
651     }
652 }
653 
654 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
655         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
656 {
657     static const unsigned char convert_5to8[] =
658     {
659         0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
660         0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
661         0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
662         0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
663     };
664     static const unsigned char convert_6to8[] =
665     {
666         0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
667         0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
668         0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
669         0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
670         0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
671         0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
672         0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
673         0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
674     };
675     unsigned int x, y;
676 
677     TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
678 
679     for (y = 0; y < h; ++y)
680     {
681         const WORD *src_line = (const WORD *)(src + y * pitch_in);
682         DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
683         for (x = 0; x < w; ++x)
684         {
685             WORD pixel = src_line[x];
686             dst_line[x] = 0xff000000u
687                     | convert_5to8[(pixel & 0xf800u) >> 11] << 16
688                     | convert_6to8[(pixel & 0x07e0u) >> 5] << 8
689                     | convert_5to8[(pixel & 0x001fu)];
690         }
691     }
692 }
693 
694 /* We use this for both B8G8R8A8 -> B8G8R8X8 and B8G8R8X8 -> B8G8R8A8, since
695  * in both cases we're just setting the X / Alpha channel to 0xff. */
696 static void convert_a8r8g8b8_x8r8g8b8(const BYTE *src, BYTE *dst,
697         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
698 {
699     unsigned int x, y;
700 
701     TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
702 
703     for (y = 0; y < h; ++y)
704     {
705         const DWORD *src_line = (const DWORD *)(src + y * pitch_in);
706         DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
707 
708         for (x = 0; x < w; ++x)
709         {
710             dst_line[x] = 0xff000000 | (src_line[x] & 0xffffff);
711         }
712     }
713 }
714 
715 static inline BYTE cliptobyte(int x)
716 {
717     return (BYTE)((x < 0) ? 0 : ((x > 255) ? 255 : x));
718 }
719 
720 static void convert_yuy2_x8r8g8b8(const BYTE *src, BYTE *dst,
721         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
722 {
723     int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
724     unsigned int x, y;
725 
726     TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
727 
728     for (y = 0; y < h; ++y)
729     {
730         const BYTE *src_line = src + y * pitch_in;
731         DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
732         for (x = 0; x < w; ++x)
733         {
734             /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
735              *     C = Y - 16; D = U - 128; E = V - 128;
736              *     R = cliptobyte((298 * C + 409 * E + 128) >> 8);
737              *     G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
738              *     B = cliptobyte((298 * C + 516 * D + 128) >> 8);
739              * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
740              * U and V are shared between the pixels. */
741             if (!(x & 1)) /* For every even pixel, read new U and V. */
742             {
743                 d = (int) src_line[1] - 128;
744                 e = (int) src_line[3] - 128;
745                 r2 = 409 * e + 128;
746                 g2 = - 100 * d - 208 * e + 128;
747                 b2 = 516 * d + 128;
748             }
749             c2 = 298 * ((int) src_line[0] - 16);
750             dst_line[x] = 0xff000000
751                 | cliptobyte((c2 + r2) >> 8) << 16    /* red   */
752                 | cliptobyte((c2 + g2) >> 8) << 8     /* green */
753                 | cliptobyte((c2 + b2) >> 8);         /* blue  */
754                 /* Scale RGB values to 0..255 range,
755                  * then clip them if still not in range (may be negative),
756                  * then shift them within DWORD if necessary. */
757             src_line += 2;
758         }
759     }
760 }
761 
762 static void convert_yuy2_r5g6b5(const BYTE *src, BYTE *dst,
763         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
764 {
765     unsigned int x, y;
766     int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
767 
768     TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
769 
770     for (y = 0; y < h; ++y)
771     {
772         const BYTE *src_line = src + y * pitch_in;
773         WORD *dst_line = (WORD *)(dst + y * pitch_out);
774         for (x = 0; x < w; ++x)
775         {
776             /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
777              *     C = Y - 16; D = U - 128; E = V - 128;
778              *     R = cliptobyte((298 * C + 409 * E + 128) >> 8);
779              *     G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
780              *     B = cliptobyte((298 * C + 516 * D + 128) >> 8);
781              * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
782              * U and V are shared between the pixels. */
783             if (!(x & 1)) /* For every even pixel, read new U and V. */
784             {
785                 d = (int) src_line[1] - 128;
786                 e = (int) src_line[3] - 128;
787                 r2 = 409 * e + 128;
788                 g2 = - 100 * d - 208 * e + 128;
789                 b2 = 516 * d + 128;
790             }
791             c2 = 298 * ((int) src_line[0] - 16);
792             dst_line[x] = (cliptobyte((c2 + r2) >> 8) >> 3) << 11   /* red   */
793                 | (cliptobyte((c2 + g2) >> 8) >> 2) << 5            /* green */
794                 | (cliptobyte((c2 + b2) >> 8) >> 3);                /* blue  */
795                 /* Scale RGB values to 0..255 range,
796                  * then clip them if still not in range (may be negative),
797                  * then shift them within DWORD if necessary. */
798             src_line += 2;
799         }
800     }
801 }
802 
803 static void convert_dxt1_a8r8g8b8(const BYTE *src, BYTE *dst,
804         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
805 {
806     wined3d_dxt1_decode(src, dst, pitch_in, pitch_out, WINED3DFMT_B8G8R8A8_UNORM, w, h);
807 }
808 
809 static void convert_dxt1_x8r8g8b8(const BYTE *src, BYTE *dst,
810         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
811 {
812     wined3d_dxt1_decode(src, dst, pitch_in, pitch_out, WINED3DFMT_B8G8R8X8_UNORM, w, h);
813 }
814 
815 static void convert_dxt1_a4r4g4b4(const BYTE *src, BYTE *dst,
816         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
817 {
818     wined3d_dxt1_decode(src, dst, pitch_in, pitch_out, WINED3DFMT_B4G4R4A4_UNORM, w, h);
819 }
820 
821 static void convert_dxt1_x4r4g4b4(const BYTE *src, BYTE *dst,
822         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
823 {
824     wined3d_dxt1_decode(src, dst, pitch_in, pitch_out, WINED3DFMT_B4G4R4X4_UNORM, w, h);
825 }
826 
827 static void convert_dxt1_a1r5g5b5(const BYTE *src, BYTE *dst,
828         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
829 {
830     wined3d_dxt1_decode(src, dst, pitch_in, pitch_out, WINED3DFMT_B5G5R5A1_UNORM, w, h);
831 }
832 
833 static void convert_dxt1_x1r5g5b5(const BYTE *src, BYTE *dst,
834         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
835 {
836     wined3d_dxt1_decode(src, dst, pitch_in, pitch_out, WINED3DFMT_B5G5R5X1_UNORM, w, h);
837 }
838 
839 static void convert_dxt3_a8r8g8b8(const BYTE *src, BYTE *dst,
840         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
841 {
842     wined3d_dxt3_decode(src, dst, pitch_in, pitch_out, WINED3DFMT_B8G8R8A8_UNORM, w, h);
843 }
844 
845 static void convert_dxt3_x8r8g8b8(const BYTE *src, BYTE *dst,
846         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
847 {
848     wined3d_dxt3_decode(src, dst, pitch_in, pitch_out, WINED3DFMT_B8G8R8X8_UNORM, w, h);
849 }
850 
851 static void convert_dxt3_a4r4g4b4(const BYTE *src, BYTE *dst,
852         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
853 {
854     wined3d_dxt3_decode(src, dst, pitch_in, pitch_out, WINED3DFMT_B4G4R4A4_UNORM, w, h);
855 }
856 
857 static void convert_dxt3_x4r4g4b4(const BYTE *src, BYTE *dst,
858         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
859 {
860     wined3d_dxt3_decode(src, dst, pitch_in, pitch_out, WINED3DFMT_B4G4R4X4_UNORM, w, h);
861 }
862 
863 static void convert_dxt5_a8r8g8b8(const BYTE *src, BYTE *dst,
864         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
865 {
866     wined3d_dxt5_decode(src, dst, pitch_in, pitch_out, WINED3DFMT_B8G8R8A8_UNORM, w, h);
867 }
868 
869 static void convert_dxt5_x8r8g8b8(const BYTE *src, BYTE *dst,
870         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
871 {
872     wined3d_dxt5_decode(src, dst, pitch_in, pitch_out, WINED3DFMT_B8G8R8X8_UNORM, w, h);
873 }
874 
875 static void convert_a8r8g8b8_dxt1(const BYTE *src, BYTE *dst,
876         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
877 {
878     wined3d_dxt1_encode(src, dst, pitch_in, pitch_out, WINED3DFMT_B8G8R8A8_UNORM, w, h);
879 }
880 
881 static void convert_x8r8g8b8_dxt1(const BYTE *src, BYTE *dst,
882         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
883 {
884     wined3d_dxt1_encode(src, dst, pitch_in, pitch_out, WINED3DFMT_B8G8R8X8_UNORM, w, h);
885 }
886 
887 static void convert_a1r5g5b5_dxt1(const BYTE *src, BYTE *dst,
888         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
889 {
890     wined3d_dxt1_encode(src, dst, pitch_in, pitch_out, WINED3DFMT_B5G5R5A1_UNORM, w, h);
891 }
892 
893 static void convert_x1r5g5b5_dxt1(const BYTE *src, BYTE *dst,
894         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
895 {
896     wined3d_dxt1_encode(src, dst, pitch_in, pitch_out, WINED3DFMT_B5G5R5X1_UNORM, w, h);
897 }
898 
899 static void convert_a8r8g8b8_dxt3(const BYTE *src, BYTE *dst,
900         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
901 {
902     wined3d_dxt3_encode(src, dst, pitch_in, pitch_out, WINED3DFMT_B8G8R8A8_UNORM, w, h);
903 }
904 
905 static void convert_x8r8g8b8_dxt3(const BYTE *src, BYTE *dst,
906         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
907 {
908     wined3d_dxt3_encode(src, dst, pitch_in, pitch_out, WINED3DFMT_B8G8R8X8_UNORM, w, h);
909 }
910 
911 static void convert_a8r8g8b8_dxt5(const BYTE *src, BYTE *dst,
912         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
913 {
914     wined3d_dxt5_encode(src, dst, pitch_in, pitch_out, WINED3DFMT_B8G8R8A8_UNORM, w, h);
915 }
916 
917 static void convert_x8r8g8b8_dxt5(const BYTE *src, BYTE *dst,
918         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
919 {
920     wined3d_dxt5_encode(src, dst, pitch_in, pitch_out, WINED3DFMT_B8G8R8X8_UNORM, w, h);
921 }
922 
923 struct d3dfmt_converter_desc
924 {
925     enum wined3d_format_id from, to;
926     void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
927 };
928 
929 static const struct d3dfmt_converter_desc converters[] =
930 {
931     {WINED3DFMT_R32_FLOAT,      WINED3DFMT_R16_FLOAT,       convert_r32_float_r16_float},
932     {WINED3DFMT_B5G6R5_UNORM,   WINED3DFMT_B8G8R8X8_UNORM,  convert_r5g6b5_x8r8g8b8},
933     {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_B8G8R8X8_UNORM,  convert_a8r8g8b8_x8r8g8b8},
934     {WINED3DFMT_B8G8R8X8_UNORM, WINED3DFMT_B8G8R8A8_UNORM,  convert_a8r8g8b8_x8r8g8b8},
935     {WINED3DFMT_YUY2,           WINED3DFMT_B8G8R8X8_UNORM,  convert_yuy2_x8r8g8b8},
936     {WINED3DFMT_YUY2,           WINED3DFMT_B5G6R5_UNORM,    convert_yuy2_r5g6b5},
937 };
938 
939 static const struct d3dfmt_converter_desc dxtn_converters[] =
940 {
941     /* decode DXT */
942     {WINED3DFMT_DXT1,           WINED3DFMT_B8G8R8A8_UNORM,  convert_dxt1_a8r8g8b8},
943     {WINED3DFMT_DXT1,           WINED3DFMT_B8G8R8X8_UNORM,  convert_dxt1_x8r8g8b8},
944     {WINED3DFMT_DXT1,           WINED3DFMT_B4G4R4A4_UNORM,  convert_dxt1_a4r4g4b4},
945     {WINED3DFMT_DXT1,           WINED3DFMT_B4G4R4X4_UNORM,  convert_dxt1_x4r4g4b4},
946     {WINED3DFMT_DXT1,           WINED3DFMT_B5G5R5A1_UNORM,  convert_dxt1_a1r5g5b5},
947     {WINED3DFMT_DXT1,           WINED3DFMT_B5G5R5X1_UNORM,  convert_dxt1_x1r5g5b5},
948     {WINED3DFMT_DXT3,           WINED3DFMT_B8G8R8A8_UNORM,  convert_dxt3_a8r8g8b8},
949     {WINED3DFMT_DXT3,           WINED3DFMT_B8G8R8X8_UNORM,  convert_dxt3_x8r8g8b8},
950     {WINED3DFMT_DXT3,           WINED3DFMT_B4G4R4A4_UNORM,  convert_dxt3_a4r4g4b4},
951     {WINED3DFMT_DXT3,           WINED3DFMT_B4G4R4X4_UNORM,  convert_dxt3_x4r4g4b4},
952     {WINED3DFMT_DXT5,           WINED3DFMT_B8G8R8A8_UNORM,  convert_dxt5_a8r8g8b8},
953     {WINED3DFMT_DXT5,           WINED3DFMT_B8G8R8X8_UNORM,  convert_dxt5_x8r8g8b8},
954 
955     /* encode DXT */
956     {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_DXT1,            convert_a8r8g8b8_dxt1},
957     {WINED3DFMT_B8G8R8X8_UNORM, WINED3DFMT_DXT1,            convert_x8r8g8b8_dxt1},
958     {WINED3DFMT_B5G5R5A1_UNORM, WINED3DFMT_DXT1,            convert_a1r5g5b5_dxt1},
959     {WINED3DFMT_B5G5R5X1_UNORM, WINED3DFMT_DXT1,            convert_x1r5g5b5_dxt1},
960     {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_DXT3,            convert_a8r8g8b8_dxt3},
961     {WINED3DFMT_B8G8R8X8_UNORM, WINED3DFMT_DXT3,            convert_x8r8g8b8_dxt3},
962     {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_DXT5,            convert_a8r8g8b8_dxt5},
963     {WINED3DFMT_B8G8R8X8_UNORM, WINED3DFMT_DXT5,            convert_x8r8g8b8_dxt5}
964 };
965 
966 static inline const struct d3dfmt_converter_desc *find_converter(enum wined3d_format_id from,
967         enum wined3d_format_id to)
968 {
969     unsigned int i;
970 
971     for (i = 0; i < ARRAY_SIZE(converters); ++i)
972     {
973         if (converters[i].from == from && converters[i].to == to)
974             return &converters[i];
975     }
976 
977     for (i = 0; i < (sizeof(dxtn_converters) / sizeof(*dxtn_converters)); ++i)
978     {
979         if (dxtn_converters[i].from == from && dxtn_converters[i].to == to)
980             return wined3d_dxtn_supported() ? &dxtn_converters[i] : NULL;
981     }
982 
983     return NULL;
984 }
985 
986 static struct wined3d_texture *surface_convert_format(struct wined3d_texture *src_texture,
987         unsigned int sub_resource_idx, const struct wined3d_format *dst_format)
988 {
989     unsigned int texture_level = sub_resource_idx % src_texture->level_count;
990     const struct wined3d_format *src_format = src_texture->resource.format;
991     struct wined3d_device *device = src_texture->resource.device;
992     const struct d3dfmt_converter_desc *conv = NULL;
993     unsigned int src_row_pitch, src_slice_pitch;
994     struct wined3d_context *context = NULL;
995     struct wined3d_texture *dst_texture;
996     struct wined3d_bo_address src_data;
997     struct wined3d_resource_desc desc;
998     DWORD map_binding;
999 
1000     if (!(conv = find_converter(src_format->id, dst_format->id)) && (!device->d3d_initialized
1001             || !is_identity_fixup(src_format->color_fixup) || src_format->conv_byte_count
1002             || !is_identity_fixup(dst_format->color_fixup) || dst_format->conv_byte_count
1003             || (src_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_COMPRESSED)))
1004     {
1005         FIXME("Cannot find a conversion function from format %s to %s.\n",
1006                 debug_d3dformat(src_format->id), debug_d3dformat(dst_format->id));
1007         return NULL;
1008     }
1009 
1010     /* FIXME: Multisampled conversion? */
1011     desc.resource_type = WINED3D_RTYPE_TEXTURE_2D;
1012     desc.format = dst_format->id;
1013     desc.multisample_type = WINED3D_MULTISAMPLE_NONE;
1014     desc.multisample_quality = 0;
1015     desc.usage = WINED3DUSAGE_SCRATCH | WINED3DUSAGE_PRIVATE;
1016     desc.access = WINED3D_RESOURCE_ACCESS_CPU | WINED3D_RESOURCE_ACCESS_MAP_R | WINED3D_RESOURCE_ACCESS_MAP_W;
1017     desc.width = wined3d_texture_get_level_width(src_texture, texture_level);
1018     desc.height = wined3d_texture_get_level_height(src_texture, texture_level);
1019     desc.depth = 1;
1020     desc.size = 0;
1021     if (FAILED(wined3d_texture_create(device, &desc, 1, 1,
1022             WINED3D_TEXTURE_CREATE_MAPPABLE | WINED3D_TEXTURE_CREATE_DISCARD,
1023             NULL, NULL, &wined3d_null_parent_ops, &dst_texture)))
1024     {
1025         ERR("Failed to create a destination texture for conversion.\n");
1026         return NULL;
1027     }
1028 
1029     if (device->d3d_initialized)
1030         context = context_acquire(device, NULL, 0);
1031 
1032     map_binding = src_texture->resource.map_binding;
1033     if (!wined3d_texture_load_location(src_texture, sub_resource_idx, context, map_binding))
1034         ERR("Failed to load the source sub-resource into %s.\n", wined3d_debug_location(map_binding));
1035     wined3d_texture_get_pitch(src_texture, texture_level, &src_row_pitch, &src_slice_pitch);
1036     wined3d_texture_get_memory(src_texture, sub_resource_idx, &src_data, map_binding);
1037 
1038     if (conv)
1039     {
1040         unsigned int dst_row_pitch, dst_slice_pitch;
1041         struct wined3d_bo_address dst_data;
1042         const BYTE *src;
1043         BYTE *dst;
1044 
1045         map_binding = dst_texture->resource.map_binding;
1046         if (!wined3d_texture_load_location(dst_texture, 0, context, map_binding))
1047             ERR("Failed to load the destination sub-resource into %s.\n", wined3d_debug_location(map_binding));
1048         wined3d_texture_get_pitch(dst_texture, 0, &dst_row_pitch, &dst_slice_pitch);
1049         wined3d_texture_get_memory(dst_texture, 0, &dst_data, map_binding);
1050 
1051         src = context_map_bo_address(context, &src_data,
1052                 src_texture->sub_resources[sub_resource_idx].size, GL_PIXEL_UNPACK_BUFFER, WINED3D_MAP_READ);
1053         dst = context_map_bo_address(context,
1054                 &dst_data, dst_texture->sub_resources[0].size, GL_PIXEL_UNPACK_BUFFER, WINED3D_MAP_WRITE);
1055 
1056         conv->convert(src, dst, src_row_pitch, dst_row_pitch, desc.width, desc.height);
1057 
1058         wined3d_texture_invalidate_location(dst_texture, 0, ~map_binding);
1059         context_unmap_bo_address(context, &dst_data, GL_PIXEL_UNPACK_BUFFER);
1060         context_unmap_bo_address(context, &src_data, GL_PIXEL_UNPACK_BUFFER);
1061     }
1062     else
1063     {
1064         struct wined3d_box src_box = {0, 0, desc.width, desc.height, 0, 1};
1065 
1066         TRACE("Using upload conversion.\n");
1067 
1068         wined3d_texture_prepare_texture(dst_texture, context, FALSE);
1069         wined3d_texture_bind_and_dirtify(dst_texture, context, FALSE);
1070         wined3d_texture_upload_data(dst_texture, 0, context, src_format, &src_box,
1071                 wined3d_const_bo_address(&src_data), src_row_pitch, src_slice_pitch, 0, 0, 0, FALSE);
1072 
1073         wined3d_texture_validate_location(dst_texture, 0, WINED3D_LOCATION_TEXTURE_RGB);
1074         wined3d_texture_invalidate_location(dst_texture, 0, ~WINED3D_LOCATION_TEXTURE_RGB);
1075     }
1076 
1077     if (context)
1078         context_release(context);
1079 
1080     return dst_texture;
1081 }
1082 
1083 static void texture2d_read_from_framebuffer(struct wined3d_texture *texture, unsigned int sub_resource_idx,
1084         struct wined3d_context *context, DWORD src_location, DWORD dst_location)
1085 {
1086     struct wined3d_device *device = texture->resource.device;
1087     struct wined3d_texture *restore_texture;
1088     const struct wined3d_gl_info *gl_info;
1089     unsigned int row_pitch, slice_pitch;
1090     unsigned int width, height, level;
1091     struct wined3d_bo_address data;
1092     unsigned int restore_idx;
1093     BYTE *row, *top, *bottom;
1094     BOOL src_is_upside_down;
1095     unsigned int i;
1096     BYTE *mem;
1097 
1098     wined3d_texture_get_memory(texture, sub_resource_idx, &data, dst_location);
1099 
1100     restore_texture = context->current_rt.texture;
1101     restore_idx = context->current_rt.sub_resource_idx;
1102     if (restore_texture != texture || restore_idx != sub_resource_idx)
1103         context = context_acquire(device, texture, sub_resource_idx);
1104     else
1105         restore_texture = NULL;
1106     gl_info = context->gl_info;
1107 
1108     if (src_location != texture->resource.draw_binding)
1109     {
1110         context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER,
1111                 &texture->resource, sub_resource_idx, NULL, 0, src_location);
1112         context_check_fbo_status(context, GL_READ_FRAMEBUFFER);
1113         context_invalidate_state(context, STATE_FRAMEBUFFER);
1114     }
1115     else
1116     {
1117         context_apply_blit_state(context, device);
1118     }
1119 
1120     /* Select the correct read buffer, and give some debug output.
1121      * There is no need to keep track of the current read buffer or reset it,
1122      * every part of the code that reads sets the read buffer as desired.
1123      */
1124     if (src_location != WINED3D_LOCATION_DRAWABLE || wined3d_resource_is_offscreen(&texture->resource))
1125     {
1126         /* Mapping the primary render target which is not on a swapchain.
1127          * Read from the back buffer. */
1128         TRACE("Mapping offscreen render target.\n");
1129         gl_info->gl_ops.gl.p_glReadBuffer(context_get_offscreen_gl_buffer(context));
1130         src_is_upside_down = TRUE;
1131     }
1132     else
1133     {
1134         /* Onscreen surfaces are always part of a swapchain */
1135         GLenum buffer = wined3d_texture_get_gl_buffer(texture);
1136         TRACE("Mapping %#x buffer.\n", buffer);
1137         gl_info->gl_ops.gl.p_glReadBuffer(buffer);
1138         src_is_upside_down = FALSE;
1139     }
1140     checkGLcall("glReadBuffer");
1141 
1142     if (data.buffer_object)
1143     {
1144         GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, data.buffer_object));
1145         checkGLcall("glBindBuffer");
1146     }
1147 
1148     level = sub_resource_idx % texture->level_count;
1149     wined3d_texture_get_pitch(texture, level, &row_pitch, &slice_pitch);
1150 
1151     /* Setup pixel store pack state -- to glReadPixels into the correct place */
1152     gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_ROW_LENGTH, row_pitch / texture->resource.format->byte_count);
1153     checkGLcall("glPixelStorei");
1154 
1155     width = wined3d_texture_get_level_width(texture, level);
1156     height = wined3d_texture_get_level_height(texture, level);
1157     gl_info->gl_ops.gl.p_glReadPixels(0, 0, width, height,
1158             texture->resource.format->glFormat,
1159             texture->resource.format->glType, data.addr);
1160     checkGLcall("glReadPixels");
1161 
1162     /* Reset previous pixel store pack state */
1163     gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_ROW_LENGTH, 0);
1164     checkGLcall("glPixelStorei");
1165 
1166     if (!src_is_upside_down)
1167     {
1168         /* glReadPixels returns the image upside down, and there is no way to
1169          * prevent this. Flip the lines in software. */
1170 
1171         if (!(row = heap_alloc(row_pitch)))
1172             goto error;
1173 
1174         if (data.buffer_object)
1175         {
1176             mem = GL_EXTCALL(glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_WRITE));
1177             checkGLcall("glMapBuffer");
1178         }
1179         else
1180             mem = data.addr;
1181 
1182         top = mem;
1183         bottom = mem + row_pitch * (height - 1);
1184         for (i = 0; i < height / 2; i++)
1185         {
1186             memcpy(row, top, row_pitch);
1187             memcpy(top, bottom, row_pitch);
1188             memcpy(bottom, row, row_pitch);
1189             top += row_pitch;
1190             bottom -= row_pitch;
1191         }
1192         heap_free(row);
1193 
1194         if (data.buffer_object)
1195             GL_EXTCALL(glUnmapBuffer(GL_PIXEL_PACK_BUFFER));
1196     }
1197 
1198 error:
1199     if (data.buffer_object)
1200     {
1201         GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));
1202         checkGLcall("glBindBuffer");
1203     }
1204 
1205     if (restore_texture)
1206         context_restore(context, restore_texture, restore_idx);
1207 }
1208 
1209 /* Read the framebuffer contents into a texture. Note that this function
1210  * doesn't do any kind of flipping. Using this on an onscreen surface will
1211  * result in a flipped D3D texture.
1212  *
1213  * Context activation is done by the caller. This function may temporarily
1214  * switch to a different context and restore the original one before return. */
1215 void texture2d_load_fb_texture(struct wined3d_texture *texture,
1216         unsigned int sub_resource_idx, BOOL srgb, struct wined3d_context *context)
1217 {
1218     struct wined3d_device *device = texture->resource.device;
1219     struct wined3d_texture *restore_texture;
1220     const struct wined3d_gl_info *gl_info;
1221     unsigned int restore_idx, level;
1222     GLenum target;
1223 
1224     restore_texture = context->current_rt.texture;
1225     restore_idx = context->current_rt.sub_resource_idx;
1226     if (restore_texture != texture || restore_idx != sub_resource_idx)
1227         context = context_acquire(device, texture, sub_resource_idx);
1228     else
1229         restore_texture = NULL;
1230 
1231     gl_info = context->gl_info;
1232     device_invalidate_state(device, STATE_FRAMEBUFFER);
1233 
1234     wined3d_texture_prepare_texture(texture, context, srgb);
1235     wined3d_texture_bind_and_dirtify(texture, context, srgb);
1236 
1237     TRACE("Reading back offscreen render target %p, %u.\n", texture, sub_resource_idx);
1238 
1239     if (wined3d_resource_is_offscreen(&texture->resource))
1240         gl_info->gl_ops.gl.p_glReadBuffer(context_get_offscreen_gl_buffer(context));
1241     else
1242         gl_info->gl_ops.gl.p_glReadBuffer(wined3d_texture_get_gl_buffer(texture));
1243     checkGLcall("glReadBuffer");
1244 
1245     level = sub_resource_idx % texture->level_count;
1246     target = wined3d_texture_get_sub_resource_target(texture, sub_resource_idx);
1247     gl_info->gl_ops.gl.p_glCopyTexSubImage2D(target, level, 0, 0, 0, 0,
1248             wined3d_texture_get_level_width(texture, level),
1249             wined3d_texture_get_level_height(texture, level));
1250     checkGLcall("glCopyTexSubImage2D");
1251 
1252     if (restore_texture)
1253         context_restore(context, restore_texture, restore_idx);
1254 }
1255 
1256 /* Does a direct frame buffer -> texture copy. Stretching is done with single
1257  * pixel copy calls. */
1258 static void fb_copy_to_texture_direct(struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx,
1259         const RECT *dst_rect_in, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx,
1260         const RECT *src_rect, enum wined3d_texture_filter_type filter)
1261 {
1262     struct wined3d_device *device = dst_texture->resource.device;
1263     unsigned int src_height, src_level, dst_level;
1264     const struct wined3d_gl_info *gl_info;
1265     float xrel, yrel;
1266     struct wined3d_context *context;
1267     BOOL upsidedown = FALSE;
1268     RECT dst_rect = *dst_rect_in;
1269     GLenum dst_target;
1270 
1271     /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
1272      * glCopyTexSubImage is a bit picky about the parameters we pass to it
1273      */
1274     if(dst_rect.top > dst_rect.bottom) {
1275         UINT tmp = dst_rect.bottom;
1276         dst_rect.bottom = dst_rect.top;
1277         dst_rect.top = tmp;
1278         upsidedown = TRUE;
1279     }
1280 
1281     context = context_acquire(device, src_texture, src_sub_resource_idx);
1282     gl_info = context->gl_info;
1283     context_apply_blit_state(context, device);
1284     wined3d_texture_load(dst_texture, context, FALSE);
1285 
1286     /* Bind the target texture */
1287     context_bind_texture(context, dst_texture->target, dst_texture->texture_rgb.name);
1288     if (wined3d_resource_is_offscreen(&src_texture->resource))
1289     {
1290         TRACE("Reading from an offscreen target\n");
1291         upsidedown = !upsidedown;
1292         gl_info->gl_ops.gl.p_glReadBuffer(context_get_offscreen_gl_buffer(context));
1293     }
1294     else
1295     {
1296         gl_info->gl_ops.gl.p_glReadBuffer(wined3d_texture_get_gl_buffer(src_texture));
1297     }
1298     checkGLcall("glReadBuffer");
1299 
1300     xrel = (float) (src_rect->right - src_rect->left) / (float) (dst_rect.right - dst_rect.left);
1301     yrel = (float) (src_rect->bottom - src_rect->top) / (float) (dst_rect.bottom - dst_rect.top);
1302 
1303     if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
1304     {
1305         FIXME_(d3d_perf)("Doing a pixel by pixel copy from the framebuffer to a texture.\n");
1306 
1307         if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT)
1308             ERR("Texture filtering not supported in direct blit.\n");
1309     }
1310     else if ((filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT)
1311             && ((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
1312     {
1313         ERR("Texture filtering not supported in direct blit\n");
1314     }
1315 
1316     src_level = src_sub_resource_idx % src_texture->level_count;
1317     dst_level = dst_sub_resource_idx % dst_texture->level_count;
1318 
1319     src_height = wined3d_texture_get_level_height(src_texture, src_level);
1320     dst_target = wined3d_texture_get_sub_resource_target(dst_texture, dst_sub_resource_idx);
1321     if (upsidedown
1322             && !((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
1323             && !((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
1324     {
1325         /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do. */
1326         gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_target, dst_level,
1327                 dst_rect.left /*xoffset */, dst_rect.top /* y offset */,
1328                 src_rect->left, src_height - src_rect->bottom,
1329                 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
1330     }
1331     else
1332     {
1333         LONG row;
1334         UINT yoffset = src_height - src_rect->top + dst_rect.top - 1;
1335         /* I have to process this row by row to swap the image,
1336          * otherwise it would be upside down, so stretching in y direction
1337          * doesn't cost extra time
1338          *
1339          * However, stretching in x direction can be avoided if not necessary
1340          */
1341         for(row = dst_rect.top; row < dst_rect.bottom; row++) {
1342             if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
1343             {
1344                 /* Well, that stuff works, but it's very slow.
1345                  * find a better way instead
1346                  */
1347                 LONG col;
1348 
1349                 for (col = dst_rect.left; col < dst_rect.right; ++col)
1350                 {
1351                     gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_target, dst_level,
1352                             dst_rect.left + col /* x offset */, row /* y offset */,
1353                             src_rect->left + col * xrel, yoffset - (int) (row * yrel), 1, 1);
1354                 }
1355             }
1356             else
1357             {
1358                 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_target, dst_level,
1359                         dst_rect.left /* x offset */, row /* y offset */,
1360                         src_rect->left, yoffset - (int) (row * yrel), dst_rect.right - dst_rect.left, 1);
1361             }
1362         }
1363     }
1364     checkGLcall("glCopyTexSubImage2D");
1365 
1366     context_release(context);
1367 
1368     /* The texture is now most up to date - If the surface is a render target
1369      * and has a drawable, this path is never entered. */
1370     wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB);
1371     wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB);
1372 }
1373 
1374 /* Uses the hardware to stretch and flip the image */
1375 static void fb_copy_to_texture_hwstretch(struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx,
1376         const RECT *dst_rect_in, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx,
1377         const RECT *src_rect, enum wined3d_texture_filter_type filter)
1378 {
1379     unsigned int src_width, src_height, src_pow2_width, src_pow2_height, src_level;
1380     struct wined3d_device *device = dst_texture->resource.device;
1381     GLenum src_target, dst_target, texture_target;
1382     GLuint src, backup = 0;
1383     float left, right, top, bottom; /* Texture coordinates */
1384     const struct wined3d_gl_info *gl_info;
1385     struct wined3d_context *context;
1386     GLenum drawBuffer = GL_BACK;
1387     GLenum offscreen_buffer;
1388     BOOL noBackBufferBackup;
1389     BOOL src_offscreen;
1390     BOOL upsidedown = FALSE;
1391     RECT dst_rect = *dst_rect_in;
1392 
1393     TRACE("Using hwstretch blit\n");
1394 
1395     src_target = wined3d_texture_get_sub_resource_target(src_texture, src_sub_resource_idx);
1396     dst_target = wined3d_texture_get_sub_resource_target(dst_texture, dst_sub_resource_idx);
1397 
1398     /* Activate the Proper context for reading from the source surface, set it up for blitting */
1399     context = context_acquire(device, src_texture, src_sub_resource_idx);
1400     gl_info = context->gl_info;
1401     context_apply_ffp_blit_state(context, device);
1402     wined3d_texture_load(dst_texture, context, FALSE);
1403 
1404     offscreen_buffer = context_get_offscreen_gl_buffer(context);
1405     src_level = src_sub_resource_idx % src_texture->level_count;
1406     src_width = wined3d_texture_get_level_width(src_texture, src_level);
1407     src_height = wined3d_texture_get_level_height(src_texture, src_level);
1408     src_pow2_width = wined3d_texture_get_level_pow2_width(src_texture, src_level);
1409     src_pow2_height = wined3d_texture_get_level_pow2_height(src_texture, src_level);
1410 
1411     src_offscreen = wined3d_resource_is_offscreen(&src_texture->resource);
1412     noBackBufferBackup = src_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO;
1413     if (!noBackBufferBackup && !src_texture->texture_rgb.name)
1414     {
1415         /* Get it a description */
1416         wined3d_texture_load(src_texture, context, FALSE);
1417     }
1418 
1419     /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
1420      * This way we don't have to wait for the 2nd readback to finish to leave this function.
1421      */
1422     if (context->aux_buffers >= 2)
1423     {
1424         /* Got more than one aux buffer? Use the 2nd aux buffer */
1425         drawBuffer = GL_AUX1;
1426     }
1427     else if ((!src_offscreen || offscreen_buffer == GL_BACK) && context->aux_buffers >= 1)
1428     {
1429         /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
1430         drawBuffer = GL_AUX0;
1431     }
1432 
1433     if (noBackBufferBackup)
1434     {
1435         gl_info->gl_ops.gl.p_glGenTextures(1, &backup);
1436         checkGLcall("glGenTextures");
1437         context_bind_texture(context, GL_TEXTURE_2D, backup);
1438         texture_target = GL_TEXTURE_2D;
1439     }
1440     else
1441     {
1442         /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
1443          * we are reading from the back buffer, the backup can be used as source texture
1444          */
1445         texture_target = src_target;
1446         context_bind_texture(context, texture_target, src_texture->texture_rgb.name);
1447         gl_info->gl_ops.gl.p_glEnable(texture_target);
1448         checkGLcall("glEnable(texture_target)");
1449 
1450         /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
1451         src_texture->sub_resources[src_sub_resource_idx].locations &= ~WINED3D_LOCATION_TEXTURE_RGB;
1452     }
1453 
1454     /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
1455      * glCopyTexSubImage is a bit picky about the parameters we pass to it
1456      */
1457     if(dst_rect.top > dst_rect.bottom) {
1458         UINT tmp = dst_rect.bottom;
1459         dst_rect.bottom = dst_rect.top;
1460         dst_rect.top = tmp;
1461         upsidedown = TRUE;
1462     }
1463 
1464     if (src_offscreen)
1465     {
1466         TRACE("Reading from an offscreen target\n");
1467         upsidedown = !upsidedown;
1468         gl_info->gl_ops.gl.p_glReadBuffer(offscreen_buffer);
1469     }
1470     else
1471     {
1472         gl_info->gl_ops.gl.p_glReadBuffer(wined3d_texture_get_gl_buffer(src_texture));
1473     }
1474 
1475     /* TODO: Only back up the part that will be overwritten */
1476     gl_info->gl_ops.gl.p_glCopyTexSubImage2D(texture_target, 0, 0, 0, 0, 0, src_width, src_height);
1477 
1478     checkGLcall("glCopyTexSubImage2D");
1479 
1480     /* No issue with overriding these - the sampler is dirty due to blit usage */
1481     gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, wined3d_gl_mag_filter(filter));
1482     checkGLcall("glTexParameteri");
1483     gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER,
1484             wined3d_gl_min_mip_filter(filter, WINED3D_TEXF_NONE));
1485     checkGLcall("glTexParameteri");
1486 
1487     if (!src_texture->swapchain || src_texture == src_texture->swapchain->back_buffers[0])
1488     {
1489         src = backup ? backup : src_texture->texture_rgb.name;
1490     }
1491     else
1492     {
1493         gl_info->gl_ops.gl.p_glReadBuffer(GL_FRONT);
1494         checkGLcall("glReadBuffer(GL_FRONT)");
1495 
1496         gl_info->gl_ops.gl.p_glGenTextures(1, &src);
1497         checkGLcall("glGenTextures(1, &src)");
1498         context_bind_texture(context, GL_TEXTURE_2D, src);
1499 
1500         /* TODO: Only copy the part that will be read. Use src_rect->left,
1501          * src_rect->bottom as origin, but with the width watch out for power
1502          * of 2 sizes. */
1503         gl_info->gl_ops.gl.p_glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, src_pow2_width,
1504                 src_pow2_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
1505         checkGLcall("glTexImage2D");
1506         gl_info->gl_ops.gl.p_glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, src_width, src_height);
1507 
1508         gl_info->gl_ops.gl.p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1509         checkGLcall("glTexParameteri");
1510         gl_info->gl_ops.gl.p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1511         checkGLcall("glTexParameteri");
1512 
1513         gl_info->gl_ops.gl.p_glReadBuffer(GL_BACK);
1514         checkGLcall("glReadBuffer(GL_BACK)");
1515 
1516         if (texture_target != GL_TEXTURE_2D)
1517         {
1518             gl_info->gl_ops.gl.p_glDisable(texture_target);
1519             gl_info->gl_ops.gl.p_glEnable(GL_TEXTURE_2D);
1520             texture_target = GL_TEXTURE_2D;
1521         }
1522     }
1523     checkGLcall("glEnd and previous");
1524 
1525     left = src_rect->left;
1526     right = src_rect->right;
1527 
1528     if (!upsidedown)
1529     {
1530         top = src_height - src_rect->top;
1531         bottom = src_height - src_rect->bottom;
1532     }
1533     else
1534     {
1535         top = src_height - src_rect->bottom;
1536         bottom = src_height - src_rect->top;
1537     }
1538 
1539     if (src_texture->flags & WINED3D_TEXTURE_NORMALIZED_COORDS)
1540     {
1541         left /= src_pow2_width;
1542         right /= src_pow2_width;
1543         top /= src_pow2_height;
1544         bottom /= src_pow2_height;
1545     }
1546 
1547     /* draw the source texture stretched and upside down. The correct surface is bound already */
1548     gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1549     gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1550 
1551     context_set_draw_buffer(context, drawBuffer);
1552     gl_info->gl_ops.gl.p_glReadBuffer(drawBuffer);
1553 
1554     gl_info->gl_ops.gl.p_glBegin(GL_QUADS);
1555         /* bottom left */
1556         gl_info->gl_ops.gl.p_glTexCoord2f(left, bottom);
1557         gl_info->gl_ops.gl.p_glVertex2i(0, 0);
1558 
1559         /* top left */
1560         gl_info->gl_ops.gl.p_glTexCoord2f(left, top);
1561         gl_info->gl_ops.gl.p_glVertex2i(0, dst_rect.bottom - dst_rect.top);
1562 
1563         /* top right */
1564         gl_info->gl_ops.gl.p_glTexCoord2f(right, top);
1565         gl_info->gl_ops.gl.p_glVertex2i(dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
1566 
1567         /* bottom right */
1568         gl_info->gl_ops.gl.p_glTexCoord2f(right, bottom);
1569         gl_info->gl_ops.gl.p_glVertex2i(dst_rect.right - dst_rect.left, 0);
1570     gl_info->gl_ops.gl.p_glEnd();
1571     checkGLcall("glEnd and previous");
1572 
1573     if (texture_target != dst_target)
1574     {
1575         gl_info->gl_ops.gl.p_glDisable(texture_target);
1576         gl_info->gl_ops.gl.p_glEnable(dst_target);
1577         texture_target = dst_target;
1578     }
1579 
1580     /* Now read the stretched and upside down image into the destination texture */
1581     context_bind_texture(context, texture_target, dst_texture->texture_rgb.name);
1582     gl_info->gl_ops.gl.p_glCopyTexSubImage2D(texture_target,
1583                         0,
1584                         dst_rect.left, dst_rect.top, /* xoffset, yoffset */
1585                         0, 0, /* We blitted the image to the origin */
1586                         dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
1587     checkGLcall("glCopyTexSubImage2D");
1588 
1589     if (drawBuffer == GL_BACK)
1590     {
1591         /* Write the back buffer backup back. */
1592         if (backup)
1593         {
1594             if (texture_target != GL_TEXTURE_2D)
1595             {
1596                 gl_info->gl_ops.gl.p_glDisable(texture_target);
1597                 gl_info->gl_ops.gl.p_glEnable(GL_TEXTURE_2D);
1598                 texture_target = GL_TEXTURE_2D;
1599             }
1600             context_bind_texture(context, GL_TEXTURE_2D, backup);
1601         }
1602         else
1603         {
1604             if (texture_target != src_target)
1605             {
1606                 gl_info->gl_ops.gl.p_glDisable(texture_target);
1607                 gl_info->gl_ops.gl.p_glEnable(src_target);
1608                 texture_target = src_target;
1609             }
1610             context_bind_texture(context, src_target, src_texture->texture_rgb.name);
1611         }
1612 
1613         gl_info->gl_ops.gl.p_glBegin(GL_QUADS);
1614             /* top left */
1615             gl_info->gl_ops.gl.p_glTexCoord2f(0.0f, 0.0f);
1616             gl_info->gl_ops.gl.p_glVertex2i(0, src_height);
1617 
1618             /* bottom left */
1619             gl_info->gl_ops.gl.p_glTexCoord2f(0.0f, (float)src_height / (float)src_pow2_height);
1620             gl_info->gl_ops.gl.p_glVertex2i(0, 0);
1621 
1622             /* bottom right */
1623             gl_info->gl_ops.gl.p_glTexCoord2f((float)src_width / (float)src_pow2_width,
1624                     (float)src_height / (float)src_pow2_height);
1625             gl_info->gl_ops.gl.p_glVertex2i(src_width, 0);
1626 
1627             /* top right */
1628             gl_info->gl_ops.gl.p_glTexCoord2f((float)src_width / (float)src_pow2_width, 0.0f);
1629             gl_info->gl_ops.gl.p_glVertex2i(src_width, src_height);
1630         gl_info->gl_ops.gl.p_glEnd();
1631     }
1632     gl_info->gl_ops.gl.p_glDisable(texture_target);
1633     checkGLcall("glDisable(texture_target)");
1634 
1635     /* Cleanup */
1636     if (src != src_texture->texture_rgb.name && src != backup)
1637     {
1638         gl_info->gl_ops.gl.p_glDeleteTextures(1, &src);
1639         checkGLcall("glDeleteTextures(1, &src)");
1640     }
1641     if (backup)
1642     {
1643         gl_info->gl_ops.gl.p_glDeleteTextures(1, &backup);
1644         checkGLcall("glDeleteTextures(1, &backup)");
1645     }
1646 
1647     context_release(context);
1648 
1649     /* The texture is now most up to date - If the surface is a render target
1650      * and has a drawable, this path is never entered. */
1651     wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB);
1652     wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB);
1653 }
1654 
1655 static HRESULT wined3d_texture_blt_special(struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx,
1656         const RECT *dst_rect, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx,
1657         const RECT *src_rect, DWORD flags, const struct wined3d_blt_fx *fx, enum wined3d_texture_filter_type filter)
1658 {
1659     struct wined3d_swapchain *src_swapchain, *dst_swapchain;
1660     const struct wined3d_rendertarget_view *rtv;
1661 
1662     TRACE("dst_texture %p, dst_sub_resource_idx %u, dst_rect %s, src_texture %p, "
1663             "src_sub_resource_idx %u, src_rect %s, flags %#x, fx %p, filter %s.\n",
1664             dst_texture, dst_sub_resource_idx, wine_dbgstr_rect(dst_rect), src_texture, src_sub_resource_idx,
1665             wine_dbgstr_rect(src_rect), flags, fx, debug_d3dtexturefiltertype(filter));
1666 
1667     if (dst_texture->resource.type != WINED3D_RTYPE_TEXTURE_2D)
1668     {
1669         FIXME("Not implemented for %s resources.\n", debug_d3dresourcetype(dst_texture->resource.type));
1670         return WINED3DERR_INVALIDCALL;
1671     }
1672 
1673     /* Get the swapchain. One of the surfaces has to be a primary surface. */
1674     if (!(dst_texture->resource.access & WINED3D_RESOURCE_ACCESS_GPU))
1675     {
1676         WARN("Destination resource is not GPU accessible, rejecting GL blit.\n");
1677         return WINED3DERR_INVALIDCALL;
1678     }
1679 
1680     if (!(src_texture->resource.access & WINED3D_RESOURCE_ACCESS_GPU))
1681     {
1682         WARN("Source resource is not GPU accessible, rejecting GL blit.\n");
1683         return WINED3DERR_INVALIDCALL;
1684     }
1685 
1686     src_swapchain = src_texture->swapchain;
1687     dst_swapchain = dst_texture->swapchain;
1688 
1689     /* Early sort out of cases where no render target is used */
1690     if (!(rtv = dst_texture->resource.device->fb.render_targets[0]) || (!src_swapchain && !dst_swapchain
1691             && (&src_texture->resource != rtv->resource || src_sub_resource_idx != rtv->sub_resource_idx)
1692             && (&dst_texture->resource != rtv->resource || dst_sub_resource_idx != rtv->sub_resource_idx)))
1693     {
1694         TRACE("No surface is render target, not using hardware blit.\n");
1695         return WINED3DERR_INVALIDCALL;
1696     }
1697 
1698     /* No destination color keying supported */
1699     if (flags & (WINED3D_BLT_DST_CKEY | WINED3D_BLT_DST_CKEY_OVERRIDE))
1700     {
1701         /* Can we support that with glBlendFunc if blitting to the frame buffer? */
1702         TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
1703         return WINED3DERR_INVALIDCALL;
1704     }
1705 
1706     if (dst_swapchain && dst_swapchain == src_swapchain)
1707     {
1708         FIXME("Implement hardware blit between two surfaces on the same swapchain\n");
1709         return WINED3DERR_INVALIDCALL;
1710     }
1711 
1712     if (dst_swapchain && src_swapchain)
1713     {
1714         FIXME("Implement hardware blit between two different swapchains\n");
1715         return WINED3DERR_INVALIDCALL;
1716     }
1717 
1718     if (dst_swapchain)
1719     {
1720         /* Handled with regular texture -> swapchain blit */
1721         if (&src_texture->resource == rtv->resource && src_sub_resource_idx == rtv->sub_resource_idx)
1722             TRACE("Blit from active render target to a swapchain\n");
1723     }
1724     else if (src_swapchain && &dst_texture->resource == rtv->resource
1725             && dst_sub_resource_idx == rtv->sub_resource_idx)
1726     {
1727         FIXME("Implement blit from a swapchain to the active render target\n");
1728         return WINED3DERR_INVALIDCALL;
1729     }
1730 
1731     if (!dst_swapchain && (src_swapchain || (&src_texture->resource == rtv->resource
1732             && src_sub_resource_idx == rtv->sub_resource_idx)))
1733     {
1734         unsigned int src_level, src_width, src_height;
1735         /* Blit from render target to texture */
1736         BOOL stretchx;
1737 
1738         /* P8 read back is not implemented */
1739         if (src_texture->resource.format->id == WINED3DFMT_P8_UINT
1740                 || dst_texture->resource.format->id == WINED3DFMT_P8_UINT)
1741         {
1742             TRACE("P8 read back not supported by frame buffer to texture blit\n");
1743             return WINED3DERR_INVALIDCALL;
1744         }
1745 
1746         if (flags & (WINED3D_BLT_SRC_CKEY | WINED3D_BLT_SRC_CKEY_OVERRIDE))
1747         {
1748             TRACE("Color keying not supported by frame buffer to texture blit\n");
1749             return WINED3DERR_INVALIDCALL;
1750             /* Destination color key is checked above */
1751         }
1752 
1753         if (dst_rect->right - dst_rect->left != src_rect->right - src_rect->left)
1754             stretchx = TRUE;
1755         else
1756             stretchx = FALSE;
1757 
1758         /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
1759          * flip the image nor scale it.
1760          *
1761          * -> If the app asks for an unscaled, upside down copy, just perform one glCopyTexSubImage2D call
1762          * -> If the app wants an image width an unscaled width, copy it line per line
1763          * -> If the app wants an image that is scaled on the x axis, and the destination rectangle is smaller
1764          *    than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
1765          *    back buffer. This is slower than reading line per line, thus not used for flipping
1766          * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
1767          *    pixel by pixel. */
1768         src_level = src_sub_resource_idx % src_texture->level_count;
1769         src_width = wined3d_texture_get_level_width(src_texture, src_level);
1770         src_height = wined3d_texture_get_level_height(src_texture, src_level);
1771         if (!stretchx || dst_rect->right - dst_rect->left > src_width
1772                 || dst_rect->bottom - dst_rect->top > src_height)
1773         {
1774             TRACE("No stretching in x direction, using direct framebuffer -> texture copy.\n");
1775             fb_copy_to_texture_direct(dst_texture, dst_sub_resource_idx, dst_rect,
1776                     src_texture, src_sub_resource_idx, src_rect, filter);
1777         }
1778         else
1779         {
1780             TRACE("Using hardware stretching to flip / stretch the texture.\n");
1781             fb_copy_to_texture_hwstretch(dst_texture, dst_sub_resource_idx, dst_rect,
1782                     src_texture, src_sub_resource_idx, src_rect, filter);
1783         }
1784 
1785         return WINED3D_OK;
1786     }
1787 
1788     /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
1789     TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
1790     return WINED3DERR_INVALIDCALL;
1791 }
1792 
1793 /* Context activation is done by the caller. */
1794 BOOL texture2d_load_sysmem(struct wined3d_texture *texture, unsigned int sub_resource_idx,
1795         struct wined3d_context *context, DWORD dst_location)
1796 {
1797     struct wined3d_texture_sub_resource *sub_resource;
1798 
1799     sub_resource = &texture->sub_resources[sub_resource_idx];
1800     wined3d_texture_prepare_location(texture, sub_resource_idx, context, dst_location);
1801 
1802     /* We cannot download data from multisample textures directly. */
1803     if (is_multisample_location(texture, WINED3D_LOCATION_TEXTURE_RGB))
1804     {
1805         wined3d_texture_load_location(texture, sub_resource_idx, context, WINED3D_LOCATION_RB_RESOLVED);
1806         texture2d_read_from_framebuffer(texture, sub_resource_idx, context,
1807                 WINED3D_LOCATION_RB_RESOLVED, dst_location);
1808         return TRUE;
1809     }
1810     else
1811     {
1812         if (sub_resource->locations & (WINED3D_LOCATION_RB_MULTISAMPLE | WINED3D_LOCATION_RB_RESOLVED))
1813             wined3d_texture_load_location(texture, sub_resource_idx, context, WINED3D_LOCATION_TEXTURE_RGB);
1814 
1815         /* Download the sub-resource to system memory. */
1816         if (sub_resource->locations & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB))
1817         {
1818             wined3d_texture_bind_and_dirtify(texture, context,
1819                     !(sub_resource->locations & WINED3D_LOCATION_TEXTURE_RGB));
1820             texture2d_download_data(texture, sub_resource_idx, context, dst_location);
1821             ++texture->download_count;
1822 
1823             return TRUE;
1824         }
1825     }
1826 
1827     if (!(texture->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
1828             && (sub_resource->locations & WINED3D_LOCATION_DRAWABLE))
1829     {
1830         texture2d_read_from_framebuffer(texture, sub_resource_idx, context,
1831                 texture->resource.draw_binding, dst_location);
1832         return TRUE;
1833     }
1834 
1835     FIXME("Can't load texture %p, %u with location flags %s into sysmem.\n",
1836             texture, sub_resource_idx, wined3d_debug_location(sub_resource->locations));
1837     return FALSE;
1838 }
1839 
1840 /* Context activation is done by the caller. */
1841 BOOL texture2d_load_drawable(struct wined3d_texture *texture,
1842         unsigned int sub_resource_idx, struct wined3d_context *context)
1843 {
1844     struct wined3d_texture *restore_texture;
1845     struct wined3d_device *device;
1846     unsigned int restore_idx;
1847     unsigned int level;
1848     RECT r;
1849 
1850     if (texture->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
1851     {
1852         DWORD current = texture->sub_resources[sub_resource_idx].locations;
1853         FIXME("Unimplemented copy from %s for depth/stencil buffers.\n",
1854                 wined3d_debug_location(current));
1855         return FALSE;
1856     }
1857 
1858     if (wined3d_settings.offscreen_rendering_mode == ORM_FBO
1859             && wined3d_resource_is_offscreen(&texture->resource))
1860     {
1861         ERR("Trying to load offscreen texture into WINED3D_LOCATION_DRAWABLE.\n");
1862         return FALSE;
1863     }
1864 
1865     device = texture->resource.device;
1866     restore_texture = context->current_rt.texture;
1867     restore_idx = context->current_rt.sub_resource_idx;
1868     if (restore_texture != texture || restore_idx != sub_resource_idx)
1869         context = context_acquire(device, texture, sub_resource_idx);
1870     else
1871         restore_texture = NULL;
1872 
1873     level = sub_resource_idx % texture->level_count;
1874     SetRect(&r, 0, 0, wined3d_texture_get_level_width(texture, level),
1875             wined3d_texture_get_level_height(texture, level));
1876     wined3d_texture_load_location(texture, sub_resource_idx, context, WINED3D_LOCATION_TEXTURE_RGB);
1877     device->blitter->ops->blitter_blit(device->blitter, WINED3D_BLIT_OP_COLOR_BLIT, context,
1878             texture, sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB, &r,
1879             texture, sub_resource_idx, WINED3D_LOCATION_DRAWABLE, &r,
1880             NULL, WINED3D_TEXF_POINT);
1881 
1882     if (restore_texture)
1883         context_restore(context, restore_texture, restore_idx);
1884 
1885     return TRUE;
1886 }
1887 
1888 BOOL texture2d_load_texture(struct wined3d_texture *texture, unsigned int sub_resource_idx,
1889         struct wined3d_context *context, BOOL srgb)
1890 {
1891     unsigned int width, height, level, src_row_pitch, src_slice_pitch, dst_row_pitch, dst_slice_pitch;
1892     const struct wined3d_gl_info *gl_info = context->gl_info;
1893     struct wined3d_device *device = texture->resource.device;
1894     const struct wined3d_color_key_conversion *conversion;
1895     struct wined3d_texture_sub_resource *sub_resource;
1896     const struct wined3d_format *format;
1897     struct wined3d_bo_address data;
1898     BYTE *src_mem, *dst_mem = NULL;
1899     struct wined3d_box src_box;
1900     BOOL depth;
1901 
1902     depth = texture->resource.usage & WINED3DUSAGE_DEPTHSTENCIL;
1903     sub_resource = &texture->sub_resources[sub_resource_idx];
1904 
1905     if (!depth && wined3d_settings.offscreen_rendering_mode != ORM_FBO
1906             && wined3d_resource_is_offscreen(&texture->resource)
1907             && (sub_resource->locations & WINED3D_LOCATION_DRAWABLE))
1908     {
1909         texture2d_load_fb_texture(texture, sub_resource_idx, srgb, context);
1910 
1911         return TRUE;
1912     }
1913 
1914     level = sub_resource_idx % texture->level_count;
1915     width = wined3d_texture_get_level_width(texture, level);
1916     height = wined3d_texture_get_level_height(texture, level);
1917     wined3d_box_set(&src_box, 0, 0, width, height, 0, 1);
1918 
1919     if (!depth && sub_resource->locations & (WINED3D_LOCATION_TEXTURE_SRGB | WINED3D_LOCATION_TEXTURE_RGB)
1920             && (texture->resource.format_flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB)
1921             && fbo_blitter_supported(WINED3D_BLIT_OP_COLOR_BLIT, gl_info,
1922                     &texture->resource, WINED3D_LOCATION_TEXTURE_RGB,
1923                     &texture->resource, WINED3D_LOCATION_TEXTURE_SRGB))
1924     {
1925         RECT src_rect;
1926 
1927         SetRect(&src_rect, 0, 0, width, height);
1928         if (srgb)
1929             texture2d_blt_fbo(device, context, WINED3D_TEXF_POINT,
1930                     texture, sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB, &src_rect,
1931                     texture, sub_resource_idx, WINED3D_LOCATION_TEXTURE_SRGB, &src_rect);
1932         else
1933             texture2d_blt_fbo(device, context, WINED3D_TEXF_POINT,
1934                     texture, sub_resource_idx, WINED3D_LOCATION_TEXTURE_SRGB, &src_rect,
1935                     texture, sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB, &src_rect);
1936 
1937         return TRUE;
1938     }
1939 
1940     if (!depth && sub_resource->locations & (WINED3D_LOCATION_RB_MULTISAMPLE | WINED3D_LOCATION_RB_RESOLVED)
1941             && (!srgb || (texture->resource.format_flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB)))
1942     {
1943         DWORD src_location = sub_resource->locations & WINED3D_LOCATION_RB_RESOLVED ?
1944                 WINED3D_LOCATION_RB_RESOLVED : WINED3D_LOCATION_RB_MULTISAMPLE;
1945         DWORD dst_location = srgb ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB;
1946         RECT src_rect;
1947 
1948         SetRect(&src_rect, 0, 0, width, height);
1949         if (fbo_blitter_supported(WINED3D_BLIT_OP_COLOR_BLIT, gl_info,
1950                 &texture->resource, src_location, &texture->resource, dst_location))
1951             texture2d_blt_fbo(device, context, WINED3D_TEXF_POINT, texture, sub_resource_idx,
1952                     src_location, &src_rect, texture, sub_resource_idx, dst_location, &src_rect);
1953 
1954         return TRUE;
1955     }
1956 
1957     /* Upload from system memory */
1958 
1959     if (srgb)
1960     {
1961         if ((sub_resource->locations & (WINED3D_LOCATION_TEXTURE_RGB | texture->resource.map_binding))
1962                 == WINED3D_LOCATION_TEXTURE_RGB)
1963         {
1964             FIXME_(d3d_perf)("Downloading RGB texture %p, %u to reload it as sRGB.\n", texture, sub_resource_idx);
1965             wined3d_texture_load_location(texture, sub_resource_idx, context, texture->resource.map_binding);
1966         }
1967     }
1968     else
1969     {
1970         if ((sub_resource->locations & (WINED3D_LOCATION_TEXTURE_SRGB | texture->resource.map_binding))
1971                 == WINED3D_LOCATION_TEXTURE_SRGB)
1972         {
1973             FIXME_(d3d_perf)("Downloading sRGB texture %p, %u to reload it as RGB.\n", texture, sub_resource_idx);
1974             wined3d_texture_load_location(texture, sub_resource_idx, context, texture->resource.map_binding);
1975         }
1976     }
1977 
1978     if (!(sub_resource->locations & surface_simple_locations))
1979     {
1980         WARN("Trying to load a texture from sysmem, but no simple location is valid.\n");
1981         /* Lets hope we get it from somewhere... */
1982         wined3d_texture_load_location(texture, sub_resource_idx, context, WINED3D_LOCATION_SYSMEM);
1983     }
1984 
1985     wined3d_texture_prepare_texture(texture, context, srgb);
1986     wined3d_texture_bind_and_dirtify(texture, context, srgb);
1987     wined3d_texture_get_pitch(texture, level, &src_row_pitch, &src_slice_pitch);
1988 
1989     format = texture->resource.format;
1990     if ((conversion = wined3d_format_get_color_key_conversion(texture, TRUE)))
1991         format = wined3d_get_format(gl_info, conversion->dst_format, texture->resource.usage);
1992 
1993     /* Don't use PBOs for converted surfaces. During PBO conversion we look at
1994      * WINED3D_TEXTURE_CONVERTED but it isn't set (yet) in all cases it is
1995      * getting called. */
1996     if (conversion && sub_resource->buffer_object)
1997     {
1998         TRACE("Removing the pbo attached to texture %p, %u.\n", texture, sub_resource_idx);
1999 
2000         wined3d_texture_load_location(texture, sub_resource_idx, context, WINED3D_LOCATION_SYSMEM);
2001         wined3d_texture_set_map_binding(texture, WINED3D_LOCATION_SYSMEM);
2002     }
2003 
2004     wined3d_texture_get_memory(texture, sub_resource_idx, &data, sub_resource->locations);
2005     if (conversion)
2006     {
2007         wined3d_format_calculate_pitch(format, device->surface_alignment,
2008                 width, height, &dst_row_pitch, &dst_slice_pitch);
2009 
2010         src_mem = context_map_bo_address(context, &data, src_slice_pitch,
2011                 GL_PIXEL_UNPACK_BUFFER, WINED3D_MAP_READ);
2012         if (!(dst_mem = heap_alloc(dst_slice_pitch)))
2013         {
2014             ERR("Out of memory (%u).\n", dst_slice_pitch);
2015             context_release(context);
2016             return FALSE;
2017         }
2018         conversion->convert(src_mem, src_row_pitch, dst_mem, dst_row_pitch,
2019                 width, height, &texture->async.gl_color_key);
2020         src_row_pitch = dst_row_pitch;
2021         src_slice_pitch = dst_slice_pitch;
2022         context_unmap_bo_address(context, &data, GL_PIXEL_UNPACK_BUFFER);
2023 
2024         data.buffer_object = 0;
2025         data.addr = dst_mem;
2026     }
2027 
2028     wined3d_texture_upload_data(texture, sub_resource_idx, context, format, &src_box,
2029             wined3d_const_bo_address(&data), src_row_pitch, src_slice_pitch, 0, 0, 0, srgb);
2030 
2031     heap_free(dst_mem);
2032 
2033     return TRUE;
2034 }
2035 
2036 /* Context activation is done by the caller. */
2037 BOOL texture2d_load_renderbuffer(struct wined3d_texture *texture, unsigned int sub_resource_idx,
2038         struct wined3d_context *context, DWORD dst_location)
2039 {
2040     unsigned int level = sub_resource_idx % texture->level_count;
2041     const RECT rect = {0, 0,
2042             wined3d_texture_get_level_width(texture, level),
2043             wined3d_texture_get_level_height(texture, level)};
2044     struct wined3d_texture_sub_resource *sub_resource;
2045     DWORD src_location, locations;
2046 
2047     sub_resource = &texture->sub_resources[sub_resource_idx];
2048     locations = sub_resource->locations;
2049     if (texture->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
2050     {
2051         FIXME("Unimplemented copy from %s for depth/stencil buffers.\n",
2052                 wined3d_debug_location(locations));
2053         return FALSE;
2054     }
2055 
2056     if (locations & WINED3D_LOCATION_RB_MULTISAMPLE)
2057         src_location = WINED3D_LOCATION_RB_MULTISAMPLE;
2058     else if (locations & WINED3D_LOCATION_RB_RESOLVED)
2059         src_location = WINED3D_LOCATION_RB_RESOLVED;
2060     else if (locations & WINED3D_LOCATION_TEXTURE_SRGB)
2061         src_location = WINED3D_LOCATION_TEXTURE_SRGB;
2062     else if (locations & WINED3D_LOCATION_TEXTURE_RGB)
2063         src_location = WINED3D_LOCATION_TEXTURE_RGB;
2064     else if (locations & WINED3D_LOCATION_DRAWABLE)
2065         src_location = WINED3D_LOCATION_DRAWABLE;
2066     else /* texture2d_blt_fbo() will load the source location if necessary. */
2067         src_location = WINED3D_LOCATION_TEXTURE_RGB;
2068 
2069     texture2d_blt_fbo(texture->resource.device, context, WINED3D_TEXF_POINT, texture,
2070             sub_resource_idx, src_location, &rect, texture, sub_resource_idx, dst_location, &rect);
2071 
2072     return TRUE;
2073 }
2074 
2075 /* Context activation is done by the caller. */
2076 static void fbo_blitter_destroy(struct wined3d_blitter *blitter, struct wined3d_context *context)
2077 {
2078     struct wined3d_blitter *next;
2079 
2080     if ((next = blitter->next))
2081         next->ops->blitter_destroy(next, context);
2082 
2083     heap_free(blitter);
2084 }
2085 
2086 static void fbo_blitter_clear(struct wined3d_blitter *blitter, struct wined3d_device *device,
2087         unsigned int rt_count, const struct wined3d_fb_state *fb, unsigned int rect_count, const RECT *clear_rects,
2088         const RECT *draw_rect, DWORD flags, const struct wined3d_color *colour, float depth, DWORD stencil)
2089 {
2090     struct wined3d_blitter *next;
2091 
2092     if ((next = blitter->next))
2093         next->ops->blitter_clear(next, device, rt_count, fb, rect_count,
2094                 clear_rects, draw_rect, flags, colour, depth, stencil);
2095 }
2096 
2097 static DWORD fbo_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_blit_op op,
2098         struct wined3d_context *context, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx,
2099         DWORD src_location, const RECT *src_rect, struct wined3d_texture *dst_texture,
2100         unsigned int dst_sub_resource_idx, DWORD dst_location, const RECT *dst_rect,
2101         const struct wined3d_color_key *colour_key, enum wined3d_texture_filter_type filter)
2102 {
2103     struct wined3d_resource *src_resource, *dst_resource;
2104     enum wined3d_blit_op blit_op = op;
2105     struct wined3d_device *device;
2106     struct wined3d_blitter *next;
2107 
2108     TRACE("blitter %p, op %#x, context %p, src_texture %p, src_sub_resource_idx %u, src_location %s, src_rect %s, "
2109             "dst_texture %p, dst_sub_resource_idx %u, dst_location %s, dst_rect %s, colour_key %p, filter %s.\n",
2110             blitter, op, context, src_texture, src_sub_resource_idx, wined3d_debug_location(src_location),
2111             wine_dbgstr_rect(src_rect), dst_texture, dst_sub_resource_idx, wined3d_debug_location(dst_location),
2112             wine_dbgstr_rect(dst_rect), colour_key, debug_d3dtexturefiltertype(filter));
2113 
2114     src_resource = &src_texture->resource;
2115     dst_resource = &dst_texture->resource;
2116 
2117     device = dst_resource->device;
2118 
2119     if (blit_op == WINED3D_BLIT_OP_RAW_BLIT && dst_resource->format->id == src_resource->format->id)
2120     {
2121         if (dst_resource->format_flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL))
2122             blit_op = WINED3D_BLIT_OP_DEPTH_BLIT;
2123         else
2124             blit_op = WINED3D_BLIT_OP_COLOR_BLIT;
2125     }
2126 
2127     if (!fbo_blitter_supported(blit_op, context->gl_info,
2128             src_resource, src_location, dst_resource, dst_location))
2129     {
2130         if (!(next = blitter->next))
2131         {
2132             ERR("No blitter to handle blit op %#x.\n", op);
2133             return dst_location;
2134         }
2135 
2136         TRACE("Forwarding to blitter %p.\n", next);
2137         return next->ops->blitter_blit(next, op, context, src_texture, src_sub_resource_idx, src_location,
2138                 src_rect, dst_texture, dst_sub_resource_idx, dst_location, dst_rect, colour_key, filter);
2139     }
2140 
2141     if (blit_op == WINED3D_BLIT_OP_COLOR_BLIT)
2142     {
2143         TRACE("Colour blit.\n");
2144         texture2d_blt_fbo(device, context, filter, src_texture, src_sub_resource_idx, src_location,
2145                 src_rect, dst_texture, dst_sub_resource_idx, dst_location, dst_rect);
2146         return dst_location;
2147     }
2148 
2149     if (blit_op == WINED3D_BLIT_OP_DEPTH_BLIT)
2150     {
2151         TRACE("Depth/stencil blit.\n");
2152         texture2d_depth_blt_fbo(device, context, src_texture, src_sub_resource_idx, src_location,
2153                 src_rect, dst_texture, dst_sub_resource_idx, dst_location, dst_rect);
2154         return dst_location;
2155     }
2156 
2157     ERR("This blitter does not implement blit op %#x.\n", blit_op);
2158     return dst_location;
2159 }
2160 
2161 static const struct wined3d_blitter_ops fbo_blitter_ops =
2162 {
2163     fbo_blitter_destroy,
2164     fbo_blitter_clear,
2165     fbo_blitter_blit,
2166 };
2167 
2168 void wined3d_fbo_blitter_create(struct wined3d_blitter **next, const struct wined3d_gl_info *gl_info)
2169 {
2170     struct wined3d_blitter *blitter;
2171 
2172     if ((wined3d_settings.offscreen_rendering_mode != ORM_FBO) || !gl_info->fbo_ops.glBlitFramebuffer)
2173         return;
2174 
2175     if (!(blitter = heap_alloc(sizeof(*blitter))))
2176         return;
2177 
2178     TRACE("Created blitter %p.\n", blitter);
2179 
2180     blitter->ops = &fbo_blitter_ops;
2181     blitter->next = *next;
2182     *next = blitter;
2183 }
2184 
2185 /* Context activation is done by the caller. */
2186 static void raw_blitter_destroy(struct wined3d_blitter *blitter, struct wined3d_context *context)
2187 {
2188     struct wined3d_blitter *next;
2189 
2190     if ((next = blitter->next))
2191         next->ops->blitter_destroy(next, context);
2192 
2193     heap_free(blitter);
2194 }
2195 
2196 /* Context activation is done by the caller. */
2197 static void raw_blitter_clear(struct wined3d_blitter *blitter, struct wined3d_device *device,
2198         unsigned int rt_count, const struct wined3d_fb_state *fb, unsigned int rect_count, const RECT *clear_rects,
2199         const RECT *draw_rect, DWORD flags, const struct wined3d_color *colour, float depth, DWORD stencil)
2200 {
2201     struct wined3d_blitter *next;
2202 
2203     if (!(next = blitter->next))
2204     {
2205         ERR("No blitter to handle clear.\n");
2206         return;
2207     }
2208 
2209     TRACE("Forwarding to blitter %p.\n", next);
2210     next->ops->blitter_clear(next, device, rt_count, fb, rect_count,
2211             clear_rects, draw_rect, flags, colour, depth, stencil);
2212 }
2213 
2214 /* Context activation is done by the caller. */
2215 static DWORD raw_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_blit_op op,
2216         struct wined3d_context *context, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx,
2217         DWORD src_location, const RECT *src_rect, struct wined3d_texture *dst_texture,
2218         unsigned int dst_sub_resource_idx, DWORD dst_location, const RECT *dst_rect,
2219         const struct wined3d_color_key *colour_key, enum wined3d_texture_filter_type filter)
2220 {
2221     const struct wined3d_gl_info *gl_info = context->gl_info;
2222     unsigned int src_level, src_layer, dst_level, dst_layer;
2223     struct wined3d_blitter *next;
2224     GLuint src_name, dst_name;
2225     DWORD location;
2226 
2227     /* If we would need to copy from a renderbuffer or drawable, we'd probably
2228      * be better of using the FBO blitter directly, since we'd need to use it
2229      * to copy the resource contents to the texture anyway. */
2230     if (op != WINED3D_BLIT_OP_RAW_BLIT
2231             || (src_texture->resource.format->id == dst_texture->resource.format->id
2232             && (!(src_location & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB))
2233             || !(dst_location & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB)))))
2234     {
2235         if (!(next = blitter->next))
2236         {
2237             ERR("No blitter to handle blit op %#x.\n", op);
2238             return dst_location;
2239         }
2240 
2241         TRACE("Forwarding to blitter %p.\n", next);
2242         return next->ops->blitter_blit(next, op, context, src_texture, src_sub_resource_idx, src_location,
2243                 src_rect, dst_texture, dst_sub_resource_idx, dst_location, dst_rect, colour_key, filter);
2244     }
2245 
2246     TRACE("Blit using ARB_copy_image.\n");
2247 
2248     src_level = src_sub_resource_idx % src_texture->level_count;
2249     src_layer = src_sub_resource_idx / src_texture->level_count;
2250 
2251     dst_level = dst_sub_resource_idx % dst_texture->level_count;
2252     dst_layer = dst_sub_resource_idx / dst_texture->level_count;
2253 
2254     location = src_location & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB);
2255     if (!location)
2256         location = src_texture->flags & WINED3D_TEXTURE_IS_SRGB
2257                 ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB;
2258     if (!wined3d_texture_load_location(src_texture, src_sub_resource_idx, context, location))
2259         ERR("Failed to load the source sub-resource into %s.\n", wined3d_debug_location(location));
2260     src_name = wined3d_texture_get_texture_name(src_texture, context, location == WINED3D_LOCATION_TEXTURE_SRGB);
2261 
2262     location = dst_location & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB);
2263     if (!location)
2264         location = dst_texture->flags & WINED3D_TEXTURE_IS_SRGB
2265                 ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB;
2266     if (texture2d_is_full_rect(dst_texture, dst_level, dst_rect))
2267     {
2268         if (!wined3d_texture_prepare_location(dst_texture, dst_sub_resource_idx, context, location))
2269             ERR("Failed to prepare the destination sub-resource into %s.\n", wined3d_debug_location(location));
2270     }
2271     else
2272     {
2273         if (!wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, location))
2274             ERR("Failed to load the destination sub-resource into %s.\n", wined3d_debug_location(location));
2275     }
2276     dst_name = wined3d_texture_get_texture_name(dst_texture, context, location == WINED3D_LOCATION_TEXTURE_SRGB);
2277 
2278     GL_EXTCALL(glCopyImageSubData(src_name, src_texture->target, src_level,
2279             src_rect->left, src_rect->top, src_layer, dst_name, dst_texture->target, dst_level,
2280             dst_rect->left, dst_rect->top, dst_layer, src_rect->right - src_rect->left,
2281             src_rect->bottom - src_rect->top, 1));
2282     checkGLcall("copy image data");
2283 
2284     wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, location);
2285     wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~location);
2286     if (!wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, dst_location))
2287         ERR("Failed to load the destination sub-resource into %s.\n", wined3d_debug_location(dst_location));
2288 
2289     return dst_location | location;
2290 }
2291 
2292 static const struct wined3d_blitter_ops raw_blitter_ops =
2293 {
2294     raw_blitter_destroy,
2295     raw_blitter_clear,
2296     raw_blitter_blit,
2297 };
2298 
2299 void wined3d_raw_blitter_create(struct wined3d_blitter **next, const struct wined3d_gl_info *gl_info)
2300 {
2301     struct wined3d_blitter *blitter;
2302 
2303     if (!gl_info->supported[ARB_COPY_IMAGE])
2304         return;
2305 
2306     if (!(blitter = heap_alloc(sizeof(*blitter))))
2307         return;
2308 
2309     TRACE("Created blitter %p.\n", blitter);
2310 
2311     blitter->ops = &raw_blitter_ops;
2312     blitter->next = *next;
2313     *next = blitter;
2314 }
2315 
2316 /* Context activation is done by the caller. */
2317 static void ffp_blitter_destroy(struct wined3d_blitter *blitter, struct wined3d_context *context)
2318 {
2319     struct wined3d_blitter *next;
2320 
2321     if ((next = blitter->next))
2322         next->ops->blitter_destroy(next, context);
2323 
2324     heap_free(blitter);
2325 }
2326 
2327 static BOOL ffp_blit_supported(enum wined3d_blit_op blit_op, const struct wined3d_context *context,
2328         const struct wined3d_resource *src_resource, DWORD src_location,
2329         const struct wined3d_resource *dst_resource, DWORD dst_location)
2330 {
2331     const struct wined3d_format *src_format = src_resource->format;
2332     const struct wined3d_format *dst_format = dst_resource->format;
2333     BOOL decompress;
2334 
2335     if (src_resource->type != WINED3D_RTYPE_TEXTURE_2D)
2336         return FALSE;
2337 
2338     decompress = src_format && (src_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_COMPRESSED)
2339             && !(dst_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_COMPRESSED);
2340     if (!decompress && !(src_resource->access & dst_resource->access & WINED3D_RESOURCE_ACCESS_GPU))
2341     {
2342         TRACE("Source or destination resource is not GPU accessible.\n");
2343         return FALSE;
2344     }
2345 
2346     if (blit_op == WINED3D_BLIT_OP_RAW_BLIT && dst_format->id == src_format->id)
2347     {
2348         if (dst_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL))
2349             blit_op = WINED3D_BLIT_OP_DEPTH_BLIT;
2350         else
2351             blit_op = WINED3D_BLIT_OP_COLOR_BLIT;
2352     }
2353 
2354     switch (blit_op)
2355     {
2356         case WINED3D_BLIT_OP_COLOR_BLIT_CKEY:
2357             if (context->d3d_info->shader_color_key)
2358             {
2359                 TRACE("Color keying requires converted textures.\n");
2360                 return FALSE;
2361             }
2362         case WINED3D_BLIT_OP_COLOR_BLIT:
2363         case WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST:
2364             if (!context->gl_info->supported[WINED3D_GL_LEGACY_CONTEXT])
2365                 return FALSE;
2366 
2367             if (TRACE_ON(d3d))
2368             {
2369                 TRACE("Checking support for fixup:\n");
2370                 dump_color_fixup_desc(src_format->color_fixup);
2371             }
2372 
2373             /* We only support identity conversions. */
2374             if (!is_identity_fixup(src_format->color_fixup)
2375                     || !is_identity_fixup(dst_format->color_fixup))
2376             {
2377                 if (wined3d_settings.offscreen_rendering_mode == ORM_BACKBUFFER
2378                         && dst_format->id == src_format->id && dst_location == WINED3D_LOCATION_DRAWABLE)
2379                 {
2380                     WARN("Claiming fixup support because of ORM_BACKBUFFER.\n");
2381                 }
2382                 else
2383                 {
2384                     TRACE("Fixups are not supported.\n");
2385                     return FALSE;
2386                 }
2387             }
2388 
2389             if (!(dst_resource->usage & WINED3DUSAGE_RENDERTARGET))
2390             {
2391                 TRACE("Can only blit to render targets.\n");
2392                 return FALSE;
2393             }
2394             return TRUE;
2395 
2396         default:
2397             TRACE("Unsupported blit operation %#x.\n", blit_op);
2398             return FALSE;
2399     }
2400 }
2401 
2402 static BOOL ffp_blitter_use_cpu_clear(struct wined3d_rendertarget_view *view)
2403 {
2404     struct wined3d_resource *resource;
2405     struct wined3d_texture *texture;
2406     DWORD locations;
2407 
2408     resource = view->resource;
2409     if (resource->type == WINED3D_RTYPE_BUFFER)
2410         return !(resource->access & WINED3D_RESOURCE_ACCESS_GPU);
2411 
2412     texture = texture_from_resource(resource);
2413     locations = texture->sub_resources[view->sub_resource_idx].locations;
2414     if (locations & (resource->map_binding | WINED3D_LOCATION_DISCARDED))
2415         return !(resource->access & WINED3D_RESOURCE_ACCESS_GPU)
2416                 || (texture->flags & WINED3D_TEXTURE_PIN_SYSMEM);
2417 
2418     return !(resource->access & WINED3D_RESOURCE_ACCESS_GPU)
2419             && !(texture->flags & WINED3D_TEXTURE_CONVERTED);
2420 }
2421 
2422 static void ffp_blitter_clear(struct wined3d_blitter *blitter, struct wined3d_device *device,
2423         unsigned int rt_count, const struct wined3d_fb_state *fb, unsigned int rect_count, const RECT *clear_rects,
2424         const RECT *draw_rect, DWORD flags, const struct wined3d_color *colour, float depth, DWORD stencil)
2425 {
2426     struct wined3d_rendertarget_view *view;
2427     struct wined3d_blitter *next;
2428     DWORD next_flags = 0;
2429     unsigned int i;
2430 
2431     if (flags & WINED3DCLEAR_TARGET)
2432     {
2433         for (i = 0; i < rt_count; ++i)
2434         {
2435             if (!(view = fb->render_targets[i]))
2436                 continue;
2437 
2438             if (ffp_blitter_use_cpu_clear(view)
2439                     || (!(view->resource->usage & WINED3DUSAGE_RENDERTARGET)
2440                     && (wined3d_settings.offscreen_rendering_mode != ORM_FBO
2441                     || !(view->format_flags & WINED3DFMT_FLAG_FBO_ATTACHABLE))))
2442             {
2443                 next_flags |= WINED3DCLEAR_TARGET;
2444                 flags &= ~WINED3DCLEAR_TARGET;
2445                 break;
2446             }
2447 
2448             /* FIXME: We should reject colour fills on formats with fixups,
2449              * but this would break P8 colour fills for example. */
2450         }
2451     }
2452 
2453     if ((flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL)) && (view = fb->depth_stencil)
2454             && (!view->format->depth_size || (flags & WINED3DCLEAR_ZBUFFER))
2455             && (!view->format->stencil_size || (flags & WINED3DCLEAR_STENCIL))
2456             && ffp_blitter_use_cpu_clear(view))
2457     {
2458         next_flags |= flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL);
2459         flags &= ~(WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL);
2460     }
2461 
2462     if (flags)
2463         device_clear_render_targets(device, rt_count, fb, rect_count,
2464                 clear_rects, draw_rect, flags, colour, depth, stencil);
2465 
2466     if (next_flags && (next = blitter->next))
2467         next->ops->blitter_clear(next, device, rt_count, fb, rect_count,
2468                 clear_rects, draw_rect, next_flags, colour, depth, stencil);
2469 }
2470 
2471 static DWORD ffp_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_blit_op op,
2472         struct wined3d_context *context, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx,
2473         DWORD src_location, const RECT *src_rect, struct wined3d_texture *dst_texture,
2474         unsigned int dst_sub_resource_idx, DWORD dst_location, const RECT *dst_rect,
2475         const struct wined3d_color_key *color_key, enum wined3d_texture_filter_type filter)
2476 {
2477     const struct wined3d_gl_info *gl_info = context->gl_info;
2478     struct wined3d_resource *src_resource, *dst_resource;
2479     struct wined3d_texture *staging_texture = NULL;
2480     struct wined3d_color_key old_blt_key;
2481     struct wined3d_device *device;
2482     struct wined3d_blitter *next;
2483     DWORD old_color_key_flags;
2484     RECT r;
2485 
2486     src_resource = &src_texture->resource;
2487     dst_resource = &dst_texture->resource;
2488     device = dst_resource->device;
2489 
2490     if (!ffp_blit_supported(op, context, src_resource, src_location, dst_resource, dst_location))
2491     {
2492         if ((next = blitter->next))
2493             return next->ops->blitter_blit(next, op, context, src_texture, src_sub_resource_idx, src_location,
2494                     src_rect, dst_texture, dst_sub_resource_idx, dst_location, dst_rect, color_key, filter);
2495     }
2496 
2497     TRACE("Blt from texture %p, %u to rendertarget %p, %u.\n",
2498             src_texture, src_sub_resource_idx, dst_texture, dst_sub_resource_idx);
2499 
2500     old_blt_key = src_texture->async.src_blt_color_key;
2501     old_color_key_flags = src_texture->async.color_key_flags;
2502     wined3d_texture_set_color_key(src_texture, WINED3D_CKEY_SRC_BLT, color_key);
2503 
2504     if (!(src_texture->resource.access & WINED3D_RESOURCE_ACCESS_GPU))
2505     {
2506         struct wined3d_resource_desc desc;
2507         struct wined3d_box upload_box;
2508         unsigned int src_level;
2509         HRESULT hr;
2510 
2511         TRACE("Source texture is not GPU accessible, creating a staging texture.\n");
2512 
2513         src_level = src_sub_resource_idx % src_texture->level_count;
2514         desc.resource_type = WINED3D_RTYPE_TEXTURE_2D;
2515         desc.format = src_texture->resource.format->id;
2516         desc.multisample_type = src_texture->resource.multisample_type;
2517         desc.multisample_quality = src_texture->resource.multisample_quality;
2518         desc.usage = WINED3DUSAGE_PRIVATE;
2519         desc.access = WINED3D_RESOURCE_ACCESS_GPU;
2520         desc.width = wined3d_texture_get_level_width(src_texture, src_level);
2521         desc.height = wined3d_texture_get_level_height(src_texture, src_level);
2522         desc.depth = 1;
2523         desc.size = 0;
2524 
2525         if (FAILED(hr = wined3d_texture_create(device, &desc, 1, 1, 0,
2526                 NULL, NULL, &wined3d_null_parent_ops, &staging_texture)))
2527         {
2528             ERR("Failed to create staging texture, hr %#x.\n", hr);
2529             return dst_location;
2530         }
2531 
2532         wined3d_box_set(&upload_box, 0, 0, desc.width, desc.height, 0, desc.depth);
2533         wined3d_texture_upload_from_texture(staging_texture, 0, 0, 0, 0,
2534                 src_texture, src_sub_resource_idx, &upload_box);
2535 
2536         src_texture = staging_texture;
2537         src_sub_resource_idx = 0;
2538     }
2539     else
2540     {
2541         /* Make sure the surface is up-to-date. This should probably use
2542          * surface_load_location() and worry about the destination surface
2543          * too, unless we're overwriting it completely. */
2544         wined3d_texture_load(src_texture, context, FALSE);
2545     }
2546 
2547     context_apply_ffp_blit_state(context, device);
2548 
2549     if (dst_location == WINED3D_LOCATION_DRAWABLE)
2550     {
2551         r = *dst_rect;
2552         wined3d_texture_translate_drawable_coords(dst_texture, context->win_handle, &r);
2553         dst_rect = &r;
2554     }
2555 
2556     if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
2557     {
2558         GLenum buffer;
2559 
2560         if (dst_location == WINED3D_LOCATION_DRAWABLE)
2561         {
2562             TRACE("Destination texture %p is onscreen.\n", dst_texture);
2563             buffer = wined3d_texture_get_gl_buffer(dst_texture);
2564         }
2565         else
2566         {
2567             TRACE("Destination texture %p is offscreen.\n", dst_texture);
2568             buffer = GL_COLOR_ATTACHMENT0;
2569         }
2570         context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER,
2571                 dst_resource, dst_sub_resource_idx, NULL, 0, dst_location);
2572         context_set_draw_buffer(context, buffer);
2573         context_check_fbo_status(context, GL_DRAW_FRAMEBUFFER);
2574         context_invalidate_state(context, STATE_FRAMEBUFFER);
2575     }
2576 
2577     gl_info->gl_ops.gl.p_glEnable(src_texture->target);
2578     checkGLcall("glEnable(target)");
2579 
2580     if (op == WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST || color_key)
2581     {
2582         gl_info->gl_ops.gl.p_glEnable(GL_ALPHA_TEST);
2583         checkGLcall("glEnable(GL_ALPHA_TEST)");
2584     }
2585 
2586     if (color_key)
2587     {
2588         /* For P8 surfaces, the alpha component contains the palette index.
2589          * Which means that the colorkey is one of the palette entries. In
2590          * other cases pixels that should be masked away have alpha set to 0. */
2591         if (src_texture->resource.format->id == WINED3DFMT_P8_UINT)
2592             gl_info->gl_ops.gl.p_glAlphaFunc(GL_NOTEQUAL,
2593                     (float)src_texture->async.src_blt_color_key.color_space_low_value / 255.0f);
2594         else
2595             gl_info->gl_ops.gl.p_glAlphaFunc(GL_NOTEQUAL, 0.0f);
2596         checkGLcall("glAlphaFunc");
2597     }
2598 
2599     context_draw_textured_quad(context, src_texture, src_sub_resource_idx, src_rect, dst_rect, filter);
2600 
2601     if (op == WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST || color_key)
2602     {
2603         gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
2604         checkGLcall("glDisable(GL_ALPHA_TEST)");
2605     }
2606 
2607     gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_2D);
2608     checkGLcall("glDisable(GL_TEXTURE_2D)");
2609     if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
2610     {
2611         gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_CUBE_MAP_ARB);
2612         checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
2613     }
2614     if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
2615     {
2616         gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_RECTANGLE_ARB);
2617         checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)");
2618     }
2619 
2620     if (dst_texture->swapchain && dst_texture->swapchain->front_buffer == dst_texture)
2621         gl_info->gl_ops.gl.p_glFlush();
2622 
2623     /* Restore the color key parameters */
2624     wined3d_texture_set_color_key(src_texture, WINED3D_CKEY_SRC_BLT,
2625             (old_color_key_flags & WINED3D_CKEY_SRC_BLT) ? &old_blt_key : NULL);
2626 
2627     if (staging_texture)
2628         wined3d_texture_decref(staging_texture);
2629 
2630     return dst_location;
2631 }
2632 
2633 static const struct wined3d_blitter_ops ffp_blitter_ops =
2634 {
2635     ffp_blitter_destroy,
2636     ffp_blitter_clear,
2637     ffp_blitter_blit,
2638 };
2639 
2640 void wined3d_ffp_blitter_create(struct wined3d_blitter **next, const struct wined3d_gl_info *gl_info)
2641 {
2642     struct wined3d_blitter *blitter;
2643 
2644     if (!(blitter = heap_alloc(sizeof(*blitter))))
2645         return;
2646 
2647     TRACE("Created blitter %p.\n", blitter);
2648 
2649     blitter->ops = &ffp_blitter_ops;
2650     blitter->next = *next;
2651     *next = blitter;
2652 }
2653 
2654 /* Context activation is done by the caller. */
2655 static void cpu_blitter_destroy(struct wined3d_blitter *blitter, struct wined3d_context *context)
2656 {
2657     struct wined3d_blitter *next;
2658 
2659     if ((next = blitter->next))
2660         next->ops->blitter_destroy(next, context);
2661 
2662     heap_free(blitter);
2663 }
2664 
2665 static HRESULT surface_cpu_blt_compressed(const BYTE *src_data, BYTE *dst_data,
2666         UINT src_pitch, UINT dst_pitch, UINT update_w, UINT update_h,
2667         const struct wined3d_format *format, DWORD flags, const struct wined3d_blt_fx *fx)
2668 {
2669     UINT row_block_count;
2670     const BYTE *src_row;
2671     BYTE *dst_row;
2672     UINT x, y;
2673 
2674     src_row = src_data;
2675     dst_row = dst_data;
2676 
2677     row_block_count = (update_w + format->block_width - 1) / format->block_width;
2678 
2679     if (!flags)
2680     {
2681         for (y = 0; y < update_h; y += format->block_height)
2682         {
2683             memcpy(dst_row, src_row, row_block_count * format->block_byte_count);
2684             src_row += src_pitch;
2685             dst_row += dst_pitch;
2686         }
2687 
2688         return WINED3D_OK;
2689     }
2690 
2691     if (flags == WINED3D_BLT_FX && fx->fx == WINEDDBLTFX_MIRRORUPDOWN)
2692     {
2693         src_row += (((update_h / format->block_height) - 1) * src_pitch);
2694 
2695         switch (format->id)
2696         {
2697             case WINED3DFMT_DXT1:
2698                 for (y = 0; y < update_h; y += format->block_height)
2699                 {
2700                     struct block
2701                     {
2702                         WORD color[2];
2703                         BYTE control_row[4];
2704                     };
2705 
2706                     const struct block *s = (const struct block *)src_row;
2707                     struct block *d = (struct block *)dst_row;
2708 
2709                     for (x = 0; x < row_block_count; ++x)
2710                     {
2711                         d[x].color[0] = s[x].color[0];
2712                         d[x].color[1] = s[x].color[1];
2713                         d[x].control_row[0] = s[x].control_row[3];
2714                         d[x].control_row[1] = s[x].control_row[2];
2715                         d[x].control_row[2] = s[x].control_row[1];
2716                         d[x].control_row[3] = s[x].control_row[0];
2717                     }
2718                     src_row -= src_pitch;
2719                     dst_row += dst_pitch;
2720                 }
2721                 return WINED3D_OK;
2722 
2723             case WINED3DFMT_DXT2:
2724             case WINED3DFMT_DXT3:
2725                 for (y = 0; y < update_h; y += format->block_height)
2726                 {
2727                     struct block
2728                     {
2729                         WORD alpha_row[4];
2730                         WORD color[2];
2731                         BYTE control_row[4];
2732                     };
2733 
2734                     const struct block *s = (const struct block *)src_row;
2735                     struct block *d = (struct block *)dst_row;
2736 
2737                     for (x = 0; x < row_block_count; ++x)
2738                     {
2739                         d[x].alpha_row[0] = s[x].alpha_row[3];
2740                         d[x].alpha_row[1] = s[x].alpha_row[2];
2741                         d[x].alpha_row[2] = s[x].alpha_row[1];
2742                         d[x].alpha_row[3] = s[x].alpha_row[0];
2743                         d[x].color[0] = s[x].color[0];
2744                         d[x].color[1] = s[x].color[1];
2745                         d[x].control_row[0] = s[x].control_row[3];
2746                         d[x].control_row[1] = s[x].control_row[2];
2747                         d[x].control_row[2] = s[x].control_row[1];
2748                         d[x].control_row[3] = s[x].control_row[0];
2749                     }
2750                     src_row -= src_pitch;
2751                     dst_row += dst_pitch;
2752                 }
2753                 return WINED3D_OK;
2754 
2755             default:
2756                 FIXME("Compressed flip not implemented for format %s.\n",
2757                         debug_d3dformat(format->id));
2758                 return E_NOTIMPL;
2759         }
2760     }
2761 
2762     FIXME("Unsupported blit on compressed surface (format %s, flags %#x, DDFX %#x).\n",
2763             debug_d3dformat(format->id), flags, flags & WINED3D_BLT_FX ? fx->fx : 0);
2764 
2765     return E_NOTIMPL;
2766 }
2767 
2768 static HRESULT surface_cpu_blt(struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx,
2769         const struct wined3d_box *dst_box, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx,
2770         const struct wined3d_box *src_box, DWORD flags, const struct wined3d_blt_fx *fx,
2771         enum wined3d_texture_filter_type filter)
2772 {
2773     unsigned int bpp, src_height, src_width, dst_height, dst_width, row_byte_count;
2774     struct wined3d_device *device = dst_texture->resource.device;
2775     const struct wined3d_format *src_format, *dst_format;
2776     struct wined3d_texture *converted_texture = NULL;
2777     struct wined3d_bo_address src_data, dst_data;
2778     unsigned int src_fmt_flags, dst_fmt_flags;
2779     struct wined3d_map_desc dst_map, src_map;
2780     struct wined3d_context *context = NULL;
2781     unsigned int x, sx, xinc, y, sy, yinc;
2782     unsigned int texture_level;
2783     HRESULT hr = WINED3D_OK;
2784     BOOL same_sub_resource;
2785     DWORD map_binding;
2786     const BYTE *sbase;
2787     const BYTE *sbuf;
2788     BYTE *dbuf;
2789 
2790     TRACE("dst_texture %p, dst_sub_resource_idx %u, dst_box %s, src_texture %p, "
2791             "src_sub_resource_idx %u, src_box %s, flags %#x, fx %p, filter %s.\n",
2792             dst_texture, dst_sub_resource_idx, debug_box(dst_box), src_texture,
2793             src_sub_resource_idx, debug_box(src_box), flags, fx, debug_d3dtexturefiltertype(filter));
2794 
2795     if (device->d3d_initialized)
2796         context = context_acquire(device, NULL, 0);
2797 
2798     if (src_texture == dst_texture && src_sub_resource_idx == dst_sub_resource_idx)
2799     {
2800         same_sub_resource = TRUE;
2801 
2802         map_binding = dst_texture->resource.map_binding;
2803         texture_level = dst_sub_resource_idx % dst_texture->level_count;
2804         if (!wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, map_binding))
2805             ERR("Failed to load the destination sub-resource into %s.\n", wined3d_debug_location(map_binding));
2806         wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~map_binding);
2807         wined3d_texture_get_pitch(dst_texture, texture_level, &dst_map.row_pitch, &dst_map.slice_pitch);
2808         wined3d_texture_get_memory(dst_texture, dst_sub_resource_idx, &dst_data, map_binding);
2809         dst_map.data = context_map_bo_address(context, &dst_data,
2810                 dst_texture->sub_resources[dst_sub_resource_idx].size,
2811                 GL_PIXEL_UNPACK_BUFFER, WINED3D_MAP_READ | WINED3D_MAP_WRITE);
2812 
2813         src_map = dst_map;
2814         src_format = dst_texture->resource.format;
2815         dst_format = src_format;
2816         dst_fmt_flags = dst_texture->resource.format_flags;
2817         src_fmt_flags = dst_fmt_flags;
2818     }
2819     else
2820     {
2821         same_sub_resource = FALSE;
2822         dst_format = dst_texture->resource.format;
2823         dst_fmt_flags = dst_texture->resource.format_flags;
2824         if (!(flags & WINED3D_BLT_RAW) && dst_texture->resource.format->id != src_texture->resource.format->id)
2825         {
2826             if (!(converted_texture = surface_convert_format(src_texture, src_sub_resource_idx, dst_format)))
2827             {
2828                 FIXME("Cannot convert %s to %s.\n", debug_d3dformat(src_texture->resource.format->id),
2829                         debug_d3dformat(dst_texture->resource.format->id));
2830                 if (context)
2831                     context_release(context);
2832                 return WINED3DERR_NOTAVAILABLE;
2833             }
2834             src_texture = converted_texture;
2835             src_sub_resource_idx = 0;
2836         }
2837         src_format = src_texture->resource.format;
2838         src_fmt_flags = src_texture->resource.format_flags;
2839 
2840         map_binding = src_texture->resource.map_binding;
2841         texture_level = src_sub_resource_idx % src_texture->level_count;
2842         if (!wined3d_texture_load_location(src_texture, src_sub_resource_idx, context, map_binding))
2843             ERR("Failed to load the source sub-resource into %s.\n", wined3d_debug_location(map_binding));
2844         wined3d_texture_get_pitch(src_texture, texture_level, &src_map.row_pitch, &src_map.slice_pitch);
2845         wined3d_texture_get_memory(src_texture, src_sub_resource_idx, &src_data, map_binding);
2846         src_map.data = context_map_bo_address(context, &src_data,
2847                 src_texture->sub_resources[src_sub_resource_idx].size, GL_PIXEL_UNPACK_BUFFER, WINED3D_MAP_READ);
2848 
2849         map_binding = dst_texture->resource.map_binding;
2850         texture_level = dst_sub_resource_idx % dst_texture->level_count;
2851         if (!wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, map_binding))
2852             ERR("Failed to load the destination sub-resource into %s.\n", wined3d_debug_location(map_binding));
2853         wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~map_binding);
2854         wined3d_texture_get_pitch(dst_texture, texture_level, &dst_map.row_pitch, &dst_map.slice_pitch);
2855         wined3d_texture_get_memory(dst_texture, dst_sub_resource_idx, &dst_data, map_binding);
2856         dst_map.data = context_map_bo_address(context, &dst_data,
2857                 dst_texture->sub_resources[dst_sub_resource_idx].size, GL_PIXEL_UNPACK_BUFFER, WINED3D_MAP_WRITE);
2858     }
2859     flags &= ~WINED3D_BLT_RAW;
2860 
2861     bpp = dst_format->byte_count;
2862     src_height = src_box->bottom - src_box->top;
2863     src_width = src_box->right - src_box->left;
2864     dst_height = dst_box->bottom - dst_box->top;
2865     dst_width = dst_box->right - dst_box->left;
2866     row_byte_count = dst_width * bpp;
2867 
2868     sbase = (BYTE *)src_map.data
2869             + ((src_box->top / src_format->block_height) * src_map.row_pitch)
2870             + ((src_box->left / src_format->block_width) * src_format->block_byte_count);
2871     dbuf = (BYTE *)dst_map.data
2872             + ((dst_box->top / dst_format->block_height) * dst_map.row_pitch)
2873             + ((dst_box->left / dst_format->block_width) * dst_format->block_byte_count);
2874 
2875     if (src_fmt_flags & dst_fmt_flags & WINED3DFMT_FLAG_BLOCKS)
2876     {
2877         TRACE("%s -> %s copy.\n", debug_d3dformat(src_format->id), debug_d3dformat(dst_format->id));
2878 
2879         if (same_sub_resource)
2880         {
2881             FIXME("Only plain blits supported on compressed surfaces.\n");
2882             hr = E_NOTIMPL;
2883             goto release;
2884         }
2885 
2886         if (src_height != dst_height || src_width != dst_width)
2887         {
2888             WARN("Stretching not supported on compressed surfaces.\n");
2889             hr = WINED3DERR_INVALIDCALL;
2890             goto release;
2891         }
2892 
2893         hr = surface_cpu_blt_compressed(sbase, dbuf,
2894                 src_map.row_pitch, dst_map.row_pitch, dst_width, dst_height,
2895                 src_format, flags, fx);
2896         goto release;
2897     }
2898 
2899     if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT
2900             && (src_width != dst_width || src_height != dst_height))
2901     {
2902         /* Can happen when d3d9 apps do a StretchRect() call which isn't handled in GL. */
2903         static int once;
2904         if (!once++) FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(filter));
2905     }
2906 
2907     xinc = (src_width << 16) / dst_width;
2908     yinc = (src_height << 16) / dst_height;
2909 
2910     if (!flags)
2911     {
2912         /* No effects, we can cheat here. */
2913         if (dst_width == src_width)
2914         {
2915             if (dst_height == src_height)
2916             {
2917                 /* No stretching in either direction. This needs to be as fast
2918                  * as possible. */
2919                 sbuf = sbase;
2920 
2921                 /* Check for overlapping surfaces. */
2922                 if (!same_sub_resource || dst_box->top < src_box->top
2923                         || dst_box->right <= src_box->left || src_box->right <= dst_box->left)
2924                 {
2925                     /* No overlap, or dst above src, so copy from top downwards. */
2926                     for (y = 0; y < dst_height; ++y)
2927                     {
2928                         memcpy(dbuf, sbuf, row_byte_count);
2929                         sbuf += src_map.row_pitch;
2930                         dbuf += dst_map.row_pitch;
2931                     }
2932                 }
2933                 else if (dst_box->top > src_box->top)
2934                 {
2935                     /* Copy from bottom upwards. */
2936                     sbuf += src_map.row_pitch * dst_height;
2937                     dbuf += dst_map.row_pitch * dst_height;
2938                     for (y = 0; y < dst_height; ++y)
2939                     {
2940                         sbuf -= src_map.row_pitch;
2941                         dbuf -= dst_map.row_pitch;
2942                         memcpy(dbuf, sbuf, row_byte_count);
2943                     }
2944                 }
2945                 else
2946                 {
2947                     /* Src and dst overlapping on the same line, use memmove. */
2948                     for (y = 0; y < dst_height; ++y)
2949                     {
2950                         memmove(dbuf, sbuf, row_byte_count);
2951                         sbuf += src_map.row_pitch;
2952                         dbuf += dst_map.row_pitch;
2953                     }
2954                 }
2955             }
2956             else
2957             {
2958                 /* Stretching in y direction only. */
2959                 for (y = sy = 0; y < dst_height; ++y, sy += yinc)
2960                 {
2961                     sbuf = sbase + (sy >> 16) * src_map.row_pitch;
2962                     memcpy(dbuf, sbuf, row_byte_count);
2963                     dbuf += dst_map.row_pitch;
2964                 }
2965             }
2966         }
2967         else
2968         {
2969             /* Stretching in X direction. */
2970             unsigned int last_sy = ~0u;
2971             for (y = sy = 0; y < dst_height; ++y, sy += yinc)
2972             {
2973                 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
2974 
2975                 if ((sy >> 16) == (last_sy >> 16))
2976                 {
2977                     /* This source row is the same as last source row -
2978                      * Copy the already stretched row. */
2979                     memcpy(dbuf, dbuf - dst_map.row_pitch, row_byte_count);
2980                 }
2981                 else
2982                 {
2983 #define STRETCH_ROW(type) \
2984 do { \
2985     const type *s = (const type *)sbuf; \
2986     type *d = (type *)dbuf; \
2987     for (x = sx = 0; x < dst_width; ++x, sx += xinc) \
2988         d[x] = s[sx >> 16]; \
2989 } while(0)
2990 
2991                     switch(bpp)
2992                     {
2993                         case 1:
2994                             STRETCH_ROW(BYTE);
2995                             break;
2996                         case 2:
2997                             STRETCH_ROW(WORD);
2998                             break;
2999                         case 4:
3000                             STRETCH_ROW(DWORD);
3001                             break;
3002                         case 3:
3003                         {
3004                             const BYTE *s;
3005                             BYTE *d = dbuf;
3006                             for (x = sx = 0; x < dst_width; x++, sx+= xinc)
3007                             {
3008                                 DWORD pixel;
3009 
3010                                 s = sbuf + 3 * (sx >> 16);
3011                                 pixel = s[0] | (s[1] << 8) | (s[2] << 16);
3012                                 d[0] = (pixel      ) & 0xff;
3013                                 d[1] = (pixel >>  8) & 0xff;
3014                                 d[2] = (pixel >> 16) & 0xff;
3015                                 d += 3;
3016                             }
3017                             break;
3018                         }
3019                         default:
3020                             FIXME("Stretched blit not implemented for bpp %u.\n", bpp * 8);
3021                             hr = WINED3DERR_NOTAVAILABLE;
3022                             goto error;
3023                     }
3024 #undef STRETCH_ROW
3025                 }
3026                 dbuf += dst_map.row_pitch;
3027                 last_sy = sy;
3028             }
3029         }
3030     }
3031     else
3032     {
3033         LONG dstyinc = dst_map.row_pitch, dstxinc = bpp;
3034         DWORD keylow = 0xffffffff, keyhigh = 0, keymask = 0xffffffff;
3035         DWORD destkeylow = 0x0, destkeyhigh = 0xffffffff, destkeymask = 0xffffffff;
3036         if (flags & (WINED3D_BLT_SRC_CKEY | WINED3D_BLT_DST_CKEY
3037                 | WINED3D_BLT_SRC_CKEY_OVERRIDE | WINED3D_BLT_DST_CKEY_OVERRIDE))
3038         {
3039             /* The color keying flags are checked for correctness in ddraw. */
3040             if (flags & WINED3D_BLT_SRC_CKEY)
3041             {
3042                 keylow  = src_texture->async.src_blt_color_key.color_space_low_value;
3043                 keyhigh = src_texture->async.src_blt_color_key.color_space_high_value;
3044             }
3045             else if (flags & WINED3D_BLT_SRC_CKEY_OVERRIDE)
3046             {
3047                 keylow = fx->src_color_key.color_space_low_value;
3048                 keyhigh = fx->src_color_key.color_space_high_value;
3049             }
3050 
3051             if (flags & WINED3D_BLT_DST_CKEY)
3052             {
3053                 /* Destination color keys are taken from the source surface! */
3054                 destkeylow = src_texture->async.dst_blt_color_key.color_space_low_value;
3055                 destkeyhigh = src_texture->async.dst_blt_color_key.color_space_high_value;
3056             }
3057             else if (flags & WINED3D_BLT_DST_CKEY_OVERRIDE)
3058             {
3059                 destkeylow = fx->dst_color_key.color_space_low_value;
3060                 destkeyhigh = fx->dst_color_key.color_space_high_value;
3061             }
3062 
3063             if (bpp == 1)
3064             {
3065                 keymask = 0xff;
3066             }
3067             else
3068             {
3069                 DWORD masks[3];
3070                 get_color_masks(src_format, masks);
3071                 keymask = masks[0] | masks[1] | masks[2];
3072             }
3073             flags &= ~(WINED3D_BLT_SRC_CKEY | WINED3D_BLT_DST_CKEY
3074                     | WINED3D_BLT_SRC_CKEY_OVERRIDE | WINED3D_BLT_DST_CKEY_OVERRIDE);
3075         }
3076 
3077         if (flags & WINED3D_BLT_FX)
3078         {
3079             BYTE *dTopLeft, *dTopRight, *dBottomLeft, *dBottomRight, *tmp;
3080             LONG tmpxy;
3081             dTopLeft     = dbuf;
3082             dTopRight    = dbuf + ((dst_width - 1) * bpp);
3083             dBottomLeft  = dTopLeft + ((dst_height - 1) * dst_map.row_pitch);
3084             dBottomRight = dBottomLeft + ((dst_width - 1) * bpp);
3085 
3086             if (fx->fx & WINEDDBLTFX_ARITHSTRETCHY)
3087             {
3088                 /* I don't think we need to do anything about this flag. */
3089                 WARN("Nothing done for WINEDDBLTFX_ARITHSTRETCHY.\n");
3090             }
3091             if (fx->fx & WINEDDBLTFX_MIRRORLEFTRIGHT)
3092             {
3093                 tmp          = dTopRight;
3094                 dTopRight    = dTopLeft;
3095                 dTopLeft     = tmp;
3096                 tmp          = dBottomRight;
3097                 dBottomRight = dBottomLeft;
3098                 dBottomLeft  = tmp;
3099                 dstxinc = dstxinc * -1;
3100             }
3101             if (fx->fx & WINEDDBLTFX_MIRRORUPDOWN)
3102             {
3103                 tmp          = dTopLeft;
3104                 dTopLeft     = dBottomLeft;
3105                 dBottomLeft  = tmp;
3106                 tmp          = dTopRight;
3107                 dTopRight    = dBottomRight;
3108                 dBottomRight = tmp;
3109                 dstyinc = dstyinc * -1;
3110             }
3111             if (fx->fx & WINEDDBLTFX_NOTEARING)
3112             {
3113                 /* I don't think we need to do anything about this flag. */
3114                 WARN("Nothing done for WINEDDBLTFX_NOTEARING.\n");
3115             }
3116             if (fx->fx & WINEDDBLTFX_ROTATE180)
3117             {
3118                 tmp          = dBottomRight;
3119                 dBottomRight = dTopLeft;
3120                 dTopLeft     = tmp;
3121                 tmp          = dBottomLeft;
3122                 dBottomLeft  = dTopRight;
3123                 dTopRight    = tmp;
3124                 dstxinc = dstxinc * -1;
3125                 dstyinc = dstyinc * -1;
3126             }
3127             if (fx->fx & WINEDDBLTFX_ROTATE270)
3128             {
3129                 tmp          = dTopLeft;
3130                 dTopLeft     = dBottomLeft;
3131                 dBottomLeft  = dBottomRight;
3132                 dBottomRight = dTopRight;
3133                 dTopRight    = tmp;
3134                 tmpxy   = dstxinc;
3135                 dstxinc = dstyinc;
3136                 dstyinc = tmpxy;
3137                 dstxinc = dstxinc * -1;
3138             }
3139             if (fx->fx & WINEDDBLTFX_ROTATE90)
3140             {
3141                 tmp          = dTopLeft;
3142                 dTopLeft     = dTopRight;
3143                 dTopRight    = dBottomRight;
3144                 dBottomRight = dBottomLeft;
3145                 dBottomLeft  = tmp;
3146                 tmpxy   = dstxinc;
3147                 dstxinc = dstyinc;
3148                 dstyinc = tmpxy;
3149                 dstyinc = dstyinc * -1;
3150             }
3151             if (fx->fx & WINEDDBLTFX_ZBUFFERBASEDEST)
3152             {
3153                 /* I don't think we need to do anything about this flag. */
3154                 WARN("Nothing done for WINEDDBLTFX_ZBUFFERBASEDEST.\n");
3155             }
3156             dbuf = dTopLeft;
3157             flags &= ~(WINED3D_BLT_FX);
3158         }
3159 
3160 #define COPY_COLORKEY_FX(type) \
3161 do { \
3162     const type *s; \
3163     type *d = (type *)dbuf, *dx, tmp; \
3164     for (y = sy = 0; y < dst_height; ++y, sy += yinc) \
3165     { \
3166         s = (const type *)(sbase + (sy >> 16) * src_map.row_pitch); \
3167         dx = d; \
3168         for (x = sx = 0; x < dst_width; ++x, sx += xinc) \
3169         { \
3170             tmp = s[sx >> 16]; \
3171             if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) \
3172                     && ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) \
3173             { \
3174                 dx[0] = tmp; \
3175             } \
3176             dx = (type *)(((BYTE *)dx) + dstxinc); \
3177         } \
3178         d = (type *)(((BYTE *)d) + dstyinc); \
3179     } \
3180 } while(0)
3181 
3182         switch (bpp)
3183         {
3184             case 1:
3185                 COPY_COLORKEY_FX(BYTE);
3186                 break;
3187             case 2:
3188                 COPY_COLORKEY_FX(WORD);
3189                 break;
3190             case 4:
3191                 COPY_COLORKEY_FX(DWORD);
3192                 break;
3193             case 3:
3194             {
3195                 const BYTE *s;
3196                 BYTE *d = dbuf, *dx;
3197                 for (y = sy = 0; y < dst_height; ++y, sy += yinc)
3198                 {
3199                     sbuf = sbase + (sy >> 16) * src_map.row_pitch;
3200                     dx = d;
3201                     for (x = sx = 0; x < dst_width; ++x, sx+= xinc)
3202                     {
3203                         DWORD pixel, dpixel = 0;
3204                         s = sbuf + 3 * (sx>>16);
3205                         pixel = s[0] | (s[1] << 8) | (s[2] << 16);
3206                         dpixel = dx[0] | (dx[1] << 8 ) | (dx[2] << 16);
3207                         if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh)
3208                                 && ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
3209                         {
3210                             dx[0] = (pixel      ) & 0xff;
3211                             dx[1] = (pixel >>  8) & 0xff;
3212                             dx[2] = (pixel >> 16) & 0xff;
3213                         }
3214                         dx += dstxinc;
3215                     }
3216                     d += dstyinc;
3217                 }
3218                 break;
3219             }
3220             default:
3221                 FIXME("%s color-keyed blit not implemented for bpp %u.\n",
3222                       (flags & WINED3D_BLT_SRC_CKEY) ? "Source" : "Destination", bpp * 8);
3223                 hr = WINED3DERR_NOTAVAILABLE;
3224                 goto error;
3225 #undef COPY_COLORKEY_FX
3226         }
3227     }
3228 
3229 error:
3230     if (flags)
3231         FIXME("    Unsupported flags %#x.\n", flags);
3232 
3233 release:
3234     context_unmap_bo_address(context, &dst_data, GL_PIXEL_UNPACK_BUFFER);
3235     if (!same_sub_resource)
3236         context_unmap_bo_address(context, &src_data, GL_PIXEL_UNPACK_BUFFER);
3237     if (SUCCEEDED(hr) && dst_texture->swapchain && dst_texture->swapchain->front_buffer == dst_texture)
3238     {
3239         SetRect(&dst_texture->swapchain->front_buffer_update,
3240                 dst_box->left, dst_box->top, dst_box->right, dst_box->bottom);
3241         dst_texture->swapchain->swapchain_ops->swapchain_frontbuffer_updated(dst_texture->swapchain);
3242     }
3243     if (converted_texture)
3244         wined3d_texture_decref(converted_texture);
3245     if (context)
3246         context_release(context);
3247 
3248     return hr;
3249 }
3250 
3251 static void surface_cpu_blt_colour_fill(struct wined3d_rendertarget_view *view,
3252         const struct wined3d_box *box, const struct wined3d_color *colour)
3253 {
3254     struct wined3d_device *device = view->resource->device;
3255     struct wined3d_context *context = NULL;
3256     struct wined3d_texture *texture;
3257     struct wined3d_bo_address data;
3258     unsigned int x, y, w, h, bpp;
3259     struct wined3d_map_desc map;
3260     DWORD map_binding;
3261     BYTE *row;
3262     DWORD c;
3263 
3264     TRACE("view %p, box %s, colour %s.\n", view, debug_box(box), debug_color(colour));
3265 
3266     if (view->format_flags & WINED3DFMT_FLAG_BLOCKS)
3267     {
3268         FIXME("Not implemented for format %s.\n", debug_d3dformat(view->format->id));
3269         return;
3270     }
3271 
3272     if (view->format->id != view->resource->format->id)
3273         FIXME("View format %s doesn't match resource format %s.\n",
3274                 debug_d3dformat(view->format->id), debug_d3dformat(view->resource->format->id));
3275 
3276     if (view->resource->type == WINED3D_RTYPE_BUFFER)
3277     {
3278         FIXME("Not implemented for buffers.\n");
3279         return;
3280     }
3281 
3282     if (device->d3d_initialized)
3283         context = context_acquire(device, NULL, 0);
3284 
3285     c = wined3d_format_convert_from_float(view->format, colour);
3286     bpp = view->format->byte_count;
3287     w = box->right - box->left;
3288     h = box->bottom - box->top;
3289 
3290     texture = texture_from_resource(view->resource);
3291     map_binding = texture->resource.map_binding;
3292     if (!wined3d_texture_load_location(texture, view->sub_resource_idx, context, map_binding))
3293         ERR("Failed to load the sub-resource into %s.\n", wined3d_debug_location(map_binding));
3294     wined3d_texture_invalidate_location(texture, view->sub_resource_idx, ~map_binding);
3295     wined3d_texture_get_pitch(texture, view->sub_resource_idx % texture->level_count,
3296             &map.row_pitch, &map.slice_pitch);
3297     wined3d_texture_get_memory(texture, view->sub_resource_idx, &data, map_binding);
3298     map.data = context_map_bo_address(context, &data,
3299             texture->sub_resources[view->sub_resource_idx].size, GL_PIXEL_UNPACK_BUFFER, WINED3D_MAP_WRITE);
3300     map.data = (BYTE *)map.data
3301             + (box->front * map.slice_pitch)
3302             + ((box->top / view->format->block_height) * map.row_pitch)
3303             + ((box->left / view->format->block_width) * view->format->block_byte_count);
3304 
3305     switch (bpp)
3306     {
3307         case 1:
3308             for (x = 0; x < w; ++x)
3309             {
3310                 ((BYTE *)map.data)[x] = c;
3311             }
3312             break;
3313 
3314         case 2:
3315             for (x = 0; x < w; ++x)
3316             {
3317                 ((WORD *)map.data)[x] = c;
3318             }
3319             break;
3320 
3321         case 3:
3322         {
3323             row = map.data;
3324             for (x = 0; x < w; ++x, row += 3)
3325             {
3326                 row[0] = (c      ) & 0xff;
3327                 row[1] = (c >>  8) & 0xff;
3328                 row[2] = (c >> 16) & 0xff;
3329             }
3330             break;
3331         }
3332         case 4:
3333             for (x = 0; x < w; ++x)
3334             {
3335                 ((DWORD *)map.data)[x] = c;
3336             }
3337             break;
3338 
3339         default:
3340             FIXME("Not implemented for bpp %u.\n", bpp);
3341             wined3d_resource_unmap(view->resource, view->sub_resource_idx);
3342             return;
3343     }
3344 
3345     row = map.data;
3346     for (y = 1; y < h; ++y)
3347     {
3348         row += map.row_pitch;
3349         memcpy(row, map.data, w * bpp);
3350     }
3351 
3352     context_unmap_bo_address(context, &data, GL_PIXEL_UNPACK_BUFFER);
3353     if (context)
3354         context_release(context);
3355 }
3356 
3357 static void cpu_blitter_clear(struct wined3d_blitter *blitter, struct wined3d_device *device,
3358         unsigned int rt_count, const struct wined3d_fb_state *fb, unsigned int rect_count, const RECT *clear_rects,
3359         const RECT *draw_rect, DWORD flags, const struct wined3d_color *colour, float depth, DWORD stencil)
3360 {
3361     struct wined3d_color c = {depth, 0.0f, 0.0f, 0.0f};
3362     struct wined3d_rendertarget_view *view;
3363     struct wined3d_box box;
3364     unsigned int i, j;
3365 
3366     if (!rect_count)
3367     {
3368         rect_count = 1;
3369         clear_rects = draw_rect;
3370     }
3371 
3372     for (i = 0; i < rect_count; ++i)
3373     {
3374         box.left = max(clear_rects[i].left, draw_rect->left);
3375         box.top = max(clear_rects[i].top, draw_rect->top);
3376         box.right = min(clear_rects[i].right, draw_rect->right);
3377         box.bottom = min(clear_rects[i].bottom, draw_rect->bottom);
3378         box.front = 0;
3379         box.back = 1;
3380 
3381         if (box.left >= box.right || box.top >= box.bottom)
3382             continue;
3383 
3384         if (flags & WINED3DCLEAR_TARGET)
3385         {
3386             for (j = 0; j < rt_count; ++j)
3387             {
3388                 if ((view = fb->render_targets[j]))
3389                     surface_cpu_blt_colour_fill(view, &box, colour);
3390             }
3391         }
3392 
3393         if ((flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL)) && (view = fb->depth_stencil))
3394         {
3395             if ((view->format->depth_size && !(flags & WINED3DCLEAR_ZBUFFER))
3396                     || (view->format->stencil_size && !(flags & WINED3DCLEAR_STENCIL)))
3397                 FIXME("Clearing %#x on %s.\n", flags, debug_d3dformat(view->format->id));
3398 
3399             surface_cpu_blt_colour_fill(view, &box, &c);
3400         }
3401     }
3402 }
3403 
3404 static DWORD cpu_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_blit_op op,
3405         struct wined3d_context *context, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx,
3406         DWORD src_location, const RECT *src_rect, struct wined3d_texture *dst_texture,
3407         unsigned int dst_sub_resource_idx, DWORD dst_location, const RECT *dst_rect,
3408         const struct wined3d_color_key *color_key, enum wined3d_texture_filter_type filter)
3409 {
3410     struct wined3d_box dst_box = {dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, 0, 1};
3411     struct wined3d_box src_box = {src_rect->left, src_rect->top, src_rect->right, src_rect->bottom, 0, 1};
3412     struct wined3d_blt_fx fx;
3413     DWORD flags = 0;
3414 
3415     memset(&fx, 0, sizeof(fx));
3416     switch (op)
3417     {
3418         case WINED3D_BLIT_OP_COLOR_BLIT:
3419         case WINED3D_BLIT_OP_DEPTH_BLIT:
3420         case WINED3D_BLIT_OP_RAW_BLIT:
3421             break;
3422         case WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST:
3423             flags |= WINED3D_BLT_ALPHA_TEST;
3424             break;
3425         case WINED3D_BLIT_OP_COLOR_BLIT_CKEY:
3426             flags |= WINED3D_BLT_SRC_CKEY_OVERRIDE | WINED3D_BLT_FX;
3427             fx.src_color_key = *color_key;
3428             break;
3429         default:
3430             FIXME("Unhandled op %#x.\n", op);
3431             break;
3432     }
3433 
3434     if (FAILED(surface_cpu_blt(dst_texture, dst_sub_resource_idx, &dst_box,
3435             src_texture, src_sub_resource_idx, &src_box, flags, &fx, filter)))
3436         ERR("Failed to blit.\n");
3437     wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, dst_location);
3438 
3439     return dst_location | (dst_texture->sub_resources[dst_sub_resource_idx].locations
3440             & dst_texture->resource.map_binding);
3441 }
3442 
3443 static const struct wined3d_blitter_ops cpu_blitter_ops =
3444 {
3445     cpu_blitter_destroy,
3446     cpu_blitter_clear,
3447     cpu_blitter_blit,
3448 };
3449 
3450 struct wined3d_blitter *wined3d_cpu_blitter_create(void)
3451 {
3452     struct wined3d_blitter *blitter;
3453 
3454     if (!(blitter = heap_alloc(sizeof(*blitter))))
3455         return NULL;
3456 
3457     TRACE("Created blitter %p.\n", blitter);
3458 
3459     blitter->ops = &cpu_blitter_ops;
3460     blitter->next = NULL;
3461 
3462     return blitter;
3463 }
3464 
3465 HRESULT texture2d_blt(struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx,
3466         const struct wined3d_box *dst_box, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx,
3467         const struct wined3d_box *src_box, DWORD flags, const struct wined3d_blt_fx *fx,
3468         enum wined3d_texture_filter_type filter)
3469 {
3470     struct wined3d_texture_sub_resource *src_sub_resource, *dst_sub_resource;
3471     struct wined3d_device *device = dst_texture->resource.device;
3472     struct wined3d_swapchain *src_swapchain, *dst_swapchain;
3473     const struct wined3d_color_key *colour_key = NULL;
3474     DWORD dst_location, valid_locations;
3475     DWORD src_ds_flags, dst_ds_flags;
3476     struct wined3d_context *context;
3477     enum wined3d_blit_op blit_op;
3478     BOOL scale, convert, resolve;
3479     RECT src_rect, dst_rect;
3480 
3481     static const DWORD simple_blit = WINED3D_BLT_SRC_CKEY
3482             | WINED3D_BLT_SRC_CKEY_OVERRIDE
3483             | WINED3D_BLT_ALPHA_TEST
3484             | WINED3D_BLT_RAW;
3485 
3486     TRACE("dst_texture %p, dst_sub_resource_idx %u, dst_box %s, src_texture %p, "
3487             "src_sub_resource_idx %u, src_box %s, flags %#x, fx %p, filter %s.\n",
3488             dst_texture, dst_sub_resource_idx, debug_box(dst_box), src_texture, src_sub_resource_idx,
3489             debug_box(src_box), flags, fx, debug_d3dtexturefiltertype(filter));
3490     TRACE("Usage is %s.\n", debug_d3dusage(dst_texture->resource.usage));
3491 
3492     if (fx)
3493     {
3494         TRACE("fx %#x.\n", fx->fx);
3495         TRACE("dst_color_key {0x%08x, 0x%08x}.\n",
3496                 fx->dst_color_key.color_space_low_value,
3497                 fx->dst_color_key.color_space_high_value);
3498         TRACE("src_color_key {0x%08x, 0x%08x}.\n",
3499                 fx->src_color_key.color_space_low_value,
3500                 fx->src_color_key.color_space_high_value);
3501     }
3502 
3503     SetRect(&src_rect, src_box->left, src_box->top, src_box->right, src_box->bottom);
3504     SetRect(&dst_rect, dst_box->left, dst_box->top, dst_box->right, dst_box->bottom);
3505 
3506     if (!fx || !(fx->fx))
3507         flags &= ~WINED3D_BLT_FX;
3508 
3509     /* WINED3D_BLT_DO_NOT_WAIT appeared in DX7. */
3510     if (flags & WINED3D_BLT_DO_NOT_WAIT)
3511     {
3512         static unsigned int once;
3513 
3514         if (!once++)
3515             FIXME("Can't handle WINED3D_BLT_DO_NOT_WAIT flag.\n");
3516     }
3517 
3518     flags &= ~(WINED3D_BLT_SYNCHRONOUS | WINED3D_BLT_DO_NOT_WAIT | WINED3D_BLT_WAIT);
3519 
3520     if (!device->d3d_initialized)
3521     {
3522         WARN("D3D not initialized, using fallback.\n");
3523         goto cpu;
3524     }
3525 
3526     if (flags & ~simple_blit)
3527     {
3528         WARN_(d3d_perf)("Using fallback for complex blit (%#x).\n", flags);
3529         goto fallback;
3530     }
3531 
3532     src_swapchain = src_texture->swapchain;
3533     dst_swapchain = dst_texture->swapchain;
3534 
3535     /* This isn't strictly needed. FBO blits for example could deal with
3536      * cross-swapchain blits by first downloading the source to a texture
3537      * before switching to the destination context. We just have this here to
3538      * not have to deal with the issue, since cross-swapchain blits should be
3539      * rare. */
3540     if (src_swapchain && dst_swapchain && src_swapchain != dst_swapchain)
3541     {
3542         FIXME("Using fallback for cross-swapchain blit.\n");
3543         goto fallback;
3544     }
3545 
3546     scale = src_box->right - src_box->left != dst_box->right - dst_box->left
3547             || src_box->bottom - src_box->top != dst_box->bottom - dst_box->top;
3548     convert = src_texture->resource.format->id != dst_texture->resource.format->id;
3549     resolve = src_texture->resource.multisample_type != dst_texture->resource.multisample_type;
3550 
3551     dst_ds_flags = dst_texture->resource.format_flags
3552             & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
3553     src_ds_flags = src_texture->resource.format_flags
3554             & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
3555 
3556     if (src_ds_flags || dst_ds_flags)
3557     {
3558         TRACE("Depth/stencil blit.\n");
3559 
3560         if (dst_texture->resource.access & WINED3D_RESOURCE_ACCESS_GPU)
3561             dst_location = dst_texture->resource.draw_binding;
3562         else
3563             dst_location = dst_texture->resource.map_binding;
3564 
3565         context = context_acquire(device, dst_texture, dst_sub_resource_idx);
3566         valid_locations = device->blitter->ops->blitter_blit(device->blitter,
3567                 WINED3D_BLIT_OP_DEPTH_BLIT, context,
3568                 src_texture, src_sub_resource_idx, src_texture->resource.draw_binding, &src_rect,
3569                 dst_texture, dst_sub_resource_idx, dst_location, &dst_rect, NULL, filter);
3570         context_release(context);
3571 
3572         wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, valid_locations);
3573         wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~valid_locations);
3574 
3575         return WINED3D_OK;
3576     }
3577 
3578     TRACE("Colour blit.\n");
3579 
3580     dst_sub_resource = &dst_texture->sub_resources[dst_sub_resource_idx];
3581     src_sub_resource = &src_texture->sub_resources[src_sub_resource_idx];
3582 
3583     /* In principle this would apply to depth blits as well, but we don't
3584      * implement those in the CPU blitter at the moment. */
3585     if ((dst_sub_resource->locations & dst_texture->resource.map_binding)
3586             && (src_sub_resource->locations & src_texture->resource.map_binding))
3587     {
3588         if (scale)
3589             TRACE("Not doing sysmem blit because of scaling.\n");
3590         else if (convert)
3591             TRACE("Not doing sysmem blit because of format conversion.\n");
3592         else
3593             goto cpu;
3594     }
3595 
3596     blit_op = WINED3D_BLIT_OP_COLOR_BLIT;
3597     if (flags & WINED3D_BLT_SRC_CKEY_OVERRIDE)
3598     {
3599         colour_key = &fx->src_color_key;
3600         blit_op = WINED3D_BLIT_OP_COLOR_BLIT_CKEY;
3601     }
3602     else if (flags & WINED3D_BLT_SRC_CKEY)
3603     {
3604         colour_key = &src_texture->async.src_blt_color_key;
3605         blit_op = WINED3D_BLIT_OP_COLOR_BLIT_CKEY;
3606     }
3607     else if (flags & WINED3D_BLT_ALPHA_TEST)
3608     {
3609         blit_op = WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST;
3610     }
3611     else if ((src_sub_resource->locations & surface_simple_locations)
3612             && !(dst_sub_resource->locations & surface_simple_locations))
3613     {
3614         /* Upload */
3615         if (scale)
3616             TRACE("Not doing upload because of scaling.\n");
3617         else if (convert)
3618             TRACE("Not doing upload because of format conversion.\n");
3619         else if (dst_texture->resource.format->conv_byte_count)
3620             TRACE("Not doing upload because the destination format needs conversion.\n");
3621         else
3622         {
3623             wined3d_texture_upload_from_texture(dst_texture, dst_sub_resource_idx, dst_box->left,
3624                     dst_box->top, dst_box->front, src_texture, src_sub_resource_idx, src_box);
3625             if (!wined3d_resource_is_offscreen(&dst_texture->resource))
3626             {
3627                 context = context_acquire(device, dst_texture, dst_sub_resource_idx);
3628                 wined3d_texture_load_location(dst_texture, dst_sub_resource_idx,
3629                         context, dst_texture->resource.draw_binding);
3630                 context_release(context);
3631             }
3632             return WINED3D_OK;
3633         }
3634     }
3635     else if (dst_swapchain && dst_swapchain->back_buffers
3636             && dst_texture == dst_swapchain->front_buffer
3637             && src_texture == dst_swapchain->back_buffers[0])
3638     {
3639         /* Use present for back -> front blits. The idea behind this is that
3640          * present is potentially faster than a blit, in particular when FBO
3641          * blits aren't available. Some ddraw applications like Half-Life and
3642          * Prince of Persia 3D use Blt() from the backbuffer to the
3643          * frontbuffer instead of doing a Flip(). D3d8 and d3d9 applications
3644          * can't blit directly to the frontbuffer. */
3645         enum wined3d_swap_effect swap_effect = dst_swapchain->desc.swap_effect;
3646 
3647         TRACE("Using present for backbuffer -> frontbuffer blit.\n");
3648 
3649         /* Set the swap effect to COPY, we don't want the backbuffer to become
3650          * undefined. */
3651         dst_swapchain->desc.swap_effect = WINED3D_SWAP_EFFECT_COPY;
3652         wined3d_swapchain_present(dst_swapchain, NULL, NULL,
3653                 dst_swapchain->win_handle, dst_swapchain->swap_interval, 0);
3654         dst_swapchain->desc.swap_effect = swap_effect;
3655 
3656         return WINED3D_OK;
3657     }
3658     else if ((flags & WINED3D_BLT_RAW) || (!scale && !convert && !resolve))
3659     {
3660         blit_op = WINED3D_BLIT_OP_RAW_BLIT;
3661     }
3662 
3663     if (dst_texture->resource.access & WINED3D_RESOURCE_ACCESS_GPU)
3664         dst_location = dst_texture->resource.draw_binding;
3665     else
3666         dst_location = dst_texture->resource.map_binding;
3667 
3668     context = context_acquire(device, dst_texture, dst_sub_resource_idx);
3669     valid_locations = device->blitter->ops->blitter_blit(device->blitter, blit_op, context,
3670             src_texture, src_sub_resource_idx, src_texture->resource.draw_binding, &src_rect,
3671             dst_texture, dst_sub_resource_idx, dst_location, &dst_rect, colour_key, filter);
3672     context_release(context);
3673 
3674     wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, valid_locations);
3675     wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~valid_locations);
3676 
3677     return WINED3D_OK;
3678 
3679 fallback:
3680     /* Special cases for render targets. */
3681     if (SUCCEEDED(wined3d_texture_blt_special(dst_texture, dst_sub_resource_idx, &dst_rect,
3682             src_texture, src_sub_resource_idx, &src_rect, flags, fx, filter)))
3683         return WINED3D_OK;
3684 
3685 cpu:
3686     return surface_cpu_blt(dst_texture, dst_sub_resource_idx, dst_box,
3687             src_texture, src_sub_resource_idx, src_box, flags, fx, filter);
3688 }
3689