wineconsole: Try harder to get a scalable font.
[wine.git] / dlls / wined3d / surface.c
blob71693adc589da7663f776ab47d75e1f83d067481
1 /*
2 * Copyright 1997-2000 Marcus Meissner
3 * Copyright 1998-2000 Lionel Ulmer
4 * Copyright 2000-2001 TransGaming Technologies Inc.
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2002-2003 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2011, 2013-2014 Stefan Dösinger for CodeWeavers
10 * Copyright 2007-2008 Henri Verbeet
11 * Copyright 2006-2008 Roderick Colenbrander
12 * Copyright 2009-2011 Henri Verbeet for CodeWeavers
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 #include "config.h"
30 #include "wine/port.h"
31 #include "wined3d_private.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
34 WINE_DECLARE_DEBUG_CHANNEL(d3d_perf);
36 static const DWORD surface_simple_locations = WINED3D_LOCATION_SYSMEM
37 | WINED3D_LOCATION_USER_MEMORY | WINED3D_LOCATION_BUFFER;
39 /* Works correctly only for <= 4 bpp formats. */
40 static void get_color_masks(const struct wined3d_format *format, DWORD *masks)
42 masks[0] = ((1u << format->red_size) - 1) << format->red_offset;
43 masks[1] = ((1u << format->green_size) - 1) << format->green_offset;
44 masks[2] = ((1u << format->blue_size) - 1) << format->blue_offset;
47 static BOOL texture2d_is_full_rect(const struct wined3d_texture *texture, unsigned int level, const RECT *r)
49 unsigned int t;
51 t = wined3d_texture_get_level_width(texture, level);
52 if ((r->left && r->right) || abs(r->right - r->left) != t)
53 return FALSE;
54 t = wined3d_texture_get_level_height(texture, level);
55 if ((r->top && r->bottom) || abs(r->bottom - r->top) != t)
56 return FALSE;
57 return TRUE;
60 static void texture2d_depth_blt_fbo(const struct wined3d_device *device, struct wined3d_context *context,
61 struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx, DWORD src_location,
62 const RECT *src_rect, struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx,
63 DWORD dst_location, const RECT *dst_rect)
65 const struct wined3d_gl_info *gl_info = context->gl_info;
66 DWORD src_mask, dst_mask;
67 GLbitfield gl_mask;
69 TRACE("device %p, src_texture %p, src_sub_resource_idx %u, src_location %s, src_rect %s, "
70 "dst_texture %p, dst_sub_resource_idx %u, dst_location %s, dst_rect %s.\n", device,
71 src_texture, src_sub_resource_idx, wined3d_debug_location(src_location), wine_dbgstr_rect(src_rect),
72 dst_texture, dst_sub_resource_idx, wined3d_debug_location(dst_location), wine_dbgstr_rect(dst_rect));
74 src_mask = src_texture->resource.format_flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
75 dst_mask = dst_texture->resource.format_flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
77 if (src_mask != dst_mask)
79 ERR("Incompatible formats %s and %s.\n",
80 debug_d3dformat(src_texture->resource.format->id),
81 debug_d3dformat(dst_texture->resource.format->id));
82 return;
85 if (!src_mask)
87 ERR("Not a depth / stencil format: %s.\n",
88 debug_d3dformat(src_texture->resource.format->id));
89 return;
92 gl_mask = 0;
93 if (src_mask & WINED3DFMT_FLAG_DEPTH)
94 gl_mask |= GL_DEPTH_BUFFER_BIT;
95 if (src_mask & WINED3DFMT_FLAG_STENCIL)
96 gl_mask |= GL_STENCIL_BUFFER_BIT;
98 /* Make sure the locations are up-to-date. Loading the destination
99 * surface isn't required if the entire surface is overwritten. */
100 wined3d_texture_load_location(src_texture, src_sub_resource_idx, context, src_location);
101 if (!texture2d_is_full_rect(dst_texture, dst_sub_resource_idx % dst_texture->level_count, dst_rect))
102 wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, dst_location);
103 else
104 wined3d_texture_prepare_location(dst_texture, dst_sub_resource_idx, context, dst_location);
106 context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER, NULL, 0,
107 &src_texture->resource, src_sub_resource_idx, src_location);
108 context_check_fbo_status(context, GL_READ_FRAMEBUFFER);
110 context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER, NULL, 0,
111 &dst_texture->resource, dst_sub_resource_idx, dst_location);
112 context_set_draw_buffer(context, GL_NONE);
113 context_check_fbo_status(context, GL_DRAW_FRAMEBUFFER);
114 context_invalidate_state(context, STATE_FRAMEBUFFER);
116 if (gl_mask & GL_DEPTH_BUFFER_BIT)
118 gl_info->gl_ops.gl.p_glDepthMask(GL_TRUE);
119 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_ZWRITEENABLE));
121 if (gl_mask & GL_STENCIL_BUFFER_BIT)
123 if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
125 gl_info->gl_ops.gl.p_glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
126 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_TWOSIDEDSTENCILMODE));
128 gl_info->gl_ops.gl.p_glStencilMask(~0U);
129 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_STENCILWRITEMASK));
132 gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
133 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE));
135 gl_info->fbo_ops.glBlitFramebuffer(src_rect->left, src_rect->top, src_rect->right, src_rect->bottom,
136 dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, gl_mask, GL_NEAREST);
137 checkGLcall("glBlitFramebuffer()");
140 static BOOL is_multisample_location(const struct wined3d_texture *texture, DWORD location)
142 if (location == WINED3D_LOCATION_RB_MULTISAMPLE)
143 return TRUE;
144 if (location != WINED3D_LOCATION_TEXTURE_RGB && location != WINED3D_LOCATION_TEXTURE_SRGB)
145 return FALSE;
146 return texture->target == GL_TEXTURE_2D_MULTISAMPLE || texture->target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY;
149 /* Blit between surface locations. Onscreen on different swapchains is not supported.
150 * Depth / stencil is not supported. Context activation is done by the caller. */
151 static void texture2d_blt_fbo(const struct wined3d_device *device, struct wined3d_context *context,
152 enum wined3d_texture_filter_type filter, struct wined3d_texture *src_texture,
153 unsigned int src_sub_resource_idx, DWORD src_location, const RECT *src_rect,
154 struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx, DWORD dst_location,
155 const RECT *dst_rect)
157 struct wined3d_texture *required_texture, *restore_texture;
158 unsigned int required_idx, restore_idx;
159 const struct wined3d_gl_info *gl_info;
160 GLenum gl_filter;
161 GLenum buffer;
162 RECT s, d;
164 TRACE("device %p, context %p, filter %s, src_texture %p, src_sub_resource_idx %u, src_location %s, "
165 "src_rect %s, dst_texture %p, dst_sub_resource_idx %u, dst_location %s, dst_rect %s.\n",
166 device, context, debug_d3dtexturefiltertype(filter), src_texture, src_sub_resource_idx,
167 wined3d_debug_location(src_location), wine_dbgstr_rect(src_rect), dst_texture,
168 dst_sub_resource_idx, wined3d_debug_location(dst_location), wine_dbgstr_rect(dst_rect));
170 switch (filter)
172 case WINED3D_TEXF_LINEAR:
173 gl_filter = GL_LINEAR;
174 break;
176 default:
177 FIXME("Unsupported filter mode %s (%#x).\n", debug_d3dtexturefiltertype(filter), filter);
178 /* fall through */
179 case WINED3D_TEXF_NONE:
180 case WINED3D_TEXF_POINT:
181 gl_filter = GL_NEAREST;
182 break;
185 /* Resolve the source surface first if needed. */
186 if (is_multisample_location(src_texture, src_location)
187 && (src_texture->resource.format->id != dst_texture->resource.format->id
188 || abs(src_rect->bottom - src_rect->top) != abs(dst_rect->bottom - dst_rect->top)
189 || abs(src_rect->right - src_rect->left) != abs(dst_rect->right - dst_rect->left)))
190 src_location = WINED3D_LOCATION_RB_RESOLVED;
192 /* Make sure the locations are up-to-date. Loading the destination
193 * surface isn't required if the entire surface is overwritten. (And is
194 * in fact harmful if we're being called by surface_load_location() with
195 * the purpose of loading the destination surface.) */
196 wined3d_texture_load_location(src_texture, src_sub_resource_idx, context, src_location);
197 if (!texture2d_is_full_rect(dst_texture, dst_sub_resource_idx % dst_texture->level_count, dst_rect))
198 wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, dst_location);
199 else
200 wined3d_texture_prepare_location(dst_texture, dst_sub_resource_idx, context, dst_location);
202 if (src_location == WINED3D_LOCATION_DRAWABLE)
204 required_texture = src_texture;
205 required_idx = src_sub_resource_idx;
207 else if (dst_location == WINED3D_LOCATION_DRAWABLE)
209 required_texture = dst_texture;
210 required_idx = dst_sub_resource_idx;
212 else
214 required_texture = NULL;
215 required_idx = 0;
218 restore_texture = context->current_rt.texture;
219 restore_idx = context->current_rt.sub_resource_idx;
220 if (restore_texture != required_texture || restore_idx != required_idx)
221 context = context_acquire(device, required_texture, required_idx);
222 else
223 restore_texture = NULL;
225 if (!context->valid)
227 context_release(context);
228 WARN("Invalid context, skipping blit.\n");
229 return;
232 gl_info = context->gl_info;
234 if (src_location == WINED3D_LOCATION_DRAWABLE)
236 TRACE("Source texture %p is onscreen.\n", src_texture);
237 buffer = wined3d_texture_get_gl_buffer(src_texture);
238 s = *src_rect;
239 wined3d_texture_translate_drawable_coords(src_texture, context->win_handle, &s);
240 src_rect = &s;
242 else
244 TRACE("Source texture %p is offscreen.\n", src_texture);
245 buffer = GL_COLOR_ATTACHMENT0;
248 context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER,
249 &src_texture->resource, src_sub_resource_idx, NULL, 0, src_location);
250 gl_info->gl_ops.gl.p_glReadBuffer(buffer);
251 checkGLcall("glReadBuffer()");
252 context_check_fbo_status(context, GL_READ_FRAMEBUFFER);
254 if (dst_location == WINED3D_LOCATION_DRAWABLE)
256 TRACE("Destination texture %p is onscreen.\n", dst_texture);
257 buffer = wined3d_texture_get_gl_buffer(dst_texture);
258 d = *dst_rect;
259 wined3d_texture_translate_drawable_coords(dst_texture, context->win_handle, &d);
260 dst_rect = &d;
262 else
264 TRACE("Destination texture %p is offscreen.\n", dst_texture);
265 buffer = GL_COLOR_ATTACHMENT0;
268 context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER,
269 &dst_texture->resource, dst_sub_resource_idx, NULL, 0, dst_location);
270 context_set_draw_buffer(context, buffer);
271 context_check_fbo_status(context, GL_DRAW_FRAMEBUFFER);
272 context_invalidate_state(context, STATE_FRAMEBUFFER);
274 gl_info->gl_ops.gl.p_glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
275 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE));
276 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE1));
277 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE2));
278 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE3));
280 gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
281 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE));
283 gl_info->fbo_ops.glBlitFramebuffer(src_rect->left, src_rect->top, src_rect->right, src_rect->bottom,
284 dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, GL_COLOR_BUFFER_BIT, gl_filter);
285 checkGLcall("glBlitFramebuffer()");
287 if (dst_location == WINED3D_LOCATION_DRAWABLE && dst_texture->swapchain->front_buffer == dst_texture)
288 gl_info->gl_ops.gl.p_glFlush();
290 if (restore_texture)
291 context_restore(context, restore_texture, restore_idx);
294 static BOOL fbo_blitter_supported(enum wined3d_blit_op blit_op, const struct wined3d_gl_info *gl_info,
295 const struct wined3d_resource *src_resource, DWORD src_location,
296 const struct wined3d_resource *dst_resource, DWORD dst_location)
298 const struct wined3d_format *src_format = src_resource->format;
299 const struct wined3d_format *dst_format = dst_resource->format;
301 if ((wined3d_settings.offscreen_rendering_mode != ORM_FBO) || !gl_info->fbo_ops.glBlitFramebuffer)
302 return FALSE;
304 /* Source and/or destination need to be on the GL side */
305 if (!(src_resource->access & dst_resource->access & WINED3D_RESOURCE_ACCESS_GPU))
306 return FALSE;
308 if (src_resource->type != WINED3D_RTYPE_TEXTURE_2D)
309 return FALSE;
311 switch (blit_op)
313 case WINED3D_BLIT_OP_COLOR_BLIT:
314 if (!((src_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_FBO_ATTACHABLE)
315 || (src_resource->usage & WINED3DUSAGE_RENDERTARGET)))
316 return FALSE;
317 if (!((dst_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_FBO_ATTACHABLE)
318 || (dst_resource->usage & WINED3DUSAGE_RENDERTARGET)))
319 return FALSE;
320 if ((src_format->id != dst_format->id || dst_location == WINED3D_LOCATION_DRAWABLE)
321 && (!is_identity_fixup(src_format->color_fixup) || !is_identity_fixup(dst_format->color_fixup)))
322 return FALSE;
323 break;
325 case WINED3D_BLIT_OP_DEPTH_BLIT:
326 if (!(src_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL)))
327 return FALSE;
328 if (!(dst_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL)))
329 return FALSE;
330 /* Accept pure swizzle fixups for depth formats. In general we
331 * ignore the stencil component (if present) at the moment and the
332 * swizzle is not relevant with just the depth component. */
333 if (is_complex_fixup(src_format->color_fixup) || is_complex_fixup(dst_format->color_fixup)
334 || is_scaling_fixup(src_format->color_fixup) || is_scaling_fixup(dst_format->color_fixup))
335 return FALSE;
336 break;
338 default:
339 return FALSE;
342 return TRUE;
345 /* See also float_16_to_32() in wined3d_private.h */
346 static inline unsigned short float_32_to_16(const float *in)
348 int exp = 0;
349 float tmp = fabsf(*in);
350 unsigned int mantissa;
351 unsigned short ret;
353 /* Deal with special numbers */
354 if (*in == 0.0f)
355 return 0x0000;
356 if (isnan(*in))
357 return 0x7c01;
358 if (isinf(*in))
359 return (*in < 0.0f ? 0xfc00 : 0x7c00);
361 if (tmp < (float)(1u << 10))
365 tmp = tmp * 2.0f;
366 exp--;
367 } while (tmp < (float)(1u << 10));
369 else if (tmp >= (float)(1u << 11))
373 tmp /= 2.0f;
374 exp++;
375 } while (tmp >= (float)(1u << 11));
378 mantissa = (unsigned int)tmp;
379 if (tmp - mantissa >= 0.5f)
380 ++mantissa; /* Round to nearest, away from zero. */
382 exp += 10; /* Normalize the mantissa. */
383 exp += 15; /* Exponent is encoded with excess 15. */
385 if (exp > 30) /* too big */
387 ret = 0x7c00; /* INF */
389 else if (exp <= 0)
391 /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers. */
392 while (exp <= 0)
394 mantissa = mantissa >> 1;
395 ++exp;
397 ret = mantissa & 0x3ff;
399 else
401 ret = (exp << 10) | (mantissa & 0x3ff);
404 ret |= ((*in < 0.0f ? 1 : 0) << 15); /* Add the sign */
405 return ret;
408 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst,
409 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
411 unsigned short *dst_s;
412 const float *src_f;
413 unsigned int x, y;
415 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
417 for (y = 0; y < h; ++y)
419 src_f = (const float *)(src + y * pitch_in);
420 dst_s = (unsigned short *) (dst + y * pitch_out);
421 for (x = 0; x < w; ++x)
423 dst_s[x] = float_32_to_16(src_f + x);
428 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
429 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
431 static const unsigned char convert_5to8[] =
433 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
434 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
435 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
436 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
438 static const unsigned char convert_6to8[] =
440 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
441 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
442 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
443 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
444 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
445 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
446 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
447 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
449 unsigned int x, y;
451 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
453 for (y = 0; y < h; ++y)
455 const WORD *src_line = (const WORD *)(src + y * pitch_in);
456 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
457 for (x = 0; x < w; ++x)
459 WORD pixel = src_line[x];
460 dst_line[x] = 0xff000000u
461 | convert_5to8[(pixel & 0xf800u) >> 11] << 16
462 | convert_6to8[(pixel & 0x07e0u) >> 5] << 8
463 | convert_5to8[(pixel & 0x001fu)];
468 /* We use this for both B8G8R8A8 -> B8G8R8X8 and B8G8R8X8 -> B8G8R8A8, since
469 * in both cases we're just setting the X / Alpha channel to 0xff. */
470 static void convert_a8r8g8b8_x8r8g8b8(const BYTE *src, BYTE *dst,
471 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
473 unsigned int x, y;
475 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
477 for (y = 0; y < h; ++y)
479 const DWORD *src_line = (const DWORD *)(src + y * pitch_in);
480 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
482 for (x = 0; x < w; ++x)
484 dst_line[x] = 0xff000000 | (src_line[x] & 0xffffff);
489 static inline BYTE cliptobyte(int x)
491 return (BYTE)((x < 0) ? 0 : ((x > 255) ? 255 : x));
494 static void convert_yuy2_x8r8g8b8(const BYTE *src, BYTE *dst,
495 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
497 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
498 unsigned int x, y;
500 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
502 for (y = 0; y < h; ++y)
504 const BYTE *src_line = src + y * pitch_in;
505 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
506 for (x = 0; x < w; ++x)
508 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
509 * C = Y - 16; D = U - 128; E = V - 128;
510 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
511 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
512 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
513 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
514 * U and V are shared between the pixels. */
515 if (!(x & 1)) /* For every even pixel, read new U and V. */
517 d = (int) src_line[1] - 128;
518 e = (int) src_line[3] - 128;
519 r2 = 409 * e + 128;
520 g2 = - 100 * d - 208 * e + 128;
521 b2 = 516 * d + 128;
523 c2 = 298 * ((int) src_line[0] - 16);
524 dst_line[x] = 0xff000000
525 | cliptobyte((c2 + r2) >> 8) << 16 /* red */
526 | cliptobyte((c2 + g2) >> 8) << 8 /* green */
527 | cliptobyte((c2 + b2) >> 8); /* blue */
528 /* Scale RGB values to 0..255 range,
529 * then clip them if still not in range (may be negative),
530 * then shift them within DWORD if necessary. */
531 src_line += 2;
536 static void convert_yuy2_r5g6b5(const BYTE *src, BYTE *dst,
537 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
539 unsigned int x, y;
540 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
542 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
544 for (y = 0; y < h; ++y)
546 const BYTE *src_line = src + y * pitch_in;
547 WORD *dst_line = (WORD *)(dst + y * pitch_out);
548 for (x = 0; x < w; ++x)
550 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
551 * C = Y - 16; D = U - 128; E = V - 128;
552 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
553 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
554 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
555 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
556 * U and V are shared between the pixels. */
557 if (!(x & 1)) /* For every even pixel, read new U and V. */
559 d = (int) src_line[1] - 128;
560 e = (int) src_line[3] - 128;
561 r2 = 409 * e + 128;
562 g2 = - 100 * d - 208 * e + 128;
563 b2 = 516 * d + 128;
565 c2 = 298 * ((int) src_line[0] - 16);
566 dst_line[x] = (cliptobyte((c2 + r2) >> 8) >> 3) << 11 /* red */
567 | (cliptobyte((c2 + g2) >> 8) >> 2) << 5 /* green */
568 | (cliptobyte((c2 + b2) >> 8) >> 3); /* blue */
569 /* Scale RGB values to 0..255 range,
570 * then clip them if still not in range (may be negative),
571 * then shift them within DWORD if necessary. */
572 src_line += 2;
577 struct d3dfmt_converter_desc
579 enum wined3d_format_id from, to;
580 void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
583 static const struct d3dfmt_converter_desc converters[] =
585 {WINED3DFMT_R32_FLOAT, WINED3DFMT_R16_FLOAT, convert_r32_float_r16_float},
586 {WINED3DFMT_B5G6R5_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_r5g6b5_x8r8g8b8},
587 {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_a8r8g8b8_x8r8g8b8},
588 {WINED3DFMT_B8G8R8X8_UNORM, WINED3DFMT_B8G8R8A8_UNORM, convert_a8r8g8b8_x8r8g8b8},
589 {WINED3DFMT_YUY2, WINED3DFMT_B8G8R8X8_UNORM, convert_yuy2_x8r8g8b8},
590 {WINED3DFMT_YUY2, WINED3DFMT_B5G6R5_UNORM, convert_yuy2_r5g6b5},
593 static inline const struct d3dfmt_converter_desc *find_converter(enum wined3d_format_id from,
594 enum wined3d_format_id to)
596 unsigned int i;
598 for (i = 0; i < ARRAY_SIZE(converters); ++i)
600 if (converters[i].from == from && converters[i].to == to)
601 return &converters[i];
604 return NULL;
607 static struct wined3d_texture *surface_convert_format(struct wined3d_texture *src_texture,
608 unsigned int sub_resource_idx, const struct wined3d_format *dst_format)
610 unsigned int texture_level = sub_resource_idx % src_texture->level_count;
611 const struct wined3d_format *src_format = src_texture->resource.format;
612 struct wined3d_device *device = src_texture->resource.device;
613 const struct d3dfmt_converter_desc *conv = NULL;
614 unsigned int src_row_pitch, src_slice_pitch;
615 struct wined3d_context *context = NULL;
616 struct wined3d_texture *dst_texture;
617 struct wined3d_bo_address src_data;
618 struct wined3d_resource_desc desc;
619 DWORD map_binding;
621 if (!(conv = find_converter(src_format->id, dst_format->id)) && (!device->d3d_initialized
622 || !is_identity_fixup(src_format->color_fixup) || src_format->conv_byte_count
623 || !is_identity_fixup(dst_format->color_fixup) || dst_format->conv_byte_count
624 || (src_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_COMPRESSED)))
626 FIXME("Cannot find a conversion function from format %s to %s.\n",
627 debug_d3dformat(src_format->id), debug_d3dformat(dst_format->id));
628 return NULL;
631 /* FIXME: Multisampled conversion? */
632 desc.resource_type = WINED3D_RTYPE_TEXTURE_2D;
633 desc.format = dst_format->id;
634 desc.multisample_type = WINED3D_MULTISAMPLE_NONE;
635 desc.multisample_quality = 0;
636 desc.usage = WINED3DUSAGE_SCRATCH | WINED3DUSAGE_PRIVATE;
637 desc.access = WINED3D_RESOURCE_ACCESS_CPU | WINED3D_RESOURCE_ACCESS_MAP_R | WINED3D_RESOURCE_ACCESS_MAP_W;
638 desc.width = wined3d_texture_get_level_width(src_texture, texture_level);
639 desc.height = wined3d_texture_get_level_height(src_texture, texture_level);
640 desc.depth = 1;
641 desc.size = 0;
642 if (FAILED(wined3d_texture_create(device, &desc, 1, 1,
643 WINED3D_TEXTURE_CREATE_MAPPABLE | WINED3D_TEXTURE_CREATE_DISCARD,
644 NULL, NULL, &wined3d_null_parent_ops, &dst_texture)))
646 ERR("Failed to create a destination texture for conversion.\n");
647 return NULL;
650 if (device->d3d_initialized)
651 context = context_acquire(device, NULL, 0);
653 map_binding = src_texture->resource.map_binding;
654 if (!wined3d_texture_load_location(src_texture, sub_resource_idx, context, map_binding))
655 ERR("Failed to load the source sub-resource into %s.\n", wined3d_debug_location(map_binding));
656 wined3d_texture_get_pitch(src_texture, texture_level, &src_row_pitch, &src_slice_pitch);
657 wined3d_texture_get_memory(src_texture, sub_resource_idx, &src_data, map_binding);
659 if (conv)
661 unsigned int dst_row_pitch, dst_slice_pitch;
662 struct wined3d_bo_address dst_data;
663 const BYTE *src;
664 BYTE *dst;
666 map_binding = dst_texture->resource.map_binding;
667 if (!wined3d_texture_load_location(dst_texture, 0, context, map_binding))
668 ERR("Failed to load the destination sub-resource into %s.\n", wined3d_debug_location(map_binding));
669 wined3d_texture_get_pitch(dst_texture, 0, &dst_row_pitch, &dst_slice_pitch);
670 wined3d_texture_get_memory(dst_texture, 0, &dst_data, map_binding);
672 src = context_map_bo_address(context, &src_data,
673 src_texture->sub_resources[sub_resource_idx].size, GL_PIXEL_UNPACK_BUFFER, WINED3D_MAP_READ);
674 dst = context_map_bo_address(context,
675 &dst_data, dst_texture->sub_resources[0].size, GL_PIXEL_UNPACK_BUFFER, WINED3D_MAP_WRITE);
677 conv->convert(src, dst, src_row_pitch, dst_row_pitch, desc.width, desc.height);
679 wined3d_texture_invalidate_location(dst_texture, 0, ~map_binding);
680 context_unmap_bo_address(context, &dst_data, GL_PIXEL_UNPACK_BUFFER);
681 context_unmap_bo_address(context, &src_data, GL_PIXEL_UNPACK_BUFFER);
683 else
685 struct wined3d_box src_box = {0, 0, desc.width, desc.height, 0, 1};
687 TRACE("Using upload conversion.\n");
689 wined3d_texture_prepare_texture(dst_texture, context, FALSE);
690 wined3d_texture_bind_and_dirtify(dst_texture, context, FALSE);
691 wined3d_texture_upload_data(dst_texture, 0, context, src_format, &src_box,
692 wined3d_const_bo_address(&src_data), src_row_pitch, src_slice_pitch, 0, 0, 0, FALSE);
694 wined3d_texture_validate_location(dst_texture, 0, WINED3D_LOCATION_TEXTURE_RGB);
695 wined3d_texture_invalidate_location(dst_texture, 0, ~WINED3D_LOCATION_TEXTURE_RGB);
698 if (context)
699 context_release(context);
701 return dst_texture;
704 static void texture2d_read_from_framebuffer(struct wined3d_texture *texture, unsigned int sub_resource_idx,
705 struct wined3d_context *context, DWORD src_location, DWORD dst_location)
707 struct wined3d_resource *resource = &texture->resource;
708 struct wined3d_device *device = resource->device;
709 const struct wined3d_format_gl *format_gl;
710 struct wined3d_texture *restore_texture;
711 const struct wined3d_gl_info *gl_info;
712 unsigned int row_pitch, slice_pitch;
713 unsigned int width, height, level;
714 struct wined3d_bo_address data;
715 unsigned int restore_idx;
716 BYTE *row, *top, *bottom;
717 BOOL src_is_upside_down;
718 unsigned int i;
719 BYTE *mem;
721 wined3d_texture_get_memory(texture, sub_resource_idx, &data, dst_location);
723 restore_texture = context->current_rt.texture;
724 restore_idx = context->current_rt.sub_resource_idx;
725 if (restore_texture != texture || restore_idx != sub_resource_idx)
726 context = context_acquire(device, texture, sub_resource_idx);
727 else
728 restore_texture = NULL;
729 gl_info = context->gl_info;
731 if (src_location != resource->draw_binding)
733 context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER,
734 resource, sub_resource_idx, NULL, 0, src_location);
735 context_check_fbo_status(context, GL_READ_FRAMEBUFFER);
736 context_invalidate_state(context, STATE_FRAMEBUFFER);
738 else
740 context_apply_blit_state(context, device);
743 /* Select the correct read buffer, and give some debug output.
744 * There is no need to keep track of the current read buffer or reset it,
745 * every part of the code that reads sets the read buffer as desired.
747 if (src_location != WINED3D_LOCATION_DRAWABLE || wined3d_resource_is_offscreen(resource))
749 /* Mapping the primary render target which is not on a swapchain.
750 * Read from the back buffer. */
751 TRACE("Mapping offscreen render target.\n");
752 gl_info->gl_ops.gl.p_glReadBuffer(context_get_offscreen_gl_buffer(context));
753 src_is_upside_down = TRUE;
755 else
757 /* Onscreen surfaces are always part of a swapchain */
758 GLenum buffer = wined3d_texture_get_gl_buffer(texture);
759 TRACE("Mapping %#x buffer.\n", buffer);
760 gl_info->gl_ops.gl.p_glReadBuffer(buffer);
761 src_is_upside_down = FALSE;
763 checkGLcall("glReadBuffer");
765 if (data.buffer_object)
767 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, data.buffer_object));
768 checkGLcall("glBindBuffer");
771 level = sub_resource_idx % texture->level_count;
772 wined3d_texture_get_pitch(texture, level, &row_pitch, &slice_pitch);
773 format_gl = wined3d_format_gl(resource->format);
775 /* Setup pixel store pack state -- to glReadPixels into the correct place */
776 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_ROW_LENGTH, row_pitch / format_gl->f.byte_count);
777 checkGLcall("glPixelStorei");
779 width = wined3d_texture_get_level_width(texture, level);
780 height = wined3d_texture_get_level_height(texture, level);
781 gl_info->gl_ops.gl.p_glReadPixels(0, 0, width, height,
782 format_gl->format, format_gl->type, data.addr);
783 checkGLcall("glReadPixels");
785 /* Reset previous pixel store pack state */
786 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_ROW_LENGTH, 0);
787 checkGLcall("glPixelStorei");
789 if (!src_is_upside_down)
791 /* glReadPixels returns the image upside down, and there is no way to
792 * prevent this. Flip the lines in software. */
794 if (!(row = heap_alloc(row_pitch)))
795 goto error;
797 if (data.buffer_object)
799 mem = GL_EXTCALL(glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_WRITE));
800 checkGLcall("glMapBuffer");
802 else
803 mem = data.addr;
805 top = mem;
806 bottom = mem + row_pitch * (height - 1);
807 for (i = 0; i < height / 2; i++)
809 memcpy(row, top, row_pitch);
810 memcpy(top, bottom, row_pitch);
811 memcpy(bottom, row, row_pitch);
812 top += row_pitch;
813 bottom -= row_pitch;
815 heap_free(row);
817 if (data.buffer_object)
818 GL_EXTCALL(glUnmapBuffer(GL_PIXEL_PACK_BUFFER));
821 error:
822 if (data.buffer_object)
824 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));
825 checkGLcall("glBindBuffer");
828 if (restore_texture)
829 context_restore(context, restore_texture, restore_idx);
832 /* Read the framebuffer contents into a texture. Note that this function
833 * doesn't do any kind of flipping. Using this on an onscreen surface will
834 * result in a flipped D3D texture.
836 * Context activation is done by the caller. This function may temporarily
837 * switch to a different context and restore the original one before return. */
838 void texture2d_load_fb_texture(struct wined3d_texture *texture,
839 unsigned int sub_resource_idx, BOOL srgb, struct wined3d_context *context)
841 struct wined3d_device *device = texture->resource.device;
842 struct wined3d_texture *restore_texture;
843 const struct wined3d_gl_info *gl_info;
844 unsigned int restore_idx, level;
845 GLenum target;
847 restore_texture = context->current_rt.texture;
848 restore_idx = context->current_rt.sub_resource_idx;
849 if (restore_texture != texture || restore_idx != sub_resource_idx)
850 context = context_acquire(device, texture, sub_resource_idx);
851 else
852 restore_texture = NULL;
854 gl_info = context->gl_info;
855 device_invalidate_state(device, STATE_FRAMEBUFFER);
857 wined3d_texture_prepare_texture(texture, context, srgb);
858 wined3d_texture_bind_and_dirtify(texture, context, srgb);
860 TRACE("Reading back offscreen render target %p, %u.\n", texture, sub_resource_idx);
862 if (wined3d_resource_is_offscreen(&texture->resource))
863 gl_info->gl_ops.gl.p_glReadBuffer(context_get_offscreen_gl_buffer(context));
864 else
865 gl_info->gl_ops.gl.p_glReadBuffer(wined3d_texture_get_gl_buffer(texture));
866 checkGLcall("glReadBuffer");
868 level = sub_resource_idx % texture->level_count;
869 target = wined3d_texture_get_sub_resource_target(texture, sub_resource_idx);
870 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(target, level, 0, 0, 0, 0,
871 wined3d_texture_get_level_width(texture, level),
872 wined3d_texture_get_level_height(texture, level));
873 checkGLcall("glCopyTexSubImage2D");
875 if (restore_texture)
876 context_restore(context, restore_texture, restore_idx);
879 /* Does a direct frame buffer -> texture copy. Stretching is done with single
880 * pixel copy calls. */
881 static void fb_copy_to_texture_direct(struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx,
882 const RECT *dst_rect_in, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx,
883 const RECT *src_rect, enum wined3d_texture_filter_type filter)
885 struct wined3d_device *device = dst_texture->resource.device;
886 unsigned int src_height, src_level, dst_level;
887 const struct wined3d_gl_info *gl_info;
888 float xrel, yrel;
889 struct wined3d_context *context;
890 BOOL upsidedown = FALSE;
891 RECT dst_rect = *dst_rect_in;
892 GLenum dst_target;
894 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
895 * glCopyTexSubImage is a bit picky about the parameters we pass to it
897 if(dst_rect.top > dst_rect.bottom) {
898 UINT tmp = dst_rect.bottom;
899 dst_rect.bottom = dst_rect.top;
900 dst_rect.top = tmp;
901 upsidedown = TRUE;
904 context = context_acquire(device, src_texture, src_sub_resource_idx);
905 gl_info = context->gl_info;
906 context_apply_blit_state(context, device);
907 wined3d_texture_load(dst_texture, context, FALSE);
909 /* Bind the target texture */
910 context_bind_texture(context, dst_texture->target, dst_texture->texture_rgb.name);
911 if (wined3d_resource_is_offscreen(&src_texture->resource))
913 TRACE("Reading from an offscreen target\n");
914 upsidedown = !upsidedown;
915 gl_info->gl_ops.gl.p_glReadBuffer(context_get_offscreen_gl_buffer(context));
917 else
919 gl_info->gl_ops.gl.p_glReadBuffer(wined3d_texture_get_gl_buffer(src_texture));
921 checkGLcall("glReadBuffer");
923 xrel = (float) (src_rect->right - src_rect->left) / (float) (dst_rect.right - dst_rect.left);
924 yrel = (float) (src_rect->bottom - src_rect->top) / (float) (dst_rect.bottom - dst_rect.top);
926 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
928 FIXME_(d3d_perf)("Doing a pixel by pixel copy from the framebuffer to a texture.\n");
930 if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT)
931 ERR("Texture filtering not supported in direct blit.\n");
933 else if ((filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT)
934 && ((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
936 ERR("Texture filtering not supported in direct blit\n");
939 src_level = src_sub_resource_idx % src_texture->level_count;
940 dst_level = dst_sub_resource_idx % dst_texture->level_count;
942 src_height = wined3d_texture_get_level_height(src_texture, src_level);
943 dst_target = wined3d_texture_get_sub_resource_target(dst_texture, dst_sub_resource_idx);
944 if (upsidedown
945 && !((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
946 && !((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
948 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do. */
949 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_target, dst_level,
950 dst_rect.left /*xoffset */, dst_rect.top /* y offset */,
951 src_rect->left, src_height - src_rect->bottom,
952 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
954 else
956 LONG row;
957 UINT yoffset = src_height - src_rect->top + dst_rect.top - 1;
958 /* I have to process this row by row to swap the image,
959 * otherwise it would be upside down, so stretching in y direction
960 * doesn't cost extra time
962 * However, stretching in x direction can be avoided if not necessary
964 for(row = dst_rect.top; row < dst_rect.bottom; row++) {
965 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
967 /* Well, that stuff works, but it's very slow.
968 * find a better way instead
970 LONG col;
972 for (col = dst_rect.left; col < dst_rect.right; ++col)
974 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_target, dst_level,
975 dst_rect.left + col /* x offset */, row /* y offset */,
976 src_rect->left + col * xrel, yoffset - (int) (row * yrel), 1, 1);
979 else
981 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_target, dst_level,
982 dst_rect.left /* x offset */, row /* y offset */,
983 src_rect->left, yoffset - (int) (row * yrel), dst_rect.right - dst_rect.left, 1);
987 checkGLcall("glCopyTexSubImage2D");
989 context_release(context);
991 /* The texture is now most up to date - If the surface is a render target
992 * and has a drawable, this path is never entered. */
993 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB);
994 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB);
997 /* Uses the hardware to stretch and flip the image */
998 static void fb_copy_to_texture_hwstretch(struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx,
999 const RECT *dst_rect_in, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx,
1000 const RECT *src_rect, enum wined3d_texture_filter_type filter)
1002 unsigned int src_width, src_height, src_pow2_width, src_pow2_height, src_level;
1003 struct wined3d_device *device = dst_texture->resource.device;
1004 GLenum src_target, dst_target, texture_target;
1005 GLuint src, backup = 0;
1006 float left, right, top, bottom; /* Texture coordinates */
1007 const struct wined3d_gl_info *gl_info;
1008 struct wined3d_context *context;
1009 GLenum drawBuffer = GL_BACK;
1010 GLenum offscreen_buffer;
1011 BOOL noBackBufferBackup;
1012 BOOL src_offscreen;
1013 BOOL upsidedown = FALSE;
1014 RECT dst_rect = *dst_rect_in;
1016 TRACE("Using hwstretch blit\n");
1018 src_target = wined3d_texture_get_sub_resource_target(src_texture, src_sub_resource_idx);
1019 dst_target = wined3d_texture_get_sub_resource_target(dst_texture, dst_sub_resource_idx);
1021 /* Activate the Proper context for reading from the source surface, set it up for blitting */
1022 context = context_acquire(device, src_texture, src_sub_resource_idx);
1023 gl_info = context->gl_info;
1024 context_apply_ffp_blit_state(context, device);
1025 wined3d_texture_load(dst_texture, context, FALSE);
1027 offscreen_buffer = context_get_offscreen_gl_buffer(context);
1028 src_level = src_sub_resource_idx % src_texture->level_count;
1029 src_width = wined3d_texture_get_level_width(src_texture, src_level);
1030 src_height = wined3d_texture_get_level_height(src_texture, src_level);
1031 src_pow2_width = wined3d_texture_get_level_pow2_width(src_texture, src_level);
1032 src_pow2_height = wined3d_texture_get_level_pow2_height(src_texture, src_level);
1034 src_offscreen = wined3d_resource_is_offscreen(&src_texture->resource);
1035 noBackBufferBackup = src_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO;
1036 if (!noBackBufferBackup && !src_texture->texture_rgb.name)
1038 /* Get it a description */
1039 wined3d_texture_load(src_texture, context, FALSE);
1042 /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
1043 * This way we don't have to wait for the 2nd readback to finish to leave this function.
1045 if (context->aux_buffers >= 2)
1047 /* Got more than one aux buffer? Use the 2nd aux buffer */
1048 drawBuffer = GL_AUX1;
1050 else if ((!src_offscreen || offscreen_buffer == GL_BACK) && context->aux_buffers >= 1)
1052 /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
1053 drawBuffer = GL_AUX0;
1056 if (noBackBufferBackup)
1058 gl_info->gl_ops.gl.p_glGenTextures(1, &backup);
1059 checkGLcall("glGenTextures");
1060 context_bind_texture(context, GL_TEXTURE_2D, backup);
1061 texture_target = GL_TEXTURE_2D;
1063 else
1065 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
1066 * we are reading from the back buffer, the backup can be used as source texture
1068 texture_target = src_target;
1069 context_bind_texture(context, texture_target, src_texture->texture_rgb.name);
1070 gl_info->gl_ops.gl.p_glEnable(texture_target);
1071 checkGLcall("glEnable(texture_target)");
1073 /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
1074 src_texture->sub_resources[src_sub_resource_idx].locations &= ~WINED3D_LOCATION_TEXTURE_RGB;
1077 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
1078 * glCopyTexSubImage is a bit picky about the parameters we pass to it
1080 if(dst_rect.top > dst_rect.bottom) {
1081 UINT tmp = dst_rect.bottom;
1082 dst_rect.bottom = dst_rect.top;
1083 dst_rect.top = tmp;
1084 upsidedown = TRUE;
1087 if (src_offscreen)
1089 TRACE("Reading from an offscreen target\n");
1090 upsidedown = !upsidedown;
1091 gl_info->gl_ops.gl.p_glReadBuffer(offscreen_buffer);
1093 else
1095 gl_info->gl_ops.gl.p_glReadBuffer(wined3d_texture_get_gl_buffer(src_texture));
1098 /* TODO: Only back up the part that will be overwritten */
1099 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(texture_target, 0, 0, 0, 0, 0, src_width, src_height);
1101 checkGLcall("glCopyTexSubImage2D");
1103 /* No issue with overriding these - the sampler is dirty due to blit usage */
1104 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, wined3d_gl_mag_filter(filter));
1105 checkGLcall("glTexParameteri");
1106 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER,
1107 wined3d_gl_min_mip_filter(filter, WINED3D_TEXF_NONE));
1108 checkGLcall("glTexParameteri");
1110 if (!src_texture->swapchain || src_texture == src_texture->swapchain->back_buffers[0])
1112 src = backup ? backup : src_texture->texture_rgb.name;
1114 else
1116 gl_info->gl_ops.gl.p_glReadBuffer(GL_FRONT);
1117 checkGLcall("glReadBuffer(GL_FRONT)");
1119 gl_info->gl_ops.gl.p_glGenTextures(1, &src);
1120 checkGLcall("glGenTextures(1, &src)");
1121 context_bind_texture(context, GL_TEXTURE_2D, src);
1123 /* TODO: Only copy the part that will be read. Use src_rect->left,
1124 * src_rect->bottom as origin, but with the width watch out for power
1125 * of 2 sizes. */
1126 gl_info->gl_ops.gl.p_glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, src_pow2_width,
1127 src_pow2_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
1128 checkGLcall("glTexImage2D");
1129 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, src_width, src_height);
1131 gl_info->gl_ops.gl.p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1132 checkGLcall("glTexParameteri");
1133 gl_info->gl_ops.gl.p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1134 checkGLcall("glTexParameteri");
1136 gl_info->gl_ops.gl.p_glReadBuffer(GL_BACK);
1137 checkGLcall("glReadBuffer(GL_BACK)");
1139 if (texture_target != GL_TEXTURE_2D)
1141 gl_info->gl_ops.gl.p_glDisable(texture_target);
1142 gl_info->gl_ops.gl.p_glEnable(GL_TEXTURE_2D);
1143 texture_target = GL_TEXTURE_2D;
1146 checkGLcall("glEnd and previous");
1148 left = src_rect->left;
1149 right = src_rect->right;
1151 if (!upsidedown)
1153 top = src_height - src_rect->top;
1154 bottom = src_height - src_rect->bottom;
1156 else
1158 top = src_height - src_rect->bottom;
1159 bottom = src_height - src_rect->top;
1162 if (src_texture->flags & WINED3D_TEXTURE_NORMALIZED_COORDS)
1164 left /= src_pow2_width;
1165 right /= src_pow2_width;
1166 top /= src_pow2_height;
1167 bottom /= src_pow2_height;
1170 /* draw the source texture stretched and upside down. The correct surface is bound already */
1171 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1172 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1174 context_set_draw_buffer(context, drawBuffer);
1175 gl_info->gl_ops.gl.p_glReadBuffer(drawBuffer);
1177 gl_info->gl_ops.gl.p_glBegin(GL_QUADS);
1178 /* bottom left */
1179 gl_info->gl_ops.gl.p_glTexCoord2f(left, bottom);
1180 gl_info->gl_ops.gl.p_glVertex2i(0, 0);
1182 /* top left */
1183 gl_info->gl_ops.gl.p_glTexCoord2f(left, top);
1184 gl_info->gl_ops.gl.p_glVertex2i(0, dst_rect.bottom - dst_rect.top);
1186 /* top right */
1187 gl_info->gl_ops.gl.p_glTexCoord2f(right, top);
1188 gl_info->gl_ops.gl.p_glVertex2i(dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
1190 /* bottom right */
1191 gl_info->gl_ops.gl.p_glTexCoord2f(right, bottom);
1192 gl_info->gl_ops.gl.p_glVertex2i(dst_rect.right - dst_rect.left, 0);
1193 gl_info->gl_ops.gl.p_glEnd();
1194 checkGLcall("glEnd and previous");
1196 if (texture_target != dst_target)
1198 gl_info->gl_ops.gl.p_glDisable(texture_target);
1199 gl_info->gl_ops.gl.p_glEnable(dst_target);
1200 texture_target = dst_target;
1203 /* Now read the stretched and upside down image into the destination texture */
1204 context_bind_texture(context, texture_target, dst_texture->texture_rgb.name);
1205 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(texture_target,
1207 dst_rect.left, dst_rect.top, /* xoffset, yoffset */
1208 0, 0, /* We blitted the image to the origin */
1209 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
1210 checkGLcall("glCopyTexSubImage2D");
1212 if (drawBuffer == GL_BACK)
1214 /* Write the back buffer backup back. */
1215 if (backup)
1217 if (texture_target != GL_TEXTURE_2D)
1219 gl_info->gl_ops.gl.p_glDisable(texture_target);
1220 gl_info->gl_ops.gl.p_glEnable(GL_TEXTURE_2D);
1221 texture_target = GL_TEXTURE_2D;
1223 context_bind_texture(context, GL_TEXTURE_2D, backup);
1225 else
1227 if (texture_target != src_target)
1229 gl_info->gl_ops.gl.p_glDisable(texture_target);
1230 gl_info->gl_ops.gl.p_glEnable(src_target);
1231 texture_target = src_target;
1233 context_bind_texture(context, src_target, src_texture->texture_rgb.name);
1236 gl_info->gl_ops.gl.p_glBegin(GL_QUADS);
1237 /* top left */
1238 gl_info->gl_ops.gl.p_glTexCoord2f(0.0f, 0.0f);
1239 gl_info->gl_ops.gl.p_glVertex2i(0, src_height);
1241 /* bottom left */
1242 gl_info->gl_ops.gl.p_glTexCoord2f(0.0f, (float)src_height / (float)src_pow2_height);
1243 gl_info->gl_ops.gl.p_glVertex2i(0, 0);
1245 /* bottom right */
1246 gl_info->gl_ops.gl.p_glTexCoord2f((float)src_width / (float)src_pow2_width,
1247 (float)src_height / (float)src_pow2_height);
1248 gl_info->gl_ops.gl.p_glVertex2i(src_width, 0);
1250 /* top right */
1251 gl_info->gl_ops.gl.p_glTexCoord2f((float)src_width / (float)src_pow2_width, 0.0f);
1252 gl_info->gl_ops.gl.p_glVertex2i(src_width, src_height);
1253 gl_info->gl_ops.gl.p_glEnd();
1255 gl_info->gl_ops.gl.p_glDisable(texture_target);
1256 checkGLcall("glDisable(texture_target)");
1258 /* Cleanup */
1259 if (src != src_texture->texture_rgb.name && src != backup)
1261 gl_info->gl_ops.gl.p_glDeleteTextures(1, &src);
1262 checkGLcall("glDeleteTextures(1, &src)");
1264 if (backup)
1266 gl_info->gl_ops.gl.p_glDeleteTextures(1, &backup);
1267 checkGLcall("glDeleteTextures(1, &backup)");
1270 context_release(context);
1272 /* The texture is now most up to date - If the surface is a render target
1273 * and has a drawable, this path is never entered. */
1274 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB);
1275 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB);
1278 static HRESULT wined3d_texture_blt_special(struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx,
1279 const RECT *dst_rect, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx,
1280 const RECT *src_rect, DWORD flags, const struct wined3d_blt_fx *fx, enum wined3d_texture_filter_type filter)
1282 struct wined3d_swapchain *src_swapchain, *dst_swapchain;
1283 const struct wined3d_rendertarget_view *rtv;
1285 TRACE("dst_texture %p, dst_sub_resource_idx %u, dst_rect %s, src_texture %p, "
1286 "src_sub_resource_idx %u, src_rect %s, flags %#x, fx %p, filter %s.\n",
1287 dst_texture, dst_sub_resource_idx, wine_dbgstr_rect(dst_rect), src_texture, src_sub_resource_idx,
1288 wine_dbgstr_rect(src_rect), flags, fx, debug_d3dtexturefiltertype(filter));
1290 if (dst_texture->resource.type != WINED3D_RTYPE_TEXTURE_2D)
1292 FIXME("Not implemented for %s resources.\n", debug_d3dresourcetype(dst_texture->resource.type));
1293 return WINED3DERR_INVALIDCALL;
1296 /* Get the swapchain. One of the surfaces has to be a primary surface. */
1297 if (!(dst_texture->resource.access & WINED3D_RESOURCE_ACCESS_GPU))
1299 WARN("Destination resource is not GPU accessible, rejecting GL blit.\n");
1300 return WINED3DERR_INVALIDCALL;
1303 if (!(src_texture->resource.access & WINED3D_RESOURCE_ACCESS_GPU))
1305 WARN("Source resource is not GPU accessible, rejecting GL blit.\n");
1306 return WINED3DERR_INVALIDCALL;
1309 src_swapchain = src_texture->swapchain;
1310 dst_swapchain = dst_texture->swapchain;
1312 /* Early sort out of cases where no render target is used */
1313 if (!(rtv = dst_texture->resource.device->fb.render_targets[0]) || (!src_swapchain && !dst_swapchain
1314 && (&src_texture->resource != rtv->resource || src_sub_resource_idx != rtv->sub_resource_idx)
1315 && (&dst_texture->resource != rtv->resource || dst_sub_resource_idx != rtv->sub_resource_idx)))
1317 TRACE("No surface is render target, not using hardware blit.\n");
1318 return WINED3DERR_INVALIDCALL;
1321 /* No destination color keying supported */
1322 if (flags & (WINED3D_BLT_DST_CKEY | WINED3D_BLT_DST_CKEY_OVERRIDE))
1324 /* Can we support that with glBlendFunc if blitting to the frame buffer? */
1325 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
1326 return WINED3DERR_INVALIDCALL;
1329 if (dst_swapchain && dst_swapchain == src_swapchain)
1331 FIXME("Implement hardware blit between two surfaces on the same swapchain\n");
1332 return WINED3DERR_INVALIDCALL;
1335 if (dst_swapchain && src_swapchain)
1337 FIXME("Implement hardware blit between two different swapchains\n");
1338 return WINED3DERR_INVALIDCALL;
1341 if (dst_swapchain)
1343 /* Handled with regular texture -> swapchain blit */
1344 if (&src_texture->resource == rtv->resource && src_sub_resource_idx == rtv->sub_resource_idx)
1345 TRACE("Blit from active render target to a swapchain\n");
1347 else if (src_swapchain && &dst_texture->resource == rtv->resource
1348 && dst_sub_resource_idx == rtv->sub_resource_idx)
1350 FIXME("Implement blit from a swapchain to the active render target\n");
1351 return WINED3DERR_INVALIDCALL;
1354 if (!dst_swapchain && (src_swapchain || (&src_texture->resource == rtv->resource
1355 && src_sub_resource_idx == rtv->sub_resource_idx)))
1357 unsigned int src_level, src_width, src_height;
1358 /* Blit from render target to texture */
1359 BOOL stretchx;
1361 /* P8 read back is not implemented */
1362 if (src_texture->resource.format->id == WINED3DFMT_P8_UINT
1363 || dst_texture->resource.format->id == WINED3DFMT_P8_UINT)
1365 TRACE("P8 read back not supported by frame buffer to texture blit\n");
1366 return WINED3DERR_INVALIDCALL;
1369 if (flags & (WINED3D_BLT_SRC_CKEY | WINED3D_BLT_SRC_CKEY_OVERRIDE))
1371 TRACE("Color keying not supported by frame buffer to texture blit\n");
1372 return WINED3DERR_INVALIDCALL;
1373 /* Destination color key is checked above */
1376 if (dst_rect->right - dst_rect->left != src_rect->right - src_rect->left)
1377 stretchx = TRUE;
1378 else
1379 stretchx = FALSE;
1381 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
1382 * flip the image nor scale it.
1384 * -> If the app asks for an unscaled, upside down copy, just perform one glCopyTexSubImage2D call
1385 * -> If the app wants an image width an unscaled width, copy it line per line
1386 * -> If the app wants an image that is scaled on the x axis, and the destination rectangle is smaller
1387 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
1388 * back buffer. This is slower than reading line per line, thus not used for flipping
1389 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
1390 * pixel by pixel. */
1391 src_level = src_sub_resource_idx % src_texture->level_count;
1392 src_width = wined3d_texture_get_level_width(src_texture, src_level);
1393 src_height = wined3d_texture_get_level_height(src_texture, src_level);
1394 if (!stretchx || dst_rect->right - dst_rect->left > src_width
1395 || dst_rect->bottom - dst_rect->top > src_height)
1397 TRACE("No stretching in x direction, using direct framebuffer -> texture copy.\n");
1398 fb_copy_to_texture_direct(dst_texture, dst_sub_resource_idx, dst_rect,
1399 src_texture, src_sub_resource_idx, src_rect, filter);
1401 else
1403 TRACE("Using hardware stretching to flip / stretch the texture.\n");
1404 fb_copy_to_texture_hwstretch(dst_texture, dst_sub_resource_idx, dst_rect,
1405 src_texture, src_sub_resource_idx, src_rect, filter);
1408 return WINED3D_OK;
1411 /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
1412 TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
1413 return WINED3DERR_INVALIDCALL;
1416 /* Context activation is done by the caller. */
1417 BOOL texture2d_load_sysmem(struct wined3d_texture *texture, unsigned int sub_resource_idx,
1418 struct wined3d_context *context, DWORD dst_location)
1420 struct wined3d_texture_sub_resource *sub_resource;
1422 sub_resource = &texture->sub_resources[sub_resource_idx];
1423 wined3d_texture_prepare_location(texture, sub_resource_idx, context, dst_location);
1425 /* We cannot download data from multisample textures directly. */
1426 if (is_multisample_location(texture, WINED3D_LOCATION_TEXTURE_RGB))
1428 wined3d_texture_load_location(texture, sub_resource_idx, context, WINED3D_LOCATION_RB_RESOLVED);
1429 texture2d_read_from_framebuffer(texture, sub_resource_idx, context,
1430 WINED3D_LOCATION_RB_RESOLVED, dst_location);
1431 return TRUE;
1434 if (sub_resource->locations & (WINED3D_LOCATION_RB_MULTISAMPLE | WINED3D_LOCATION_RB_RESOLVED))
1435 wined3d_texture_load_location(texture, sub_resource_idx, context, WINED3D_LOCATION_TEXTURE_RGB);
1437 /* Download the sub-resource to system memory. */
1438 if (sub_resource->locations & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB))
1440 struct wined3d_bo_address data;
1441 wined3d_texture_bind_and_dirtify(texture, context,
1442 !(sub_resource->locations & WINED3D_LOCATION_TEXTURE_RGB));
1443 wined3d_texture_get_memory(texture, sub_resource_idx, &data, dst_location);
1444 wined3d_texture_download_data(texture, sub_resource_idx, context, &data);
1445 ++texture->download_count;
1446 return TRUE;
1449 if (!(texture->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
1450 && (sub_resource->locations & WINED3D_LOCATION_DRAWABLE))
1452 texture2d_read_from_framebuffer(texture, sub_resource_idx, context,
1453 texture->resource.draw_binding, dst_location);
1454 return TRUE;
1457 FIXME("Can't load texture %p, %u with location flags %s into sysmem.\n",
1458 texture, sub_resource_idx, wined3d_debug_location(sub_resource->locations));
1459 return FALSE;
1462 /* Context activation is done by the caller. */
1463 BOOL texture2d_load_drawable(struct wined3d_texture *texture,
1464 unsigned int sub_resource_idx, struct wined3d_context *context)
1466 struct wined3d_texture *restore_texture;
1467 struct wined3d_device *device;
1468 unsigned int restore_idx;
1469 unsigned int level;
1470 RECT r;
1472 if (texture->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
1474 DWORD current = texture->sub_resources[sub_resource_idx].locations;
1475 FIXME("Unimplemented copy from %s for depth/stencil buffers.\n",
1476 wined3d_debug_location(current));
1477 return FALSE;
1480 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO
1481 && wined3d_resource_is_offscreen(&texture->resource))
1483 ERR("Trying to load offscreen texture into WINED3D_LOCATION_DRAWABLE.\n");
1484 return FALSE;
1487 device = texture->resource.device;
1488 restore_texture = context->current_rt.texture;
1489 restore_idx = context->current_rt.sub_resource_idx;
1490 if (restore_texture != texture || restore_idx != sub_resource_idx)
1491 context = context_acquire(device, texture, sub_resource_idx);
1492 else
1493 restore_texture = NULL;
1495 level = sub_resource_idx % texture->level_count;
1496 SetRect(&r, 0, 0, wined3d_texture_get_level_width(texture, level),
1497 wined3d_texture_get_level_height(texture, level));
1498 wined3d_texture_load_location(texture, sub_resource_idx, context, WINED3D_LOCATION_TEXTURE_RGB);
1499 device->blitter->ops->blitter_blit(device->blitter, WINED3D_BLIT_OP_COLOR_BLIT, context,
1500 texture, sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB, &r,
1501 texture, sub_resource_idx, WINED3D_LOCATION_DRAWABLE, &r,
1502 NULL, WINED3D_TEXF_POINT);
1504 if (restore_texture)
1505 context_restore(context, restore_texture, restore_idx);
1507 return TRUE;
1510 BOOL texture2d_load_texture(struct wined3d_texture *texture, unsigned int sub_resource_idx,
1511 struct wined3d_context *context, BOOL srgb)
1513 unsigned int width, height, level, src_row_pitch, src_slice_pitch, dst_row_pitch, dst_slice_pitch;
1514 const struct wined3d_gl_info *gl_info = context->gl_info;
1515 struct wined3d_device *device = texture->resource.device;
1516 const struct wined3d_color_key_conversion *conversion;
1517 struct wined3d_texture_sub_resource *sub_resource;
1518 const struct wined3d_format *format;
1519 struct wined3d_bo_address data;
1520 BYTE *src_mem, *dst_mem = NULL;
1521 struct wined3d_box src_box;
1522 BOOL depth;
1524 depth = texture->resource.usage & WINED3DUSAGE_DEPTHSTENCIL;
1525 sub_resource = &texture->sub_resources[sub_resource_idx];
1527 if (!depth && wined3d_settings.offscreen_rendering_mode != ORM_FBO
1528 && wined3d_resource_is_offscreen(&texture->resource)
1529 && (sub_resource->locations & WINED3D_LOCATION_DRAWABLE))
1531 texture2d_load_fb_texture(texture, sub_resource_idx, srgb, context);
1533 return TRUE;
1536 level = sub_resource_idx % texture->level_count;
1537 width = wined3d_texture_get_level_width(texture, level);
1538 height = wined3d_texture_get_level_height(texture, level);
1539 wined3d_box_set(&src_box, 0, 0, width, height, 0, 1);
1541 if (!depth && sub_resource->locations & (WINED3D_LOCATION_TEXTURE_SRGB | WINED3D_LOCATION_TEXTURE_RGB)
1542 && (texture->resource.format_flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB)
1543 && fbo_blitter_supported(WINED3D_BLIT_OP_COLOR_BLIT, gl_info,
1544 &texture->resource, WINED3D_LOCATION_TEXTURE_RGB,
1545 &texture->resource, WINED3D_LOCATION_TEXTURE_SRGB))
1547 RECT src_rect;
1549 SetRect(&src_rect, 0, 0, width, height);
1550 if (srgb)
1551 texture2d_blt_fbo(device, context, WINED3D_TEXF_POINT,
1552 texture, sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB, &src_rect,
1553 texture, sub_resource_idx, WINED3D_LOCATION_TEXTURE_SRGB, &src_rect);
1554 else
1555 texture2d_blt_fbo(device, context, WINED3D_TEXF_POINT,
1556 texture, sub_resource_idx, WINED3D_LOCATION_TEXTURE_SRGB, &src_rect,
1557 texture, sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB, &src_rect);
1559 return TRUE;
1562 if (!depth && sub_resource->locations & (WINED3D_LOCATION_RB_MULTISAMPLE | WINED3D_LOCATION_RB_RESOLVED)
1563 && (!srgb || (texture->resource.format_flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB)))
1565 DWORD src_location = sub_resource->locations & WINED3D_LOCATION_RB_RESOLVED ?
1566 WINED3D_LOCATION_RB_RESOLVED : WINED3D_LOCATION_RB_MULTISAMPLE;
1567 DWORD dst_location = srgb ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB;
1568 RECT src_rect;
1570 SetRect(&src_rect, 0, 0, width, height);
1571 if (fbo_blitter_supported(WINED3D_BLIT_OP_COLOR_BLIT, gl_info,
1572 &texture->resource, src_location, &texture->resource, dst_location))
1573 texture2d_blt_fbo(device, context, WINED3D_TEXF_POINT, texture, sub_resource_idx,
1574 src_location, &src_rect, texture, sub_resource_idx, dst_location, &src_rect);
1576 return TRUE;
1579 /* Upload from system memory */
1581 if (srgb)
1583 if ((sub_resource->locations & (WINED3D_LOCATION_TEXTURE_RGB | texture->resource.map_binding))
1584 == WINED3D_LOCATION_TEXTURE_RGB)
1586 FIXME_(d3d_perf)("Downloading RGB texture %p, %u to reload it as sRGB.\n", texture, sub_resource_idx);
1587 wined3d_texture_load_location(texture, sub_resource_idx, context, texture->resource.map_binding);
1590 else
1592 if ((sub_resource->locations & (WINED3D_LOCATION_TEXTURE_SRGB | texture->resource.map_binding))
1593 == WINED3D_LOCATION_TEXTURE_SRGB)
1595 FIXME_(d3d_perf)("Downloading sRGB texture %p, %u to reload it as RGB.\n", texture, sub_resource_idx);
1596 wined3d_texture_load_location(texture, sub_resource_idx, context, texture->resource.map_binding);
1600 if (!(sub_resource->locations & surface_simple_locations))
1602 WARN("Trying to load a texture from sysmem, but no simple location is valid.\n");
1603 /* Lets hope we get it from somewhere... */
1604 wined3d_texture_load_location(texture, sub_resource_idx, context, WINED3D_LOCATION_SYSMEM);
1607 wined3d_texture_prepare_texture(texture, context, srgb);
1608 wined3d_texture_bind_and_dirtify(texture, context, srgb);
1609 wined3d_texture_get_pitch(texture, level, &src_row_pitch, &src_slice_pitch);
1611 format = texture->resource.format;
1612 if ((conversion = wined3d_format_get_color_key_conversion(texture, TRUE)))
1613 format = wined3d_get_format(device->adapter, conversion->dst_format, texture->resource.usage);
1615 /* Don't use PBOs for converted surfaces. During PBO conversion we look at
1616 * WINED3D_TEXTURE_CONVERTED but it isn't set (yet) in all cases it is
1617 * getting called. */
1618 if (conversion && sub_resource->buffer_object)
1620 TRACE("Removing the pbo attached to texture %p, %u.\n", texture, sub_resource_idx);
1622 wined3d_texture_load_location(texture, sub_resource_idx, context, WINED3D_LOCATION_SYSMEM);
1623 wined3d_texture_set_map_binding(texture, WINED3D_LOCATION_SYSMEM);
1626 wined3d_texture_get_memory(texture, sub_resource_idx, &data, sub_resource->locations);
1627 if (conversion)
1629 wined3d_format_calculate_pitch(format, device->surface_alignment,
1630 width, height, &dst_row_pitch, &dst_slice_pitch);
1632 src_mem = context_map_bo_address(context, &data, src_slice_pitch,
1633 GL_PIXEL_UNPACK_BUFFER, WINED3D_MAP_READ);
1634 if (!(dst_mem = heap_alloc(dst_slice_pitch)))
1636 ERR("Out of memory (%u).\n", dst_slice_pitch);
1637 context_release(context);
1638 return FALSE;
1640 conversion->convert(src_mem, src_row_pitch, dst_mem, dst_row_pitch,
1641 width, height, &texture->async.gl_color_key);
1642 src_row_pitch = dst_row_pitch;
1643 src_slice_pitch = dst_slice_pitch;
1644 context_unmap_bo_address(context, &data, GL_PIXEL_UNPACK_BUFFER);
1646 data.buffer_object = 0;
1647 data.addr = dst_mem;
1650 wined3d_texture_upload_data(texture, sub_resource_idx, context, format, &src_box,
1651 wined3d_const_bo_address(&data), src_row_pitch, src_slice_pitch, 0, 0, 0, srgb);
1653 heap_free(dst_mem);
1655 return TRUE;
1658 /* Context activation is done by the caller. */
1659 BOOL texture2d_load_renderbuffer(struct wined3d_texture *texture, unsigned int sub_resource_idx,
1660 struct wined3d_context *context, DWORD dst_location)
1662 unsigned int level = sub_resource_idx % texture->level_count;
1663 const RECT rect = {0, 0,
1664 wined3d_texture_get_level_width(texture, level),
1665 wined3d_texture_get_level_height(texture, level)};
1666 struct wined3d_texture_sub_resource *sub_resource;
1667 DWORD src_location, locations;
1669 sub_resource = &texture->sub_resources[sub_resource_idx];
1670 locations = sub_resource->locations;
1671 if (texture->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
1673 FIXME("Unimplemented copy from %s for depth/stencil buffers.\n",
1674 wined3d_debug_location(locations));
1675 return FALSE;
1678 if (locations & WINED3D_LOCATION_RB_MULTISAMPLE)
1679 src_location = WINED3D_LOCATION_RB_MULTISAMPLE;
1680 else if (locations & WINED3D_LOCATION_RB_RESOLVED)
1681 src_location = WINED3D_LOCATION_RB_RESOLVED;
1682 else if (locations & WINED3D_LOCATION_TEXTURE_SRGB)
1683 src_location = WINED3D_LOCATION_TEXTURE_SRGB;
1684 else if (locations & WINED3D_LOCATION_TEXTURE_RGB)
1685 src_location = WINED3D_LOCATION_TEXTURE_RGB;
1686 else if (locations & WINED3D_LOCATION_DRAWABLE)
1687 src_location = WINED3D_LOCATION_DRAWABLE;
1688 else /* texture2d_blt_fbo() will load the source location if necessary. */
1689 src_location = WINED3D_LOCATION_TEXTURE_RGB;
1691 texture2d_blt_fbo(texture->resource.device, context, WINED3D_TEXF_POINT, texture,
1692 sub_resource_idx, src_location, &rect, texture, sub_resource_idx, dst_location, &rect);
1694 return TRUE;
1697 /* Context activation is done by the caller. */
1698 static void fbo_blitter_destroy(struct wined3d_blitter *blitter, struct wined3d_context *context)
1700 struct wined3d_blitter *next;
1702 if ((next = blitter->next))
1703 next->ops->blitter_destroy(next, context);
1705 heap_free(blitter);
1708 static void fbo_blitter_clear(struct wined3d_blitter *blitter, struct wined3d_device *device,
1709 unsigned int rt_count, const struct wined3d_fb_state *fb, unsigned int rect_count, const RECT *clear_rects,
1710 const RECT *draw_rect, DWORD flags, const struct wined3d_color *colour, float depth, DWORD stencil)
1712 struct wined3d_blitter *next;
1714 if ((next = blitter->next))
1715 next->ops->blitter_clear(next, device, rt_count, fb, rect_count,
1716 clear_rects, draw_rect, flags, colour, depth, stencil);
1719 static DWORD fbo_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_blit_op op,
1720 struct wined3d_context *context, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx,
1721 DWORD src_location, const RECT *src_rect, struct wined3d_texture *dst_texture,
1722 unsigned int dst_sub_resource_idx, DWORD dst_location, const RECT *dst_rect,
1723 const struct wined3d_color_key *colour_key, enum wined3d_texture_filter_type filter)
1725 struct wined3d_resource *src_resource, *dst_resource;
1726 enum wined3d_blit_op blit_op = op;
1727 struct wined3d_device *device;
1728 struct wined3d_blitter *next;
1730 TRACE("blitter %p, op %#x, context %p, src_texture %p, src_sub_resource_idx %u, src_location %s, src_rect %s, "
1731 "dst_texture %p, dst_sub_resource_idx %u, dst_location %s, dst_rect %s, colour_key %p, filter %s.\n",
1732 blitter, op, context, src_texture, src_sub_resource_idx, wined3d_debug_location(src_location),
1733 wine_dbgstr_rect(src_rect), dst_texture, dst_sub_resource_idx, wined3d_debug_location(dst_location),
1734 wine_dbgstr_rect(dst_rect), colour_key, debug_d3dtexturefiltertype(filter));
1736 src_resource = &src_texture->resource;
1737 dst_resource = &dst_texture->resource;
1739 device = dst_resource->device;
1741 if (blit_op == WINED3D_BLIT_OP_RAW_BLIT && dst_resource->format->id == src_resource->format->id)
1743 if (dst_resource->format_flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL))
1744 blit_op = WINED3D_BLIT_OP_DEPTH_BLIT;
1745 else
1746 blit_op = WINED3D_BLIT_OP_COLOR_BLIT;
1749 if (!fbo_blitter_supported(blit_op, context->gl_info,
1750 src_resource, src_location, dst_resource, dst_location))
1752 if (!(next = blitter->next))
1754 ERR("No blitter to handle blit op %#x.\n", op);
1755 return dst_location;
1758 TRACE("Forwarding to blitter %p.\n", next);
1759 return next->ops->blitter_blit(next, op, context, src_texture, src_sub_resource_idx, src_location,
1760 src_rect, dst_texture, dst_sub_resource_idx, dst_location, dst_rect, colour_key, filter);
1763 if (blit_op == WINED3D_BLIT_OP_COLOR_BLIT)
1765 TRACE("Colour blit.\n");
1766 texture2d_blt_fbo(device, context, filter, src_texture, src_sub_resource_idx, src_location,
1767 src_rect, dst_texture, dst_sub_resource_idx, dst_location, dst_rect);
1768 return dst_location;
1771 if (blit_op == WINED3D_BLIT_OP_DEPTH_BLIT)
1773 TRACE("Depth/stencil blit.\n");
1774 texture2d_depth_blt_fbo(device, context, src_texture, src_sub_resource_idx, src_location,
1775 src_rect, dst_texture, dst_sub_resource_idx, dst_location, dst_rect);
1776 return dst_location;
1779 ERR("This blitter does not implement blit op %#x.\n", blit_op);
1780 return dst_location;
1783 static const struct wined3d_blitter_ops fbo_blitter_ops =
1785 fbo_blitter_destroy,
1786 fbo_blitter_clear,
1787 fbo_blitter_blit,
1790 void wined3d_fbo_blitter_create(struct wined3d_blitter **next, const struct wined3d_gl_info *gl_info)
1792 struct wined3d_blitter *blitter;
1794 if ((wined3d_settings.offscreen_rendering_mode != ORM_FBO) || !gl_info->fbo_ops.glBlitFramebuffer)
1795 return;
1797 if (!(blitter = heap_alloc(sizeof(*blitter))))
1798 return;
1800 TRACE("Created blitter %p.\n", blitter);
1802 blitter->ops = &fbo_blitter_ops;
1803 blitter->next = *next;
1804 *next = blitter;
1807 /* Context activation is done by the caller. */
1808 static void raw_blitter_destroy(struct wined3d_blitter *blitter, struct wined3d_context *context)
1810 struct wined3d_blitter *next;
1812 if ((next = blitter->next))
1813 next->ops->blitter_destroy(next, context);
1815 heap_free(blitter);
1818 /* Context activation is done by the caller. */
1819 static void raw_blitter_clear(struct wined3d_blitter *blitter, struct wined3d_device *device,
1820 unsigned int rt_count, const struct wined3d_fb_state *fb, unsigned int rect_count, const RECT *clear_rects,
1821 const RECT *draw_rect, DWORD flags, const struct wined3d_color *colour, float depth, DWORD stencil)
1823 struct wined3d_blitter *next;
1825 if (!(next = blitter->next))
1827 ERR("No blitter to handle clear.\n");
1828 return;
1831 TRACE("Forwarding to blitter %p.\n", next);
1832 next->ops->blitter_clear(next, device, rt_count, fb, rect_count,
1833 clear_rects, draw_rect, flags, colour, depth, stencil);
1836 /* Context activation is done by the caller. */
1837 static DWORD raw_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_blit_op op,
1838 struct wined3d_context *context, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx,
1839 DWORD src_location, const RECT *src_rect, struct wined3d_texture *dst_texture,
1840 unsigned int dst_sub_resource_idx, DWORD dst_location, const RECT *dst_rect,
1841 const struct wined3d_color_key *colour_key, enum wined3d_texture_filter_type filter)
1843 const struct wined3d_gl_info *gl_info = context->gl_info;
1844 unsigned int src_level, src_layer, dst_level, dst_layer;
1845 struct wined3d_blitter *next;
1846 GLuint src_name, dst_name;
1847 DWORD location;
1849 /* If we would need to copy from a renderbuffer or drawable, we'd probably
1850 * be better of using the FBO blitter directly, since we'd need to use it
1851 * to copy the resource contents to the texture anyway. */
1852 if (op != WINED3D_BLIT_OP_RAW_BLIT
1853 || (src_texture->resource.format->id == dst_texture->resource.format->id
1854 && (!(src_location & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB))
1855 || !(dst_location & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB)))))
1857 if (!(next = blitter->next))
1859 ERR("No blitter to handle blit op %#x.\n", op);
1860 return dst_location;
1863 TRACE("Forwarding to blitter %p.\n", next);
1864 return next->ops->blitter_blit(next, op, context, src_texture, src_sub_resource_idx, src_location,
1865 src_rect, dst_texture, dst_sub_resource_idx, dst_location, dst_rect, colour_key, filter);
1868 TRACE("Blit using ARB_copy_image.\n");
1870 src_level = src_sub_resource_idx % src_texture->level_count;
1871 src_layer = src_sub_resource_idx / src_texture->level_count;
1873 dst_level = dst_sub_resource_idx % dst_texture->level_count;
1874 dst_layer = dst_sub_resource_idx / dst_texture->level_count;
1876 location = src_location & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB);
1877 if (!location)
1878 location = src_texture->flags & WINED3D_TEXTURE_IS_SRGB
1879 ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB;
1880 if (!wined3d_texture_load_location(src_texture, src_sub_resource_idx, context, location))
1881 ERR("Failed to load the source sub-resource into %s.\n", wined3d_debug_location(location));
1882 src_name = wined3d_texture_get_texture_name(src_texture, context, location == WINED3D_LOCATION_TEXTURE_SRGB);
1884 location = dst_location & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB);
1885 if (!location)
1886 location = dst_texture->flags & WINED3D_TEXTURE_IS_SRGB
1887 ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB;
1888 if (texture2d_is_full_rect(dst_texture, dst_level, dst_rect))
1890 if (!wined3d_texture_prepare_location(dst_texture, dst_sub_resource_idx, context, location))
1891 ERR("Failed to prepare the destination sub-resource into %s.\n", wined3d_debug_location(location));
1893 else
1895 if (!wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, location))
1896 ERR("Failed to load the destination sub-resource into %s.\n", wined3d_debug_location(location));
1898 dst_name = wined3d_texture_get_texture_name(dst_texture, context, location == WINED3D_LOCATION_TEXTURE_SRGB);
1900 GL_EXTCALL(glCopyImageSubData(src_name, src_texture->target, src_level,
1901 src_rect->left, src_rect->top, src_layer, dst_name, dst_texture->target, dst_level,
1902 dst_rect->left, dst_rect->top, dst_layer, src_rect->right - src_rect->left,
1903 src_rect->bottom - src_rect->top, 1));
1904 checkGLcall("copy image data");
1906 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, location);
1907 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~location);
1908 if (!wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, dst_location))
1909 ERR("Failed to load the destination sub-resource into %s.\n", wined3d_debug_location(dst_location));
1911 return dst_location | location;
1914 static const struct wined3d_blitter_ops raw_blitter_ops =
1916 raw_blitter_destroy,
1917 raw_blitter_clear,
1918 raw_blitter_blit,
1921 void wined3d_raw_blitter_create(struct wined3d_blitter **next, const struct wined3d_gl_info *gl_info)
1923 struct wined3d_blitter *blitter;
1925 if (!gl_info->supported[ARB_COPY_IMAGE])
1926 return;
1928 if (!(blitter = heap_alloc(sizeof(*blitter))))
1929 return;
1931 TRACE("Created blitter %p.\n", blitter);
1933 blitter->ops = &raw_blitter_ops;
1934 blitter->next = *next;
1935 *next = blitter;
1938 /* Context activation is done by the caller. */
1939 static void ffp_blitter_destroy(struct wined3d_blitter *blitter, struct wined3d_context *context)
1941 struct wined3d_blitter *next;
1943 if ((next = blitter->next))
1944 next->ops->blitter_destroy(next, context);
1946 heap_free(blitter);
1949 static BOOL ffp_blit_supported(enum wined3d_blit_op blit_op, const struct wined3d_context *context,
1950 const struct wined3d_resource *src_resource, DWORD src_location,
1951 const struct wined3d_resource *dst_resource, DWORD dst_location)
1953 const struct wined3d_format *src_format = src_resource->format;
1954 const struct wined3d_format *dst_format = dst_resource->format;
1955 BOOL decompress;
1957 if (src_resource->type != WINED3D_RTYPE_TEXTURE_2D)
1958 return FALSE;
1960 decompress = src_format && (src_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_COMPRESSED)
1961 && !(dst_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_COMPRESSED);
1962 if (!decompress && !(src_resource->access & dst_resource->access & WINED3D_RESOURCE_ACCESS_GPU))
1964 TRACE("Source or destination resource is not GPU accessible.\n");
1965 return FALSE;
1968 if (blit_op == WINED3D_BLIT_OP_RAW_BLIT && dst_format->id == src_format->id)
1970 if (dst_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL))
1971 blit_op = WINED3D_BLIT_OP_DEPTH_BLIT;
1972 else
1973 blit_op = WINED3D_BLIT_OP_COLOR_BLIT;
1976 switch (blit_op)
1978 case WINED3D_BLIT_OP_COLOR_BLIT_CKEY:
1979 if (context->d3d_info->shader_color_key)
1981 TRACE("Color keying requires converted textures.\n");
1982 return FALSE;
1984 case WINED3D_BLIT_OP_COLOR_BLIT:
1985 case WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST:
1986 if (!context->gl_info->supported[WINED3D_GL_LEGACY_CONTEXT])
1987 return FALSE;
1989 if (TRACE_ON(d3d))
1991 TRACE("Checking support for fixup:\n");
1992 dump_color_fixup_desc(src_format->color_fixup);
1995 /* We only support identity conversions. */
1996 if (!is_identity_fixup(src_format->color_fixup)
1997 || !is_identity_fixup(dst_format->color_fixup))
1999 if (wined3d_settings.offscreen_rendering_mode == ORM_BACKBUFFER
2000 && dst_format->id == src_format->id && dst_location == WINED3D_LOCATION_DRAWABLE)
2002 WARN("Claiming fixup support because of ORM_BACKBUFFER.\n");
2004 else
2006 TRACE("Fixups are not supported.\n");
2007 return FALSE;
2011 if (!(dst_resource->usage & WINED3DUSAGE_RENDERTARGET))
2013 TRACE("Can only blit to render targets.\n");
2014 return FALSE;
2016 return TRUE;
2018 default:
2019 TRACE("Unsupported blit operation %#x.\n", blit_op);
2020 return FALSE;
2024 static BOOL ffp_blitter_use_cpu_clear(struct wined3d_rendertarget_view *view)
2026 struct wined3d_resource *resource;
2027 struct wined3d_texture *texture;
2028 DWORD locations;
2030 resource = view->resource;
2031 if (resource->type == WINED3D_RTYPE_BUFFER)
2032 return !(resource->access & WINED3D_RESOURCE_ACCESS_GPU);
2034 texture = texture_from_resource(resource);
2035 locations = texture->sub_resources[view->sub_resource_idx].locations;
2036 if (locations & (resource->map_binding | WINED3D_LOCATION_DISCARDED))
2037 return !(resource->access & WINED3D_RESOURCE_ACCESS_GPU)
2038 || (texture->flags & WINED3D_TEXTURE_PIN_SYSMEM);
2040 return !(resource->access & WINED3D_RESOURCE_ACCESS_GPU)
2041 && !(texture->flags & WINED3D_TEXTURE_CONVERTED);
2044 static void ffp_blitter_clear(struct wined3d_blitter *blitter, struct wined3d_device *device,
2045 unsigned int rt_count, const struct wined3d_fb_state *fb, unsigned int rect_count, const RECT *clear_rects,
2046 const RECT *draw_rect, DWORD flags, const struct wined3d_color *colour, float depth, DWORD stencil)
2048 struct wined3d_rendertarget_view *view;
2049 struct wined3d_blitter *next;
2050 DWORD next_flags = 0;
2051 unsigned int i;
2053 if (flags & WINED3DCLEAR_TARGET)
2055 for (i = 0; i < rt_count; ++i)
2057 if (!(view = fb->render_targets[i]))
2058 continue;
2060 if (ffp_blitter_use_cpu_clear(view)
2061 || (!(view->resource->usage & WINED3DUSAGE_RENDERTARGET)
2062 && (wined3d_settings.offscreen_rendering_mode != ORM_FBO
2063 || !(view->format_flags & WINED3DFMT_FLAG_FBO_ATTACHABLE))))
2065 next_flags |= WINED3DCLEAR_TARGET;
2066 flags &= ~WINED3DCLEAR_TARGET;
2067 break;
2070 /* FIXME: We should reject colour fills on formats with fixups,
2071 * but this would break P8 colour fills for example. */
2075 if ((flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL)) && (view = fb->depth_stencil)
2076 && (!view->format->depth_size || (flags & WINED3DCLEAR_ZBUFFER))
2077 && (!view->format->stencil_size || (flags & WINED3DCLEAR_STENCIL))
2078 && ffp_blitter_use_cpu_clear(view))
2080 next_flags |= flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL);
2081 flags &= ~(WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL);
2084 if (flags)
2085 device_clear_render_targets(device, rt_count, fb, rect_count,
2086 clear_rects, draw_rect, flags, colour, depth, stencil);
2088 if (next_flags && (next = blitter->next))
2089 next->ops->blitter_clear(next, device, rt_count, fb, rect_count,
2090 clear_rects, draw_rect, next_flags, colour, depth, stencil);
2093 static DWORD ffp_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_blit_op op,
2094 struct wined3d_context *context, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx,
2095 DWORD src_location, const RECT *src_rect, struct wined3d_texture *dst_texture,
2096 unsigned int dst_sub_resource_idx, DWORD dst_location, const RECT *dst_rect,
2097 const struct wined3d_color_key *color_key, enum wined3d_texture_filter_type filter)
2099 const struct wined3d_gl_info *gl_info = context->gl_info;
2100 struct wined3d_resource *src_resource, *dst_resource;
2101 struct wined3d_texture *staging_texture = NULL;
2102 struct wined3d_color_key old_blt_key;
2103 struct wined3d_device *device;
2104 struct wined3d_blitter *next;
2105 DWORD old_color_key_flags;
2106 RECT r;
2108 src_resource = &src_texture->resource;
2109 dst_resource = &dst_texture->resource;
2110 device = dst_resource->device;
2112 if (!ffp_blit_supported(op, context, src_resource, src_location, dst_resource, dst_location))
2114 if ((next = blitter->next))
2115 return next->ops->blitter_blit(next, op, context, src_texture, src_sub_resource_idx, src_location,
2116 src_rect, dst_texture, dst_sub_resource_idx, dst_location, dst_rect, color_key, filter);
2119 TRACE("Blt from texture %p, %u to rendertarget %p, %u.\n",
2120 src_texture, src_sub_resource_idx, dst_texture, dst_sub_resource_idx);
2122 old_blt_key = src_texture->async.src_blt_color_key;
2123 old_color_key_flags = src_texture->async.color_key_flags;
2124 wined3d_texture_set_color_key(src_texture, WINED3D_CKEY_SRC_BLT, color_key);
2126 if (!(src_texture->resource.access & WINED3D_RESOURCE_ACCESS_GPU))
2128 struct wined3d_resource_desc desc;
2129 struct wined3d_box upload_box;
2130 unsigned int src_level;
2131 HRESULT hr;
2133 TRACE("Source texture is not GPU accessible, creating a staging texture.\n");
2135 src_level = src_sub_resource_idx % src_texture->level_count;
2136 desc.resource_type = WINED3D_RTYPE_TEXTURE_2D;
2137 desc.format = src_texture->resource.format->id;
2138 desc.multisample_type = src_texture->resource.multisample_type;
2139 desc.multisample_quality = src_texture->resource.multisample_quality;
2140 desc.usage = WINED3DUSAGE_PRIVATE;
2141 desc.access = WINED3D_RESOURCE_ACCESS_GPU;
2142 desc.width = wined3d_texture_get_level_width(src_texture, src_level);
2143 desc.height = wined3d_texture_get_level_height(src_texture, src_level);
2144 desc.depth = 1;
2145 desc.size = 0;
2147 if (FAILED(hr = wined3d_texture_create(device, &desc, 1, 1, 0,
2148 NULL, NULL, &wined3d_null_parent_ops, &staging_texture)))
2150 ERR("Failed to create staging texture, hr %#x.\n", hr);
2151 return dst_location;
2154 wined3d_box_set(&upload_box, 0, 0, desc.width, desc.height, 0, desc.depth);
2155 wined3d_texture_upload_from_texture(staging_texture, 0, 0, 0, 0,
2156 src_texture, src_sub_resource_idx, &upload_box);
2158 src_texture = staging_texture;
2159 src_sub_resource_idx = 0;
2161 else
2163 /* Make sure the surface is up-to-date. This should probably use
2164 * surface_load_location() and worry about the destination surface
2165 * too, unless we're overwriting it completely. */
2166 wined3d_texture_load(src_texture, context, FALSE);
2169 context_apply_ffp_blit_state(context, device);
2171 if (dst_location == WINED3D_LOCATION_DRAWABLE)
2173 r = *dst_rect;
2174 wined3d_texture_translate_drawable_coords(dst_texture, context->win_handle, &r);
2175 dst_rect = &r;
2178 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
2180 GLenum buffer;
2182 if (dst_location == WINED3D_LOCATION_DRAWABLE)
2184 TRACE("Destination texture %p is onscreen.\n", dst_texture);
2185 buffer = wined3d_texture_get_gl_buffer(dst_texture);
2187 else
2189 TRACE("Destination texture %p is offscreen.\n", dst_texture);
2190 buffer = GL_COLOR_ATTACHMENT0;
2192 context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER,
2193 dst_resource, dst_sub_resource_idx, NULL, 0, dst_location);
2194 context_set_draw_buffer(context, buffer);
2195 context_check_fbo_status(context, GL_DRAW_FRAMEBUFFER);
2196 context_invalidate_state(context, STATE_FRAMEBUFFER);
2199 gl_info->gl_ops.gl.p_glEnable(src_texture->target);
2200 checkGLcall("glEnable(target)");
2202 if (op == WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST || color_key)
2204 gl_info->gl_ops.gl.p_glEnable(GL_ALPHA_TEST);
2205 checkGLcall("glEnable(GL_ALPHA_TEST)");
2208 if (color_key)
2210 /* For P8 surfaces, the alpha component contains the palette index.
2211 * Which means that the colorkey is one of the palette entries. In
2212 * other cases pixels that should be masked away have alpha set to 0. */
2213 if (src_texture->resource.format->id == WINED3DFMT_P8_UINT)
2214 gl_info->gl_ops.gl.p_glAlphaFunc(GL_NOTEQUAL,
2215 (float)src_texture->async.src_blt_color_key.color_space_low_value / 255.0f);
2216 else
2217 gl_info->gl_ops.gl.p_glAlphaFunc(GL_NOTEQUAL, 0.0f);
2218 checkGLcall("glAlphaFunc");
2221 context_draw_textured_quad(context, src_texture, src_sub_resource_idx, src_rect, dst_rect, filter);
2223 if (op == WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST || color_key)
2225 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
2226 checkGLcall("glDisable(GL_ALPHA_TEST)");
2229 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_2D);
2230 checkGLcall("glDisable(GL_TEXTURE_2D)");
2231 if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
2233 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_CUBE_MAP_ARB);
2234 checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
2236 if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
2238 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_RECTANGLE_ARB);
2239 checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)");
2242 if (dst_texture->swapchain && dst_texture->swapchain->front_buffer == dst_texture)
2243 gl_info->gl_ops.gl.p_glFlush();
2245 /* Restore the color key parameters */
2246 wined3d_texture_set_color_key(src_texture, WINED3D_CKEY_SRC_BLT,
2247 (old_color_key_flags & WINED3D_CKEY_SRC_BLT) ? &old_blt_key : NULL);
2249 if (staging_texture)
2250 wined3d_texture_decref(staging_texture);
2252 return dst_location;
2255 static const struct wined3d_blitter_ops ffp_blitter_ops =
2257 ffp_blitter_destroy,
2258 ffp_blitter_clear,
2259 ffp_blitter_blit,
2262 void wined3d_ffp_blitter_create(struct wined3d_blitter **next, const struct wined3d_gl_info *gl_info)
2264 struct wined3d_blitter *blitter;
2266 if (!(blitter = heap_alloc(sizeof(*blitter))))
2267 return;
2269 TRACE("Created blitter %p.\n", blitter);
2271 blitter->ops = &ffp_blitter_ops;
2272 blitter->next = *next;
2273 *next = blitter;
2276 /* Context activation is done by the caller. */
2277 static void cpu_blitter_destroy(struct wined3d_blitter *blitter, struct wined3d_context *context)
2279 struct wined3d_blitter *next;
2281 if ((next = blitter->next))
2282 next->ops->blitter_destroy(next, context);
2284 heap_free(blitter);
2287 static HRESULT surface_cpu_blt_compressed(const BYTE *src_data, BYTE *dst_data,
2288 UINT src_pitch, UINT dst_pitch, UINT update_w, UINT update_h,
2289 const struct wined3d_format *format, DWORD flags, const struct wined3d_blt_fx *fx)
2291 UINT row_block_count;
2292 const BYTE *src_row;
2293 BYTE *dst_row;
2294 UINT x, y;
2296 src_row = src_data;
2297 dst_row = dst_data;
2299 row_block_count = (update_w + format->block_width - 1) / format->block_width;
2301 if (!flags)
2303 for (y = 0; y < update_h; y += format->block_height)
2305 memcpy(dst_row, src_row, row_block_count * format->block_byte_count);
2306 src_row += src_pitch;
2307 dst_row += dst_pitch;
2310 return WINED3D_OK;
2313 if (flags == WINED3D_BLT_FX && fx->fx == WINEDDBLTFX_MIRRORUPDOWN)
2315 src_row += (((update_h / format->block_height) - 1) * src_pitch);
2317 switch (format->id)
2319 case WINED3DFMT_DXT1:
2320 for (y = 0; y < update_h; y += format->block_height)
2322 struct block
2324 WORD color[2];
2325 BYTE control_row[4];
2328 const struct block *s = (const struct block *)src_row;
2329 struct block *d = (struct block *)dst_row;
2331 for (x = 0; x < row_block_count; ++x)
2333 d[x].color[0] = s[x].color[0];
2334 d[x].color[1] = s[x].color[1];
2335 d[x].control_row[0] = s[x].control_row[3];
2336 d[x].control_row[1] = s[x].control_row[2];
2337 d[x].control_row[2] = s[x].control_row[1];
2338 d[x].control_row[3] = s[x].control_row[0];
2340 src_row -= src_pitch;
2341 dst_row += dst_pitch;
2343 return WINED3D_OK;
2345 case WINED3DFMT_DXT2:
2346 case WINED3DFMT_DXT3:
2347 for (y = 0; y < update_h; y += format->block_height)
2349 struct block
2351 WORD alpha_row[4];
2352 WORD color[2];
2353 BYTE control_row[4];
2356 const struct block *s = (const struct block *)src_row;
2357 struct block *d = (struct block *)dst_row;
2359 for (x = 0; x < row_block_count; ++x)
2361 d[x].alpha_row[0] = s[x].alpha_row[3];
2362 d[x].alpha_row[1] = s[x].alpha_row[2];
2363 d[x].alpha_row[2] = s[x].alpha_row[1];
2364 d[x].alpha_row[3] = s[x].alpha_row[0];
2365 d[x].color[0] = s[x].color[0];
2366 d[x].color[1] = s[x].color[1];
2367 d[x].control_row[0] = s[x].control_row[3];
2368 d[x].control_row[1] = s[x].control_row[2];
2369 d[x].control_row[2] = s[x].control_row[1];
2370 d[x].control_row[3] = s[x].control_row[0];
2372 src_row -= src_pitch;
2373 dst_row += dst_pitch;
2375 return WINED3D_OK;
2377 default:
2378 FIXME("Compressed flip not implemented for format %s.\n",
2379 debug_d3dformat(format->id));
2380 return E_NOTIMPL;
2384 FIXME("Unsupported blit on compressed surface (format %s, flags %#x, DDFX %#x).\n",
2385 debug_d3dformat(format->id), flags, flags & WINED3D_BLT_FX ? fx->fx : 0);
2387 return E_NOTIMPL;
2390 static HRESULT surface_cpu_blt(struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx,
2391 const struct wined3d_box *dst_box, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx,
2392 const struct wined3d_box *src_box, DWORD flags, const struct wined3d_blt_fx *fx,
2393 enum wined3d_texture_filter_type filter)
2395 unsigned int bpp, src_height, src_width, dst_height, dst_width, row_byte_count;
2396 struct wined3d_device *device = dst_texture->resource.device;
2397 const struct wined3d_format *src_format, *dst_format;
2398 struct wined3d_texture *converted_texture = NULL;
2399 struct wined3d_bo_address src_data, dst_data;
2400 unsigned int src_fmt_flags, dst_fmt_flags;
2401 struct wined3d_map_desc dst_map, src_map;
2402 struct wined3d_context *context = NULL;
2403 unsigned int x, sx, xinc, y, sy, yinc;
2404 unsigned int texture_level;
2405 HRESULT hr = WINED3D_OK;
2406 BOOL same_sub_resource;
2407 DWORD map_binding;
2408 const BYTE *sbase;
2409 const BYTE *sbuf;
2410 BYTE *dbuf;
2412 TRACE("dst_texture %p, dst_sub_resource_idx %u, dst_box %s, src_texture %p, "
2413 "src_sub_resource_idx %u, src_box %s, flags %#x, fx %p, filter %s.\n",
2414 dst_texture, dst_sub_resource_idx, debug_box(dst_box), src_texture,
2415 src_sub_resource_idx, debug_box(src_box), flags, fx, debug_d3dtexturefiltertype(filter));
2417 if (device->d3d_initialized)
2418 context = context_acquire(device, NULL, 0);
2420 if (src_texture == dst_texture && src_sub_resource_idx == dst_sub_resource_idx)
2422 same_sub_resource = TRUE;
2424 map_binding = dst_texture->resource.map_binding;
2425 texture_level = dst_sub_resource_idx % dst_texture->level_count;
2426 if (!wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, map_binding))
2427 ERR("Failed to load the destination sub-resource into %s.\n", wined3d_debug_location(map_binding));
2428 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~map_binding);
2429 wined3d_texture_get_pitch(dst_texture, texture_level, &dst_map.row_pitch, &dst_map.slice_pitch);
2430 wined3d_texture_get_memory(dst_texture, dst_sub_resource_idx, &dst_data, map_binding);
2431 dst_map.data = context_map_bo_address(context, &dst_data,
2432 dst_texture->sub_resources[dst_sub_resource_idx].size,
2433 GL_PIXEL_UNPACK_BUFFER, WINED3D_MAP_READ | WINED3D_MAP_WRITE);
2435 src_map = dst_map;
2436 src_format = dst_texture->resource.format;
2437 dst_format = src_format;
2438 dst_fmt_flags = dst_texture->resource.format_flags;
2439 src_fmt_flags = dst_fmt_flags;
2441 else
2443 same_sub_resource = FALSE;
2444 dst_format = dst_texture->resource.format;
2445 dst_fmt_flags = dst_texture->resource.format_flags;
2446 if (!(flags & WINED3D_BLT_RAW) && dst_texture->resource.format->id != src_texture->resource.format->id)
2448 if (!(converted_texture = surface_convert_format(src_texture, src_sub_resource_idx, dst_format)))
2450 FIXME("Cannot convert %s to %s.\n", debug_d3dformat(src_texture->resource.format->id),
2451 debug_d3dformat(dst_texture->resource.format->id));
2452 if (context)
2453 context_release(context);
2454 return WINED3DERR_NOTAVAILABLE;
2456 src_texture = converted_texture;
2457 src_sub_resource_idx = 0;
2459 src_format = src_texture->resource.format;
2460 src_fmt_flags = src_texture->resource.format_flags;
2462 map_binding = src_texture->resource.map_binding;
2463 texture_level = src_sub_resource_idx % src_texture->level_count;
2464 if (!wined3d_texture_load_location(src_texture, src_sub_resource_idx, context, map_binding))
2465 ERR("Failed to load the source sub-resource into %s.\n", wined3d_debug_location(map_binding));
2466 wined3d_texture_get_pitch(src_texture, texture_level, &src_map.row_pitch, &src_map.slice_pitch);
2467 wined3d_texture_get_memory(src_texture, src_sub_resource_idx, &src_data, map_binding);
2468 src_map.data = context_map_bo_address(context, &src_data,
2469 src_texture->sub_resources[src_sub_resource_idx].size, GL_PIXEL_UNPACK_BUFFER, WINED3D_MAP_READ);
2471 map_binding = dst_texture->resource.map_binding;
2472 texture_level = dst_sub_resource_idx % dst_texture->level_count;
2473 if (!wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, map_binding))
2474 ERR("Failed to load the destination sub-resource into %s.\n", wined3d_debug_location(map_binding));
2475 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~map_binding);
2476 wined3d_texture_get_pitch(dst_texture, texture_level, &dst_map.row_pitch, &dst_map.slice_pitch);
2477 wined3d_texture_get_memory(dst_texture, dst_sub_resource_idx, &dst_data, map_binding);
2478 dst_map.data = context_map_bo_address(context, &dst_data,
2479 dst_texture->sub_resources[dst_sub_resource_idx].size, GL_PIXEL_UNPACK_BUFFER, WINED3D_MAP_WRITE);
2481 flags &= ~WINED3D_BLT_RAW;
2483 bpp = dst_format->byte_count;
2484 src_height = src_box->bottom - src_box->top;
2485 src_width = src_box->right - src_box->left;
2486 dst_height = dst_box->bottom - dst_box->top;
2487 dst_width = dst_box->right - dst_box->left;
2488 row_byte_count = dst_width * bpp;
2490 sbase = (BYTE *)src_map.data
2491 + ((src_box->top / src_format->block_height) * src_map.row_pitch)
2492 + ((src_box->left / src_format->block_width) * src_format->block_byte_count);
2493 dbuf = (BYTE *)dst_map.data
2494 + ((dst_box->top / dst_format->block_height) * dst_map.row_pitch)
2495 + ((dst_box->left / dst_format->block_width) * dst_format->block_byte_count);
2497 if (src_fmt_flags & dst_fmt_flags & WINED3DFMT_FLAG_BLOCKS)
2499 TRACE("%s -> %s copy.\n", debug_d3dformat(src_format->id), debug_d3dformat(dst_format->id));
2501 if (same_sub_resource)
2503 FIXME("Only plain blits supported on compressed surfaces.\n");
2504 hr = E_NOTIMPL;
2505 goto release;
2508 if (src_height != dst_height || src_width != dst_width)
2510 WARN("Stretching not supported on compressed surfaces.\n");
2511 hr = WINED3DERR_INVALIDCALL;
2512 goto release;
2515 hr = surface_cpu_blt_compressed(sbase, dbuf,
2516 src_map.row_pitch, dst_map.row_pitch, dst_width, dst_height,
2517 src_format, flags, fx);
2518 goto release;
2521 if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT
2522 && (src_width != dst_width || src_height != dst_height))
2524 /* Can happen when d3d9 apps do a StretchRect() call which isn't handled in GL. */
2525 FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(filter));
2528 xinc = (src_width << 16) / dst_width;
2529 yinc = (src_height << 16) / dst_height;
2531 if (!flags)
2533 /* No effects, we can cheat here. */
2534 if (dst_width == src_width)
2536 if (dst_height == src_height)
2538 /* No stretching in either direction. This needs to be as fast
2539 * as possible. */
2540 sbuf = sbase;
2542 /* Check for overlapping surfaces. */
2543 if (!same_sub_resource || dst_box->top < src_box->top
2544 || dst_box->right <= src_box->left || src_box->right <= dst_box->left)
2546 /* No overlap, or dst above src, so copy from top downwards. */
2547 for (y = 0; y < dst_height; ++y)
2549 memcpy(dbuf, sbuf, row_byte_count);
2550 sbuf += src_map.row_pitch;
2551 dbuf += dst_map.row_pitch;
2554 else if (dst_box->top > src_box->top)
2556 /* Copy from bottom upwards. */
2557 sbuf += src_map.row_pitch * dst_height;
2558 dbuf += dst_map.row_pitch * dst_height;
2559 for (y = 0; y < dst_height; ++y)
2561 sbuf -= src_map.row_pitch;
2562 dbuf -= dst_map.row_pitch;
2563 memcpy(dbuf, sbuf, row_byte_count);
2566 else
2568 /* Src and dst overlapping on the same line, use memmove. */
2569 for (y = 0; y < dst_height; ++y)
2571 memmove(dbuf, sbuf, row_byte_count);
2572 sbuf += src_map.row_pitch;
2573 dbuf += dst_map.row_pitch;
2577 else
2579 /* Stretching in y direction only. */
2580 for (y = sy = 0; y < dst_height; ++y, sy += yinc)
2582 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
2583 memcpy(dbuf, sbuf, row_byte_count);
2584 dbuf += dst_map.row_pitch;
2588 else
2590 /* Stretching in X direction. */
2591 unsigned int last_sy = ~0u;
2592 for (y = sy = 0; y < dst_height; ++y, sy += yinc)
2594 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
2596 if ((sy >> 16) == (last_sy >> 16))
2598 /* This source row is the same as last source row -
2599 * Copy the already stretched row. */
2600 memcpy(dbuf, dbuf - dst_map.row_pitch, row_byte_count);
2602 else
2604 #define STRETCH_ROW(type) \
2605 do { \
2606 const type *s = (const type *)sbuf; \
2607 type *d = (type *)dbuf; \
2608 for (x = sx = 0; x < dst_width; ++x, sx += xinc) \
2609 d[x] = s[sx >> 16]; \
2610 } while(0)
2612 switch(bpp)
2614 case 1:
2615 STRETCH_ROW(BYTE);
2616 break;
2617 case 2:
2618 STRETCH_ROW(WORD);
2619 break;
2620 case 4:
2621 STRETCH_ROW(DWORD);
2622 break;
2623 case 3:
2625 const BYTE *s;
2626 BYTE *d = dbuf;
2627 for (x = sx = 0; x < dst_width; x++, sx+= xinc)
2629 DWORD pixel;
2631 s = sbuf + 3 * (sx >> 16);
2632 pixel = s[0] | (s[1] << 8) | (s[2] << 16);
2633 d[0] = (pixel ) & 0xff;
2634 d[1] = (pixel >> 8) & 0xff;
2635 d[2] = (pixel >> 16) & 0xff;
2636 d += 3;
2638 break;
2640 default:
2641 FIXME("Stretched blit not implemented for bpp %u.\n", bpp * 8);
2642 hr = WINED3DERR_NOTAVAILABLE;
2643 goto error;
2645 #undef STRETCH_ROW
2647 dbuf += dst_map.row_pitch;
2648 last_sy = sy;
2652 else
2654 LONG dstyinc = dst_map.row_pitch, dstxinc = bpp;
2655 DWORD keylow = 0xffffffff, keyhigh = 0, keymask = 0xffffffff;
2656 DWORD destkeylow = 0x0, destkeyhigh = 0xffffffff, destkeymask = 0xffffffff;
2657 if (flags & (WINED3D_BLT_SRC_CKEY | WINED3D_BLT_DST_CKEY
2658 | WINED3D_BLT_SRC_CKEY_OVERRIDE | WINED3D_BLT_DST_CKEY_OVERRIDE))
2660 /* The color keying flags are checked for correctness in ddraw. */
2661 if (flags & WINED3D_BLT_SRC_CKEY)
2663 keylow = src_texture->async.src_blt_color_key.color_space_low_value;
2664 keyhigh = src_texture->async.src_blt_color_key.color_space_high_value;
2666 else if (flags & WINED3D_BLT_SRC_CKEY_OVERRIDE)
2668 keylow = fx->src_color_key.color_space_low_value;
2669 keyhigh = fx->src_color_key.color_space_high_value;
2672 if (flags & WINED3D_BLT_DST_CKEY)
2674 /* Destination color keys are taken from the source surface! */
2675 destkeylow = src_texture->async.dst_blt_color_key.color_space_low_value;
2676 destkeyhigh = src_texture->async.dst_blt_color_key.color_space_high_value;
2678 else if (flags & WINED3D_BLT_DST_CKEY_OVERRIDE)
2680 destkeylow = fx->dst_color_key.color_space_low_value;
2681 destkeyhigh = fx->dst_color_key.color_space_high_value;
2684 if (bpp == 1)
2686 keymask = 0xff;
2688 else
2690 DWORD masks[3];
2691 get_color_masks(src_format, masks);
2692 keymask = masks[0] | masks[1] | masks[2];
2694 flags &= ~(WINED3D_BLT_SRC_CKEY | WINED3D_BLT_DST_CKEY
2695 | WINED3D_BLT_SRC_CKEY_OVERRIDE | WINED3D_BLT_DST_CKEY_OVERRIDE);
2698 if (flags & WINED3D_BLT_FX)
2700 BYTE *dTopLeft, *dTopRight, *dBottomLeft, *dBottomRight, *tmp;
2701 LONG tmpxy;
2702 dTopLeft = dbuf;
2703 dTopRight = dbuf + ((dst_width - 1) * bpp);
2704 dBottomLeft = dTopLeft + ((dst_height - 1) * dst_map.row_pitch);
2705 dBottomRight = dBottomLeft + ((dst_width - 1) * bpp);
2707 if (fx->fx & WINEDDBLTFX_ARITHSTRETCHY)
2709 /* I don't think we need to do anything about this flag. */
2710 WARN("Nothing done for WINEDDBLTFX_ARITHSTRETCHY.\n");
2712 if (fx->fx & WINEDDBLTFX_MIRRORLEFTRIGHT)
2714 tmp = dTopRight;
2715 dTopRight = dTopLeft;
2716 dTopLeft = tmp;
2717 tmp = dBottomRight;
2718 dBottomRight = dBottomLeft;
2719 dBottomLeft = tmp;
2720 dstxinc = dstxinc * -1;
2722 if (fx->fx & WINEDDBLTFX_MIRRORUPDOWN)
2724 tmp = dTopLeft;
2725 dTopLeft = dBottomLeft;
2726 dBottomLeft = tmp;
2727 tmp = dTopRight;
2728 dTopRight = dBottomRight;
2729 dBottomRight = tmp;
2730 dstyinc = dstyinc * -1;
2732 if (fx->fx & WINEDDBLTFX_NOTEARING)
2734 /* I don't think we need to do anything about this flag. */
2735 WARN("Nothing done for WINEDDBLTFX_NOTEARING.\n");
2737 if (fx->fx & WINEDDBLTFX_ROTATE180)
2739 tmp = dBottomRight;
2740 dBottomRight = dTopLeft;
2741 dTopLeft = tmp;
2742 tmp = dBottomLeft;
2743 dBottomLeft = dTopRight;
2744 dTopRight = tmp;
2745 dstxinc = dstxinc * -1;
2746 dstyinc = dstyinc * -1;
2748 if (fx->fx & WINEDDBLTFX_ROTATE270)
2750 tmp = dTopLeft;
2751 dTopLeft = dBottomLeft;
2752 dBottomLeft = dBottomRight;
2753 dBottomRight = dTopRight;
2754 dTopRight = tmp;
2755 tmpxy = dstxinc;
2756 dstxinc = dstyinc;
2757 dstyinc = tmpxy;
2758 dstxinc = dstxinc * -1;
2760 if (fx->fx & WINEDDBLTFX_ROTATE90)
2762 tmp = dTopLeft;
2763 dTopLeft = dTopRight;
2764 dTopRight = dBottomRight;
2765 dBottomRight = dBottomLeft;
2766 dBottomLeft = tmp;
2767 tmpxy = dstxinc;
2768 dstxinc = dstyinc;
2769 dstyinc = tmpxy;
2770 dstyinc = dstyinc * -1;
2772 if (fx->fx & WINEDDBLTFX_ZBUFFERBASEDEST)
2774 /* I don't think we need to do anything about this flag. */
2775 WARN("Nothing done for WINEDDBLTFX_ZBUFFERBASEDEST.\n");
2777 dbuf = dTopLeft;
2778 flags &= ~(WINED3D_BLT_FX);
2781 #define COPY_COLORKEY_FX(type) \
2782 do { \
2783 const type *s; \
2784 type *d = (type *)dbuf, *dx, tmp; \
2785 for (y = sy = 0; y < dst_height; ++y, sy += yinc) \
2787 s = (const type *)(sbase + (sy >> 16) * src_map.row_pitch); \
2788 dx = d; \
2789 for (x = sx = 0; x < dst_width; ++x, sx += xinc) \
2791 tmp = s[sx >> 16]; \
2792 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) \
2793 && ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) \
2795 dx[0] = tmp; \
2797 dx = (type *)(((BYTE *)dx) + dstxinc); \
2799 d = (type *)(((BYTE *)d) + dstyinc); \
2801 } while(0)
2803 switch (bpp)
2805 case 1:
2806 COPY_COLORKEY_FX(BYTE);
2807 break;
2808 case 2:
2809 COPY_COLORKEY_FX(WORD);
2810 break;
2811 case 4:
2812 COPY_COLORKEY_FX(DWORD);
2813 break;
2814 case 3:
2816 const BYTE *s;
2817 BYTE *d = dbuf, *dx;
2818 for (y = sy = 0; y < dst_height; ++y, sy += yinc)
2820 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
2821 dx = d;
2822 for (x = sx = 0; x < dst_width; ++x, sx+= xinc)
2824 DWORD pixel, dpixel = 0;
2825 s = sbuf + 3 * (sx>>16);
2826 pixel = s[0] | (s[1] << 8) | (s[2] << 16);
2827 dpixel = dx[0] | (dx[1] << 8 ) | (dx[2] << 16);
2828 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh)
2829 && ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
2831 dx[0] = (pixel ) & 0xff;
2832 dx[1] = (pixel >> 8) & 0xff;
2833 dx[2] = (pixel >> 16) & 0xff;
2835 dx += dstxinc;
2837 d += dstyinc;
2839 break;
2841 default:
2842 FIXME("%s color-keyed blit not implemented for bpp %u.\n",
2843 (flags & WINED3D_BLT_SRC_CKEY) ? "Source" : "Destination", bpp * 8);
2844 hr = WINED3DERR_NOTAVAILABLE;
2845 goto error;
2846 #undef COPY_COLORKEY_FX
2850 error:
2851 if (flags)
2852 FIXME(" Unsupported flags %#x.\n", flags);
2854 release:
2855 context_unmap_bo_address(context, &dst_data, GL_PIXEL_UNPACK_BUFFER);
2856 if (!same_sub_resource)
2857 context_unmap_bo_address(context, &src_data, GL_PIXEL_UNPACK_BUFFER);
2858 if (SUCCEEDED(hr) && dst_texture->swapchain && dst_texture->swapchain->front_buffer == dst_texture)
2860 SetRect(&dst_texture->swapchain->front_buffer_update,
2861 dst_box->left, dst_box->top, dst_box->right, dst_box->bottom);
2862 dst_texture->swapchain->swapchain_ops->swapchain_frontbuffer_updated(dst_texture->swapchain);
2864 if (converted_texture)
2865 wined3d_texture_decref(converted_texture);
2866 if (context)
2867 context_release(context);
2869 return hr;
2872 static void surface_cpu_blt_colour_fill(struct wined3d_rendertarget_view *view,
2873 const struct wined3d_box *box, const struct wined3d_color *colour)
2875 struct wined3d_device *device = view->resource->device;
2876 struct wined3d_context *context = NULL;
2877 struct wined3d_texture *texture;
2878 struct wined3d_bo_address data;
2879 unsigned int x, y, w, h, bpp;
2880 struct wined3d_map_desc map;
2881 DWORD map_binding;
2882 BYTE *row;
2883 DWORD c;
2885 TRACE("view %p, box %s, colour %s.\n", view, debug_box(box), debug_color(colour));
2887 if (view->format_flags & WINED3DFMT_FLAG_BLOCKS)
2889 FIXME("Not implemented for format %s.\n", debug_d3dformat(view->format->id));
2890 return;
2893 if (view->format->id != view->resource->format->id)
2894 FIXME("View format %s doesn't match resource format %s.\n",
2895 debug_d3dformat(view->format->id), debug_d3dformat(view->resource->format->id));
2897 if (view->resource->type == WINED3D_RTYPE_BUFFER)
2899 FIXME("Not implemented for buffers.\n");
2900 return;
2903 if (device->d3d_initialized)
2904 context = context_acquire(device, NULL, 0);
2906 c = wined3d_format_convert_from_float(view->format, colour);
2907 bpp = view->format->byte_count;
2908 w = box->right - box->left;
2909 h = box->bottom - box->top;
2911 texture = texture_from_resource(view->resource);
2912 map_binding = texture->resource.map_binding;
2913 if (!wined3d_texture_load_location(texture, view->sub_resource_idx, context, map_binding))
2914 ERR("Failed to load the sub-resource into %s.\n", wined3d_debug_location(map_binding));
2915 wined3d_texture_invalidate_location(texture, view->sub_resource_idx, ~map_binding);
2916 wined3d_texture_get_pitch(texture, view->sub_resource_idx % texture->level_count,
2917 &map.row_pitch, &map.slice_pitch);
2918 wined3d_texture_get_memory(texture, view->sub_resource_idx, &data, map_binding);
2919 map.data = context_map_bo_address(context, &data,
2920 texture->sub_resources[view->sub_resource_idx].size, GL_PIXEL_UNPACK_BUFFER, WINED3D_MAP_WRITE);
2921 map.data = (BYTE *)map.data
2922 + (box->front * map.slice_pitch)
2923 + ((box->top / view->format->block_height) * map.row_pitch)
2924 + ((box->left / view->format->block_width) * view->format->block_byte_count);
2926 switch (bpp)
2928 case 1:
2929 for (x = 0; x < w; ++x)
2931 ((BYTE *)map.data)[x] = c;
2933 break;
2935 case 2:
2936 for (x = 0; x < w; ++x)
2938 ((WORD *)map.data)[x] = c;
2940 break;
2942 case 3:
2944 row = map.data;
2945 for (x = 0; x < w; ++x, row += 3)
2947 row[0] = (c ) & 0xff;
2948 row[1] = (c >> 8) & 0xff;
2949 row[2] = (c >> 16) & 0xff;
2951 break;
2953 case 4:
2954 for (x = 0; x < w; ++x)
2956 ((DWORD *)map.data)[x] = c;
2958 break;
2960 default:
2961 FIXME("Not implemented for bpp %u.\n", bpp);
2962 wined3d_resource_unmap(view->resource, view->sub_resource_idx);
2963 return;
2966 row = map.data;
2967 for (y = 1; y < h; ++y)
2969 row += map.row_pitch;
2970 memcpy(row, map.data, w * bpp);
2973 context_unmap_bo_address(context, &data, GL_PIXEL_UNPACK_BUFFER);
2974 if (context)
2975 context_release(context);
2978 static void cpu_blitter_clear(struct wined3d_blitter *blitter, struct wined3d_device *device,
2979 unsigned int rt_count, const struct wined3d_fb_state *fb, unsigned int rect_count, const RECT *clear_rects,
2980 const RECT *draw_rect, DWORD flags, const struct wined3d_color *colour, float depth, DWORD stencil)
2982 struct wined3d_color c = {depth, 0.0f, 0.0f, 0.0f};
2983 struct wined3d_rendertarget_view *view;
2984 struct wined3d_box box;
2985 unsigned int i, j;
2987 if (!rect_count)
2989 rect_count = 1;
2990 clear_rects = draw_rect;
2993 for (i = 0; i < rect_count; ++i)
2995 box.left = max(clear_rects[i].left, draw_rect->left);
2996 box.top = max(clear_rects[i].top, draw_rect->top);
2997 box.right = min(clear_rects[i].right, draw_rect->right);
2998 box.bottom = min(clear_rects[i].bottom, draw_rect->bottom);
2999 box.front = 0;
3000 box.back = 1;
3002 if (box.left >= box.right || box.top >= box.bottom)
3003 continue;
3005 if (flags & WINED3DCLEAR_TARGET)
3007 for (j = 0; j < rt_count; ++j)
3009 if ((view = fb->render_targets[j]))
3010 surface_cpu_blt_colour_fill(view, &box, colour);
3014 if ((flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL)) && (view = fb->depth_stencil))
3016 if ((view->format->depth_size && !(flags & WINED3DCLEAR_ZBUFFER))
3017 || (view->format->stencil_size && !(flags & WINED3DCLEAR_STENCIL)))
3018 FIXME("Clearing %#x on %s.\n", flags, debug_d3dformat(view->format->id));
3020 surface_cpu_blt_colour_fill(view, &box, &c);
3025 static DWORD cpu_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_blit_op op,
3026 struct wined3d_context *context, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx,
3027 DWORD src_location, const RECT *src_rect, struct wined3d_texture *dst_texture,
3028 unsigned int dst_sub_resource_idx, DWORD dst_location, const RECT *dst_rect,
3029 const struct wined3d_color_key *color_key, enum wined3d_texture_filter_type filter)
3031 struct wined3d_box dst_box = {dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, 0, 1};
3032 struct wined3d_box src_box = {src_rect->left, src_rect->top, src_rect->right, src_rect->bottom, 0, 1};
3033 struct wined3d_blt_fx fx;
3034 DWORD flags = 0;
3036 memset(&fx, 0, sizeof(fx));
3037 switch (op)
3039 case WINED3D_BLIT_OP_COLOR_BLIT:
3040 case WINED3D_BLIT_OP_DEPTH_BLIT:
3041 case WINED3D_BLIT_OP_RAW_BLIT:
3042 break;
3043 case WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST:
3044 flags |= WINED3D_BLT_ALPHA_TEST;
3045 break;
3046 case WINED3D_BLIT_OP_COLOR_BLIT_CKEY:
3047 flags |= WINED3D_BLT_SRC_CKEY_OVERRIDE | WINED3D_BLT_FX;
3048 fx.src_color_key = *color_key;
3049 break;
3050 default:
3051 FIXME("Unhandled op %#x.\n", op);
3052 break;
3055 if (FAILED(surface_cpu_blt(dst_texture, dst_sub_resource_idx, &dst_box,
3056 src_texture, src_sub_resource_idx, &src_box, flags, &fx, filter)))
3057 ERR("Failed to blit.\n");
3058 wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, dst_location);
3060 return dst_location | (dst_texture->sub_resources[dst_sub_resource_idx].locations
3061 & dst_texture->resource.map_binding);
3064 static const struct wined3d_blitter_ops cpu_blitter_ops =
3066 cpu_blitter_destroy,
3067 cpu_blitter_clear,
3068 cpu_blitter_blit,
3071 struct wined3d_blitter *wined3d_cpu_blitter_create(void)
3073 struct wined3d_blitter *blitter;
3075 if (!(blitter = heap_alloc(sizeof(*blitter))))
3076 return NULL;
3078 TRACE("Created blitter %p.\n", blitter);
3080 blitter->ops = &cpu_blitter_ops;
3081 blitter->next = NULL;
3083 return blitter;
3086 HRESULT texture2d_blt(struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx,
3087 const struct wined3d_box *dst_box, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx,
3088 const struct wined3d_box *src_box, DWORD flags, const struct wined3d_blt_fx *fx,
3089 enum wined3d_texture_filter_type filter)
3091 struct wined3d_texture_sub_resource *src_sub_resource, *dst_sub_resource;
3092 struct wined3d_device *device = dst_texture->resource.device;
3093 struct wined3d_swapchain *src_swapchain, *dst_swapchain;
3094 const struct wined3d_color_key *colour_key = NULL;
3095 DWORD dst_location, valid_locations;
3096 DWORD src_ds_flags, dst_ds_flags;
3097 struct wined3d_context *context;
3098 enum wined3d_blit_op blit_op;
3099 BOOL scale, convert, resolve;
3100 RECT src_rect, dst_rect;
3102 static const DWORD simple_blit = WINED3D_BLT_SRC_CKEY
3103 | WINED3D_BLT_SRC_CKEY_OVERRIDE
3104 | WINED3D_BLT_ALPHA_TEST
3105 | WINED3D_BLT_RAW;
3107 TRACE("dst_texture %p, dst_sub_resource_idx %u, dst_box %s, src_texture %p, "
3108 "src_sub_resource_idx %u, src_box %s, flags %#x, fx %p, filter %s.\n",
3109 dst_texture, dst_sub_resource_idx, debug_box(dst_box), src_texture, src_sub_resource_idx,
3110 debug_box(src_box), flags, fx, debug_d3dtexturefiltertype(filter));
3111 TRACE("Usage is %s.\n", debug_d3dusage(dst_texture->resource.usage));
3113 if (fx)
3115 TRACE("fx %#x.\n", fx->fx);
3116 TRACE("dst_color_key {0x%08x, 0x%08x}.\n",
3117 fx->dst_color_key.color_space_low_value,
3118 fx->dst_color_key.color_space_high_value);
3119 TRACE("src_color_key {0x%08x, 0x%08x}.\n",
3120 fx->src_color_key.color_space_low_value,
3121 fx->src_color_key.color_space_high_value);
3124 SetRect(&src_rect, src_box->left, src_box->top, src_box->right, src_box->bottom);
3125 SetRect(&dst_rect, dst_box->left, dst_box->top, dst_box->right, dst_box->bottom);
3127 if (!fx || !(fx->fx))
3128 flags &= ~WINED3D_BLT_FX;
3130 /* WINED3D_BLT_DO_NOT_WAIT appeared in DX7. */
3131 if (flags & WINED3D_BLT_DO_NOT_WAIT)
3133 static unsigned int once;
3135 if (!once++)
3136 FIXME("Can't handle WINED3D_BLT_DO_NOT_WAIT flag.\n");
3139 flags &= ~(WINED3D_BLT_SYNCHRONOUS | WINED3D_BLT_DO_NOT_WAIT | WINED3D_BLT_WAIT);
3141 if (!device->d3d_initialized)
3143 WARN("D3D not initialized, using fallback.\n");
3144 goto cpu;
3147 if (flags & ~simple_blit)
3149 WARN_(d3d_perf)("Using fallback for complex blit (%#x).\n", flags);
3150 goto fallback;
3153 src_swapchain = src_texture->swapchain;
3154 dst_swapchain = dst_texture->swapchain;
3156 /* This isn't strictly needed. FBO blits for example could deal with
3157 * cross-swapchain blits by first downloading the source to a texture
3158 * before switching to the destination context. We just have this here to
3159 * not have to deal with the issue, since cross-swapchain blits should be
3160 * rare. */
3161 if (src_swapchain && dst_swapchain && src_swapchain != dst_swapchain)
3163 FIXME("Using fallback for cross-swapchain blit.\n");
3164 goto fallback;
3167 scale = src_box->right - src_box->left != dst_box->right - dst_box->left
3168 || src_box->bottom - src_box->top != dst_box->bottom - dst_box->top;
3169 convert = src_texture->resource.format->id != dst_texture->resource.format->id;
3170 resolve = src_texture->resource.multisample_type != dst_texture->resource.multisample_type;
3172 dst_ds_flags = dst_texture->resource.format_flags
3173 & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
3174 src_ds_flags = src_texture->resource.format_flags
3175 & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
3177 if (src_ds_flags || dst_ds_flags)
3179 TRACE("Depth/stencil blit.\n");
3181 if (dst_texture->resource.access & WINED3D_RESOURCE_ACCESS_GPU)
3182 dst_location = dst_texture->resource.draw_binding;
3183 else
3184 dst_location = dst_texture->resource.map_binding;
3186 if ((flags & WINED3D_BLT_RAW) || (!scale && !convert && !resolve))
3187 blit_op = WINED3D_BLIT_OP_RAW_BLIT;
3188 else
3189 blit_op = WINED3D_BLIT_OP_DEPTH_BLIT;
3191 context = context_acquire(device, dst_texture, dst_sub_resource_idx);
3192 valid_locations = device->blitter->ops->blitter_blit(device->blitter, blit_op, context,
3193 src_texture, src_sub_resource_idx, src_texture->resource.draw_binding, &src_rect,
3194 dst_texture, dst_sub_resource_idx, dst_location, &dst_rect, NULL, filter);
3195 context_release(context);
3197 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, valid_locations);
3198 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~valid_locations);
3200 return WINED3D_OK;
3203 TRACE("Colour blit.\n");
3205 dst_sub_resource = &dst_texture->sub_resources[dst_sub_resource_idx];
3206 src_sub_resource = &src_texture->sub_resources[src_sub_resource_idx];
3208 /* In principle this would apply to depth blits as well, but we don't
3209 * implement those in the CPU blitter at the moment. */
3210 if ((dst_sub_resource->locations & dst_texture->resource.map_binding)
3211 && (src_sub_resource->locations & src_texture->resource.map_binding))
3213 if (scale)
3214 TRACE("Not doing sysmem blit because of scaling.\n");
3215 else if (convert)
3216 TRACE("Not doing sysmem blit because of format conversion.\n");
3217 else
3218 goto cpu;
3221 blit_op = WINED3D_BLIT_OP_COLOR_BLIT;
3222 if (flags & WINED3D_BLT_SRC_CKEY_OVERRIDE)
3224 colour_key = &fx->src_color_key;
3225 blit_op = WINED3D_BLIT_OP_COLOR_BLIT_CKEY;
3227 else if (flags & WINED3D_BLT_SRC_CKEY)
3229 colour_key = &src_texture->async.src_blt_color_key;
3230 blit_op = WINED3D_BLIT_OP_COLOR_BLIT_CKEY;
3232 else if (flags & WINED3D_BLT_ALPHA_TEST)
3234 blit_op = WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST;
3236 else if ((src_sub_resource->locations & surface_simple_locations)
3237 && !(dst_sub_resource->locations & surface_simple_locations))
3239 /* Upload */
3240 if (scale)
3241 TRACE("Not doing upload because of scaling.\n");
3242 else if (convert)
3243 TRACE("Not doing upload because of format conversion.\n");
3244 else if (dst_texture->resource.format->conv_byte_count)
3245 TRACE("Not doing upload because the destination format needs conversion.\n");
3246 else
3248 wined3d_texture_upload_from_texture(dst_texture, dst_sub_resource_idx, dst_box->left,
3249 dst_box->top, dst_box->front, src_texture, src_sub_resource_idx, src_box);
3250 if (!wined3d_resource_is_offscreen(&dst_texture->resource))
3252 context = context_acquire(device, dst_texture, dst_sub_resource_idx);
3253 wined3d_texture_load_location(dst_texture, dst_sub_resource_idx,
3254 context, dst_texture->resource.draw_binding);
3255 context_release(context);
3257 return WINED3D_OK;
3260 else if (!(src_sub_resource->locations & surface_simple_locations)
3261 && (dst_sub_resource->locations & dst_texture->resource.map_binding))
3263 /* Download */
3264 if (scale)
3265 TRACE("Not doing download because of scaling.\n");
3266 else if (convert)
3267 TRACE("Not doing download because of format conversion.\n");
3268 else if (src_texture->resource.format->conv_byte_count)
3269 TRACE("Not doing download because the source format needs conversion.\n");
3270 else if (is_multisample_location(src_texture, WINED3D_LOCATION_TEXTURE_RGB))
3271 TRACE("Not doing download because of multisample source.\n");
3272 else if (!texture2d_is_full_rect(src_texture, src_sub_resource_idx % src_texture->level_count, &src_rect))
3273 TRACE("Not doing download because of partial download (src).\n");
3274 else if (!texture2d_is_full_rect(dst_texture, dst_sub_resource_idx % dst_texture->level_count, &dst_rect))
3275 TRACE("Not doing download because of partial download (dst).\n");
3276 else
3278 wined3d_texture_download_from_texture(dst_texture, dst_sub_resource_idx, src_texture,
3279 src_sub_resource_idx);
3280 return WINED3D_OK;
3283 else if (dst_swapchain && dst_swapchain->back_buffers
3284 && dst_texture == dst_swapchain->front_buffer
3285 && src_texture == dst_swapchain->back_buffers[0])
3287 /* Use present for back -> front blits. The idea behind this is that
3288 * present is potentially faster than a blit, in particular when FBO
3289 * blits aren't available. Some ddraw applications like Half-Life and
3290 * Prince of Persia 3D use Blt() from the backbuffer to the
3291 * frontbuffer instead of doing a Flip(). D3d8 and d3d9 applications
3292 * can't blit directly to the frontbuffer. */
3293 enum wined3d_swap_effect swap_effect = dst_swapchain->desc.swap_effect;
3295 TRACE("Using present for backbuffer -> frontbuffer blit.\n");
3297 /* Set the swap effect to COPY, we don't want the backbuffer to become
3298 * undefined. */
3299 dst_swapchain->desc.swap_effect = WINED3D_SWAP_EFFECT_COPY;
3300 wined3d_swapchain_present(dst_swapchain, NULL, NULL,
3301 dst_swapchain->win_handle, dst_swapchain->swap_interval, 0);
3302 dst_swapchain->desc.swap_effect = swap_effect;
3304 return WINED3D_OK;
3307 if ((flags & WINED3D_BLT_RAW) || (blit_op == WINED3D_BLIT_OP_COLOR_BLIT && !scale && !convert && !resolve))
3308 blit_op = WINED3D_BLIT_OP_RAW_BLIT;
3310 if (dst_texture->resource.access & WINED3D_RESOURCE_ACCESS_GPU)
3311 dst_location = dst_texture->resource.draw_binding;
3312 else
3313 dst_location = dst_texture->resource.map_binding;
3315 context = context_acquire(device, dst_texture, dst_sub_resource_idx);
3316 valid_locations = device->blitter->ops->blitter_blit(device->blitter, blit_op, context,
3317 src_texture, src_sub_resource_idx, src_texture->resource.draw_binding, &src_rect,
3318 dst_texture, dst_sub_resource_idx, dst_location, &dst_rect, colour_key, filter);
3319 context_release(context);
3321 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, valid_locations);
3322 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~valid_locations);
3324 return WINED3D_OK;
3326 fallback:
3327 /* Special cases for render targets. */
3328 if (SUCCEEDED(wined3d_texture_blt_special(dst_texture, dst_sub_resource_idx, &dst_rect,
3329 src_texture, src_sub_resource_idx, &src_rect, flags, fx, filter)))
3330 return WINED3D_OK;
3332 cpu:
3333 return surface_cpu_blt(dst_texture, dst_sub_resource_idx, dst_box,
3334 src_texture, src_sub_resource_idx, src_box, flags, fx, filter);