user32/listbox: Make SetCount fail if LBS_NODATA is not set.
[wine.git] / dlls / wined3d / surface.c
blob5f5c53a8b8f7be2573a89679f7f99bfe3d93a244
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_gl *texture_gl, 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_gl->target == GL_TEXTURE_2D_MULTISAMPLE || texture_gl->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(wined3d_texture_gl(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->bind_flags & WINED3D_BIND_RENDER_TARGET)))
316 return FALSE;
317 if (!((dst_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_FBO_ATTACHABLE)
318 || (dst_resource->bind_flags & WINED3D_BIND_RENDER_TARGET)))
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.bind_flags = 0;
638 desc.access = WINED3D_RESOURCE_ACCESS_CPU | WINED3D_RESOURCE_ACCESS_MAP_R | WINED3D_RESOURCE_ACCESS_MAP_W;
639 desc.width = wined3d_texture_get_level_width(src_texture, texture_level);
640 desc.height = wined3d_texture_get_level_height(src_texture, texture_level);
641 desc.depth = 1;
642 desc.size = 0;
643 if (FAILED(wined3d_texture_create(device, &desc, 1, 1,
644 WINED3D_TEXTURE_CREATE_MAPPABLE | WINED3D_TEXTURE_CREATE_DISCARD,
645 NULL, NULL, &wined3d_null_parent_ops, &dst_texture)))
647 ERR("Failed to create a destination texture for conversion.\n");
648 return NULL;
651 if (device->d3d_initialized)
652 context = context_acquire(device, NULL, 0);
654 map_binding = src_texture->resource.map_binding;
655 if (!wined3d_texture_load_location(src_texture, sub_resource_idx, context, map_binding))
656 ERR("Failed to load the source sub-resource into %s.\n", wined3d_debug_location(map_binding));
657 wined3d_texture_get_pitch(src_texture, texture_level, &src_row_pitch, &src_slice_pitch);
658 wined3d_texture_get_memory(src_texture, sub_resource_idx, &src_data, map_binding);
660 if (conv)
662 unsigned int dst_row_pitch, dst_slice_pitch;
663 struct wined3d_bo_address dst_data;
664 const BYTE *src;
665 BYTE *dst;
667 map_binding = dst_texture->resource.map_binding;
668 if (!wined3d_texture_load_location(dst_texture, 0, context, map_binding))
669 ERR("Failed to load the destination sub-resource into %s.\n", wined3d_debug_location(map_binding));
670 wined3d_texture_get_pitch(dst_texture, 0, &dst_row_pitch, &dst_slice_pitch);
671 wined3d_texture_get_memory(dst_texture, 0, &dst_data, map_binding);
673 src = context_map_bo_address(context, &src_data,
674 src_texture->sub_resources[sub_resource_idx].size, GL_PIXEL_UNPACK_BUFFER, WINED3D_MAP_READ);
675 dst = context_map_bo_address(context,
676 &dst_data, dst_texture->sub_resources[0].size, GL_PIXEL_UNPACK_BUFFER, WINED3D_MAP_WRITE);
678 conv->convert(src, dst, src_row_pitch, dst_row_pitch, desc.width, desc.height);
680 wined3d_texture_invalidate_location(dst_texture, 0, ~map_binding);
681 context_unmap_bo_address(context, &dst_data, GL_PIXEL_UNPACK_BUFFER);
682 context_unmap_bo_address(context, &src_data, GL_PIXEL_UNPACK_BUFFER);
684 else
686 struct wined3d_box src_box = {0, 0, desc.width, desc.height, 0, 1};
688 TRACE("Using upload conversion.\n");
690 wined3d_texture_prepare_texture(dst_texture, context, FALSE);
691 wined3d_texture_gl_bind_and_dirtify(wined3d_texture_gl(dst_texture), context, FALSE);
692 wined3d_texture_upload_data(dst_texture, 0, context, src_format, &src_box,
693 wined3d_const_bo_address(&src_data), src_row_pitch, src_slice_pitch, 0, 0, 0, FALSE);
695 wined3d_texture_validate_location(dst_texture, 0, WINED3D_LOCATION_TEXTURE_RGB);
696 wined3d_texture_invalidate_location(dst_texture, 0, ~WINED3D_LOCATION_TEXTURE_RGB);
699 if (context)
700 context_release(context);
702 return dst_texture;
705 static void texture2d_read_from_framebuffer(struct wined3d_texture *texture, unsigned int sub_resource_idx,
706 struct wined3d_context *context, DWORD src_location, DWORD dst_location)
708 struct wined3d_resource *resource = &texture->resource;
709 struct wined3d_device *device = resource->device;
710 const struct wined3d_format_gl *format_gl;
711 struct wined3d_texture *restore_texture;
712 const struct wined3d_gl_info *gl_info;
713 unsigned int row_pitch, slice_pitch;
714 unsigned int width, height, level;
715 struct wined3d_bo_address data;
716 unsigned int restore_idx;
717 BYTE *row, *top, *bottom;
718 BOOL src_is_upside_down;
719 unsigned int i;
720 BYTE *mem;
722 wined3d_texture_get_memory(texture, sub_resource_idx, &data, dst_location);
724 restore_texture = context->current_rt.texture;
725 restore_idx = context->current_rt.sub_resource_idx;
726 if (restore_texture != texture || restore_idx != sub_resource_idx)
727 context = context_acquire(device, texture, sub_resource_idx);
728 else
729 restore_texture = NULL;
730 gl_info = context->gl_info;
732 if (src_location != resource->draw_binding)
734 context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER,
735 resource, sub_resource_idx, NULL, 0, src_location);
736 context_check_fbo_status(context, GL_READ_FRAMEBUFFER);
737 context_invalidate_state(context, STATE_FRAMEBUFFER);
739 else
741 context_apply_blit_state(context, device);
744 /* Select the correct read buffer, and give some debug output.
745 * There is no need to keep track of the current read buffer or reset it,
746 * every part of the code that reads sets the read buffer as desired.
748 if (src_location != WINED3D_LOCATION_DRAWABLE || wined3d_resource_is_offscreen(resource))
750 /* Mapping the primary render target which is not on a swapchain.
751 * Read from the back buffer. */
752 TRACE("Mapping offscreen render target.\n");
753 gl_info->gl_ops.gl.p_glReadBuffer(context_get_offscreen_gl_buffer(context));
754 src_is_upside_down = TRUE;
756 else
758 /* Onscreen surfaces are always part of a swapchain */
759 GLenum buffer = wined3d_texture_get_gl_buffer(texture);
760 TRACE("Mapping %#x buffer.\n", buffer);
761 gl_info->gl_ops.gl.p_glReadBuffer(buffer);
762 src_is_upside_down = FALSE;
764 checkGLcall("glReadBuffer");
766 if (data.buffer_object)
768 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, data.buffer_object));
769 checkGLcall("glBindBuffer");
772 level = sub_resource_idx % texture->level_count;
773 wined3d_texture_get_pitch(texture, level, &row_pitch, &slice_pitch);
774 format_gl = wined3d_format_gl(resource->format);
776 /* Setup pixel store pack state -- to glReadPixels into the correct place */
777 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_ROW_LENGTH, row_pitch / format_gl->f.byte_count);
778 checkGLcall("glPixelStorei");
780 width = wined3d_texture_get_level_width(texture, level);
781 height = wined3d_texture_get_level_height(texture, level);
782 gl_info->gl_ops.gl.p_glReadPixels(0, 0, width, height,
783 format_gl->format, format_gl->type, data.addr);
784 checkGLcall("glReadPixels");
786 /* Reset previous pixel store pack state */
787 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_ROW_LENGTH, 0);
788 checkGLcall("glPixelStorei");
790 if (!src_is_upside_down)
792 /* glReadPixels returns the image upside down, and there is no way to
793 * prevent this. Flip the lines in software. */
795 if (!(row = heap_alloc(row_pitch)))
796 goto error;
798 if (data.buffer_object)
800 mem = GL_EXTCALL(glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_WRITE));
801 checkGLcall("glMapBuffer");
803 else
804 mem = data.addr;
806 top = mem;
807 bottom = mem + row_pitch * (height - 1);
808 for (i = 0; i < height / 2; i++)
810 memcpy(row, top, row_pitch);
811 memcpy(top, bottom, row_pitch);
812 memcpy(bottom, row, row_pitch);
813 top += row_pitch;
814 bottom -= row_pitch;
816 heap_free(row);
818 if (data.buffer_object)
819 GL_EXTCALL(glUnmapBuffer(GL_PIXEL_PACK_BUFFER));
822 error:
823 if (data.buffer_object)
825 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));
826 checkGLcall("glBindBuffer");
829 if (restore_texture)
830 context_restore(context, restore_texture, restore_idx);
833 /* Read the framebuffer contents into a texture. Note that this function
834 * doesn't do any kind of flipping. Using this on an onscreen surface will
835 * result in a flipped D3D texture.
837 * Context activation is done by the caller. This function may temporarily
838 * switch to a different context and restore the original one before return. */
839 void texture2d_load_fb_texture(struct wined3d_texture_gl *texture_gl,
840 unsigned int sub_resource_idx, BOOL srgb, struct wined3d_context *context)
842 struct wined3d_texture *restore_texture;
843 const struct wined3d_gl_info *gl_info;
844 struct wined3d_resource *resource;
845 unsigned int restore_idx, level;
846 struct wined3d_device *device;
847 GLenum target;
849 resource = &texture_gl->t.resource;
850 device = resource->device;
851 restore_texture = context->current_rt.texture;
852 restore_idx = context->current_rt.sub_resource_idx;
853 if (restore_texture != &texture_gl->t || restore_idx != sub_resource_idx)
854 context = context_acquire(device, &texture_gl->t, sub_resource_idx);
855 else
856 restore_texture = NULL;
858 gl_info = context->gl_info;
859 device_invalidate_state(device, STATE_FRAMEBUFFER);
861 wined3d_texture_prepare_texture(&texture_gl->t, context, srgb);
862 wined3d_texture_gl_bind_and_dirtify(texture_gl, context, srgb);
864 TRACE("Reading back offscreen render target %p, %u.\n", texture_gl, sub_resource_idx);
866 if (wined3d_resource_is_offscreen(resource))
867 gl_info->gl_ops.gl.p_glReadBuffer(context_get_offscreen_gl_buffer(context));
868 else
869 gl_info->gl_ops.gl.p_glReadBuffer(wined3d_texture_get_gl_buffer(&texture_gl->t));
870 checkGLcall("glReadBuffer");
872 level = sub_resource_idx % texture_gl->t.level_count;
873 target = wined3d_texture_gl_get_sub_resource_target(texture_gl, sub_resource_idx);
874 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(target, level, 0, 0, 0, 0,
875 wined3d_texture_get_level_width(&texture_gl->t, level),
876 wined3d_texture_get_level_height(&texture_gl->t, level));
877 checkGLcall("glCopyTexSubImage2D");
879 if (restore_texture)
880 context_restore(context, restore_texture, restore_idx);
883 /* Does a direct frame buffer -> texture copy. Stretching is done with single
884 * pixel copy calls. */
885 static void fb_copy_to_texture_direct(struct wined3d_texture_gl *dst_texture, unsigned int dst_sub_resource_idx,
886 const RECT *dst_rect_in, struct wined3d_texture_gl *src_texture, unsigned int src_sub_resource_idx,
887 const RECT *src_rect, enum wined3d_texture_filter_type filter)
889 struct wined3d_device *device = dst_texture->t.resource.device;
890 unsigned int src_height, src_level, dst_level;
891 const struct wined3d_gl_info *gl_info;
892 float xrel, yrel;
893 struct wined3d_context *context;
894 BOOL upsidedown = FALSE;
895 RECT dst_rect = *dst_rect_in;
896 GLenum dst_target;
898 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
899 * glCopyTexSubImage is a bit picky about the parameters we pass to it
901 if(dst_rect.top > dst_rect.bottom) {
902 UINT tmp = dst_rect.bottom;
903 dst_rect.bottom = dst_rect.top;
904 dst_rect.top = tmp;
905 upsidedown = TRUE;
908 context = context_acquire(device, &src_texture->t, src_sub_resource_idx);
909 gl_info = context->gl_info;
910 context_apply_blit_state(context, device);
911 wined3d_texture_load(&dst_texture->t, context, FALSE);
913 /* Bind the target texture */
914 context_bind_texture(context, dst_texture->target, dst_texture->texture_rgb.name);
915 if (wined3d_resource_is_offscreen(&src_texture->t.resource))
917 TRACE("Reading from an offscreen target\n");
918 upsidedown = !upsidedown;
919 gl_info->gl_ops.gl.p_glReadBuffer(context_get_offscreen_gl_buffer(context));
921 else
923 gl_info->gl_ops.gl.p_glReadBuffer(wined3d_texture_get_gl_buffer(&src_texture->t));
925 checkGLcall("glReadBuffer");
927 xrel = (float) (src_rect->right - src_rect->left) / (float) (dst_rect.right - dst_rect.left);
928 yrel = (float) (src_rect->bottom - src_rect->top) / (float) (dst_rect.bottom - dst_rect.top);
930 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
932 FIXME_(d3d_perf)("Doing a pixel by pixel copy from the framebuffer to a texture.\n");
934 if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT)
935 ERR("Texture filtering not supported in direct blit.\n");
937 else if ((filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT)
938 && ((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
940 ERR("Texture filtering not supported in direct blit\n");
943 src_level = src_sub_resource_idx % src_texture->t.level_count;
944 dst_level = dst_sub_resource_idx % dst_texture->t.level_count;
946 src_height = wined3d_texture_get_level_height(&src_texture->t, src_level);
947 dst_target = wined3d_texture_gl_get_sub_resource_target(dst_texture, dst_sub_resource_idx);
948 if (upsidedown
949 && !((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
950 && !((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
952 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do. */
953 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_target, dst_level,
954 dst_rect.left /*xoffset */, dst_rect.top /* y offset */,
955 src_rect->left, src_height - src_rect->bottom,
956 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
958 else
960 LONG row;
961 UINT yoffset = src_height - src_rect->top + dst_rect.top - 1;
962 /* I have to process this row by row to swap the image,
963 * otherwise it would be upside down, so stretching in y direction
964 * doesn't cost extra time
966 * However, stretching in x direction can be avoided if not necessary
968 for(row = dst_rect.top; row < dst_rect.bottom; row++) {
969 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
971 /* Well, that stuff works, but it's very slow.
972 * find a better way instead
974 LONG col;
976 for (col = dst_rect.left; col < dst_rect.right; ++col)
978 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_target, dst_level,
979 dst_rect.left + col /* x offset */, row /* y offset */,
980 src_rect->left + col * xrel, yoffset - (int) (row * yrel), 1, 1);
983 else
985 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_target, dst_level,
986 dst_rect.left /* x offset */, row /* y offset */,
987 src_rect->left, yoffset - (int) (row * yrel), dst_rect.right - dst_rect.left, 1);
991 checkGLcall("glCopyTexSubImage2D");
993 context_release(context);
995 /* The texture is now most up to date - If the surface is a render target
996 * and has a drawable, this path is never entered. */
997 wined3d_texture_validate_location(&dst_texture->t, dst_sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB);
998 wined3d_texture_invalidate_location(&dst_texture->t, dst_sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB);
1001 /* Uses the hardware to stretch and flip the image */
1002 static void fb_copy_to_texture_hwstretch(struct wined3d_texture_gl *dst_texture, unsigned int dst_sub_resource_idx,
1003 const RECT *dst_rect_in, struct wined3d_texture_gl *src_texture, unsigned int src_sub_resource_idx,
1004 const RECT *src_rect, enum wined3d_texture_filter_type filter)
1006 unsigned int src_width, src_height, src_pow2_width, src_pow2_height, src_level;
1007 struct wined3d_device *device = dst_texture->t.resource.device;
1008 GLenum src_target, dst_target, texture_target;
1009 GLuint src, backup = 0;
1010 float left, right, top, bottom; /* Texture coordinates */
1011 const struct wined3d_gl_info *gl_info;
1012 struct wined3d_context *context;
1013 GLenum drawBuffer = GL_BACK;
1014 GLenum offscreen_buffer;
1015 BOOL noBackBufferBackup;
1016 BOOL src_offscreen;
1017 BOOL upsidedown = FALSE;
1018 RECT dst_rect = *dst_rect_in;
1020 TRACE("Using hwstretch blit\n");
1022 src_target = wined3d_texture_gl_get_sub_resource_target(src_texture, src_sub_resource_idx);
1023 dst_target = wined3d_texture_gl_get_sub_resource_target(dst_texture, dst_sub_resource_idx);
1025 /* Activate the Proper context for reading from the source surface, set it up for blitting */
1026 context = context_acquire(device, &src_texture->t, src_sub_resource_idx);
1027 gl_info = context->gl_info;
1028 context_apply_ffp_blit_state(context, device);
1029 wined3d_texture_load(&dst_texture->t, context, FALSE);
1031 offscreen_buffer = context_get_offscreen_gl_buffer(context);
1032 src_level = src_sub_resource_idx % src_texture->t.level_count;
1033 src_width = wined3d_texture_get_level_width(&src_texture->t, src_level);
1034 src_height = wined3d_texture_get_level_height(&src_texture->t, src_level);
1035 src_pow2_width = wined3d_texture_get_level_pow2_width(&src_texture->t, src_level);
1036 src_pow2_height = wined3d_texture_get_level_pow2_height(&src_texture->t, src_level);
1038 src_offscreen = wined3d_resource_is_offscreen(&src_texture->t.resource);
1039 noBackBufferBackup = src_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO;
1040 if (!noBackBufferBackup && !src_texture->texture_rgb.name)
1042 /* Get it a description */
1043 wined3d_texture_load(&src_texture->t, context, FALSE);
1046 /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
1047 * This way we don't have to wait for the 2nd readback to finish to leave this function.
1049 if (context->aux_buffers >= 2)
1051 /* Got more than one aux buffer? Use the 2nd aux buffer */
1052 drawBuffer = GL_AUX1;
1054 else if ((!src_offscreen || offscreen_buffer == GL_BACK) && context->aux_buffers >= 1)
1056 /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
1057 drawBuffer = GL_AUX0;
1060 if (noBackBufferBackup)
1062 gl_info->gl_ops.gl.p_glGenTextures(1, &backup);
1063 checkGLcall("glGenTextures");
1064 context_bind_texture(context, GL_TEXTURE_2D, backup);
1065 texture_target = GL_TEXTURE_2D;
1067 else
1069 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
1070 * we are reading from the back buffer, the backup can be used as source texture
1072 texture_target = src_target;
1073 context_bind_texture(context, texture_target, src_texture->texture_rgb.name);
1074 gl_info->gl_ops.gl.p_glEnable(texture_target);
1075 checkGLcall("glEnable(texture_target)");
1077 /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
1078 src_texture->t.sub_resources[src_sub_resource_idx].locations &= ~WINED3D_LOCATION_TEXTURE_RGB;
1081 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
1082 * glCopyTexSubImage is a bit picky about the parameters we pass to it
1084 if(dst_rect.top > dst_rect.bottom) {
1085 UINT tmp = dst_rect.bottom;
1086 dst_rect.bottom = dst_rect.top;
1087 dst_rect.top = tmp;
1088 upsidedown = TRUE;
1091 if (src_offscreen)
1093 TRACE("Reading from an offscreen target\n");
1094 upsidedown = !upsidedown;
1095 gl_info->gl_ops.gl.p_glReadBuffer(offscreen_buffer);
1097 else
1099 gl_info->gl_ops.gl.p_glReadBuffer(wined3d_texture_get_gl_buffer(&src_texture->t));
1102 /* TODO: Only back up the part that will be overwritten */
1103 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(texture_target, 0, 0, 0, 0, 0, src_width, src_height);
1105 checkGLcall("glCopyTexSubImage2D");
1107 /* No issue with overriding these - the sampler is dirty due to blit usage */
1108 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, wined3d_gl_mag_filter(filter));
1109 checkGLcall("glTexParameteri");
1110 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER,
1111 wined3d_gl_min_mip_filter(filter, WINED3D_TEXF_NONE));
1112 checkGLcall("glTexParameteri");
1114 if (!src_texture->t.swapchain || &src_texture->t == src_texture->t.swapchain->back_buffers[0])
1116 src = backup ? backup : src_texture->texture_rgb.name;
1118 else
1120 gl_info->gl_ops.gl.p_glReadBuffer(GL_FRONT);
1121 checkGLcall("glReadBuffer(GL_FRONT)");
1123 gl_info->gl_ops.gl.p_glGenTextures(1, &src);
1124 checkGLcall("glGenTextures(1, &src)");
1125 context_bind_texture(context, GL_TEXTURE_2D, src);
1127 /* TODO: Only copy the part that will be read. Use src_rect->left,
1128 * src_rect->bottom as origin, but with the width watch out for power
1129 * of 2 sizes. */
1130 gl_info->gl_ops.gl.p_glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, src_pow2_width,
1131 src_pow2_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
1132 checkGLcall("glTexImage2D");
1133 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, src_width, src_height);
1135 gl_info->gl_ops.gl.p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1136 checkGLcall("glTexParameteri");
1137 gl_info->gl_ops.gl.p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1138 checkGLcall("glTexParameteri");
1140 gl_info->gl_ops.gl.p_glReadBuffer(GL_BACK);
1141 checkGLcall("glReadBuffer(GL_BACK)");
1143 if (texture_target != GL_TEXTURE_2D)
1145 gl_info->gl_ops.gl.p_glDisable(texture_target);
1146 gl_info->gl_ops.gl.p_glEnable(GL_TEXTURE_2D);
1147 texture_target = GL_TEXTURE_2D;
1150 checkGLcall("glEnd and previous");
1152 left = src_rect->left;
1153 right = src_rect->right;
1155 if (!upsidedown)
1157 top = src_height - src_rect->top;
1158 bottom = src_height - src_rect->bottom;
1160 else
1162 top = src_height - src_rect->bottom;
1163 bottom = src_height - src_rect->top;
1166 if (src_texture->t.flags & WINED3D_TEXTURE_NORMALIZED_COORDS)
1168 left /= src_pow2_width;
1169 right /= src_pow2_width;
1170 top /= src_pow2_height;
1171 bottom /= src_pow2_height;
1174 /* draw the source texture stretched and upside down. The correct surface is bound already */
1175 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1176 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1178 context_set_draw_buffer(context, drawBuffer);
1179 gl_info->gl_ops.gl.p_glReadBuffer(drawBuffer);
1181 gl_info->gl_ops.gl.p_glBegin(GL_QUADS);
1182 /* bottom left */
1183 gl_info->gl_ops.gl.p_glTexCoord2f(left, bottom);
1184 gl_info->gl_ops.gl.p_glVertex2i(0, 0);
1186 /* top left */
1187 gl_info->gl_ops.gl.p_glTexCoord2f(left, top);
1188 gl_info->gl_ops.gl.p_glVertex2i(0, dst_rect.bottom - dst_rect.top);
1190 /* top right */
1191 gl_info->gl_ops.gl.p_glTexCoord2f(right, top);
1192 gl_info->gl_ops.gl.p_glVertex2i(dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
1194 /* bottom right */
1195 gl_info->gl_ops.gl.p_glTexCoord2f(right, bottom);
1196 gl_info->gl_ops.gl.p_glVertex2i(dst_rect.right - dst_rect.left, 0);
1197 gl_info->gl_ops.gl.p_glEnd();
1198 checkGLcall("glEnd and previous");
1200 if (texture_target != dst_target)
1202 gl_info->gl_ops.gl.p_glDisable(texture_target);
1203 gl_info->gl_ops.gl.p_glEnable(dst_target);
1204 texture_target = dst_target;
1207 /* Now read the stretched and upside down image into the destination texture */
1208 context_bind_texture(context, texture_target, dst_texture->texture_rgb.name);
1209 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(texture_target,
1211 dst_rect.left, dst_rect.top, /* xoffset, yoffset */
1212 0, 0, /* We blitted the image to the origin */
1213 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
1214 checkGLcall("glCopyTexSubImage2D");
1216 if (drawBuffer == GL_BACK)
1218 /* Write the back buffer backup back. */
1219 if (backup)
1221 if (texture_target != GL_TEXTURE_2D)
1223 gl_info->gl_ops.gl.p_glDisable(texture_target);
1224 gl_info->gl_ops.gl.p_glEnable(GL_TEXTURE_2D);
1225 texture_target = GL_TEXTURE_2D;
1227 context_bind_texture(context, GL_TEXTURE_2D, backup);
1229 else
1231 if (texture_target != src_target)
1233 gl_info->gl_ops.gl.p_glDisable(texture_target);
1234 gl_info->gl_ops.gl.p_glEnable(src_target);
1235 texture_target = src_target;
1237 context_bind_texture(context, src_target, src_texture->texture_rgb.name);
1240 gl_info->gl_ops.gl.p_glBegin(GL_QUADS);
1241 /* top left */
1242 gl_info->gl_ops.gl.p_glTexCoord2f(0.0f, 0.0f);
1243 gl_info->gl_ops.gl.p_glVertex2i(0, src_height);
1245 /* bottom left */
1246 gl_info->gl_ops.gl.p_glTexCoord2f(0.0f, (float)src_height / (float)src_pow2_height);
1247 gl_info->gl_ops.gl.p_glVertex2i(0, 0);
1249 /* bottom right */
1250 gl_info->gl_ops.gl.p_glTexCoord2f((float)src_width / (float)src_pow2_width,
1251 (float)src_height / (float)src_pow2_height);
1252 gl_info->gl_ops.gl.p_glVertex2i(src_width, 0);
1254 /* top right */
1255 gl_info->gl_ops.gl.p_glTexCoord2f((float)src_width / (float)src_pow2_width, 0.0f);
1256 gl_info->gl_ops.gl.p_glVertex2i(src_width, src_height);
1257 gl_info->gl_ops.gl.p_glEnd();
1259 gl_info->gl_ops.gl.p_glDisable(texture_target);
1260 checkGLcall("glDisable(texture_target)");
1262 /* Cleanup */
1263 if (src != src_texture->texture_rgb.name && src != backup)
1265 gl_info->gl_ops.gl.p_glDeleteTextures(1, &src);
1266 checkGLcall("glDeleteTextures(1, &src)");
1268 if (backup)
1270 gl_info->gl_ops.gl.p_glDeleteTextures(1, &backup);
1271 checkGLcall("glDeleteTextures(1, &backup)");
1274 context_release(context);
1276 /* The texture is now most up to date - If the surface is a render target
1277 * and has a drawable, this path is never entered. */
1278 wined3d_texture_validate_location(&dst_texture->t, dst_sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB);
1279 wined3d_texture_invalidate_location(&dst_texture->t, dst_sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB);
1282 static HRESULT wined3d_texture_blt_special(struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx,
1283 const RECT *dst_rect, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx,
1284 const RECT *src_rect, DWORD flags, const struct wined3d_blt_fx *fx, enum wined3d_texture_filter_type filter)
1286 struct wined3d_swapchain *src_swapchain, *dst_swapchain;
1287 const struct wined3d_rendertarget_view *rtv;
1289 TRACE("dst_texture %p, dst_sub_resource_idx %u, dst_rect %s, src_texture %p, "
1290 "src_sub_resource_idx %u, src_rect %s, flags %#x, fx %p, filter %s.\n",
1291 dst_texture, dst_sub_resource_idx, wine_dbgstr_rect(dst_rect), src_texture, src_sub_resource_idx,
1292 wine_dbgstr_rect(src_rect), flags, fx, debug_d3dtexturefiltertype(filter));
1294 if (dst_texture->resource.type != WINED3D_RTYPE_TEXTURE_2D)
1296 FIXME("Not implemented for %s resources.\n", debug_d3dresourcetype(dst_texture->resource.type));
1297 return WINED3DERR_INVALIDCALL;
1300 /* Get the swapchain. One of the surfaces has to be a primary surface. */
1301 if (!(dst_texture->resource.access & WINED3D_RESOURCE_ACCESS_GPU))
1303 WARN("Destination resource is not GPU accessible, rejecting GL blit.\n");
1304 return WINED3DERR_INVALIDCALL;
1307 if (!(src_texture->resource.access & WINED3D_RESOURCE_ACCESS_GPU))
1309 WARN("Source resource is not GPU accessible, rejecting GL blit.\n");
1310 return WINED3DERR_INVALIDCALL;
1313 src_swapchain = src_texture->swapchain;
1314 dst_swapchain = dst_texture->swapchain;
1316 /* Early sort out of cases where no render target is used */
1317 if (!(rtv = dst_texture->resource.device->fb.render_targets[0]) || (!src_swapchain && !dst_swapchain
1318 && (&src_texture->resource != rtv->resource || src_sub_resource_idx != rtv->sub_resource_idx)
1319 && (&dst_texture->resource != rtv->resource || dst_sub_resource_idx != rtv->sub_resource_idx)))
1321 TRACE("No surface is render target, not using hardware blit.\n");
1322 return WINED3DERR_INVALIDCALL;
1325 /* No destination color keying supported */
1326 if (flags & (WINED3D_BLT_DST_CKEY | WINED3D_BLT_DST_CKEY_OVERRIDE))
1328 /* Can we support that with glBlendFunc if blitting to the frame buffer? */
1329 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
1330 return WINED3DERR_INVALIDCALL;
1333 if (dst_swapchain && dst_swapchain == src_swapchain)
1335 FIXME("Implement hardware blit between two surfaces on the same swapchain\n");
1336 return WINED3DERR_INVALIDCALL;
1339 if (dst_swapchain && src_swapchain)
1341 FIXME("Implement hardware blit between two different swapchains\n");
1342 return WINED3DERR_INVALIDCALL;
1345 if (dst_swapchain)
1347 /* Handled with regular texture -> swapchain blit */
1348 if (&src_texture->resource == rtv->resource && src_sub_resource_idx == rtv->sub_resource_idx)
1349 TRACE("Blit from active render target to a swapchain\n");
1351 else if (src_swapchain && &dst_texture->resource == rtv->resource
1352 && dst_sub_resource_idx == rtv->sub_resource_idx)
1354 FIXME("Implement blit from a swapchain to the active render target\n");
1355 return WINED3DERR_INVALIDCALL;
1358 if (!dst_swapchain && (src_swapchain || (&src_texture->resource == rtv->resource
1359 && src_sub_resource_idx == rtv->sub_resource_idx)))
1361 unsigned int src_level, src_width, src_height;
1362 /* Blit from render target to texture */
1363 BOOL stretchx;
1365 /* P8 read back is not implemented */
1366 if (src_texture->resource.format->id == WINED3DFMT_P8_UINT
1367 || dst_texture->resource.format->id == WINED3DFMT_P8_UINT)
1369 TRACE("P8 read back not supported by frame buffer to texture blit\n");
1370 return WINED3DERR_INVALIDCALL;
1373 if (flags & (WINED3D_BLT_SRC_CKEY | WINED3D_BLT_SRC_CKEY_OVERRIDE))
1375 TRACE("Color keying not supported by frame buffer to texture blit\n");
1376 return WINED3DERR_INVALIDCALL;
1377 /* Destination color key is checked above */
1380 if (dst_rect->right - dst_rect->left != src_rect->right - src_rect->left)
1381 stretchx = TRUE;
1382 else
1383 stretchx = FALSE;
1385 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
1386 * flip the image nor scale it.
1388 * -> If the app asks for an unscaled, upside down copy, just perform one glCopyTexSubImage2D call
1389 * -> If the app wants an image width an unscaled width, copy it line per line
1390 * -> If the app wants an image that is scaled on the x axis, and the destination rectangle is smaller
1391 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
1392 * back buffer. This is slower than reading line per line, thus not used for flipping
1393 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
1394 * pixel by pixel. */
1395 src_level = src_sub_resource_idx % src_texture->level_count;
1396 src_width = wined3d_texture_get_level_width(src_texture, src_level);
1397 src_height = wined3d_texture_get_level_height(src_texture, src_level);
1398 if (!stretchx || dst_rect->right - dst_rect->left > src_width
1399 || dst_rect->bottom - dst_rect->top > src_height)
1401 TRACE("No stretching in x direction, using direct framebuffer -> texture copy.\n");
1402 fb_copy_to_texture_direct(wined3d_texture_gl(dst_texture), dst_sub_resource_idx, dst_rect,
1403 wined3d_texture_gl(src_texture), src_sub_resource_idx, src_rect, filter);
1405 else
1407 TRACE("Using hardware stretching to flip / stretch the texture.\n");
1408 fb_copy_to_texture_hwstretch(wined3d_texture_gl(dst_texture), dst_sub_resource_idx, dst_rect,
1409 wined3d_texture_gl(src_texture), src_sub_resource_idx, src_rect, filter);
1412 return WINED3D_OK;
1415 /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
1416 TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
1417 return WINED3DERR_INVALIDCALL;
1420 /* Context activation is done by the caller. */
1421 BOOL texture2d_load_sysmem(struct wined3d_texture *texture, unsigned int sub_resource_idx,
1422 struct wined3d_context *context, DWORD dst_location)
1424 struct wined3d_texture_sub_resource *sub_resource;
1426 sub_resource = &texture->sub_resources[sub_resource_idx];
1427 wined3d_texture_prepare_location(texture, sub_resource_idx, context, dst_location);
1429 /* We cannot download data from multisample textures directly. */
1430 if (is_multisample_location(wined3d_texture_gl(texture), WINED3D_LOCATION_TEXTURE_RGB))
1432 wined3d_texture_load_location(texture, sub_resource_idx, context, WINED3D_LOCATION_RB_RESOLVED);
1433 texture2d_read_from_framebuffer(texture, sub_resource_idx, context,
1434 WINED3D_LOCATION_RB_RESOLVED, dst_location);
1435 return TRUE;
1438 if (sub_resource->locations & (WINED3D_LOCATION_RB_MULTISAMPLE | WINED3D_LOCATION_RB_RESOLVED))
1439 wined3d_texture_load_location(texture, sub_resource_idx, context, WINED3D_LOCATION_TEXTURE_RGB);
1441 /* Download the sub-resource to system memory. */
1442 if (sub_resource->locations & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB))
1444 struct wined3d_bo_address data;
1445 wined3d_texture_gl_bind_and_dirtify(wined3d_texture_gl(texture), context,
1446 !(sub_resource->locations & WINED3D_LOCATION_TEXTURE_RGB));
1447 wined3d_texture_get_memory(texture, sub_resource_idx, &data, dst_location);
1448 wined3d_texture_download_data(texture, sub_resource_idx, context, &data);
1449 ++texture->download_count;
1450 return TRUE;
1453 if (!(texture->resource.bind_flags & WINED3D_BIND_DEPTH_STENCIL)
1454 && (sub_resource->locations & WINED3D_LOCATION_DRAWABLE))
1456 texture2d_read_from_framebuffer(texture, sub_resource_idx, context,
1457 texture->resource.draw_binding, dst_location);
1458 return TRUE;
1461 FIXME("Can't load texture %p, %u with location flags %s into sysmem.\n",
1462 texture, sub_resource_idx, wined3d_debug_location(sub_resource->locations));
1463 return FALSE;
1466 /* Context activation is done by the caller. */
1467 BOOL texture2d_load_drawable(struct wined3d_texture *texture,
1468 unsigned int sub_resource_idx, struct wined3d_context *context)
1470 struct wined3d_texture *restore_texture;
1471 struct wined3d_device *device;
1472 unsigned int restore_idx;
1473 unsigned int level;
1474 RECT r;
1476 if (texture->resource.bind_flags & WINED3D_BIND_DEPTH_STENCIL)
1478 DWORD current = texture->sub_resources[sub_resource_idx].locations;
1479 FIXME("Unimplemented copy from %s for depth/stencil buffers.\n",
1480 wined3d_debug_location(current));
1481 return FALSE;
1484 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO
1485 && wined3d_resource_is_offscreen(&texture->resource))
1487 ERR("Trying to load offscreen texture into WINED3D_LOCATION_DRAWABLE.\n");
1488 return FALSE;
1491 device = texture->resource.device;
1492 restore_texture = context->current_rt.texture;
1493 restore_idx = context->current_rt.sub_resource_idx;
1494 if (restore_texture != texture || restore_idx != sub_resource_idx)
1495 context = context_acquire(device, texture, sub_resource_idx);
1496 else
1497 restore_texture = NULL;
1499 level = sub_resource_idx % texture->level_count;
1500 SetRect(&r, 0, 0, wined3d_texture_get_level_width(texture, level),
1501 wined3d_texture_get_level_height(texture, level));
1502 wined3d_texture_load_location(texture, sub_resource_idx, context, WINED3D_LOCATION_TEXTURE_RGB);
1503 device->blitter->ops->blitter_blit(device->blitter, WINED3D_BLIT_OP_COLOR_BLIT, context,
1504 texture, sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB, &r,
1505 texture, sub_resource_idx, WINED3D_LOCATION_DRAWABLE, &r,
1506 NULL, WINED3D_TEXF_POINT);
1508 if (restore_texture)
1509 context_restore(context, restore_texture, restore_idx);
1511 return TRUE;
1514 BOOL texture2d_load_texture(struct wined3d_texture *texture, unsigned int sub_resource_idx,
1515 struct wined3d_context *context, BOOL srgb)
1517 unsigned int width, height, level, src_row_pitch, src_slice_pitch, dst_row_pitch, dst_slice_pitch;
1518 const struct wined3d_gl_info *gl_info = context->gl_info;
1519 struct wined3d_device *device = texture->resource.device;
1520 const struct wined3d_color_key_conversion *conversion;
1521 struct wined3d_texture_sub_resource *sub_resource;
1522 const struct wined3d_format *format;
1523 struct wined3d_bo_address data;
1524 BYTE *src_mem, *dst_mem = NULL;
1525 struct wined3d_box src_box;
1526 BOOL depth;
1528 depth = texture->resource.bind_flags & WINED3D_BIND_DEPTH_STENCIL;
1529 sub_resource = &texture->sub_resources[sub_resource_idx];
1531 if (!depth && wined3d_settings.offscreen_rendering_mode != ORM_FBO
1532 && wined3d_resource_is_offscreen(&texture->resource)
1533 && (sub_resource->locations & WINED3D_LOCATION_DRAWABLE))
1535 texture2d_load_fb_texture(wined3d_texture_gl(texture), sub_resource_idx, srgb, context);
1537 return TRUE;
1540 level = sub_resource_idx % texture->level_count;
1541 width = wined3d_texture_get_level_width(texture, level);
1542 height = wined3d_texture_get_level_height(texture, level);
1543 wined3d_box_set(&src_box, 0, 0, width, height, 0, 1);
1545 if (!depth && sub_resource->locations & (WINED3D_LOCATION_TEXTURE_SRGB | WINED3D_LOCATION_TEXTURE_RGB)
1546 && (texture->resource.format_flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB)
1547 && fbo_blitter_supported(WINED3D_BLIT_OP_COLOR_BLIT, gl_info,
1548 &texture->resource, WINED3D_LOCATION_TEXTURE_RGB,
1549 &texture->resource, WINED3D_LOCATION_TEXTURE_SRGB))
1551 RECT src_rect;
1553 SetRect(&src_rect, 0, 0, width, height);
1554 if (srgb)
1555 texture2d_blt_fbo(device, context, WINED3D_TEXF_POINT,
1556 texture, sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB, &src_rect,
1557 texture, sub_resource_idx, WINED3D_LOCATION_TEXTURE_SRGB, &src_rect);
1558 else
1559 texture2d_blt_fbo(device, context, WINED3D_TEXF_POINT,
1560 texture, sub_resource_idx, WINED3D_LOCATION_TEXTURE_SRGB, &src_rect,
1561 texture, sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB, &src_rect);
1563 return TRUE;
1566 if (!depth && sub_resource->locations & (WINED3D_LOCATION_RB_MULTISAMPLE | WINED3D_LOCATION_RB_RESOLVED)
1567 && (!srgb || (texture->resource.format_flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB)))
1569 DWORD src_location = sub_resource->locations & WINED3D_LOCATION_RB_RESOLVED ?
1570 WINED3D_LOCATION_RB_RESOLVED : WINED3D_LOCATION_RB_MULTISAMPLE;
1571 DWORD dst_location = srgb ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB;
1572 RECT src_rect;
1574 SetRect(&src_rect, 0, 0, width, height);
1575 if (fbo_blitter_supported(WINED3D_BLIT_OP_COLOR_BLIT, gl_info,
1576 &texture->resource, src_location, &texture->resource, dst_location))
1577 texture2d_blt_fbo(device, context, WINED3D_TEXF_POINT, texture, sub_resource_idx,
1578 src_location, &src_rect, texture, sub_resource_idx, dst_location, &src_rect);
1580 return TRUE;
1583 /* Upload from system memory */
1585 if (srgb)
1587 if ((sub_resource->locations & (WINED3D_LOCATION_TEXTURE_RGB | texture->resource.map_binding))
1588 == WINED3D_LOCATION_TEXTURE_RGB)
1590 FIXME_(d3d_perf)("Downloading RGB texture %p, %u to reload it as sRGB.\n", texture, sub_resource_idx);
1591 wined3d_texture_load_location(texture, sub_resource_idx, context, texture->resource.map_binding);
1594 else
1596 if ((sub_resource->locations & (WINED3D_LOCATION_TEXTURE_SRGB | texture->resource.map_binding))
1597 == WINED3D_LOCATION_TEXTURE_SRGB)
1599 FIXME_(d3d_perf)("Downloading sRGB texture %p, %u to reload it as RGB.\n", texture, sub_resource_idx);
1600 wined3d_texture_load_location(texture, sub_resource_idx, context, texture->resource.map_binding);
1604 if (!(sub_resource->locations & surface_simple_locations))
1606 WARN("Trying to load a texture from sysmem, but no simple location is valid.\n");
1607 /* Lets hope we get it from somewhere... */
1608 wined3d_texture_load_location(texture, sub_resource_idx, context, WINED3D_LOCATION_SYSMEM);
1611 wined3d_texture_prepare_texture(texture, context, srgb);
1612 wined3d_texture_gl_bind_and_dirtify(wined3d_texture_gl(texture), context, srgb);
1613 wined3d_texture_get_pitch(texture, level, &src_row_pitch, &src_slice_pitch);
1615 format = texture->resource.format;
1616 if ((conversion = wined3d_format_get_color_key_conversion(texture, TRUE)))
1617 format = wined3d_get_format(device->adapter, conversion->dst_format, texture->resource.bind_flags);
1619 /* Don't use PBOs for converted surfaces. During PBO conversion we look at
1620 * WINED3D_TEXTURE_CONVERTED but it isn't set (yet) in all cases it is
1621 * getting called. */
1622 if (conversion && sub_resource->buffer_object)
1624 TRACE("Removing the pbo attached to texture %p, %u.\n", texture, sub_resource_idx);
1626 wined3d_texture_load_location(texture, sub_resource_idx, context, WINED3D_LOCATION_SYSMEM);
1627 wined3d_texture_set_map_binding(texture, WINED3D_LOCATION_SYSMEM);
1630 wined3d_texture_get_memory(texture, sub_resource_idx, &data, sub_resource->locations);
1631 if (conversion)
1633 wined3d_format_calculate_pitch(format, device->surface_alignment,
1634 width, height, &dst_row_pitch, &dst_slice_pitch);
1636 src_mem = context_map_bo_address(context, &data, src_slice_pitch,
1637 GL_PIXEL_UNPACK_BUFFER, WINED3D_MAP_READ);
1638 if (!(dst_mem = heap_alloc(dst_slice_pitch)))
1640 ERR("Out of memory (%u).\n", dst_slice_pitch);
1641 context_release(context);
1642 return FALSE;
1644 conversion->convert(src_mem, src_row_pitch, dst_mem, dst_row_pitch,
1645 width, height, &texture->async.gl_color_key);
1646 src_row_pitch = dst_row_pitch;
1647 src_slice_pitch = dst_slice_pitch;
1648 context_unmap_bo_address(context, &data, GL_PIXEL_UNPACK_BUFFER);
1650 data.buffer_object = 0;
1651 data.addr = dst_mem;
1654 wined3d_texture_upload_data(texture, sub_resource_idx, context, format, &src_box,
1655 wined3d_const_bo_address(&data), src_row_pitch, src_slice_pitch, 0, 0, 0, srgb);
1657 heap_free(dst_mem);
1659 return TRUE;
1662 /* Context activation is done by the caller. */
1663 BOOL texture2d_load_renderbuffer(struct wined3d_texture *texture, unsigned int sub_resource_idx,
1664 struct wined3d_context *context, DWORD dst_location)
1666 unsigned int level = sub_resource_idx % texture->level_count;
1667 const RECT rect = {0, 0,
1668 wined3d_texture_get_level_width(texture, level),
1669 wined3d_texture_get_level_height(texture, level)};
1670 struct wined3d_texture_sub_resource *sub_resource;
1671 DWORD src_location, locations;
1673 sub_resource = &texture->sub_resources[sub_resource_idx];
1674 locations = sub_resource->locations;
1675 if (texture->resource.bind_flags & WINED3D_BIND_DEPTH_STENCIL)
1677 FIXME("Unimplemented copy from %s for depth/stencil buffers.\n",
1678 wined3d_debug_location(locations));
1679 return FALSE;
1682 if (locations & WINED3D_LOCATION_RB_MULTISAMPLE)
1683 src_location = WINED3D_LOCATION_RB_MULTISAMPLE;
1684 else if (locations & WINED3D_LOCATION_RB_RESOLVED)
1685 src_location = WINED3D_LOCATION_RB_RESOLVED;
1686 else if (locations & WINED3D_LOCATION_TEXTURE_SRGB)
1687 src_location = WINED3D_LOCATION_TEXTURE_SRGB;
1688 else if (locations & WINED3D_LOCATION_TEXTURE_RGB)
1689 src_location = WINED3D_LOCATION_TEXTURE_RGB;
1690 else if (locations & WINED3D_LOCATION_DRAWABLE)
1691 src_location = WINED3D_LOCATION_DRAWABLE;
1692 else /* texture2d_blt_fbo() will load the source location if necessary. */
1693 src_location = WINED3D_LOCATION_TEXTURE_RGB;
1695 texture2d_blt_fbo(texture->resource.device, context, WINED3D_TEXF_POINT, texture,
1696 sub_resource_idx, src_location, &rect, texture, sub_resource_idx, dst_location, &rect);
1698 return TRUE;
1701 /* Context activation is done by the caller. */
1702 static void fbo_blitter_destroy(struct wined3d_blitter *blitter, struct wined3d_context *context)
1704 struct wined3d_blitter *next;
1706 if ((next = blitter->next))
1707 next->ops->blitter_destroy(next, context);
1709 heap_free(blitter);
1712 static void fbo_blitter_clear(struct wined3d_blitter *blitter, struct wined3d_device *device,
1713 unsigned int rt_count, const struct wined3d_fb_state *fb, unsigned int rect_count, const RECT *clear_rects,
1714 const RECT *draw_rect, DWORD flags, const struct wined3d_color *colour, float depth, DWORD stencil)
1716 struct wined3d_blitter *next;
1718 if ((next = blitter->next))
1719 next->ops->blitter_clear(next, device, rt_count, fb, rect_count,
1720 clear_rects, draw_rect, flags, colour, depth, stencil);
1723 static DWORD fbo_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_blit_op op,
1724 struct wined3d_context *context, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx,
1725 DWORD src_location, const RECT *src_rect, struct wined3d_texture *dst_texture,
1726 unsigned int dst_sub_resource_idx, DWORD dst_location, const RECT *dst_rect,
1727 const struct wined3d_color_key *colour_key, enum wined3d_texture_filter_type filter)
1729 struct wined3d_resource *src_resource, *dst_resource;
1730 enum wined3d_blit_op blit_op = op;
1731 struct wined3d_device *device;
1732 struct wined3d_blitter *next;
1734 TRACE("blitter %p, op %#x, context %p, src_texture %p, src_sub_resource_idx %u, src_location %s, src_rect %s, "
1735 "dst_texture %p, dst_sub_resource_idx %u, dst_location %s, dst_rect %s, colour_key %p, filter %s.\n",
1736 blitter, op, context, src_texture, src_sub_resource_idx, wined3d_debug_location(src_location),
1737 wine_dbgstr_rect(src_rect), dst_texture, dst_sub_resource_idx, wined3d_debug_location(dst_location),
1738 wine_dbgstr_rect(dst_rect), colour_key, debug_d3dtexturefiltertype(filter));
1740 src_resource = &src_texture->resource;
1741 dst_resource = &dst_texture->resource;
1743 device = dst_resource->device;
1745 if (blit_op == WINED3D_BLIT_OP_RAW_BLIT && dst_resource->format->id == src_resource->format->id)
1747 if (dst_resource->format_flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL))
1748 blit_op = WINED3D_BLIT_OP_DEPTH_BLIT;
1749 else
1750 blit_op = WINED3D_BLIT_OP_COLOR_BLIT;
1753 if (!fbo_blitter_supported(blit_op, context->gl_info,
1754 src_resource, src_location, dst_resource, dst_location))
1756 if (!(next = blitter->next))
1758 ERR("No blitter to handle blit op %#x.\n", op);
1759 return dst_location;
1762 TRACE("Forwarding to blitter %p.\n", next);
1763 return next->ops->blitter_blit(next, op, context, src_texture, src_sub_resource_idx, src_location,
1764 src_rect, dst_texture, dst_sub_resource_idx, dst_location, dst_rect, colour_key, filter);
1767 if (blit_op == WINED3D_BLIT_OP_COLOR_BLIT)
1769 TRACE("Colour blit.\n");
1770 texture2d_blt_fbo(device, context, filter, src_texture, src_sub_resource_idx, src_location,
1771 src_rect, dst_texture, dst_sub_resource_idx, dst_location, dst_rect);
1772 return dst_location;
1775 if (blit_op == WINED3D_BLIT_OP_DEPTH_BLIT)
1777 TRACE("Depth/stencil blit.\n");
1778 texture2d_depth_blt_fbo(device, context, src_texture, src_sub_resource_idx, src_location,
1779 src_rect, dst_texture, dst_sub_resource_idx, dst_location, dst_rect);
1780 return dst_location;
1783 ERR("This blitter does not implement blit op %#x.\n", blit_op);
1784 return dst_location;
1787 static const struct wined3d_blitter_ops fbo_blitter_ops =
1789 fbo_blitter_destroy,
1790 fbo_blitter_clear,
1791 fbo_blitter_blit,
1794 void wined3d_fbo_blitter_create(struct wined3d_blitter **next, const struct wined3d_gl_info *gl_info)
1796 struct wined3d_blitter *blitter;
1798 if ((wined3d_settings.offscreen_rendering_mode != ORM_FBO) || !gl_info->fbo_ops.glBlitFramebuffer)
1799 return;
1801 if (!(blitter = heap_alloc(sizeof(*blitter))))
1802 return;
1804 TRACE("Created blitter %p.\n", blitter);
1806 blitter->ops = &fbo_blitter_ops;
1807 blitter->next = *next;
1808 *next = blitter;
1811 /* Context activation is done by the caller. */
1812 static void raw_blitter_destroy(struct wined3d_blitter *blitter, struct wined3d_context *context)
1814 struct wined3d_blitter *next;
1816 if ((next = blitter->next))
1817 next->ops->blitter_destroy(next, context);
1819 heap_free(blitter);
1822 /* Context activation is done by the caller. */
1823 static void raw_blitter_clear(struct wined3d_blitter *blitter, struct wined3d_device *device,
1824 unsigned int rt_count, const struct wined3d_fb_state *fb, unsigned int rect_count, const RECT *clear_rects,
1825 const RECT *draw_rect, DWORD flags, const struct wined3d_color *colour, float depth, DWORD stencil)
1827 struct wined3d_blitter *next;
1829 if (!(next = blitter->next))
1831 ERR("No blitter to handle clear.\n");
1832 return;
1835 TRACE("Forwarding to blitter %p.\n", next);
1836 next->ops->blitter_clear(next, device, rt_count, fb, rect_count,
1837 clear_rects, draw_rect, flags, colour, depth, stencil);
1840 /* Context activation is done by the caller. */
1841 static DWORD raw_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_blit_op op,
1842 struct wined3d_context *context, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx,
1843 DWORD src_location, const RECT *src_rect, struct wined3d_texture *dst_texture,
1844 unsigned int dst_sub_resource_idx, DWORD dst_location, const RECT *dst_rect,
1845 const struct wined3d_color_key *colour_key, enum wined3d_texture_filter_type filter)
1847 struct wined3d_texture_gl *src_texture_gl = wined3d_texture_gl(src_texture);
1848 struct wined3d_texture_gl *dst_texture_gl = wined3d_texture_gl(dst_texture);
1849 const struct wined3d_gl_info *gl_info = context->gl_info;
1850 unsigned int src_level, src_layer, dst_level, dst_layer;
1851 struct wined3d_blitter *next;
1852 GLuint src_name, dst_name;
1853 DWORD location;
1855 /* If we would need to copy from a renderbuffer or drawable, we'd probably
1856 * be better of using the FBO blitter directly, since we'd need to use it
1857 * to copy the resource contents to the texture anyway. */
1858 if (op != WINED3D_BLIT_OP_RAW_BLIT
1859 || (src_texture->resource.format->id == dst_texture->resource.format->id
1860 && (!(src_location & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB))
1861 || !(dst_location & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB)))))
1863 if (!(next = blitter->next))
1865 ERR("No blitter to handle blit op %#x.\n", op);
1866 return dst_location;
1869 TRACE("Forwarding to blitter %p.\n", next);
1870 return next->ops->blitter_blit(next, op, context, src_texture, src_sub_resource_idx, src_location,
1871 src_rect, dst_texture, dst_sub_resource_idx, dst_location, dst_rect, colour_key, filter);
1874 TRACE("Blit using ARB_copy_image.\n");
1876 src_level = src_sub_resource_idx % src_texture->level_count;
1877 src_layer = src_sub_resource_idx / src_texture->level_count;
1879 dst_level = dst_sub_resource_idx % dst_texture->level_count;
1880 dst_layer = dst_sub_resource_idx / dst_texture->level_count;
1882 location = src_location & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB);
1883 if (!location)
1884 location = src_texture->flags & WINED3D_TEXTURE_IS_SRGB
1885 ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB;
1886 if (!wined3d_texture_load_location(src_texture, src_sub_resource_idx, context, location))
1887 ERR("Failed to load the source sub-resource into %s.\n", wined3d_debug_location(location));
1888 src_name = wined3d_texture_gl_get_texture_name(src_texture_gl,
1889 context, location == WINED3D_LOCATION_TEXTURE_SRGB);
1891 location = dst_location & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB);
1892 if (!location)
1893 location = dst_texture->flags & WINED3D_TEXTURE_IS_SRGB
1894 ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB;
1895 if (texture2d_is_full_rect(dst_texture, dst_level, dst_rect))
1897 if (!wined3d_texture_prepare_location(dst_texture, dst_sub_resource_idx, context, location))
1898 ERR("Failed to prepare the destination sub-resource into %s.\n", wined3d_debug_location(location));
1900 else
1902 if (!wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, location))
1903 ERR("Failed to load the destination sub-resource into %s.\n", wined3d_debug_location(location));
1905 dst_name = wined3d_texture_gl_get_texture_name(dst_texture_gl,
1906 context, location == WINED3D_LOCATION_TEXTURE_SRGB);
1908 GL_EXTCALL(glCopyImageSubData(src_name, src_texture_gl->target, src_level,
1909 src_rect->left, src_rect->top, src_layer, dst_name, dst_texture_gl->target, dst_level,
1910 dst_rect->left, dst_rect->top, dst_layer, src_rect->right - src_rect->left,
1911 src_rect->bottom - src_rect->top, 1));
1912 checkGLcall("copy image data");
1914 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, location);
1915 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~location);
1916 if (!wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, dst_location))
1917 ERR("Failed to load the destination sub-resource into %s.\n", wined3d_debug_location(dst_location));
1919 return dst_location | location;
1922 static const struct wined3d_blitter_ops raw_blitter_ops =
1924 raw_blitter_destroy,
1925 raw_blitter_clear,
1926 raw_blitter_blit,
1929 void wined3d_raw_blitter_create(struct wined3d_blitter **next, const struct wined3d_gl_info *gl_info)
1931 struct wined3d_blitter *blitter;
1933 if (!gl_info->supported[ARB_COPY_IMAGE])
1934 return;
1936 if (!(blitter = heap_alloc(sizeof(*blitter))))
1937 return;
1939 TRACE("Created blitter %p.\n", blitter);
1941 blitter->ops = &raw_blitter_ops;
1942 blitter->next = *next;
1943 *next = blitter;
1946 /* Context activation is done by the caller. */
1947 static void ffp_blitter_destroy(struct wined3d_blitter *blitter, struct wined3d_context *context)
1949 struct wined3d_blitter *next;
1951 if ((next = blitter->next))
1952 next->ops->blitter_destroy(next, context);
1954 heap_free(blitter);
1957 static BOOL ffp_blit_supported(enum wined3d_blit_op blit_op, const struct wined3d_context *context,
1958 const struct wined3d_resource *src_resource, DWORD src_location,
1959 const struct wined3d_resource *dst_resource, DWORD dst_location)
1961 const struct wined3d_format *src_format = src_resource->format;
1962 const struct wined3d_format *dst_format = dst_resource->format;
1963 BOOL decompress;
1965 if (src_resource->type != WINED3D_RTYPE_TEXTURE_2D)
1966 return FALSE;
1968 decompress = src_format && (src_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_COMPRESSED)
1969 && !(dst_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_COMPRESSED);
1970 if (!decompress && !(src_resource->access & dst_resource->access & WINED3D_RESOURCE_ACCESS_GPU))
1972 TRACE("Source or destination resource is not GPU accessible.\n");
1973 return FALSE;
1976 if (blit_op == WINED3D_BLIT_OP_RAW_BLIT && dst_format->id == src_format->id)
1978 if (dst_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL))
1979 blit_op = WINED3D_BLIT_OP_DEPTH_BLIT;
1980 else
1981 blit_op = WINED3D_BLIT_OP_COLOR_BLIT;
1984 switch (blit_op)
1986 case WINED3D_BLIT_OP_COLOR_BLIT_CKEY:
1987 if (context->d3d_info->shader_color_key)
1989 TRACE("Color keying requires converted textures.\n");
1990 return FALSE;
1992 case WINED3D_BLIT_OP_COLOR_BLIT:
1993 case WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST:
1994 if (!context->gl_info->supported[WINED3D_GL_LEGACY_CONTEXT])
1995 return FALSE;
1997 if (TRACE_ON(d3d))
1999 TRACE("Checking support for fixup:\n");
2000 dump_color_fixup_desc(src_format->color_fixup);
2003 /* We only support identity conversions. */
2004 if (!is_identity_fixup(src_format->color_fixup)
2005 || !is_identity_fixup(dst_format->color_fixup))
2007 if (wined3d_settings.offscreen_rendering_mode == ORM_BACKBUFFER
2008 && dst_format->id == src_format->id && dst_location == WINED3D_LOCATION_DRAWABLE)
2010 WARN("Claiming fixup support because of ORM_BACKBUFFER.\n");
2012 else
2014 TRACE("Fixups are not supported.\n");
2015 return FALSE;
2019 if (!(dst_resource->bind_flags & WINED3D_BIND_RENDER_TARGET))
2021 TRACE("Can only blit to render targets.\n");
2022 return FALSE;
2024 return TRUE;
2026 default:
2027 TRACE("Unsupported blit operation %#x.\n", blit_op);
2028 return FALSE;
2032 static BOOL ffp_blitter_use_cpu_clear(struct wined3d_rendertarget_view *view)
2034 struct wined3d_resource *resource;
2035 struct wined3d_texture *texture;
2036 DWORD locations;
2038 resource = view->resource;
2039 if (resource->type == WINED3D_RTYPE_BUFFER)
2040 return !(resource->access & WINED3D_RESOURCE_ACCESS_GPU);
2042 texture = texture_from_resource(resource);
2043 locations = texture->sub_resources[view->sub_resource_idx].locations;
2044 if (locations & (resource->map_binding | WINED3D_LOCATION_DISCARDED))
2045 return !(resource->access & WINED3D_RESOURCE_ACCESS_GPU)
2046 || (texture->flags & WINED3D_TEXTURE_PIN_SYSMEM);
2048 return !(resource->access & WINED3D_RESOURCE_ACCESS_GPU)
2049 && !(texture->flags & WINED3D_TEXTURE_CONVERTED);
2052 static void ffp_blitter_clear(struct wined3d_blitter *blitter, struct wined3d_device *device,
2053 unsigned int rt_count, const struct wined3d_fb_state *fb, unsigned int rect_count, const RECT *clear_rects,
2054 const RECT *draw_rect, DWORD flags, const struct wined3d_color *colour, float depth, DWORD stencil)
2056 struct wined3d_rendertarget_view *view;
2057 struct wined3d_blitter *next;
2058 DWORD next_flags = 0;
2059 unsigned int i;
2061 if (flags & WINED3DCLEAR_TARGET)
2063 for (i = 0; i < rt_count; ++i)
2065 if (!(view = fb->render_targets[i]))
2066 continue;
2068 if (ffp_blitter_use_cpu_clear(view)
2069 || (!(view->resource->bind_flags & WINED3D_BIND_RENDER_TARGET)
2070 && (wined3d_settings.offscreen_rendering_mode != ORM_FBO
2071 || !(view->format_flags & WINED3DFMT_FLAG_FBO_ATTACHABLE))))
2073 next_flags |= WINED3DCLEAR_TARGET;
2074 flags &= ~WINED3DCLEAR_TARGET;
2075 break;
2078 /* FIXME: We should reject colour fills on formats with fixups,
2079 * but this would break P8 colour fills for example. */
2083 if ((flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL)) && (view = fb->depth_stencil)
2084 && (!view->format->depth_size || (flags & WINED3DCLEAR_ZBUFFER))
2085 && (!view->format->stencil_size || (flags & WINED3DCLEAR_STENCIL))
2086 && ffp_blitter_use_cpu_clear(view))
2088 next_flags |= flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL);
2089 flags &= ~(WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL);
2092 if (flags)
2093 device_clear_render_targets(device, rt_count, fb, rect_count,
2094 clear_rects, draw_rect, flags, colour, depth, stencil);
2096 if (next_flags && (next = blitter->next))
2097 next->ops->blitter_clear(next, device, rt_count, fb, rect_count,
2098 clear_rects, draw_rect, next_flags, colour, depth, stencil);
2101 static DWORD ffp_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_blit_op op,
2102 struct wined3d_context *context, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx,
2103 DWORD src_location, const RECT *src_rect, struct wined3d_texture *dst_texture,
2104 unsigned int dst_sub_resource_idx, DWORD dst_location, const RECT *dst_rect,
2105 const struct wined3d_color_key *color_key, enum wined3d_texture_filter_type filter)
2107 struct wined3d_texture_gl *src_texture_gl = wined3d_texture_gl(src_texture);
2108 const struct wined3d_gl_info *gl_info = context->gl_info;
2109 struct wined3d_resource *src_resource, *dst_resource;
2110 struct wined3d_texture *staging_texture = NULL;
2111 struct wined3d_color_key old_blt_key;
2112 struct wined3d_device *device;
2113 struct wined3d_blitter *next;
2114 DWORD old_color_key_flags;
2115 RECT r;
2117 src_resource = &src_texture->resource;
2118 dst_resource = &dst_texture->resource;
2119 device = dst_resource->device;
2121 if (!ffp_blit_supported(op, context, src_resource, src_location, dst_resource, dst_location))
2123 if ((next = blitter->next))
2124 return next->ops->blitter_blit(next, op, context, src_texture, src_sub_resource_idx, src_location,
2125 src_rect, dst_texture, dst_sub_resource_idx, dst_location, dst_rect, color_key, filter);
2128 TRACE("Blt from texture %p, %u to rendertarget %p, %u.\n",
2129 src_texture, src_sub_resource_idx, dst_texture, dst_sub_resource_idx);
2131 old_blt_key = src_texture->async.src_blt_color_key;
2132 old_color_key_flags = src_texture->async.color_key_flags;
2133 wined3d_texture_set_color_key(src_texture, WINED3D_CKEY_SRC_BLT, color_key);
2135 if (!(src_texture->resource.access & WINED3D_RESOURCE_ACCESS_GPU))
2137 struct wined3d_resource_desc desc;
2138 struct wined3d_box upload_box;
2139 unsigned int src_level;
2140 HRESULT hr;
2142 TRACE("Source texture is not GPU accessible, creating a staging texture.\n");
2144 src_level = src_sub_resource_idx % src_texture->level_count;
2145 desc.resource_type = WINED3D_RTYPE_TEXTURE_2D;
2146 desc.format = src_texture->resource.format->id;
2147 desc.multisample_type = src_texture->resource.multisample_type;
2148 desc.multisample_quality = src_texture->resource.multisample_quality;
2149 desc.usage = WINED3DUSAGE_PRIVATE;
2150 desc.bind_flags = 0;
2151 desc.access = WINED3D_RESOURCE_ACCESS_GPU;
2152 desc.width = wined3d_texture_get_level_width(src_texture, src_level);
2153 desc.height = wined3d_texture_get_level_height(src_texture, src_level);
2154 desc.depth = 1;
2155 desc.size = 0;
2157 if (FAILED(hr = wined3d_texture_create(device, &desc, 1, 1, 0,
2158 NULL, NULL, &wined3d_null_parent_ops, &staging_texture)))
2160 ERR("Failed to create staging texture, hr %#x.\n", hr);
2161 return dst_location;
2164 wined3d_box_set(&upload_box, 0, 0, desc.width, desc.height, 0, desc.depth);
2165 wined3d_texture_upload_from_texture(staging_texture, 0, 0, 0, 0,
2166 src_texture, src_sub_resource_idx, &upload_box);
2168 src_texture = staging_texture;
2169 src_sub_resource_idx = 0;
2171 else
2173 /* Make sure the surface is up-to-date. This should probably use
2174 * surface_load_location() and worry about the destination surface
2175 * too, unless we're overwriting it completely. */
2176 wined3d_texture_load(src_texture, context, FALSE);
2179 context_apply_ffp_blit_state(context, device);
2181 if (dst_location == WINED3D_LOCATION_DRAWABLE)
2183 r = *dst_rect;
2184 wined3d_texture_translate_drawable_coords(dst_texture, context->win_handle, &r);
2185 dst_rect = &r;
2188 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
2190 GLenum buffer;
2192 if (dst_location == WINED3D_LOCATION_DRAWABLE)
2194 TRACE("Destination texture %p is onscreen.\n", dst_texture);
2195 buffer = wined3d_texture_get_gl_buffer(dst_texture);
2197 else
2199 TRACE("Destination texture %p is offscreen.\n", dst_texture);
2200 buffer = GL_COLOR_ATTACHMENT0;
2202 context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER,
2203 dst_resource, dst_sub_resource_idx, NULL, 0, dst_location);
2204 context_set_draw_buffer(context, buffer);
2205 context_check_fbo_status(context, GL_DRAW_FRAMEBUFFER);
2206 context_invalidate_state(context, STATE_FRAMEBUFFER);
2209 gl_info->gl_ops.gl.p_glEnable(src_texture_gl->target);
2210 checkGLcall("glEnable(target)");
2212 if (op == WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST || color_key)
2214 gl_info->gl_ops.gl.p_glEnable(GL_ALPHA_TEST);
2215 checkGLcall("glEnable(GL_ALPHA_TEST)");
2218 if (color_key)
2220 /* For P8 surfaces, the alpha component contains the palette index.
2221 * Which means that the colorkey is one of the palette entries. In
2222 * other cases pixels that should be masked away have alpha set to 0. */
2223 if (src_texture->resource.format->id == WINED3DFMT_P8_UINT)
2224 gl_info->gl_ops.gl.p_glAlphaFunc(GL_NOTEQUAL,
2225 (float)src_texture->async.src_blt_color_key.color_space_low_value / 255.0f);
2226 else
2227 gl_info->gl_ops.gl.p_glAlphaFunc(GL_NOTEQUAL, 0.0f);
2228 checkGLcall("glAlphaFunc");
2231 context_draw_textured_quad(context, src_texture_gl,
2232 src_sub_resource_idx, src_rect, dst_rect, filter);
2234 if (op == WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST || color_key)
2236 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
2237 checkGLcall("glDisable(GL_ALPHA_TEST)");
2240 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_2D);
2241 checkGLcall("glDisable(GL_TEXTURE_2D)");
2242 if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
2244 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_CUBE_MAP_ARB);
2245 checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
2247 if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
2249 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_RECTANGLE_ARB);
2250 checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)");
2253 if (dst_texture->swapchain && dst_texture->swapchain->front_buffer == dst_texture)
2254 gl_info->gl_ops.gl.p_glFlush();
2256 /* Restore the color key parameters */
2257 wined3d_texture_set_color_key(src_texture, WINED3D_CKEY_SRC_BLT,
2258 (old_color_key_flags & WINED3D_CKEY_SRC_BLT) ? &old_blt_key : NULL);
2260 if (staging_texture)
2261 wined3d_texture_decref(staging_texture);
2263 return dst_location;
2266 static const struct wined3d_blitter_ops ffp_blitter_ops =
2268 ffp_blitter_destroy,
2269 ffp_blitter_clear,
2270 ffp_blitter_blit,
2273 void wined3d_ffp_blitter_create(struct wined3d_blitter **next, const struct wined3d_gl_info *gl_info)
2275 struct wined3d_blitter *blitter;
2277 if (!(blitter = heap_alloc(sizeof(*blitter))))
2278 return;
2280 TRACE("Created blitter %p.\n", blitter);
2282 blitter->ops = &ffp_blitter_ops;
2283 blitter->next = *next;
2284 *next = blitter;
2287 /* Context activation is done by the caller. */
2288 static void cpu_blitter_destroy(struct wined3d_blitter *blitter, struct wined3d_context *context)
2290 struct wined3d_blitter *next;
2292 if ((next = blitter->next))
2293 next->ops->blitter_destroy(next, context);
2295 heap_free(blitter);
2298 static HRESULT surface_cpu_blt_compressed(const BYTE *src_data, BYTE *dst_data,
2299 UINT src_pitch, UINT dst_pitch, UINT update_w, UINT update_h,
2300 const struct wined3d_format *format, DWORD flags, const struct wined3d_blt_fx *fx)
2302 UINT row_block_count;
2303 const BYTE *src_row;
2304 BYTE *dst_row;
2305 UINT x, y;
2307 src_row = src_data;
2308 dst_row = dst_data;
2310 row_block_count = (update_w + format->block_width - 1) / format->block_width;
2312 if (!flags)
2314 for (y = 0; y < update_h; y += format->block_height)
2316 memcpy(dst_row, src_row, row_block_count * format->block_byte_count);
2317 src_row += src_pitch;
2318 dst_row += dst_pitch;
2321 return WINED3D_OK;
2324 if (flags == WINED3D_BLT_FX && fx->fx == WINEDDBLTFX_MIRRORUPDOWN)
2326 src_row += (((update_h / format->block_height) - 1) * src_pitch);
2328 switch (format->id)
2330 case WINED3DFMT_DXT1:
2331 for (y = 0; y < update_h; y += format->block_height)
2333 struct block
2335 WORD color[2];
2336 BYTE control_row[4];
2339 const struct block *s = (const struct block *)src_row;
2340 struct block *d = (struct block *)dst_row;
2342 for (x = 0; x < row_block_count; ++x)
2344 d[x].color[0] = s[x].color[0];
2345 d[x].color[1] = s[x].color[1];
2346 d[x].control_row[0] = s[x].control_row[3];
2347 d[x].control_row[1] = s[x].control_row[2];
2348 d[x].control_row[2] = s[x].control_row[1];
2349 d[x].control_row[3] = s[x].control_row[0];
2351 src_row -= src_pitch;
2352 dst_row += dst_pitch;
2354 return WINED3D_OK;
2356 case WINED3DFMT_DXT2:
2357 case WINED3DFMT_DXT3:
2358 for (y = 0; y < update_h; y += format->block_height)
2360 struct block
2362 WORD alpha_row[4];
2363 WORD color[2];
2364 BYTE control_row[4];
2367 const struct block *s = (const struct block *)src_row;
2368 struct block *d = (struct block *)dst_row;
2370 for (x = 0; x < row_block_count; ++x)
2372 d[x].alpha_row[0] = s[x].alpha_row[3];
2373 d[x].alpha_row[1] = s[x].alpha_row[2];
2374 d[x].alpha_row[2] = s[x].alpha_row[1];
2375 d[x].alpha_row[3] = s[x].alpha_row[0];
2376 d[x].color[0] = s[x].color[0];
2377 d[x].color[1] = s[x].color[1];
2378 d[x].control_row[0] = s[x].control_row[3];
2379 d[x].control_row[1] = s[x].control_row[2];
2380 d[x].control_row[2] = s[x].control_row[1];
2381 d[x].control_row[3] = s[x].control_row[0];
2383 src_row -= src_pitch;
2384 dst_row += dst_pitch;
2386 return WINED3D_OK;
2388 default:
2389 FIXME("Compressed flip not implemented for format %s.\n",
2390 debug_d3dformat(format->id));
2391 return E_NOTIMPL;
2395 FIXME("Unsupported blit on compressed surface (format %s, flags %#x, DDFX %#x).\n",
2396 debug_d3dformat(format->id), flags, flags & WINED3D_BLT_FX ? fx->fx : 0);
2398 return E_NOTIMPL;
2401 static HRESULT surface_cpu_blt(struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx,
2402 const struct wined3d_box *dst_box, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx,
2403 const struct wined3d_box *src_box, DWORD flags, const struct wined3d_blt_fx *fx,
2404 enum wined3d_texture_filter_type filter)
2406 unsigned int bpp, src_height, src_width, dst_height, dst_width, row_byte_count;
2407 struct wined3d_device *device = dst_texture->resource.device;
2408 const struct wined3d_format *src_format, *dst_format;
2409 struct wined3d_texture *converted_texture = NULL;
2410 struct wined3d_bo_address src_data, dst_data;
2411 unsigned int src_fmt_flags, dst_fmt_flags;
2412 struct wined3d_map_desc dst_map, src_map;
2413 struct wined3d_context *context = NULL;
2414 unsigned int x, sx, xinc, y, sy, yinc;
2415 unsigned int texture_level;
2416 HRESULT hr = WINED3D_OK;
2417 BOOL same_sub_resource;
2418 DWORD map_binding;
2419 const BYTE *sbase;
2420 const BYTE *sbuf;
2421 BYTE *dbuf;
2423 TRACE("dst_texture %p, dst_sub_resource_idx %u, dst_box %s, src_texture %p, "
2424 "src_sub_resource_idx %u, src_box %s, flags %#x, fx %p, filter %s.\n",
2425 dst_texture, dst_sub_resource_idx, debug_box(dst_box), src_texture,
2426 src_sub_resource_idx, debug_box(src_box), flags, fx, debug_d3dtexturefiltertype(filter));
2428 if (device->d3d_initialized)
2429 context = context_acquire(device, NULL, 0);
2431 if (src_texture == dst_texture && src_sub_resource_idx == dst_sub_resource_idx)
2433 same_sub_resource = TRUE;
2435 map_binding = dst_texture->resource.map_binding;
2436 texture_level = dst_sub_resource_idx % dst_texture->level_count;
2437 if (!wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, map_binding))
2438 ERR("Failed to load the destination sub-resource into %s.\n", wined3d_debug_location(map_binding));
2439 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~map_binding);
2440 wined3d_texture_get_pitch(dst_texture, texture_level, &dst_map.row_pitch, &dst_map.slice_pitch);
2441 wined3d_texture_get_memory(dst_texture, dst_sub_resource_idx, &dst_data, map_binding);
2442 dst_map.data = context_map_bo_address(context, &dst_data,
2443 dst_texture->sub_resources[dst_sub_resource_idx].size,
2444 GL_PIXEL_UNPACK_BUFFER, WINED3D_MAP_READ | WINED3D_MAP_WRITE);
2446 src_map = dst_map;
2447 src_format = dst_texture->resource.format;
2448 dst_format = src_format;
2449 dst_fmt_flags = dst_texture->resource.format_flags;
2450 src_fmt_flags = dst_fmt_flags;
2452 else
2454 same_sub_resource = FALSE;
2455 dst_format = dst_texture->resource.format;
2456 dst_fmt_flags = dst_texture->resource.format_flags;
2457 if (!(flags & WINED3D_BLT_RAW) && dst_texture->resource.format->id != src_texture->resource.format->id)
2459 if (!(converted_texture = surface_convert_format(src_texture, src_sub_resource_idx, dst_format)))
2461 FIXME("Cannot convert %s to %s.\n", debug_d3dformat(src_texture->resource.format->id),
2462 debug_d3dformat(dst_texture->resource.format->id));
2463 if (context)
2464 context_release(context);
2465 return WINED3DERR_NOTAVAILABLE;
2467 src_texture = converted_texture;
2468 src_sub_resource_idx = 0;
2470 src_format = src_texture->resource.format;
2471 src_fmt_flags = src_texture->resource.format_flags;
2473 map_binding = src_texture->resource.map_binding;
2474 texture_level = src_sub_resource_idx % src_texture->level_count;
2475 if (!wined3d_texture_load_location(src_texture, src_sub_resource_idx, context, map_binding))
2476 ERR("Failed to load the source sub-resource into %s.\n", wined3d_debug_location(map_binding));
2477 wined3d_texture_get_pitch(src_texture, texture_level, &src_map.row_pitch, &src_map.slice_pitch);
2478 wined3d_texture_get_memory(src_texture, src_sub_resource_idx, &src_data, map_binding);
2479 src_map.data = context_map_bo_address(context, &src_data,
2480 src_texture->sub_resources[src_sub_resource_idx].size, GL_PIXEL_UNPACK_BUFFER, WINED3D_MAP_READ);
2482 map_binding = dst_texture->resource.map_binding;
2483 texture_level = dst_sub_resource_idx % dst_texture->level_count;
2484 if (!wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, map_binding))
2485 ERR("Failed to load the destination sub-resource into %s.\n", wined3d_debug_location(map_binding));
2486 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~map_binding);
2487 wined3d_texture_get_pitch(dst_texture, texture_level, &dst_map.row_pitch, &dst_map.slice_pitch);
2488 wined3d_texture_get_memory(dst_texture, dst_sub_resource_idx, &dst_data, map_binding);
2489 dst_map.data = context_map_bo_address(context, &dst_data,
2490 dst_texture->sub_resources[dst_sub_resource_idx].size, GL_PIXEL_UNPACK_BUFFER, WINED3D_MAP_WRITE);
2492 flags &= ~WINED3D_BLT_RAW;
2494 bpp = dst_format->byte_count;
2495 src_height = src_box->bottom - src_box->top;
2496 src_width = src_box->right - src_box->left;
2497 dst_height = dst_box->bottom - dst_box->top;
2498 dst_width = dst_box->right - dst_box->left;
2499 row_byte_count = dst_width * bpp;
2501 sbase = (BYTE *)src_map.data
2502 + ((src_box->top / src_format->block_height) * src_map.row_pitch)
2503 + ((src_box->left / src_format->block_width) * src_format->block_byte_count);
2504 dbuf = (BYTE *)dst_map.data
2505 + ((dst_box->top / dst_format->block_height) * dst_map.row_pitch)
2506 + ((dst_box->left / dst_format->block_width) * dst_format->block_byte_count);
2508 if (src_fmt_flags & dst_fmt_flags & WINED3DFMT_FLAG_BLOCKS)
2510 TRACE("%s -> %s copy.\n", debug_d3dformat(src_format->id), debug_d3dformat(dst_format->id));
2512 if (same_sub_resource)
2514 FIXME("Only plain blits supported on compressed surfaces.\n");
2515 hr = E_NOTIMPL;
2516 goto release;
2519 if (src_height != dst_height || src_width != dst_width)
2521 WARN("Stretching not supported on compressed surfaces.\n");
2522 hr = WINED3DERR_INVALIDCALL;
2523 goto release;
2526 hr = surface_cpu_blt_compressed(sbase, dbuf,
2527 src_map.row_pitch, dst_map.row_pitch, dst_width, dst_height,
2528 src_format, flags, fx);
2529 goto release;
2532 if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT
2533 && (src_width != dst_width || src_height != dst_height))
2535 /* Can happen when d3d9 apps do a StretchRect() call which isn't handled in GL. */
2536 FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(filter));
2539 xinc = (src_width << 16) / dst_width;
2540 yinc = (src_height << 16) / dst_height;
2542 if (!flags)
2544 /* No effects, we can cheat here. */
2545 if (dst_width == src_width)
2547 if (dst_height == src_height)
2549 /* No stretching in either direction. This needs to be as fast
2550 * as possible. */
2551 sbuf = sbase;
2553 /* Check for overlapping surfaces. */
2554 if (!same_sub_resource || dst_box->top < src_box->top
2555 || dst_box->right <= src_box->left || src_box->right <= dst_box->left)
2557 /* No overlap, or dst above src, so copy from top downwards. */
2558 for (y = 0; y < dst_height; ++y)
2560 memcpy(dbuf, sbuf, row_byte_count);
2561 sbuf += src_map.row_pitch;
2562 dbuf += dst_map.row_pitch;
2565 else if (dst_box->top > src_box->top)
2567 /* Copy from bottom upwards. */
2568 sbuf += src_map.row_pitch * dst_height;
2569 dbuf += dst_map.row_pitch * dst_height;
2570 for (y = 0; y < dst_height; ++y)
2572 sbuf -= src_map.row_pitch;
2573 dbuf -= dst_map.row_pitch;
2574 memcpy(dbuf, sbuf, row_byte_count);
2577 else
2579 /* Src and dst overlapping on the same line, use memmove. */
2580 for (y = 0; y < dst_height; ++y)
2582 memmove(dbuf, sbuf, row_byte_count);
2583 sbuf += src_map.row_pitch;
2584 dbuf += dst_map.row_pitch;
2588 else
2590 /* Stretching in y direction only. */
2591 for (y = sy = 0; y < dst_height; ++y, sy += yinc)
2593 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
2594 memcpy(dbuf, sbuf, row_byte_count);
2595 dbuf += dst_map.row_pitch;
2599 else
2601 /* Stretching in X direction. */
2602 unsigned int last_sy = ~0u;
2603 for (y = sy = 0; y < dst_height; ++y, sy += yinc)
2605 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
2607 if ((sy >> 16) == (last_sy >> 16))
2609 /* This source row is the same as last source row -
2610 * Copy the already stretched row. */
2611 memcpy(dbuf, dbuf - dst_map.row_pitch, row_byte_count);
2613 else
2615 #define STRETCH_ROW(type) \
2616 do { \
2617 const type *s = (const type *)sbuf; \
2618 type *d = (type *)dbuf; \
2619 for (x = sx = 0; x < dst_width; ++x, sx += xinc) \
2620 d[x] = s[sx >> 16]; \
2621 } while(0)
2623 switch(bpp)
2625 case 1:
2626 STRETCH_ROW(BYTE);
2627 break;
2628 case 2:
2629 STRETCH_ROW(WORD);
2630 break;
2631 case 4:
2632 STRETCH_ROW(DWORD);
2633 break;
2634 case 3:
2636 const BYTE *s;
2637 BYTE *d = dbuf;
2638 for (x = sx = 0; x < dst_width; x++, sx+= xinc)
2640 DWORD pixel;
2642 s = sbuf + 3 * (sx >> 16);
2643 pixel = s[0] | (s[1] << 8) | (s[2] << 16);
2644 d[0] = (pixel ) & 0xff;
2645 d[1] = (pixel >> 8) & 0xff;
2646 d[2] = (pixel >> 16) & 0xff;
2647 d += 3;
2649 break;
2651 default:
2652 FIXME("Stretched blit not implemented for bpp %u.\n", bpp * 8);
2653 hr = WINED3DERR_NOTAVAILABLE;
2654 goto error;
2656 #undef STRETCH_ROW
2658 dbuf += dst_map.row_pitch;
2659 last_sy = sy;
2663 else
2665 LONG dstyinc = dst_map.row_pitch, dstxinc = bpp;
2666 DWORD keylow = 0xffffffff, keyhigh = 0, keymask = 0xffffffff;
2667 DWORD destkeylow = 0x0, destkeyhigh = 0xffffffff, destkeymask = 0xffffffff;
2668 if (flags & (WINED3D_BLT_SRC_CKEY | WINED3D_BLT_DST_CKEY
2669 | WINED3D_BLT_SRC_CKEY_OVERRIDE | WINED3D_BLT_DST_CKEY_OVERRIDE))
2671 /* The color keying flags are checked for correctness in ddraw. */
2672 if (flags & WINED3D_BLT_SRC_CKEY)
2674 keylow = src_texture->async.src_blt_color_key.color_space_low_value;
2675 keyhigh = src_texture->async.src_blt_color_key.color_space_high_value;
2677 else if (flags & WINED3D_BLT_SRC_CKEY_OVERRIDE)
2679 keylow = fx->src_color_key.color_space_low_value;
2680 keyhigh = fx->src_color_key.color_space_high_value;
2683 if (flags & WINED3D_BLT_DST_CKEY)
2685 /* Destination color keys are taken from the source surface! */
2686 destkeylow = src_texture->async.dst_blt_color_key.color_space_low_value;
2687 destkeyhigh = src_texture->async.dst_blt_color_key.color_space_high_value;
2689 else if (flags & WINED3D_BLT_DST_CKEY_OVERRIDE)
2691 destkeylow = fx->dst_color_key.color_space_low_value;
2692 destkeyhigh = fx->dst_color_key.color_space_high_value;
2695 if (bpp == 1)
2697 keymask = 0xff;
2699 else
2701 DWORD masks[3];
2702 get_color_masks(src_format, masks);
2703 keymask = masks[0] | masks[1] | masks[2];
2705 flags &= ~(WINED3D_BLT_SRC_CKEY | WINED3D_BLT_DST_CKEY
2706 | WINED3D_BLT_SRC_CKEY_OVERRIDE | WINED3D_BLT_DST_CKEY_OVERRIDE);
2709 if (flags & WINED3D_BLT_FX)
2711 BYTE *dTopLeft, *dTopRight, *dBottomLeft, *dBottomRight, *tmp;
2712 LONG tmpxy;
2713 dTopLeft = dbuf;
2714 dTopRight = dbuf + ((dst_width - 1) * bpp);
2715 dBottomLeft = dTopLeft + ((dst_height - 1) * dst_map.row_pitch);
2716 dBottomRight = dBottomLeft + ((dst_width - 1) * bpp);
2718 if (fx->fx & WINEDDBLTFX_ARITHSTRETCHY)
2720 /* I don't think we need to do anything about this flag. */
2721 WARN("Nothing done for WINEDDBLTFX_ARITHSTRETCHY.\n");
2723 if (fx->fx & WINEDDBLTFX_MIRRORLEFTRIGHT)
2725 tmp = dTopRight;
2726 dTopRight = dTopLeft;
2727 dTopLeft = tmp;
2728 tmp = dBottomRight;
2729 dBottomRight = dBottomLeft;
2730 dBottomLeft = tmp;
2731 dstxinc = dstxinc * -1;
2733 if (fx->fx & WINEDDBLTFX_MIRRORUPDOWN)
2735 tmp = dTopLeft;
2736 dTopLeft = dBottomLeft;
2737 dBottomLeft = tmp;
2738 tmp = dTopRight;
2739 dTopRight = dBottomRight;
2740 dBottomRight = tmp;
2741 dstyinc = dstyinc * -1;
2743 if (fx->fx & WINEDDBLTFX_NOTEARING)
2745 /* I don't think we need to do anything about this flag. */
2746 WARN("Nothing done for WINEDDBLTFX_NOTEARING.\n");
2748 if (fx->fx & WINEDDBLTFX_ROTATE180)
2750 tmp = dBottomRight;
2751 dBottomRight = dTopLeft;
2752 dTopLeft = tmp;
2753 tmp = dBottomLeft;
2754 dBottomLeft = dTopRight;
2755 dTopRight = tmp;
2756 dstxinc = dstxinc * -1;
2757 dstyinc = dstyinc * -1;
2759 if (fx->fx & WINEDDBLTFX_ROTATE270)
2761 tmp = dTopLeft;
2762 dTopLeft = dBottomLeft;
2763 dBottomLeft = dBottomRight;
2764 dBottomRight = dTopRight;
2765 dTopRight = tmp;
2766 tmpxy = dstxinc;
2767 dstxinc = dstyinc;
2768 dstyinc = tmpxy;
2769 dstxinc = dstxinc * -1;
2771 if (fx->fx & WINEDDBLTFX_ROTATE90)
2773 tmp = dTopLeft;
2774 dTopLeft = dTopRight;
2775 dTopRight = dBottomRight;
2776 dBottomRight = dBottomLeft;
2777 dBottomLeft = tmp;
2778 tmpxy = dstxinc;
2779 dstxinc = dstyinc;
2780 dstyinc = tmpxy;
2781 dstyinc = dstyinc * -1;
2783 if (fx->fx & WINEDDBLTFX_ZBUFFERBASEDEST)
2785 /* I don't think we need to do anything about this flag. */
2786 WARN("Nothing done for WINEDDBLTFX_ZBUFFERBASEDEST.\n");
2788 dbuf = dTopLeft;
2789 flags &= ~(WINED3D_BLT_FX);
2792 #define COPY_COLORKEY_FX(type) \
2793 do { \
2794 const type *s; \
2795 type *d = (type *)dbuf, *dx, tmp; \
2796 for (y = sy = 0; y < dst_height; ++y, sy += yinc) \
2798 s = (const type *)(sbase + (sy >> 16) * src_map.row_pitch); \
2799 dx = d; \
2800 for (x = sx = 0; x < dst_width; ++x, sx += xinc) \
2802 tmp = s[sx >> 16]; \
2803 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) \
2804 && ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) \
2806 dx[0] = tmp; \
2808 dx = (type *)(((BYTE *)dx) + dstxinc); \
2810 d = (type *)(((BYTE *)d) + dstyinc); \
2812 } while(0)
2814 switch (bpp)
2816 case 1:
2817 COPY_COLORKEY_FX(BYTE);
2818 break;
2819 case 2:
2820 COPY_COLORKEY_FX(WORD);
2821 break;
2822 case 4:
2823 COPY_COLORKEY_FX(DWORD);
2824 break;
2825 case 3:
2827 const BYTE *s;
2828 BYTE *d = dbuf, *dx;
2829 for (y = sy = 0; y < dst_height; ++y, sy += yinc)
2831 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
2832 dx = d;
2833 for (x = sx = 0; x < dst_width; ++x, sx+= xinc)
2835 DWORD pixel, dpixel = 0;
2836 s = sbuf + 3 * (sx>>16);
2837 pixel = s[0] | (s[1] << 8) | (s[2] << 16);
2838 dpixel = dx[0] | (dx[1] << 8 ) | (dx[2] << 16);
2839 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh)
2840 && ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
2842 dx[0] = (pixel ) & 0xff;
2843 dx[1] = (pixel >> 8) & 0xff;
2844 dx[2] = (pixel >> 16) & 0xff;
2846 dx += dstxinc;
2848 d += dstyinc;
2850 break;
2852 default:
2853 FIXME("%s color-keyed blit not implemented for bpp %u.\n",
2854 (flags & WINED3D_BLT_SRC_CKEY) ? "Source" : "Destination", bpp * 8);
2855 hr = WINED3DERR_NOTAVAILABLE;
2856 goto error;
2857 #undef COPY_COLORKEY_FX
2861 error:
2862 if (flags)
2863 FIXME(" Unsupported flags %#x.\n", flags);
2865 release:
2866 context_unmap_bo_address(context, &dst_data, GL_PIXEL_UNPACK_BUFFER);
2867 if (!same_sub_resource)
2868 context_unmap_bo_address(context, &src_data, GL_PIXEL_UNPACK_BUFFER);
2869 if (SUCCEEDED(hr) && dst_texture->swapchain && dst_texture->swapchain->front_buffer == dst_texture)
2871 SetRect(&dst_texture->swapchain->front_buffer_update,
2872 dst_box->left, dst_box->top, dst_box->right, dst_box->bottom);
2873 dst_texture->swapchain->swapchain_ops->swapchain_frontbuffer_updated(dst_texture->swapchain);
2875 if (converted_texture)
2876 wined3d_texture_decref(converted_texture);
2877 if (context)
2878 context_release(context);
2880 return hr;
2883 static void surface_cpu_blt_colour_fill(struct wined3d_rendertarget_view *view,
2884 const struct wined3d_box *box, const struct wined3d_color *colour)
2886 struct wined3d_device *device = view->resource->device;
2887 struct wined3d_context *context = NULL;
2888 struct wined3d_texture *texture;
2889 struct wined3d_bo_address data;
2890 unsigned int x, y, w, h, bpp;
2891 struct wined3d_map_desc map;
2892 DWORD map_binding;
2893 BYTE *row;
2894 DWORD c;
2896 TRACE("view %p, box %s, colour %s.\n", view, debug_box(box), debug_color(colour));
2898 if (view->format_flags & WINED3DFMT_FLAG_BLOCKS)
2900 FIXME("Not implemented for format %s.\n", debug_d3dformat(view->format->id));
2901 return;
2904 if (view->format->id != view->resource->format->id)
2905 FIXME("View format %s doesn't match resource format %s.\n",
2906 debug_d3dformat(view->format->id), debug_d3dformat(view->resource->format->id));
2908 if (view->resource->type == WINED3D_RTYPE_BUFFER)
2910 FIXME("Not implemented for buffers.\n");
2911 return;
2914 if (device->d3d_initialized)
2915 context = context_acquire(device, NULL, 0);
2917 c = wined3d_format_convert_from_float(view->format, colour);
2918 bpp = view->format->byte_count;
2919 w = box->right - box->left;
2920 h = box->bottom - box->top;
2922 texture = texture_from_resource(view->resource);
2923 map_binding = texture->resource.map_binding;
2924 if (!wined3d_texture_load_location(texture, view->sub_resource_idx, context, map_binding))
2925 ERR("Failed to load the sub-resource into %s.\n", wined3d_debug_location(map_binding));
2926 wined3d_texture_invalidate_location(texture, view->sub_resource_idx, ~map_binding);
2927 wined3d_texture_get_pitch(texture, view->sub_resource_idx % texture->level_count,
2928 &map.row_pitch, &map.slice_pitch);
2929 wined3d_texture_get_memory(texture, view->sub_resource_idx, &data, map_binding);
2930 map.data = context_map_bo_address(context, &data,
2931 texture->sub_resources[view->sub_resource_idx].size, GL_PIXEL_UNPACK_BUFFER, WINED3D_MAP_WRITE);
2932 map.data = (BYTE *)map.data
2933 + (box->front * map.slice_pitch)
2934 + ((box->top / view->format->block_height) * map.row_pitch)
2935 + ((box->left / view->format->block_width) * view->format->block_byte_count);
2937 switch (bpp)
2939 case 1:
2940 for (x = 0; x < w; ++x)
2942 ((BYTE *)map.data)[x] = c;
2944 break;
2946 case 2:
2947 for (x = 0; x < w; ++x)
2949 ((WORD *)map.data)[x] = c;
2951 break;
2953 case 3:
2955 row = map.data;
2956 for (x = 0; x < w; ++x, row += 3)
2958 row[0] = (c ) & 0xff;
2959 row[1] = (c >> 8) & 0xff;
2960 row[2] = (c >> 16) & 0xff;
2962 break;
2964 case 4:
2965 for (x = 0; x < w; ++x)
2967 ((DWORD *)map.data)[x] = c;
2969 break;
2971 default:
2972 FIXME("Not implemented for bpp %u.\n", bpp);
2973 wined3d_resource_unmap(view->resource, view->sub_resource_idx);
2974 return;
2977 row = map.data;
2978 for (y = 1; y < h; ++y)
2980 row += map.row_pitch;
2981 memcpy(row, map.data, w * bpp);
2984 context_unmap_bo_address(context, &data, GL_PIXEL_UNPACK_BUFFER);
2985 if (context)
2986 context_release(context);
2989 static void cpu_blitter_clear(struct wined3d_blitter *blitter, struct wined3d_device *device,
2990 unsigned int rt_count, const struct wined3d_fb_state *fb, unsigned int rect_count, const RECT *clear_rects,
2991 const RECT *draw_rect, DWORD flags, const struct wined3d_color *colour, float depth, DWORD stencil)
2993 struct wined3d_color c = {depth, 0.0f, 0.0f, 0.0f};
2994 struct wined3d_rendertarget_view *view;
2995 struct wined3d_box box;
2996 unsigned int i, j;
2998 if (!rect_count)
3000 rect_count = 1;
3001 clear_rects = draw_rect;
3004 for (i = 0; i < rect_count; ++i)
3006 box.left = max(clear_rects[i].left, draw_rect->left);
3007 box.top = max(clear_rects[i].top, draw_rect->top);
3008 box.right = min(clear_rects[i].right, draw_rect->right);
3009 box.bottom = min(clear_rects[i].bottom, draw_rect->bottom);
3010 box.front = 0;
3011 box.back = 1;
3013 if (box.left >= box.right || box.top >= box.bottom)
3014 continue;
3016 if (flags & WINED3DCLEAR_TARGET)
3018 for (j = 0; j < rt_count; ++j)
3020 if ((view = fb->render_targets[j]))
3021 surface_cpu_blt_colour_fill(view, &box, colour);
3025 if ((flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL)) && (view = fb->depth_stencil))
3027 if ((view->format->depth_size && !(flags & WINED3DCLEAR_ZBUFFER))
3028 || (view->format->stencil_size && !(flags & WINED3DCLEAR_STENCIL)))
3029 FIXME("Clearing %#x on %s.\n", flags, debug_d3dformat(view->format->id));
3031 surface_cpu_blt_colour_fill(view, &box, &c);
3036 static DWORD cpu_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_blit_op op,
3037 struct wined3d_context *context, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx,
3038 DWORD src_location, const RECT *src_rect, struct wined3d_texture *dst_texture,
3039 unsigned int dst_sub_resource_idx, DWORD dst_location, const RECT *dst_rect,
3040 const struct wined3d_color_key *color_key, enum wined3d_texture_filter_type filter)
3042 struct wined3d_box dst_box = {dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, 0, 1};
3043 struct wined3d_box src_box = {src_rect->left, src_rect->top, src_rect->right, src_rect->bottom, 0, 1};
3044 struct wined3d_blt_fx fx;
3045 DWORD flags = 0;
3047 memset(&fx, 0, sizeof(fx));
3048 switch (op)
3050 case WINED3D_BLIT_OP_COLOR_BLIT:
3051 case WINED3D_BLIT_OP_DEPTH_BLIT:
3052 case WINED3D_BLIT_OP_RAW_BLIT:
3053 break;
3054 case WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST:
3055 flags |= WINED3D_BLT_ALPHA_TEST;
3056 break;
3057 case WINED3D_BLIT_OP_COLOR_BLIT_CKEY:
3058 flags |= WINED3D_BLT_SRC_CKEY_OVERRIDE | WINED3D_BLT_FX;
3059 fx.src_color_key = *color_key;
3060 break;
3061 default:
3062 FIXME("Unhandled op %#x.\n", op);
3063 break;
3066 if (FAILED(surface_cpu_blt(dst_texture, dst_sub_resource_idx, &dst_box,
3067 src_texture, src_sub_resource_idx, &src_box, flags, &fx, filter)))
3068 ERR("Failed to blit.\n");
3069 wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, dst_location);
3071 return dst_location | (dst_texture->sub_resources[dst_sub_resource_idx].locations
3072 & dst_texture->resource.map_binding);
3075 static const struct wined3d_blitter_ops cpu_blitter_ops =
3077 cpu_blitter_destroy,
3078 cpu_blitter_clear,
3079 cpu_blitter_blit,
3082 struct wined3d_blitter *wined3d_cpu_blitter_create(void)
3084 struct wined3d_blitter *blitter;
3086 if (!(blitter = heap_alloc(sizeof(*blitter))))
3087 return NULL;
3089 TRACE("Created blitter %p.\n", blitter);
3091 blitter->ops = &cpu_blitter_ops;
3092 blitter->next = NULL;
3094 return blitter;
3097 HRESULT texture2d_blt(struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx,
3098 const struct wined3d_box *dst_box, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx,
3099 const struct wined3d_box *src_box, DWORD flags, const struct wined3d_blt_fx *fx,
3100 enum wined3d_texture_filter_type filter)
3102 struct wined3d_texture_sub_resource *src_sub_resource, *dst_sub_resource;
3103 struct wined3d_device *device = dst_texture->resource.device;
3104 struct wined3d_swapchain *src_swapchain, *dst_swapchain;
3105 const struct wined3d_color_key *colour_key = NULL;
3106 DWORD dst_location, valid_locations;
3107 DWORD src_ds_flags, dst_ds_flags;
3108 struct wined3d_context *context;
3109 enum wined3d_blit_op blit_op;
3110 BOOL scale, convert, resolve;
3111 RECT src_rect, dst_rect;
3113 static const DWORD simple_blit = WINED3D_BLT_SRC_CKEY
3114 | WINED3D_BLT_SRC_CKEY_OVERRIDE
3115 | WINED3D_BLT_ALPHA_TEST
3116 | WINED3D_BLT_RAW;
3118 TRACE("dst_texture %p, dst_sub_resource_idx %u, dst_box %s, src_texture %p, "
3119 "src_sub_resource_idx %u, src_box %s, flags %#x, fx %p, filter %s.\n",
3120 dst_texture, dst_sub_resource_idx, debug_box(dst_box), src_texture, src_sub_resource_idx,
3121 debug_box(src_box), flags, fx, debug_d3dtexturefiltertype(filter));
3122 TRACE("Usage is %s.\n", debug_d3dusage(dst_texture->resource.usage));
3124 if (fx)
3126 TRACE("fx %#x.\n", fx->fx);
3127 TRACE("dst_color_key {0x%08x, 0x%08x}.\n",
3128 fx->dst_color_key.color_space_low_value,
3129 fx->dst_color_key.color_space_high_value);
3130 TRACE("src_color_key {0x%08x, 0x%08x}.\n",
3131 fx->src_color_key.color_space_low_value,
3132 fx->src_color_key.color_space_high_value);
3135 dst_sub_resource = &dst_texture->sub_resources[dst_sub_resource_idx];
3136 src_sub_resource = &src_texture->sub_resources[src_sub_resource_idx];
3138 if (src_sub_resource->locations & WINED3D_LOCATION_DISCARDED)
3140 WARN("Source sub-resource is discarded, nothing to do.\n");
3141 return WINED3D_OK;
3144 SetRect(&src_rect, src_box->left, src_box->top, src_box->right, src_box->bottom);
3145 SetRect(&dst_rect, dst_box->left, dst_box->top, dst_box->right, dst_box->bottom);
3147 if (!fx || !(fx->fx))
3148 flags &= ~WINED3D_BLT_FX;
3150 /* WINED3D_BLT_DO_NOT_WAIT appeared in DX7. */
3151 if (flags & WINED3D_BLT_DO_NOT_WAIT)
3153 static unsigned int once;
3155 if (!once++)
3156 FIXME("Can't handle WINED3D_BLT_DO_NOT_WAIT flag.\n");
3159 flags &= ~(WINED3D_BLT_SYNCHRONOUS | WINED3D_BLT_DO_NOT_WAIT | WINED3D_BLT_WAIT);
3161 if (!device->d3d_initialized)
3163 WARN("D3D not initialized, using fallback.\n");
3164 goto cpu;
3167 if (flags & ~simple_blit)
3169 WARN_(d3d_perf)("Using fallback for complex blit (%#x).\n", flags);
3170 goto fallback;
3173 src_swapchain = src_texture->swapchain;
3174 dst_swapchain = dst_texture->swapchain;
3176 /* This isn't strictly needed. FBO blits for example could deal with
3177 * cross-swapchain blits by first downloading the source to a texture
3178 * before switching to the destination context. We just have this here to
3179 * not have to deal with the issue, since cross-swapchain blits should be
3180 * rare. */
3181 if (src_swapchain && dst_swapchain && src_swapchain != dst_swapchain)
3183 FIXME("Using fallback for cross-swapchain blit.\n");
3184 goto fallback;
3187 scale = src_box->right - src_box->left != dst_box->right - dst_box->left
3188 || src_box->bottom - src_box->top != dst_box->bottom - dst_box->top;
3189 convert = src_texture->resource.format->id != dst_texture->resource.format->id;
3190 resolve = src_texture->resource.multisample_type != dst_texture->resource.multisample_type;
3192 dst_ds_flags = dst_texture->resource.format_flags
3193 & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
3194 src_ds_flags = src_texture->resource.format_flags
3195 & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
3197 if (src_ds_flags || dst_ds_flags)
3199 TRACE("Depth/stencil blit.\n");
3201 if (dst_texture->resource.access & WINED3D_RESOURCE_ACCESS_GPU)
3202 dst_location = dst_texture->resource.draw_binding;
3203 else
3204 dst_location = dst_texture->resource.map_binding;
3206 if ((flags & WINED3D_BLT_RAW) || (!scale && !convert && !resolve))
3207 blit_op = WINED3D_BLIT_OP_RAW_BLIT;
3208 else
3209 blit_op = WINED3D_BLIT_OP_DEPTH_BLIT;
3211 context = context_acquire(device, dst_texture, dst_sub_resource_idx);
3212 valid_locations = device->blitter->ops->blitter_blit(device->blitter, blit_op, context,
3213 src_texture, src_sub_resource_idx, src_texture->resource.draw_binding, &src_rect,
3214 dst_texture, dst_sub_resource_idx, dst_location, &dst_rect, NULL, filter);
3215 context_release(context);
3217 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, valid_locations);
3218 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~valid_locations);
3220 return WINED3D_OK;
3223 TRACE("Colour blit.\n");
3225 /* In principle this would apply to depth blits as well, but we don't
3226 * implement those in the CPU blitter at the moment. */
3227 if ((dst_sub_resource->locations & dst_texture->resource.map_binding)
3228 && (src_sub_resource->locations & src_texture->resource.map_binding))
3230 if (scale)
3231 TRACE("Not doing sysmem blit because of scaling.\n");
3232 else if (convert)
3233 TRACE("Not doing sysmem blit because of format conversion.\n");
3234 else
3235 goto cpu;
3238 blit_op = WINED3D_BLIT_OP_COLOR_BLIT;
3239 if (flags & WINED3D_BLT_SRC_CKEY_OVERRIDE)
3241 colour_key = &fx->src_color_key;
3242 blit_op = WINED3D_BLIT_OP_COLOR_BLIT_CKEY;
3244 else if (flags & WINED3D_BLT_SRC_CKEY)
3246 colour_key = &src_texture->async.src_blt_color_key;
3247 blit_op = WINED3D_BLIT_OP_COLOR_BLIT_CKEY;
3249 else if (flags & WINED3D_BLT_ALPHA_TEST)
3251 blit_op = WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST;
3253 else if ((src_sub_resource->locations & surface_simple_locations)
3254 && !(dst_sub_resource->locations & surface_simple_locations))
3256 /* Upload */
3257 if (scale)
3258 TRACE("Not doing upload because of scaling.\n");
3259 else if (convert)
3260 TRACE("Not doing upload because of format conversion.\n");
3261 else if (dst_texture->resource.format->conv_byte_count)
3262 TRACE("Not doing upload because the destination format needs conversion.\n");
3263 else
3265 wined3d_texture_upload_from_texture(dst_texture, dst_sub_resource_idx, dst_box->left,
3266 dst_box->top, dst_box->front, src_texture, src_sub_resource_idx, src_box);
3267 if (!wined3d_resource_is_offscreen(&dst_texture->resource))
3269 context = context_acquire(device, dst_texture, dst_sub_resource_idx);
3270 wined3d_texture_load_location(dst_texture, dst_sub_resource_idx,
3271 context, dst_texture->resource.draw_binding);
3272 context_release(context);
3274 return WINED3D_OK;
3277 else if (!(src_sub_resource->locations & surface_simple_locations)
3278 && (dst_sub_resource->locations & dst_texture->resource.map_binding))
3280 /* Download */
3281 if (scale)
3282 TRACE("Not doing download because of scaling.\n");
3283 else if (convert)
3284 TRACE("Not doing download because of format conversion.\n");
3285 else if (src_texture->resource.format->conv_byte_count)
3286 TRACE("Not doing download because the source format needs conversion.\n");
3287 else if (is_multisample_location(wined3d_texture_gl(src_texture), WINED3D_LOCATION_TEXTURE_RGB))
3288 TRACE("Not doing download because of multisample source.\n");
3289 else if (!texture2d_is_full_rect(src_texture, src_sub_resource_idx % src_texture->level_count, &src_rect))
3290 TRACE("Not doing download because of partial download (src).\n");
3291 else if (!texture2d_is_full_rect(dst_texture, dst_sub_resource_idx % dst_texture->level_count, &dst_rect))
3292 TRACE("Not doing download because of partial download (dst).\n");
3293 else
3295 wined3d_texture_download_from_texture(dst_texture, dst_sub_resource_idx, src_texture,
3296 src_sub_resource_idx);
3297 return WINED3D_OK;
3300 else if (dst_swapchain && dst_swapchain->back_buffers
3301 && dst_texture == dst_swapchain->front_buffer
3302 && src_texture == dst_swapchain->back_buffers[0])
3304 /* Use present for back -> front blits. The idea behind this is that
3305 * present is potentially faster than a blit, in particular when FBO
3306 * blits aren't available. Some ddraw applications like Half-Life and
3307 * Prince of Persia 3D use Blt() from the backbuffer to the
3308 * frontbuffer instead of doing a Flip(). D3d8 and d3d9 applications
3309 * can't blit directly to the frontbuffer. */
3310 enum wined3d_swap_effect swap_effect = dst_swapchain->desc.swap_effect;
3312 TRACE("Using present for backbuffer -> frontbuffer blit.\n");
3314 /* Set the swap effect to COPY, we don't want the backbuffer to become
3315 * undefined. */
3316 dst_swapchain->desc.swap_effect = WINED3D_SWAP_EFFECT_COPY;
3317 wined3d_swapchain_present(dst_swapchain, NULL, NULL,
3318 dst_swapchain->win_handle, dst_swapchain->swap_interval, 0);
3319 dst_swapchain->desc.swap_effect = swap_effect;
3321 return WINED3D_OK;
3324 if ((flags & WINED3D_BLT_RAW) || (blit_op == WINED3D_BLIT_OP_COLOR_BLIT && !scale && !convert && !resolve))
3325 blit_op = WINED3D_BLIT_OP_RAW_BLIT;
3327 if (dst_texture->resource.access & WINED3D_RESOURCE_ACCESS_GPU)
3328 dst_location = dst_texture->resource.draw_binding;
3329 else
3330 dst_location = dst_texture->resource.map_binding;
3332 context = context_acquire(device, dst_texture, dst_sub_resource_idx);
3333 valid_locations = device->blitter->ops->blitter_blit(device->blitter, blit_op, context,
3334 src_texture, src_sub_resource_idx, src_texture->resource.draw_binding, &src_rect,
3335 dst_texture, dst_sub_resource_idx, dst_location, &dst_rect, colour_key, filter);
3336 context_release(context);
3338 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, valid_locations);
3339 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~valid_locations);
3341 return WINED3D_OK;
3343 fallback:
3344 /* Special cases for render targets. */
3345 if (SUCCEEDED(wined3d_texture_blt_special(dst_texture, dst_sub_resource_idx, &dst_rect,
3346 src_texture, src_sub_resource_idx, &src_rect, flags, fx, filter)))
3347 return WINED3D_OK;
3349 cpu:
3350 return surface_cpu_blt(dst_texture, dst_sub_resource_idx, dst_box,
3351 src_texture, src_sub_resource_idx, src_box, flags, fx, filter);