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