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