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