2 * Copyright 1997-2000 Marcus Meissner
3 * Copyright 1998-2000 Lionel Ulmer
4 * Copyright 2000-2001 TransGaming Technologies Inc.
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2002-2003 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2011, 2013-2014 Stefan Dösinger for CodeWeavers
10 * Copyright 2007-2008 Henri Verbeet
11 * Copyright 2006-2008 Roderick Colenbrander
12 * Copyright 2009-2011 Henri Verbeet for CodeWeavers
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
30 #include "wine/port.h"
31 #include "wined3d_private.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(d3d
);
34 WINE_DECLARE_DEBUG_CHANNEL(d3d_perf
);
36 static const DWORD surface_simple_locations
= WINED3D_LOCATION_SYSMEM
| WINED3D_LOCATION_BUFFER
;
38 /* Works correctly only for <= 4 bpp formats. */
39 static void get_color_masks(const struct wined3d_format
*format
, DWORD
*masks
)
41 masks
[0] = ((1u << format
->red_size
) - 1) << format
->red_offset
;
42 masks
[1] = ((1u << format
->green_size
) - 1) << format
->green_offset
;
43 masks
[2] = ((1u << format
->blue_size
) - 1) << format
->blue_offset
;
46 /* See also float_16_to_32() in wined3d_private.h */
47 static inline unsigned short float_32_to_16(const float *in
)
50 float tmp
= fabsf(*in
);
51 unsigned int mantissa
;
54 /* Deal with special numbers */
60 return (*in
< 0.0f
? 0xfc00 : 0x7c00);
62 if (tmp
< (float)(1u << 10))
68 } while (tmp
< (float)(1u << 10));
70 else if (tmp
>= (float)(1u << 11))
76 } while (tmp
>= (float)(1u << 11));
79 mantissa
= (unsigned int)tmp
;
80 if (tmp
- mantissa
>= 0.5f
)
81 ++mantissa
; /* Round to nearest, away from zero. */
83 exp
+= 10; /* Normalize the mantissa. */
84 exp
+= 15; /* Exponent is encoded with excess 15. */
86 if (exp
> 30) /* too big */
88 ret
= 0x7c00; /* INF */
92 /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers. */
95 mantissa
= mantissa
>> 1;
98 ret
= mantissa
& 0x3ff;
102 ret
= (exp
<< 10) | (mantissa
& 0x3ff);
105 ret
|= ((*in
< 0.0f
? 1 : 0) << 15); /* Add the sign */
109 static void convert_r32_float_r16_float(const BYTE
*src
, BYTE
*dst
,
110 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
112 unsigned short *dst_s
;
116 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
118 for (y
= 0; y
< h
; ++y
)
120 src_f
= (const float *)(src
+ y
* pitch_in
);
121 dst_s
= (unsigned short *) (dst
+ y
* pitch_out
);
122 for (x
= 0; x
< w
; ++x
)
124 dst_s
[x
] = float_32_to_16(src_f
+ x
);
129 static void convert_r5g6b5_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
130 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
132 static const unsigned char convert_5to8
[] =
134 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
135 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
136 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
137 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
139 static const unsigned char convert_6to8
[] =
141 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
142 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
143 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
144 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
145 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
146 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
147 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
148 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
152 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
154 for (y
= 0; y
< h
; ++y
)
156 const WORD
*src_line
= (const WORD
*)(src
+ y
* pitch_in
);
157 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
158 for (x
= 0; x
< w
; ++x
)
160 WORD pixel
= src_line
[x
];
161 dst_line
[x
] = 0xff000000u
162 | convert_5to8
[(pixel
& 0xf800u
) >> 11] << 16
163 | convert_6to8
[(pixel
& 0x07e0u
) >> 5] << 8
164 | convert_5to8
[(pixel
& 0x001fu
)];
169 /* We use this for both B8G8R8A8 -> B8G8R8X8 and B8G8R8X8 -> B8G8R8A8, since
170 * in both cases we're just setting the X / Alpha channel to 0xff. */
171 static void convert_a8r8g8b8_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
172 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
176 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
178 for (y
= 0; y
< h
; ++y
)
180 const DWORD
*src_line
= (const DWORD
*)(src
+ y
* pitch_in
);
181 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
183 for (x
= 0; x
< w
; ++x
)
185 dst_line
[x
] = 0xff000000 | (src_line
[x
] & 0xffffff);
190 static inline BYTE
cliptobyte(int x
)
192 return (BYTE
)((x
< 0) ? 0 : ((x
> 255) ? 255 : x
));
195 static void convert_yuy2_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
196 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
198 int c2
, d
, e
, r2
= 0, g2
= 0, b2
= 0;
201 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
203 for (y
= 0; y
< h
; ++y
)
205 const BYTE
*src_line
= src
+ y
* pitch_in
;
206 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
207 for (x
= 0; x
< w
; ++x
)
209 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
210 * C = Y - 16; D = U - 128; E = V - 128;
211 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
212 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
213 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
214 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
215 * U and V are shared between the pixels. */
216 if (!(x
& 1)) /* For every even pixel, read new U and V. */
218 d
= (int) src_line
[1] - 128;
219 e
= (int) src_line
[3] - 128;
221 g2
= - 100 * d
- 208 * e
+ 128;
224 c2
= 298 * ((int) src_line
[0] - 16);
225 dst_line
[x
] = 0xff000000
226 | cliptobyte((c2
+ r2
) >> 8) << 16 /* red */
227 | cliptobyte((c2
+ g2
) >> 8) << 8 /* green */
228 | cliptobyte((c2
+ b2
) >> 8); /* blue */
229 /* Scale RGB values to 0..255 range,
230 * then clip them if still not in range (may be negative),
231 * then shift them within DWORD if necessary. */
237 static void convert_yuy2_r5g6b5(const BYTE
*src
, BYTE
*dst
,
238 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
241 int c2
, d
, e
, r2
= 0, g2
= 0, b2
= 0;
243 TRACE("Converting %ux%u pixels, pitches %u %u\n", w
, h
, pitch_in
, pitch_out
);
245 for (y
= 0; y
< h
; ++y
)
247 const BYTE
*src_line
= src
+ y
* pitch_in
;
248 WORD
*dst_line
= (WORD
*)(dst
+ y
* pitch_out
);
249 for (x
= 0; x
< w
; ++x
)
251 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
252 * C = Y - 16; D = U - 128; E = V - 128;
253 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
254 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
255 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
256 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
257 * U and V are shared between the pixels. */
258 if (!(x
& 1)) /* For every even pixel, read new U and V. */
260 d
= (int) src_line
[1] - 128;
261 e
= (int) src_line
[3] - 128;
263 g2
= - 100 * d
- 208 * e
+ 128;
266 c2
= 298 * ((int) src_line
[0] - 16);
267 dst_line
[x
] = (cliptobyte((c2
+ r2
) >> 8) >> 3) << 11 /* red */
268 | (cliptobyte((c2
+ g2
) >> 8) >> 2) << 5 /* green */
269 | (cliptobyte((c2
+ b2
) >> 8) >> 3); /* blue */
270 /* Scale RGB values to 0..255 range,
271 * then clip them if still not in range (may be negative),
272 * then shift them within DWORD if necessary. */
278 struct d3dfmt_converter_desc
280 enum wined3d_format_id from
, to
;
281 void (*convert
)(const BYTE
*src
, BYTE
*dst
, DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
);
284 static const struct d3dfmt_converter_desc converters
[] =
286 {WINED3DFMT_R32_FLOAT
, WINED3DFMT_R16_FLOAT
, convert_r32_float_r16_float
},
287 {WINED3DFMT_B5G6R5_UNORM
, WINED3DFMT_B8G8R8X8_UNORM
, convert_r5g6b5_x8r8g8b8
},
288 {WINED3DFMT_B8G8R8A8_UNORM
, WINED3DFMT_B8G8R8X8_UNORM
, convert_a8r8g8b8_x8r8g8b8
},
289 {WINED3DFMT_B8G8R8X8_UNORM
, WINED3DFMT_B8G8R8A8_UNORM
, convert_a8r8g8b8_x8r8g8b8
},
290 {WINED3DFMT_YUY2
, WINED3DFMT_B8G8R8X8_UNORM
, convert_yuy2_x8r8g8b8
},
291 {WINED3DFMT_YUY2
, WINED3DFMT_B5G6R5_UNORM
, convert_yuy2_r5g6b5
},
294 static inline const struct d3dfmt_converter_desc
*find_converter(enum wined3d_format_id from
,
295 enum wined3d_format_id to
)
299 for (i
= 0; i
< ARRAY_SIZE(converters
); ++i
)
301 if (converters
[i
].from
== from
&& converters
[i
].to
== to
)
302 return &converters
[i
];
308 static struct wined3d_texture
*surface_convert_format(struct wined3d_texture
*src_texture
,
309 unsigned int sub_resource_idx
, const struct wined3d_format
*dst_format
)
311 unsigned int texture_level
= sub_resource_idx
% src_texture
->level_count
;
312 const struct wined3d_format
*src_format
= src_texture
->resource
.format
;
313 struct wined3d_device
*device
= src_texture
->resource
.device
;
314 const struct d3dfmt_converter_desc
*conv
= NULL
;
315 unsigned int src_row_pitch
, src_slice_pitch
;
316 struct wined3d_texture
*dst_texture
;
317 struct wined3d_bo_address src_data
;
318 struct wined3d_resource_desc desc
;
319 struct wined3d_context
*context
;
322 if (!(conv
= find_converter(src_format
->id
, dst_format
->id
)) && ((device
->wined3d
->flags
& WINED3D_NO3D
)
323 || !is_identity_fixup(src_format
->color_fixup
) || src_format
->conv_byte_count
324 || !is_identity_fixup(dst_format
->color_fixup
) || dst_format
->conv_byte_count
325 || ((src_format
->flags
[WINED3D_GL_RES_TYPE_TEX_2D
] & WINED3DFMT_FLAG_COMPRESSED
)
326 && !src_format
->decompress
)))
328 FIXME("Cannot find a conversion function from format %s to %s.\n",
329 debug_d3dformat(src_format
->id
), debug_d3dformat(dst_format
->id
));
333 /* FIXME: Multisampled conversion? */
334 desc
.resource_type
= WINED3D_RTYPE_TEXTURE_2D
;
335 desc
.format
= dst_format
->id
;
336 desc
.multisample_type
= WINED3D_MULTISAMPLE_NONE
;
337 desc
.multisample_quality
= 0;
338 desc
.usage
= WINED3DUSAGE_SCRATCH
| WINED3DUSAGE_PRIVATE
;
340 desc
.access
= WINED3D_RESOURCE_ACCESS_CPU
| WINED3D_RESOURCE_ACCESS_MAP_R
| WINED3D_RESOURCE_ACCESS_MAP_W
;
341 desc
.width
= wined3d_texture_get_level_width(src_texture
, texture_level
);
342 desc
.height
= wined3d_texture_get_level_height(src_texture
, texture_level
);
345 if (FAILED(wined3d_texture_create(device
, &desc
, 1, 1, WINED3D_TEXTURE_CREATE_DISCARD
,
346 NULL
, NULL
, &wined3d_null_parent_ops
, &dst_texture
)))
348 ERR("Failed to create a destination texture for conversion.\n");
352 context
= context_acquire(device
, NULL
, 0);
354 map_binding
= src_texture
->resource
.map_binding
;
355 if (!wined3d_texture_load_location(src_texture
, sub_resource_idx
, context
, map_binding
))
356 ERR("Failed to load the source sub-resource into %s.\n", wined3d_debug_location(map_binding
));
357 wined3d_texture_get_pitch(src_texture
, texture_level
, &src_row_pitch
, &src_slice_pitch
);
358 wined3d_texture_get_memory(src_texture
, sub_resource_idx
, &src_data
, map_binding
);
362 unsigned int dst_row_pitch
, dst_slice_pitch
;
363 struct wined3d_bo_address dst_data
;
364 struct wined3d_range range
;
368 map_binding
= dst_texture
->resource
.map_binding
;
369 if (!wined3d_texture_load_location(dst_texture
, 0, context
, map_binding
))
370 ERR("Failed to load the destination sub-resource into %s.\n", wined3d_debug_location(map_binding
));
371 wined3d_texture_get_pitch(dst_texture
, 0, &dst_row_pitch
, &dst_slice_pitch
);
372 wined3d_texture_get_memory(dst_texture
, 0, &dst_data
, map_binding
);
374 src
= wined3d_context_map_bo_address(context
, &src_data
,
375 src_texture
->sub_resources
[sub_resource_idx
].size
, WINED3D_MAP_READ
);
376 dst
= wined3d_context_map_bo_address(context
, &dst_data
,
377 dst_texture
->sub_resources
[0].size
, WINED3D_MAP_WRITE
);
379 conv
->convert(src
, dst
, src_row_pitch
, dst_row_pitch
, desc
.width
, desc
.height
);
382 range
.size
= dst_texture
->sub_resources
[0].size
;
383 wined3d_texture_invalidate_location(dst_texture
, 0, ~map_binding
);
384 wined3d_context_unmap_bo_address(context
, &dst_data
, 1, &range
);
385 wined3d_context_unmap_bo_address(context
, &src_data
, 0, NULL
);
389 struct wined3d_box src_box
= {0, 0, desc
.width
, desc
.height
, 0, 1};
391 TRACE("Using upload conversion.\n");
393 wined3d_texture_prepare_location(dst_texture
, 0, context
, WINED3D_LOCATION_TEXTURE_RGB
);
394 dst_texture
->texture_ops
->texture_upload_data(context
, wined3d_const_bo_address(&src_data
),
395 src_format
, &src_box
, src_row_pitch
, src_slice_pitch
,
396 dst_texture
, 0, WINED3D_LOCATION_TEXTURE_RGB
, 0, 0, 0);
398 wined3d_texture_validate_location(dst_texture
, 0, WINED3D_LOCATION_TEXTURE_RGB
);
399 wined3d_texture_invalidate_location(dst_texture
, 0, ~WINED3D_LOCATION_TEXTURE_RGB
);
402 context_release(context
);
407 void texture2d_read_from_framebuffer(struct wined3d_texture
*texture
, unsigned int sub_resource_idx
,
408 struct wined3d_context
*context
, DWORD src_location
, DWORD dst_location
)
410 struct wined3d_resource
*resource
= &texture
->resource
;
411 struct wined3d_device
*device
= resource
->device
;
412 const struct wined3d_format_gl
*format_gl
;
413 struct wined3d_texture
*restore_texture
;
414 const struct wined3d_gl_info
*gl_info
;
415 struct wined3d_context_gl
*context_gl
;
416 unsigned int row_pitch
, slice_pitch
;
417 unsigned int width
, height
, level
;
418 struct wined3d_bo_address data
;
419 unsigned int restore_idx
;
420 BYTE
*row
, *top
, *bottom
;
421 BOOL src_is_upside_down
;
425 wined3d_texture_get_memory(texture
, sub_resource_idx
, &data
, dst_location
);
427 restore_texture
= context
->current_rt
.texture
;
428 restore_idx
= context
->current_rt
.sub_resource_idx
;
429 if (restore_texture
!= texture
|| restore_idx
!= sub_resource_idx
)
430 context
= context_acquire(device
, texture
, sub_resource_idx
);
432 restore_texture
= NULL
;
433 context_gl
= wined3d_context_gl(context
);
434 gl_info
= context_gl
->gl_info
;
436 if (src_location
!= resource
->draw_binding
)
438 wined3d_context_gl_apply_fbo_state_blit(context_gl
, GL_READ_FRAMEBUFFER
,
439 resource
, sub_resource_idx
, NULL
, 0, src_location
);
440 wined3d_context_gl_check_fbo_status(context_gl
, GL_READ_FRAMEBUFFER
);
441 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
445 wined3d_context_gl_apply_blit_state(context_gl
, device
);
448 /* Select the correct read buffer, and give some debug output.
449 * There is no need to keep track of the current read buffer or reset it,
450 * every part of the code that reads sets the read buffer as desired.
452 if (src_location
!= WINED3D_LOCATION_DRAWABLE
|| wined3d_resource_is_offscreen(resource
))
454 /* Mapping the primary render target which is not on a swapchain.
455 * Read from the back buffer. */
456 TRACE("Mapping offscreen render target.\n");
457 gl_info
->gl_ops
.gl
.p_glReadBuffer(wined3d_context_gl_get_offscreen_gl_buffer(context_gl
));
458 src_is_upside_down
= TRUE
;
462 /* Onscreen surfaces are always part of a swapchain */
463 GLenum buffer
= wined3d_texture_get_gl_buffer(texture
);
464 TRACE("Mapping %#x buffer.\n", buffer
);
465 gl_info
->gl_ops
.gl
.p_glReadBuffer(buffer
);
466 src_is_upside_down
= FALSE
;
468 checkGLcall("glReadBuffer");
470 if (data
.buffer_object
)
472 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, ((struct wined3d_bo_gl
*)data
.buffer_object
)->id
));
473 checkGLcall("glBindBuffer");
476 level
= sub_resource_idx
% texture
->level_count
;
477 wined3d_texture_get_pitch(texture
, level
, &row_pitch
, &slice_pitch
);
478 format_gl
= wined3d_format_gl(resource
->format
);
480 /* Setup pixel store pack state -- to glReadPixels into the correct place */
481 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_PACK_ROW_LENGTH
, row_pitch
/ format_gl
->f
.byte_count
);
482 checkGLcall("glPixelStorei");
484 width
= wined3d_texture_get_level_width(texture
, level
);
485 height
= wined3d_texture_get_level_height(texture
, level
);
486 gl_info
->gl_ops
.gl
.p_glReadPixels(0, 0, width
, height
,
487 format_gl
->format
, format_gl
->type
, data
.addr
);
488 checkGLcall("glReadPixels");
490 /* Reset previous pixel store pack state */
491 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_PACK_ROW_LENGTH
, 0);
492 checkGLcall("glPixelStorei");
494 if (!src_is_upside_down
)
496 /* glReadPixels returns the image upside down, and there is no way to
497 * prevent this. Flip the lines in software. */
499 if (!(row
= heap_alloc(row_pitch
)))
502 if (data
.buffer_object
)
504 mem
= GL_EXTCALL(glMapBuffer(GL_PIXEL_PACK_BUFFER
, GL_READ_WRITE
));
505 checkGLcall("glMapBuffer");
511 bottom
= mem
+ row_pitch
* (height
- 1);
512 for (i
= 0; i
< height
/ 2; i
++)
514 memcpy(row
, top
, row_pitch
);
515 memcpy(top
, bottom
, row_pitch
);
516 memcpy(bottom
, row
, row_pitch
);
522 if (data
.buffer_object
)
523 GL_EXTCALL(glUnmapBuffer(GL_PIXEL_PACK_BUFFER
));
527 if (data
.buffer_object
)
529 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, 0));
530 wined3d_context_gl_reference_bo(context_gl
, (struct wined3d_bo_gl
*)data
.buffer_object
);
531 checkGLcall("glBindBuffer");
535 context_restore(context
, restore_texture
, restore_idx
);
538 /* Read the framebuffer contents into a texture. Note that this function
539 * doesn't do any kind of flipping. Using this on an onscreen surface will
540 * result in a flipped D3D texture.
542 * Context activation is done by the caller. This function may temporarily
543 * switch to a different context and restore the original one before return. */
544 void texture2d_load_fb_texture(struct wined3d_texture_gl
*texture_gl
,
545 unsigned int sub_resource_idx
, BOOL srgb
, struct wined3d_context
*context
)
547 struct wined3d_texture
*restore_texture
;
548 const struct wined3d_gl_info
*gl_info
;
549 struct wined3d_context_gl
*context_gl
;
550 struct wined3d_resource
*resource
;
551 unsigned int restore_idx
, level
;
552 struct wined3d_device
*device
;
555 resource
= &texture_gl
->t
.resource
;
556 device
= resource
->device
;
557 restore_texture
= context
->current_rt
.texture
;
558 restore_idx
= context
->current_rt
.sub_resource_idx
;
559 if (restore_texture
!= &texture_gl
->t
|| restore_idx
!= sub_resource_idx
)
560 context
= context_acquire(device
, &texture_gl
->t
, sub_resource_idx
);
562 restore_texture
= NULL
;
563 context_gl
= wined3d_context_gl(context
);
565 gl_info
= context_gl
->gl_info
;
566 device_invalidate_state(device
, STATE_FRAMEBUFFER
);
568 wined3d_texture_gl_prepare_texture(texture_gl
, context_gl
, srgb
);
569 wined3d_texture_gl_bind_and_dirtify(texture_gl
, context_gl
, srgb
);
571 TRACE("Reading back offscreen render target %p, %u.\n", texture_gl
, sub_resource_idx
);
573 if (wined3d_resource_is_offscreen(resource
))
574 gl_info
->gl_ops
.gl
.p_glReadBuffer(wined3d_context_gl_get_offscreen_gl_buffer(context_gl
));
576 gl_info
->gl_ops
.gl
.p_glReadBuffer(wined3d_texture_get_gl_buffer(&texture_gl
->t
));
577 checkGLcall("glReadBuffer");
579 level
= sub_resource_idx
% texture_gl
->t
.level_count
;
580 target
= wined3d_texture_gl_get_sub_resource_target(texture_gl
, sub_resource_idx
);
581 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(target
, level
, 0, 0, 0, 0,
582 wined3d_texture_get_level_width(&texture_gl
->t
, level
),
583 wined3d_texture_get_level_height(&texture_gl
->t
, level
));
584 checkGLcall("glCopyTexSubImage2D");
587 context_restore(context
, restore_texture
, restore_idx
);
590 /* Context activation is done by the caller. */
591 static void cpu_blitter_destroy(struct wined3d_blitter
*blitter
, struct wined3d_context
*context
)
593 struct wined3d_blitter
*next
;
595 if ((next
= blitter
->next
))
596 next
->ops
->blitter_destroy(next
, context
);
601 static HRESULT
surface_cpu_blt_compressed(const BYTE
*src_data
, BYTE
*dst_data
,
602 UINT src_pitch
, UINT dst_pitch
, UINT update_w
, UINT update_h
,
603 const struct wined3d_format
*format
, DWORD flags
, const struct wined3d_blt_fx
*fx
)
605 UINT row_block_count
;
613 row_block_count
= (update_w
+ format
->block_width
- 1) / format
->block_width
;
617 for (y
= 0; y
< update_h
; y
+= format
->block_height
)
619 memcpy(dst_row
, src_row
, row_block_count
* format
->block_byte_count
);
620 src_row
+= src_pitch
;
621 dst_row
+= dst_pitch
;
627 if (flags
== WINED3D_BLT_FX
&& fx
->fx
== WINEDDBLTFX_MIRRORUPDOWN
)
629 src_row
+= (((update_h
/ format
->block_height
) - 1) * src_pitch
);
633 case WINED3DFMT_DXT1
:
634 for (y
= 0; y
< update_h
; y
+= format
->block_height
)
642 const struct block
*s
= (const struct block
*)src_row
;
643 struct block
*d
= (struct block
*)dst_row
;
645 for (x
= 0; x
< row_block_count
; ++x
)
647 d
[x
].color
[0] = s
[x
].color
[0];
648 d
[x
].color
[1] = s
[x
].color
[1];
649 d
[x
].control_row
[0] = s
[x
].control_row
[3];
650 d
[x
].control_row
[1] = s
[x
].control_row
[2];
651 d
[x
].control_row
[2] = s
[x
].control_row
[1];
652 d
[x
].control_row
[3] = s
[x
].control_row
[0];
654 src_row
-= src_pitch
;
655 dst_row
+= dst_pitch
;
659 case WINED3DFMT_DXT2
:
660 case WINED3DFMT_DXT3
:
661 for (y
= 0; y
< update_h
; y
+= format
->block_height
)
670 const struct block
*s
= (const struct block
*)src_row
;
671 struct block
*d
= (struct block
*)dst_row
;
673 for (x
= 0; x
< row_block_count
; ++x
)
675 d
[x
].alpha_row
[0] = s
[x
].alpha_row
[3];
676 d
[x
].alpha_row
[1] = s
[x
].alpha_row
[2];
677 d
[x
].alpha_row
[2] = s
[x
].alpha_row
[1];
678 d
[x
].alpha_row
[3] = s
[x
].alpha_row
[0];
679 d
[x
].color
[0] = s
[x
].color
[0];
680 d
[x
].color
[1] = s
[x
].color
[1];
681 d
[x
].control_row
[0] = s
[x
].control_row
[3];
682 d
[x
].control_row
[1] = s
[x
].control_row
[2];
683 d
[x
].control_row
[2] = s
[x
].control_row
[1];
684 d
[x
].control_row
[3] = s
[x
].control_row
[0];
686 src_row
-= src_pitch
;
687 dst_row
+= dst_pitch
;
692 FIXME("Compressed flip not implemented for format %s.\n",
693 debug_d3dformat(format
->id
));
698 FIXME("Unsupported blit on compressed surface (format %s, flags %#x, DDFX %#x).\n",
699 debug_d3dformat(format
->id
), flags
, flags
& WINED3D_BLT_FX
? fx
->fx
: 0);
704 static HRESULT
surface_cpu_blt(struct wined3d_texture
*dst_texture
, unsigned int dst_sub_resource_idx
,
705 const struct wined3d_box
*dst_box
, struct wined3d_texture
*src_texture
, unsigned int src_sub_resource_idx
,
706 const struct wined3d_box
*src_box
, DWORD flags
, const struct wined3d_blt_fx
*fx
,
707 enum wined3d_texture_filter_type filter
)
709 unsigned int bpp
, src_height
, src_width
, dst_height
, dst_width
, row_byte_count
;
710 struct wined3d_device
*device
= dst_texture
->resource
.device
;
711 const struct wined3d_format
*src_format
, *dst_format
;
712 struct wined3d_texture
*converted_texture
= NULL
;
713 struct wined3d_bo_address src_data
, dst_data
;
714 unsigned int src_fmt_flags
, dst_fmt_flags
;
715 struct wined3d_map_desc dst_map
, src_map
;
716 unsigned int x
, sx
, xinc
, y
, sy
, yinc
;
717 struct wined3d_context
*context
;
718 struct wined3d_range dst_range
;
719 unsigned int texture_level
;
720 HRESULT hr
= WINED3D_OK
;
721 BOOL same_sub_resource
;
728 TRACE("dst_texture %p, dst_sub_resource_idx %u, dst_box %s, src_texture %p, "
729 "src_sub_resource_idx %u, src_box %s, flags %#x, fx %p, filter %s.\n",
730 dst_texture
, dst_sub_resource_idx
, debug_box(dst_box
), src_texture
,
731 src_sub_resource_idx
, debug_box(src_box
), flags
, fx
, debug_d3dtexturefiltertype(filter
));
733 context
= context_acquire(device
, NULL
, 0);
735 src_format
= src_texture
->resource
.format
;
736 dst_format
= dst_texture
->resource
.format
;
738 if (wined3d_format_is_typeless(src_format
) && src_format
->id
== dst_format
->typeless_id
)
739 src_format
= dst_format
;
740 if (wined3d_format_is_typeless(dst_format
) && dst_format
->id
== src_format
->typeless_id
)
741 dst_format
= src_format
;
743 src_height
= src_box
->bottom
- src_box
->top
;
744 src_width
= src_box
->right
- src_box
->left
;
745 dst_height
= dst_box
->bottom
- dst_box
->top
;
746 dst_width
= dst_box
->right
- dst_box
->left
;
748 dst_range
.offset
= 0;
749 dst_range
.size
= dst_texture
->sub_resources
[dst_sub_resource_idx
].size
;
750 if (src_texture
== dst_texture
&& src_sub_resource_idx
== dst_sub_resource_idx
)
752 same_sub_resource
= TRUE
;
754 map_binding
= dst_texture
->resource
.map_binding
;
755 texture_level
= dst_sub_resource_idx
% dst_texture
->level_count
;
756 if (!wined3d_texture_load_location(dst_texture
, dst_sub_resource_idx
, context
, map_binding
))
757 ERR("Failed to load the destination sub-resource into %s.\n", wined3d_debug_location(map_binding
));
758 wined3d_texture_invalidate_location(dst_texture
, dst_sub_resource_idx
, ~map_binding
);
759 wined3d_texture_get_pitch(dst_texture
, texture_level
, &dst_map
.row_pitch
, &dst_map
.slice_pitch
);
760 wined3d_texture_get_memory(dst_texture
, dst_sub_resource_idx
, &dst_data
, map_binding
);
761 dst_map
.data
= wined3d_context_map_bo_address(context
, &dst_data
,
762 dst_texture
->sub_resources
[dst_sub_resource_idx
].size
, WINED3D_MAP_READ
| WINED3D_MAP_WRITE
);
768 same_sub_resource
= FALSE
;
769 upload
= dst_format
->flags
[dst_texture
->resource
.gl_type
] & WINED3DFMT_FLAG_BLOCKS
770 && (dst_width
!= src_width
|| dst_height
!= src_height
);
774 dst_format
= src_format
->flags
[dst_texture
->resource
.gl_type
] & WINED3DFMT_FLAG_BLOCKS
775 ? wined3d_get_format(device
->adapter
, WINED3DFMT_B8G8R8A8_UNORM
, 0) : src_format
;
778 if (!(flags
& WINED3D_BLT_RAW
) && dst_format
->id
!= src_format
->id
)
780 if (!(converted_texture
= surface_convert_format(src_texture
, src_sub_resource_idx
, dst_format
)))
782 FIXME("Cannot convert %s to %s.\n", debug_d3dformat(src_format
->id
),
783 debug_d3dformat(dst_format
->id
));
784 context_release(context
);
785 return WINED3DERR_NOTAVAILABLE
;
787 src_texture
= converted_texture
;
788 src_sub_resource_idx
= 0;
789 src_format
= src_texture
->resource
.format
;
792 map_binding
= src_texture
->resource
.map_binding
;
793 texture_level
= src_sub_resource_idx
% src_texture
->level_count
;
794 if (!wined3d_texture_load_location(src_texture
, src_sub_resource_idx
, context
, map_binding
))
795 ERR("Failed to load the source sub-resource into %s.\n", wined3d_debug_location(map_binding
));
796 wined3d_texture_get_pitch(src_texture
, texture_level
, &src_map
.row_pitch
, &src_map
.slice_pitch
);
797 wined3d_texture_get_memory(src_texture
, src_sub_resource_idx
, &src_data
, map_binding
);
798 src_map
.data
= wined3d_context_map_bo_address(context
, &src_data
,
799 src_texture
->sub_resources
[src_sub_resource_idx
].size
, WINED3D_MAP_READ
);
803 wined3d_format_calculate_pitch(dst_format
, 1, dst_box
->right
, dst_box
->bottom
,
804 &dst_map
.row_pitch
, &dst_map
.slice_pitch
);
805 dst_map
.data
= heap_alloc(dst_map
.slice_pitch
);
809 map_binding
= dst_texture
->resource
.map_binding
;
810 texture_level
= dst_sub_resource_idx
% dst_texture
->level_count
;
811 if (!wined3d_texture_load_location(dst_texture
, dst_sub_resource_idx
, context
, map_binding
))
812 ERR("Failed to load the destination sub-resource into %s.\n", wined3d_debug_location(map_binding
));
814 wined3d_texture_invalidate_location(dst_texture
, dst_sub_resource_idx
, ~map_binding
);
815 wined3d_texture_get_pitch(dst_texture
, texture_level
, &dst_map
.row_pitch
, &dst_map
.slice_pitch
);
816 wined3d_texture_get_memory(dst_texture
, dst_sub_resource_idx
, &dst_data
, map_binding
);
817 dst_map
.data
= wined3d_context_map_bo_address(context
, &dst_data
,
818 dst_texture
->sub_resources
[dst_sub_resource_idx
].size
, WINED3D_MAP_WRITE
);
821 src_fmt_flags
= src_format
->flags
[src_texture
->resource
.gl_type
];
822 dst_fmt_flags
= dst_format
->flags
[dst_texture
->resource
.gl_type
];
823 flags
&= ~WINED3D_BLT_RAW
;
825 bpp
= dst_format
->byte_count
;
826 row_byte_count
= dst_width
* bpp
;
828 sbase
= (BYTE
*)src_map
.data
829 + ((src_box
->top
/ src_format
->block_height
) * src_map
.row_pitch
)
830 + ((src_box
->left
/ src_format
->block_width
) * src_format
->block_byte_count
);
831 dbuf
= (BYTE
*)dst_map
.data
832 + ((dst_box
->top
/ dst_format
->block_height
) * dst_map
.row_pitch
)
833 + ((dst_box
->left
/ dst_format
->block_width
) * dst_format
->block_byte_count
);
835 if (src_fmt_flags
& dst_fmt_flags
& WINED3DFMT_FLAG_BLOCKS
)
837 TRACE("%s -> %s copy.\n", debug_d3dformat(src_format
->id
), debug_d3dformat(dst_format
->id
));
839 if (same_sub_resource
)
841 FIXME("Only plain blits supported on compressed surfaces.\n");
846 hr
= surface_cpu_blt_compressed(sbase
, dbuf
,
847 src_map
.row_pitch
, dst_map
.row_pitch
, dst_width
, dst_height
,
848 src_format
, flags
, fx
);
852 if (filter
!= WINED3D_TEXF_NONE
&& filter
!= WINED3D_TEXF_POINT
853 && (src_width
!= dst_width
|| src_height
!= dst_height
))
855 /* Can happen when d3d9 apps do a StretchRect() call which isn't handled in GL. */
856 FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(filter
));
859 xinc
= (src_width
<< 16) / dst_width
;
860 yinc
= (src_height
<< 16) / dst_height
;
864 /* No effects, we can cheat here. */
865 if (dst_width
== src_width
)
867 if (dst_height
== src_height
)
869 /* No stretching in either direction. This needs to be as fast
873 /* Check for overlapping surfaces. */
874 if (!same_sub_resource
|| dst_box
->top
< src_box
->top
875 || dst_box
->right
<= src_box
->left
|| src_box
->right
<= dst_box
->left
)
877 /* No overlap, or dst above src, so copy from top downwards. */
878 for (y
= 0; y
< dst_height
; ++y
)
880 memcpy(dbuf
, sbuf
, row_byte_count
);
881 sbuf
+= src_map
.row_pitch
;
882 dbuf
+= dst_map
.row_pitch
;
885 else if (dst_box
->top
> src_box
->top
)
887 /* Copy from bottom upwards. */
888 sbuf
+= src_map
.row_pitch
* dst_height
;
889 dbuf
+= dst_map
.row_pitch
* dst_height
;
890 for (y
= 0; y
< dst_height
; ++y
)
892 sbuf
-= src_map
.row_pitch
;
893 dbuf
-= dst_map
.row_pitch
;
894 memcpy(dbuf
, sbuf
, row_byte_count
);
899 /* Src and dst overlapping on the same line, use memmove. */
900 for (y
= 0; y
< dst_height
; ++y
)
902 memmove(dbuf
, sbuf
, row_byte_count
);
903 sbuf
+= src_map
.row_pitch
;
904 dbuf
+= dst_map
.row_pitch
;
910 /* Stretching in y direction only. */
911 for (y
= sy
= 0; y
< dst_height
; ++y
, sy
+= yinc
)
913 sbuf
= sbase
+ (sy
>> 16) * src_map
.row_pitch
;
914 memcpy(dbuf
, sbuf
, row_byte_count
);
915 dbuf
+= dst_map
.row_pitch
;
921 /* Stretching in X direction. */
922 unsigned int last_sy
= ~0u;
923 for (y
= sy
= 0; y
< dst_height
; ++y
, sy
+= yinc
)
925 sbuf
= sbase
+ (sy
>> 16) * src_map
.row_pitch
;
927 if ((sy
>> 16) == (last_sy
>> 16))
929 /* This source row is the same as last source row -
930 * Copy the already stretched row. */
931 memcpy(dbuf
, dbuf
- dst_map
.row_pitch
, row_byte_count
);
935 #define STRETCH_ROW(type) \
937 const type *s = (const type *)sbuf; \
938 type *d = (type *)dbuf; \
939 for (x = sx = 0; x < dst_width; ++x, sx += xinc) \
940 d[x] = s[sx >> 16]; \
958 for (x
= sx
= 0; x
< dst_width
; x
++, sx
+= xinc
)
962 s
= sbuf
+ 3 * (sx
>> 16);
963 pixel
= s
[0] | (s
[1] << 8) | (s
[2] << 16);
964 d
[0] = (pixel
) & 0xff;
965 d
[1] = (pixel
>> 8) & 0xff;
966 d
[2] = (pixel
>> 16) & 0xff;
972 FIXME("Stretched blit not implemented for bpp %u.\n", bpp
* 8);
973 hr
= WINED3DERR_NOTAVAILABLE
;
978 dbuf
+= dst_map
.row_pitch
;
985 LONG dstyinc
= dst_map
.row_pitch
, dstxinc
= bpp
;
986 DWORD keylow
= 0xffffffff, keyhigh
= 0, keymask
= 0xffffffff;
987 DWORD destkeylow
= 0x0, destkeyhigh
= 0xffffffff, destkeymask
= 0xffffffff;
988 if (flags
& (WINED3D_BLT_SRC_CKEY
| WINED3D_BLT_DST_CKEY
989 | WINED3D_BLT_SRC_CKEY_OVERRIDE
| WINED3D_BLT_DST_CKEY_OVERRIDE
))
991 /* The color keying flags are checked for correctness in ddraw. */
992 if (flags
& WINED3D_BLT_SRC_CKEY
)
994 keylow
= src_texture
->async
.src_blt_color_key
.color_space_low_value
;
995 keyhigh
= src_texture
->async
.src_blt_color_key
.color_space_high_value
;
997 else if (flags
& WINED3D_BLT_SRC_CKEY_OVERRIDE
)
999 keylow
= fx
->src_color_key
.color_space_low_value
;
1000 keyhigh
= fx
->src_color_key
.color_space_high_value
;
1003 if (flags
& WINED3D_BLT_DST_CKEY
)
1005 /* Destination color keys are taken from the source surface! */
1006 destkeylow
= src_texture
->async
.dst_blt_color_key
.color_space_low_value
;
1007 destkeyhigh
= src_texture
->async
.dst_blt_color_key
.color_space_high_value
;
1009 else if (flags
& WINED3D_BLT_DST_CKEY_OVERRIDE
)
1011 destkeylow
= fx
->dst_color_key
.color_space_low_value
;
1012 destkeyhigh
= fx
->dst_color_key
.color_space_high_value
;
1022 get_color_masks(src_format
, masks
);
1023 keymask
= masks
[0] | masks
[1] | masks
[2];
1025 flags
&= ~(WINED3D_BLT_SRC_CKEY
| WINED3D_BLT_DST_CKEY
1026 | WINED3D_BLT_SRC_CKEY_OVERRIDE
| WINED3D_BLT_DST_CKEY_OVERRIDE
);
1029 if (flags
& WINED3D_BLT_FX
)
1031 BYTE
*dTopLeft
, *dTopRight
, *dBottomLeft
, *dBottomRight
, *tmp
;
1034 dTopRight
= dbuf
+ ((dst_width
- 1) * bpp
);
1035 dBottomLeft
= dTopLeft
+ ((dst_height
- 1) * dst_map
.row_pitch
);
1036 dBottomRight
= dBottomLeft
+ ((dst_width
- 1) * bpp
);
1038 if (fx
->fx
& WINEDDBLTFX_ARITHSTRETCHY
)
1040 /* I don't think we need to do anything about this flag. */
1041 WARN("Nothing done for WINEDDBLTFX_ARITHSTRETCHY.\n");
1043 if (fx
->fx
& WINEDDBLTFX_MIRRORLEFTRIGHT
)
1046 dTopRight
= dTopLeft
;
1049 dBottomRight
= dBottomLeft
;
1051 dstxinc
= dstxinc
* -1;
1053 if (fx
->fx
& WINEDDBLTFX_MIRRORUPDOWN
)
1056 dTopLeft
= dBottomLeft
;
1059 dTopRight
= dBottomRight
;
1061 dstyinc
= dstyinc
* -1;
1063 if (fx
->fx
& WINEDDBLTFX_NOTEARING
)
1065 /* I don't think we need to do anything about this flag. */
1066 WARN("Nothing done for WINEDDBLTFX_NOTEARING.\n");
1068 if (fx
->fx
& WINEDDBLTFX_ROTATE180
)
1071 dBottomRight
= dTopLeft
;
1074 dBottomLeft
= dTopRight
;
1076 dstxinc
= dstxinc
* -1;
1077 dstyinc
= dstyinc
* -1;
1079 if (fx
->fx
& WINEDDBLTFX_ROTATE270
)
1082 dTopLeft
= dBottomLeft
;
1083 dBottomLeft
= dBottomRight
;
1084 dBottomRight
= dTopRight
;
1089 dstxinc
= dstxinc
* -1;
1091 if (fx
->fx
& WINEDDBLTFX_ROTATE90
)
1094 dTopLeft
= dTopRight
;
1095 dTopRight
= dBottomRight
;
1096 dBottomRight
= dBottomLeft
;
1101 dstyinc
= dstyinc
* -1;
1103 if (fx
->fx
& WINEDDBLTFX_ZBUFFERBASEDEST
)
1105 /* I don't think we need to do anything about this flag. */
1106 WARN("Nothing done for WINEDDBLTFX_ZBUFFERBASEDEST.\n");
1109 flags
&= ~(WINED3D_BLT_FX
);
1112 #define COPY_COLORKEY_FX(type) \
1115 type *d = (type *)dbuf, *dx, tmp; \
1116 for (y = sy = 0; y < dst_height; ++y, sy += yinc) \
1118 s = (const type *)(sbase + (sy >> 16) * src_map.row_pitch); \
1120 for (x = sx = 0; x < dst_width; ++x, sx += xinc) \
1122 tmp = s[sx >> 16]; \
1123 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) \
1124 && ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) \
1128 dx = (type *)(((BYTE *)dx) + dstxinc); \
1130 d = (type *)(((BYTE *)d) + dstyinc); \
1137 COPY_COLORKEY_FX(BYTE
);
1140 COPY_COLORKEY_FX(WORD
);
1143 COPY_COLORKEY_FX(DWORD
);
1148 BYTE
*d
= dbuf
, *dx
;
1149 for (y
= sy
= 0; y
< dst_height
; ++y
, sy
+= yinc
)
1151 sbuf
= sbase
+ (sy
>> 16) * src_map
.row_pitch
;
1153 for (x
= sx
= 0; x
< dst_width
; ++x
, sx
+= xinc
)
1155 DWORD pixel
, dpixel
= 0;
1156 s
= sbuf
+ 3 * (sx
>>16);
1157 pixel
= s
[0] | (s
[1] << 8) | (s
[2] << 16);
1158 dpixel
= dx
[0] | (dx
[1] << 8 ) | (dx
[2] << 16);
1159 if (((pixel
& keymask
) < keylow
|| (pixel
& keymask
) > keyhigh
)
1160 && ((dpixel
& keymask
) >= destkeylow
|| (dpixel
& keymask
) <= keyhigh
))
1162 dx
[0] = (pixel
) & 0xff;
1163 dx
[1] = (pixel
>> 8) & 0xff;
1164 dx
[2] = (pixel
>> 16) & 0xff;
1173 FIXME("%s color-keyed blit not implemented for bpp %u.\n",
1174 (flags
& WINED3D_BLT_SRC_CKEY
) ? "Source" : "Destination", bpp
* 8);
1175 hr
= WINED3DERR_NOTAVAILABLE
;
1177 #undef COPY_COLORKEY_FX
1183 FIXME(" Unsupported flags %#x.\n", flags
);
1186 if (upload
&& hr
== WINED3D_OK
)
1188 struct wined3d_bo_address data
;
1190 data
.buffer_object
= 0;
1191 data
.addr
= dst_map
.data
;
1193 texture_level
= dst_sub_resource_idx
% dst_texture
->level_count
;
1195 wined3d_texture_prepare_location(dst_texture
, texture_level
, context
, WINED3D_LOCATION_TEXTURE_RGB
);
1196 dst_texture
->texture_ops
->texture_upload_data(context
, wined3d_const_bo_address(&data
), dst_format
,
1197 dst_box
, dst_map
.row_pitch
, dst_map
.slice_pitch
, dst_texture
, texture_level
,
1198 WINED3D_LOCATION_TEXTURE_RGB
, dst_box
->left
, dst_box
->top
, 0);
1200 wined3d_texture_validate_location(dst_texture
, texture_level
, WINED3D_LOCATION_TEXTURE_RGB
);
1201 wined3d_texture_invalidate_location(dst_texture
, texture_level
, ~WINED3D_LOCATION_TEXTURE_RGB
);
1206 heap_free(dst_map
.data
);
1210 wined3d_context_unmap_bo_address(context
, &dst_data
, 1, &dst_range
);
1213 if (!same_sub_resource
)
1214 wined3d_context_unmap_bo_address(context
, &src_data
, 0, NULL
);
1215 if (SUCCEEDED(hr
) && dst_texture
->swapchain
&& dst_texture
->swapchain
->front_buffer
== dst_texture
)
1217 SetRect(&dst_texture
->swapchain
->front_buffer_update
,
1218 dst_box
->left
, dst_box
->top
, dst_box
->right
, dst_box
->bottom
);
1219 dst_texture
->swapchain
->swapchain_ops
->swapchain_frontbuffer_updated(dst_texture
->swapchain
);
1221 if (converted_texture
)
1222 wined3d_texture_decref(converted_texture
);
1223 context_release(context
);
1228 static void surface_cpu_blt_colour_fill(struct wined3d_rendertarget_view
*view
,
1229 const struct wined3d_box
*box
, const struct wined3d_color
*colour
)
1231 struct wined3d_device
*device
= view
->resource
->device
;
1232 unsigned int x
, y
, z
, w
, h
, d
, bpp
, level
;
1233 struct wined3d_context
*context
;
1234 struct wined3d_texture
*texture
;
1235 struct wined3d_bo_address data
;
1236 struct wined3d_map_desc map
;
1237 struct wined3d_range range
;
1242 TRACE("view %p, box %s, colour %s.\n", view
, debug_box(box
), debug_color(colour
));
1244 if (view
->format_flags
& WINED3DFMT_FLAG_BLOCKS
)
1246 FIXME("Not implemented for format %s.\n", debug_d3dformat(view
->format
->id
));
1250 if (view
->format
->id
!= view
->resource
->format
->id
)
1251 FIXME("View format %s doesn't match resource format %s.\n",
1252 debug_d3dformat(view
->format
->id
), debug_d3dformat(view
->resource
->format
->id
));
1254 if (view
->resource
->type
== WINED3D_RTYPE_BUFFER
)
1256 FIXME("Not implemented for buffers.\n");
1260 context
= context_acquire(device
, NULL
, 0);
1262 texture
= texture_from_resource(view
->resource
);
1263 level
= view
->sub_resource_idx
% texture
->level_count
;
1265 c
= wined3d_format_convert_from_float(view
->format
, colour
);
1266 bpp
= view
->format
->byte_count
;
1267 w
= min(box
->right
, view
->width
) - min(box
->left
, view
->width
);
1268 h
= min(box
->bottom
, view
->height
) - min(box
->top
, view
->height
);
1269 if (view
->resource
->type
!= WINED3D_RTYPE_TEXTURE_3D
)
1275 d
= wined3d_texture_get_level_depth(texture
, level
);
1276 d
= min(box
->back
, d
) - min(box
->front
, d
);
1279 map_binding
= texture
->resource
.map_binding
;
1280 if (!wined3d_texture_load_location(texture
, view
->sub_resource_idx
, context
, map_binding
))
1281 ERR("Failed to load the sub-resource into %s.\n", wined3d_debug_location(map_binding
));
1282 wined3d_texture_invalidate_location(texture
, view
->sub_resource_idx
, ~map_binding
);
1283 wined3d_texture_get_pitch(texture
, level
, &map
.row_pitch
, &map
.slice_pitch
);
1284 wined3d_texture_get_memory(texture
, view
->sub_resource_idx
, &data
, map_binding
);
1285 map
.data
= wined3d_context_map_bo_address(context
, &data
,
1286 texture
->sub_resources
[view
->sub_resource_idx
].size
, WINED3D_MAP_WRITE
);
1287 map
.data
= (BYTE
*)map
.data
1288 + (box
->front
* map
.slice_pitch
)
1289 + ((box
->top
/ view
->format
->block_height
) * map
.row_pitch
)
1290 + ((box
->left
/ view
->format
->block_width
) * view
->format
->block_byte_count
);
1292 range
.size
= texture
->sub_resources
[view
->sub_resource_idx
].size
;
1297 for (x
= 0; x
< w
; ++x
)
1299 ((BYTE
*)map
.data
)[x
] = c
;
1304 for (x
= 0; x
< w
; ++x
)
1306 ((WORD
*)map
.data
)[x
] = c
;
1313 for (x
= 0; x
< w
; ++x
, dst
+= 3)
1315 dst
[0] = (c
) & 0xff;
1316 dst
[1] = (c
>> 8) & 0xff;
1317 dst
[2] = (c
>> 16) & 0xff;
1322 for (x
= 0; x
< w
; ++x
)
1324 ((DWORD
*)map
.data
)[x
] = c
;
1329 FIXME("Not implemented for bpp %u.\n", bpp
);
1330 wined3d_resource_unmap(view
->resource
, view
->sub_resource_idx
);
1335 for (y
= 1; y
< h
; ++y
)
1337 dst
+= map
.row_pitch
;
1338 memcpy(dst
, map
.data
, w
* bpp
);
1342 for (z
= 1; z
< d
; ++z
)
1344 dst
+= map
.slice_pitch
;
1345 memcpy(dst
, map
.data
, w
* h
* bpp
);
1348 wined3d_context_unmap_bo_address(context
, &data
, 1, &range
);
1349 context_release(context
);
1352 static void cpu_blitter_clear(struct wined3d_blitter
*blitter
, struct wined3d_device
*device
,
1353 unsigned int rt_count
, const struct wined3d_fb_state
*fb
, unsigned int rect_count
, const RECT
*clear_rects
,
1354 const RECT
*draw_rect
, DWORD flags
, const struct wined3d_color
*colour
, float depth
, DWORD stencil
)
1356 struct wined3d_color c
= {depth
, 0.0f
, 0.0f
, 0.0f
};
1357 struct wined3d_rendertarget_view
*view
;
1358 struct wined3d_box box
;
1364 clear_rects
= draw_rect
;
1367 for (i
= 0; i
< rect_count
; ++i
)
1369 box
.left
= max(clear_rects
[i
].left
, draw_rect
->left
);
1370 box
.top
= max(clear_rects
[i
].top
, draw_rect
->top
);
1371 box
.right
= min(clear_rects
[i
].right
, draw_rect
->right
);
1372 box
.bottom
= min(clear_rects
[i
].bottom
, draw_rect
->bottom
);
1376 if (box
.left
>= box
.right
|| box
.top
>= box
.bottom
)
1379 if (flags
& WINED3DCLEAR_TARGET
)
1381 for (j
= 0; j
< rt_count
; ++j
)
1383 if ((view
= fb
->render_targets
[j
]))
1384 surface_cpu_blt_colour_fill(view
, &box
, colour
);
1388 if ((flags
& (WINED3DCLEAR_ZBUFFER
| WINED3DCLEAR_STENCIL
)) && (view
= fb
->depth_stencil
))
1390 if ((view
->format
->depth_size
&& !(flags
& WINED3DCLEAR_ZBUFFER
))
1391 || (view
->format
->stencil_size
&& !(flags
& WINED3DCLEAR_STENCIL
)))
1392 FIXME("Clearing %#x on %s.\n", flags
, debug_d3dformat(view
->format
->id
));
1394 surface_cpu_blt_colour_fill(view
, &box
, &c
);
1399 static DWORD
cpu_blitter_blit(struct wined3d_blitter
*blitter
, enum wined3d_blit_op op
,
1400 struct wined3d_context
*context
, struct wined3d_texture
*src_texture
, unsigned int src_sub_resource_idx
,
1401 DWORD src_location
, const RECT
*src_rect
, struct wined3d_texture
*dst_texture
,
1402 unsigned int dst_sub_resource_idx
, DWORD dst_location
, const RECT
*dst_rect
,
1403 const struct wined3d_color_key
*color_key
, enum wined3d_texture_filter_type filter
,
1404 const struct wined3d_format
*resolve_format
)
1406 struct wined3d_box dst_box
= {dst_rect
->left
, dst_rect
->top
, dst_rect
->right
, dst_rect
->bottom
, 0, 1};
1407 struct wined3d_box src_box
= {src_rect
->left
, src_rect
->top
, src_rect
->right
, src_rect
->bottom
, 0, 1};
1408 struct wined3d_blt_fx fx
;
1411 memset(&fx
, 0, sizeof(fx
));
1414 case WINED3D_BLIT_OP_COLOR_BLIT
:
1415 case WINED3D_BLIT_OP_DEPTH_BLIT
:
1417 case WINED3D_BLIT_OP_RAW_BLIT
:
1418 flags
|= WINED3D_BLT_RAW
;
1420 case WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST
:
1421 flags
|= WINED3D_BLT_ALPHA_TEST
;
1423 case WINED3D_BLIT_OP_COLOR_BLIT_CKEY
:
1424 flags
|= WINED3D_BLT_SRC_CKEY_OVERRIDE
| WINED3D_BLT_FX
;
1425 fx
.src_color_key
= *color_key
;
1428 FIXME("Unhandled op %#x.\n", op
);
1432 if (FAILED(surface_cpu_blt(dst_texture
, dst_sub_resource_idx
, &dst_box
,
1433 src_texture
, src_sub_resource_idx
, &src_box
, flags
, &fx
, filter
)))
1434 ERR("Failed to blit.\n");
1435 wined3d_texture_load_location(dst_texture
, dst_sub_resource_idx
, context
, dst_location
);
1437 return dst_location
| (dst_texture
->sub_resources
[dst_sub_resource_idx
].locations
1438 & dst_texture
->resource
.map_binding
);
1441 static const struct wined3d_blitter_ops cpu_blitter_ops
=
1443 cpu_blitter_destroy
,
1448 struct wined3d_blitter
*wined3d_cpu_blitter_create(void)
1450 struct wined3d_blitter
*blitter
;
1452 if (!(blitter
= heap_alloc(sizeof(*blitter
))))
1455 TRACE("Created blitter %p.\n", blitter
);
1457 blitter
->ops
= &cpu_blitter_ops
;
1458 blitter
->next
= NULL
;
1463 static bool wined3d_is_colour_blit(enum wined3d_blit_op blit_op
)
1467 case WINED3D_BLIT_OP_COLOR_BLIT
:
1468 case WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST
:
1469 case WINED3D_BLIT_OP_COLOR_BLIT_CKEY
:
1477 HRESULT
texture2d_blt(struct wined3d_texture
*dst_texture
, unsigned int dst_sub_resource_idx
,
1478 const struct wined3d_box
*dst_box
, struct wined3d_texture
*src_texture
, unsigned int src_sub_resource_idx
,
1479 const struct wined3d_box
*src_box
, DWORD flags
, const struct wined3d_blt_fx
*fx
,
1480 enum wined3d_texture_filter_type filter
)
1482 struct wined3d_texture_sub_resource
*src_sub_resource
, *dst_sub_resource
;
1483 struct wined3d_device
*device
= dst_texture
->resource
.device
;
1484 struct wined3d_swapchain
*src_swapchain
, *dst_swapchain
;
1485 BOOL scale
, convert
, resolve
, resolve_typeless
= FALSE
;
1486 const struct wined3d_format
*resolve_format
= NULL
;
1487 const struct wined3d_color_key
*colour_key
= NULL
;
1488 DWORD src_location
, dst_location
, valid_locations
;
1489 struct wined3d_context
*context
;
1490 enum wined3d_blit_op blit_op
;
1491 RECT src_rect
, dst_rect
;
1492 bool src_ds
, dst_ds
;
1494 static const DWORD simple_blit
= WINED3D_BLT_SRC_CKEY
1495 | WINED3D_BLT_SRC_CKEY_OVERRIDE
1496 | WINED3D_BLT_ALPHA_TEST
1499 TRACE("dst_texture %p, dst_sub_resource_idx %u, dst_box %s, src_texture %p, "
1500 "src_sub_resource_idx %u, src_box %s, flags %#x, fx %p, filter %s.\n",
1501 dst_texture
, dst_sub_resource_idx
, debug_box(dst_box
), src_texture
, src_sub_resource_idx
,
1502 debug_box(src_box
), flags
, fx
, debug_d3dtexturefiltertype(filter
));
1503 TRACE("Usage is %s.\n", debug_d3dusage(dst_texture
->resource
.usage
));
1507 TRACE("fx %#x.\n", fx
->fx
);
1508 TRACE("dst_color_key {0x%08x, 0x%08x}.\n",
1509 fx
->dst_color_key
.color_space_low_value
,
1510 fx
->dst_color_key
.color_space_high_value
);
1511 TRACE("src_color_key {0x%08x, 0x%08x}.\n",
1512 fx
->src_color_key
.color_space_low_value
,
1513 fx
->src_color_key
.color_space_high_value
);
1514 TRACE("resolve_format_id %s.\n", debug_d3dformat(fx
->resolve_format_id
));
1516 if (fx
->resolve_format_id
!= WINED3DFMT_UNKNOWN
)
1517 resolve_format
= wined3d_get_format(device
->adapter
, fx
->resolve_format_id
, 0);
1520 dst_sub_resource
= &dst_texture
->sub_resources
[dst_sub_resource_idx
];
1521 src_sub_resource
= &src_texture
->sub_resources
[src_sub_resource_idx
];
1523 if (src_sub_resource
->locations
& WINED3D_LOCATION_DISCARDED
)
1525 WARN("Source sub-resource is discarded, nothing to do.\n");
1529 SetRect(&src_rect
, src_box
->left
, src_box
->top
, src_box
->right
, src_box
->bottom
);
1530 SetRect(&dst_rect
, dst_box
->left
, dst_box
->top
, dst_box
->right
, dst_box
->bottom
);
1532 if (!fx
|| !(fx
->fx
))
1533 flags
&= ~WINED3D_BLT_FX
;
1535 /* WINED3D_BLT_DO_NOT_WAIT appeared in DX7. */
1536 if (flags
& WINED3D_BLT_DO_NOT_WAIT
)
1538 static unsigned int once
;
1541 FIXME("Can't handle WINED3D_BLT_DO_NOT_WAIT flag.\n");
1544 flags
&= ~(WINED3D_BLT_SYNCHRONOUS
| WINED3D_BLT_DO_NOT_WAIT
| WINED3D_BLT_WAIT
);
1546 if (flags
& ~simple_blit
)
1548 WARN_(d3d_perf
)("Using CPU fallback for complex blit (%#x).\n", flags
);
1552 src_swapchain
= src_texture
->swapchain
;
1553 dst_swapchain
= dst_texture
->swapchain
;
1555 if (src_swapchain
&& dst_swapchain
&& src_swapchain
!= dst_swapchain
1556 && (wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
1557 || src_texture
== src_swapchain
->front_buffer
))
1559 /* TODO: We could support cross-swapchain blits by first downloading
1560 * the source to a texture. */
1561 FIXME("Cross-swapchain blit not supported.\n");
1562 return WINED3DERR_INVALIDCALL
;
1565 scale
= src_box
->right
- src_box
->left
!= dst_box
->right
- dst_box
->left
1566 || src_box
->bottom
- src_box
->top
!= dst_box
->bottom
- dst_box
->top
;
1567 convert
= src_texture
->resource
.format
->id
!= dst_texture
->resource
.format
->id
;
1568 resolve
= src_texture
->resource
.multisample_type
!= dst_texture
->resource
.multisample_type
;
1571 resolve_typeless
= (wined3d_format_is_typeless(src_texture
->resource
.format
)
1572 || wined3d_format_is_typeless(dst_texture
->resource
.format
))
1573 && (src_texture
->resource
.format
->typeless_id
== dst_texture
->resource
.format
->typeless_id
);
1574 if (resolve_typeless
&& !resolve_format
)
1575 WARN("Resolve format for typeless resolve not specified.\n");
1578 dst_ds
= dst_texture
->resource
.format
->depth_size
|| dst_texture
->resource
.format
->stencil_size
;
1579 src_ds
= src_texture
->resource
.format
->depth_size
|| src_texture
->resource
.format
->stencil_size
;
1581 if (src_ds
|| dst_ds
)
1583 TRACE("Depth/stencil blit.\n");
1585 if (dst_texture
->resource
.access
& WINED3D_RESOURCE_ACCESS_GPU
)
1586 dst_location
= dst_texture
->resource
.draw_binding
;
1588 dst_location
= dst_texture
->resource
.map_binding
;
1590 if ((flags
& WINED3D_BLT_RAW
) || (!scale
&& !convert
&& !resolve
))
1591 blit_op
= WINED3D_BLIT_OP_RAW_BLIT
;
1593 blit_op
= WINED3D_BLIT_OP_DEPTH_BLIT
;
1595 context
= context_acquire(device
, dst_texture
, dst_sub_resource_idx
);
1596 valid_locations
= device
->blitter
->ops
->blitter_blit(device
->blitter
, blit_op
, context
,
1597 src_texture
, src_sub_resource_idx
, src_texture
->resource
.draw_binding
, &src_rect
,
1598 dst_texture
, dst_sub_resource_idx
, dst_location
, &dst_rect
, NULL
, filter
, resolve_format
);
1599 context_release(context
);
1601 wined3d_texture_validate_location(dst_texture
, dst_sub_resource_idx
, valid_locations
);
1602 wined3d_texture_invalidate_location(dst_texture
, dst_sub_resource_idx
, ~valid_locations
);
1607 TRACE("Colour blit.\n");
1609 /* In principle this would apply to depth blits as well, but we don't
1610 * implement those in the CPU blitter at the moment. */
1611 if ((dst_sub_resource
->locations
& dst_texture
->resource
.map_binding
)
1612 && (src_sub_resource
->locations
& src_texture
->resource
.map_binding
))
1615 TRACE("Not doing sysmem blit because of scaling.\n");
1617 TRACE("Not doing sysmem blit because of format conversion.\n");
1622 blit_op
= WINED3D_BLIT_OP_COLOR_BLIT
;
1623 if (flags
& WINED3D_BLT_SRC_CKEY_OVERRIDE
)
1625 colour_key
= &fx
->src_color_key
;
1626 blit_op
= WINED3D_BLIT_OP_COLOR_BLIT_CKEY
;
1628 else if (flags
& WINED3D_BLT_SRC_CKEY
)
1630 colour_key
= &src_texture
->async
.src_blt_color_key
;
1631 blit_op
= WINED3D_BLIT_OP_COLOR_BLIT_CKEY
;
1633 else if (flags
& WINED3D_BLT_ALPHA_TEST
)
1635 blit_op
= WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST
;
1637 else if ((src_sub_resource
->locations
& surface_simple_locations
)
1638 && !(dst_sub_resource
->locations
& surface_simple_locations
)
1639 && (dst_texture
->resource
.access
& WINED3D_RESOURCE_ACCESS_GPU
))
1643 TRACE("Not doing upload because of scaling.\n");
1645 TRACE("Not doing upload because of format conversion.\n");
1646 else if (dst_texture
->resource
.format
->conv_byte_count
)
1647 TRACE("Not doing upload because the destination format needs conversion.\n");
1650 wined3d_texture_upload_from_texture(dst_texture
, dst_sub_resource_idx
, dst_box
->left
,
1651 dst_box
->top
, dst_box
->front
, src_texture
, src_sub_resource_idx
, src_box
);
1652 if (!wined3d_resource_is_offscreen(&dst_texture
->resource
))
1654 context
= context_acquire(device
, dst_texture
, dst_sub_resource_idx
);
1655 wined3d_texture_load_location(dst_texture
, dst_sub_resource_idx
,
1656 context
, dst_texture
->resource
.draw_binding
);
1657 context_release(context
);
1662 else if (!(src_sub_resource
->locations
& surface_simple_locations
)
1663 && (dst_sub_resource
->locations
& dst_texture
->resource
.map_binding
)
1664 && !(dst_texture
->resource
.access
& WINED3D_RESOURCE_ACCESS_GPU
))
1668 TRACE("Not doing download because of scaling.\n");
1670 TRACE("Not doing download because of format conversion.\n");
1671 else if (src_texture
->resource
.format
->conv_byte_count
)
1672 TRACE("Not doing download because the source format needs conversion.\n");
1673 else if (!(src_texture
->flags
& WINED3D_TEXTURE_DOWNLOADABLE
))
1674 TRACE("Not doing download because texture is not downloadable.\n");
1675 else if (!wined3d_texture_is_full_rect(src_texture
, src_sub_resource_idx
% src_texture
->level_count
, &src_rect
))
1676 TRACE("Not doing download because of partial download (src).\n");
1677 else if (!wined3d_texture_is_full_rect(dst_texture
, dst_sub_resource_idx
% dst_texture
->level_count
, &dst_rect
))
1678 TRACE("Not doing download because of partial download (dst).\n");
1681 wined3d_texture_download_from_texture(dst_texture
, dst_sub_resource_idx
, src_texture
,
1682 src_sub_resource_idx
);
1686 else if (dst_swapchain
&& dst_swapchain
->back_buffers
1687 && dst_texture
== dst_swapchain
->front_buffer
1688 && src_texture
== dst_swapchain
->back_buffers
[0])
1690 /* Use present for back -> front blits. The idea behind this is that
1691 * present is potentially faster than a blit, in particular when FBO
1692 * blits aren't available. Some ddraw applications like Half-Life and
1693 * Prince of Persia 3D use Blt() from the backbuffer to the
1694 * frontbuffer instead of doing a Flip(). D3d8 and d3d9 applications
1695 * can't blit directly to the frontbuffer. */
1696 enum wined3d_swap_effect swap_effect
= dst_swapchain
->state
.desc
.swap_effect
;
1698 TRACE("Using present for backbuffer -> frontbuffer blit.\n");
1700 /* Set the swap effect to COPY, we don't want the backbuffer to become
1702 dst_swapchain
->state
.desc
.swap_effect
= WINED3D_SWAP_EFFECT_COPY
;
1703 wined3d_swapchain_present(dst_swapchain
, NULL
, NULL
,
1704 dst_swapchain
->win_handle
, dst_swapchain
->swap_interval
, 0);
1705 dst_swapchain
->state
.desc
.swap_effect
= swap_effect
;
1710 if ((flags
& WINED3D_BLT_RAW
) || (blit_op
== WINED3D_BLIT_OP_COLOR_BLIT
&& !scale
&& !convert
&& !resolve
))
1711 blit_op
= WINED3D_BLIT_OP_RAW_BLIT
;
1713 context
= context_acquire(device
, dst_texture
, dst_sub_resource_idx
);
1715 if (src_texture
->resource
.multisample_type
!= WINED3D_MULTISAMPLE_NONE
&& !resolve_typeless
1716 && ((scale
&& !context
->d3d_info
->scaled_resolve
)
1717 || convert
|| !wined3d_is_colour_blit(blit_op
)))
1718 src_location
= WINED3D_LOCATION_RB_RESOLVED
;
1720 src_location
= src_texture
->resource
.draw_binding
;
1722 if (!(dst_texture
->resource
.access
& WINED3D_RESOURCE_ACCESS_GPU
))
1723 dst_location
= dst_texture
->resource
.map_binding
;
1724 else if (dst_texture
->resource
.multisample_type
!= WINED3D_MULTISAMPLE_NONE
1725 && (scale
|| convert
|| !wined3d_is_colour_blit(blit_op
)))
1726 dst_location
= WINED3D_LOCATION_RB_RESOLVED
;
1728 dst_location
= dst_texture
->resource
.draw_binding
;
1730 valid_locations
= device
->blitter
->ops
->blitter_blit(device
->blitter
, blit_op
, context
,
1731 src_texture
, src_sub_resource_idx
, src_location
, &src_rect
,
1732 dst_texture
, dst_sub_resource_idx
, dst_location
, &dst_rect
, colour_key
, filter
, resolve_format
);
1734 context_release(context
);
1736 wined3d_texture_validate_location(dst_texture
, dst_sub_resource_idx
, valid_locations
);
1737 wined3d_texture_invalidate_location(dst_texture
, dst_sub_resource_idx
, ~valid_locations
);
1742 return surface_cpu_blt(dst_texture
, dst_sub_resource_idx
, dst_box
,
1743 src_texture
, src_sub_resource_idx
, src_box
, flags
, fx
, filter
);