2 * Copyright 1997-2000 Marcus Meissner
3 * Copyright 1998-2000 Lionel Ulmer
4 * Copyright 2000-2001 TransGaming Technologies Inc.
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2002-2003 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2011, 2013-2014 Stefan Dösinger for CodeWeavers
10 * Copyright 2007-2008 Henri Verbeet
11 * Copyright 2006-2008 Roderick Colenbrander
12 * Copyright 2009-2011 Henri Verbeet for CodeWeavers
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 #include "wined3d_private.h"
30 #include "wined3d_gl.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(d3d
);
33 WINE_DECLARE_DEBUG_CHANNEL(d3d_perf
);
35 /* Works correctly only for <= 4 bpp formats. */
36 static void get_color_masks(const struct wined3d_format
*format
, uint32_t *masks
)
38 masks
[0] = wined3d_mask_from_size(format
->red_size
) << format
->red_offset
;
39 masks
[1] = wined3d_mask_from_size(format
->green_size
) << format
->green_offset
;
40 masks
[2] = wined3d_mask_from_size(format
->blue_size
) << format
->blue_offset
;
43 static void convert_r32_float_r16_float(const BYTE
*src
, BYTE
*dst
,
44 unsigned int pitch_in
, unsigned int pitch_out
, unsigned int w
, unsigned int h
)
46 unsigned short *dst_s
;
50 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
52 for (y
= 0; y
< h
; ++y
)
54 src_f
= (const float *)(src
+ y
* pitch_in
);
55 dst_s
= (unsigned short *) (dst
+ y
* pitch_out
);
56 for (x
= 0; x
< w
; ++x
)
58 dst_s
[x
] = float_32_to_16(src_f
+ x
);
63 static void convert_r5g6b5_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
64 unsigned int pitch_in
, unsigned int pitch_out
, unsigned int w
, unsigned int h
)
66 static const unsigned char convert_5to8
[] =
68 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
69 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
70 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
71 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
73 static const unsigned char convert_6to8
[] =
75 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
76 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
77 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
78 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
79 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
80 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
81 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
82 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
86 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
88 for (y
= 0; y
< h
; ++y
)
90 const WORD
*src_line
= (const WORD
*)(src
+ y
* pitch_in
);
91 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
92 for (x
= 0; x
< w
; ++x
)
94 WORD pixel
= src_line
[x
];
95 dst_line
[x
] = 0xff000000u
96 | convert_5to8
[(pixel
& 0xf800u
) >> 11] << 16
97 | convert_6to8
[(pixel
& 0x07e0u
) >> 5] << 8
98 | convert_5to8
[(pixel
& 0x001fu
)];
103 /* We use this for both B8G8R8A8 -> B8G8R8X8 and B8G8R8X8 -> B8G8R8A8, since
104 * in both cases we're just setting the X / Alpha channel to 0xff. */
105 static void convert_a8r8g8b8_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
106 unsigned int pitch_in
, unsigned int pitch_out
, unsigned int w
, unsigned int h
)
110 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
112 for (y
= 0; y
< h
; ++y
)
114 const DWORD
*src_line
= (const DWORD
*)(src
+ y
* pitch_in
);
115 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
117 for (x
= 0; x
< w
; ++x
)
119 dst_line
[x
] = 0xff000000 | (src_line
[x
] & 0xffffff);
124 static inline BYTE
cliptobyte(int x
)
126 return (BYTE
)((x
< 0) ? 0 : ((x
> 255) ? 255 : x
));
129 static void convert_yuy2_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
130 unsigned int pitch_in
, unsigned int pitch_out
, unsigned int w
, unsigned int h
)
132 int c2
, d
, e
, r2
= 0, g2
= 0, b2
= 0;
135 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
137 for (y
= 0; y
< h
; ++y
)
139 const BYTE
*src_line
= src
+ y
* pitch_in
;
140 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
141 for (x
= 0; x
< w
; ++x
)
143 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
144 * C = Y - 16; D = U - 128; E = V - 128;
145 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
146 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
147 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
148 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
149 * U and V are shared between the pixels. */
150 if (!(x
& 1)) /* For every even pixel, read new U and V. */
152 d
= (int) src_line
[1] - 128;
153 e
= (int) src_line
[3] - 128;
155 g2
= - 100 * d
- 208 * e
+ 128;
158 c2
= 298 * ((int) src_line
[0] - 16);
159 dst_line
[x
] = 0xff000000
160 | cliptobyte((c2
+ r2
) >> 8) << 16 /* red */
161 | cliptobyte((c2
+ g2
) >> 8) << 8 /* green */
162 | cliptobyte((c2
+ b2
) >> 8); /* blue */
163 /* Scale RGB values to 0..255 range,
164 * then clip them if still not in range (may be negative),
165 * then shift them within DWORD if necessary. */
171 static void convert_yuy2_r5g6b5(const BYTE
*src
, BYTE
*dst
,
172 unsigned int pitch_in
, unsigned int pitch_out
, unsigned int w
, unsigned int h
)
175 int c2
, d
, e
, r2
= 0, g2
= 0, b2
= 0;
177 TRACE("Converting %ux%u pixels, pitches %u %u\n", w
, h
, pitch_in
, pitch_out
);
179 for (y
= 0; y
< h
; ++y
)
181 const BYTE
*src_line
= src
+ y
* pitch_in
;
182 WORD
*dst_line
= (WORD
*)(dst
+ y
* pitch_out
);
183 for (x
= 0; x
< w
; ++x
)
185 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
186 * C = Y - 16; D = U - 128; E = V - 128;
187 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
188 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
189 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
190 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
191 * U and V are shared between the pixels. */
192 if (!(x
& 1)) /* For every even pixel, read new U and V. */
194 d
= (int) src_line
[1] - 128;
195 e
= (int) src_line
[3] - 128;
197 g2
= - 100 * d
- 208 * e
+ 128;
200 c2
= 298 * ((int) src_line
[0] - 16);
201 dst_line
[x
] = (cliptobyte((c2
+ r2
) >> 8) >> 3) << 11 /* red */
202 | (cliptobyte((c2
+ g2
) >> 8) >> 2) << 5 /* green */
203 | (cliptobyte((c2
+ b2
) >> 8) >> 3); /* blue */
204 /* Scale RGB values to 0..255 range,
205 * then clip them if still not in range (may be negative),
206 * then shift them within DWORD if necessary. */
212 struct d3dfmt_converter_desc
214 enum wined3d_format_id from
, to
;
215 void (*convert
)(const BYTE
*src
, BYTE
*dst
,
216 unsigned int pitch_in
, unsigned int pitch_out
,
217 unsigned int w
, unsigned int h
);
220 static const struct d3dfmt_converter_desc converters
[] =
222 {WINED3DFMT_R32_FLOAT
, WINED3DFMT_R16_FLOAT
, convert_r32_float_r16_float
},
223 {WINED3DFMT_B5G6R5_UNORM
, WINED3DFMT_B8G8R8X8_UNORM
, convert_r5g6b5_x8r8g8b8
},
224 {WINED3DFMT_B8G8R8A8_UNORM
, WINED3DFMT_B8G8R8X8_UNORM
, convert_a8r8g8b8_x8r8g8b8
},
225 {WINED3DFMT_B8G8R8X8_UNORM
, WINED3DFMT_B8G8R8A8_UNORM
, convert_a8r8g8b8_x8r8g8b8
},
226 {WINED3DFMT_YUY2
, WINED3DFMT_B8G8R8X8_UNORM
, convert_yuy2_x8r8g8b8
},
227 {WINED3DFMT_YUY2
, WINED3DFMT_B5G6R5_UNORM
, convert_yuy2_r5g6b5
},
230 static inline const struct d3dfmt_converter_desc
*find_converter(enum wined3d_format_id from
,
231 enum wined3d_format_id to
)
235 for (i
= 0; i
< ARRAY_SIZE(converters
); ++i
)
237 if (converters
[i
].from
== from
&& converters
[i
].to
== to
)
238 return &converters
[i
];
244 static struct wined3d_texture
*surface_convert_format(struct wined3d_texture
*src_texture
,
245 unsigned int sub_resource_idx
, const struct wined3d_format
*dst_format
)
247 unsigned int texture_level
= sub_resource_idx
% src_texture
->level_count
;
248 const struct wined3d_format
*src_format
= src_texture
->resource
.format
;
249 struct wined3d_device
*device
= src_texture
->resource
.device
;
250 const struct d3dfmt_converter_desc
*conv
= NULL
;
251 unsigned int src_row_pitch
, src_slice_pitch
;
252 struct wined3d_texture
*dst_texture
;
253 struct wined3d_bo_address src_data
;
254 struct wined3d_resource_desc desc
;
255 struct wined3d_context
*context
;
258 if (!(conv
= find_converter(src_format
->id
, dst_format
->id
)) && ((device
->wined3d
->flags
& WINED3D_NO3D
)
259 || !is_identity_fixup(src_format
->color_fixup
) || src_format
->conv_byte_count
260 || !is_identity_fixup(dst_format
->color_fixup
) || dst_format
->conv_byte_count
261 || ((src_format
->attrs
& WINED3D_FORMAT_ATTR_COMPRESSED
)
262 && !src_format
->decompress
)))
264 FIXME("Cannot find a conversion function from format %s to %s.\n",
265 debug_d3dformat(src_format
->id
), debug_d3dformat(dst_format
->id
));
269 /* FIXME: Multisampled conversion? */
270 desc
.resource_type
= WINED3D_RTYPE_TEXTURE_2D
;
271 desc
.format
= dst_format
->id
;
272 desc
.multisample_type
= WINED3D_MULTISAMPLE_NONE
;
273 desc
.multisample_quality
= 0;
274 desc
.usage
= WINED3DUSAGE_SCRATCH
| WINED3DUSAGE_CS
;
276 desc
.access
= WINED3D_RESOURCE_ACCESS_CPU
| WINED3D_RESOURCE_ACCESS_MAP_R
| WINED3D_RESOURCE_ACCESS_MAP_W
;
277 desc
.width
= wined3d_texture_get_level_width(src_texture
, texture_level
);
278 desc
.height
= wined3d_texture_get_level_height(src_texture
, texture_level
);
281 if (FAILED(wined3d_texture_create(device
, &desc
, 1, 1, WINED3D_TEXTURE_CREATE_DISCARD
,
282 NULL
, NULL
, &wined3d_null_parent_ops
, &dst_texture
)))
284 ERR("Failed to create a destination texture for conversion.\n");
288 context
= context_acquire(device
, NULL
, 0);
290 map_binding
= src_texture
->resource
.map_binding
;
291 if (!wined3d_texture_load_location(src_texture
, sub_resource_idx
, context
, map_binding
))
292 ERR("Failed to load the source sub-resource into %s.\n", wined3d_debug_location(map_binding
));
293 wined3d_texture_get_pitch(src_texture
, texture_level
, &src_row_pitch
, &src_slice_pitch
);
294 wined3d_texture_get_bo_address(src_texture
, sub_resource_idx
, &src_data
, map_binding
);
298 unsigned int dst_row_pitch
, dst_slice_pitch
;
299 struct wined3d_bo_address dst_data
;
300 struct wined3d_range range
;
304 map_binding
= dst_texture
->resource
.map_binding
;
305 if (!wined3d_texture_load_location(dst_texture
, 0, context
, map_binding
))
306 ERR("Failed to load the destination sub-resource into %s.\n", wined3d_debug_location(map_binding
));
307 wined3d_texture_get_pitch(dst_texture
, 0, &dst_row_pitch
, &dst_slice_pitch
);
308 wined3d_texture_get_bo_address(dst_texture
, 0, &dst_data
, map_binding
);
310 src
= wined3d_context_map_bo_address(context
, &src_data
,
311 src_texture
->sub_resources
[sub_resource_idx
].size
, WINED3D_MAP_READ
);
312 dst
= wined3d_context_map_bo_address(context
, &dst_data
,
313 dst_texture
->sub_resources
[0].size
, WINED3D_MAP_WRITE
);
315 conv
->convert(src
, dst
, src_row_pitch
, dst_row_pitch
, desc
.width
, desc
.height
);
318 range
.size
= dst_texture
->sub_resources
[0].size
;
319 wined3d_texture_invalidate_location(dst_texture
, 0, ~map_binding
);
320 wined3d_context_unmap_bo_address(context
, &dst_data
, 1, &range
);
321 wined3d_context_unmap_bo_address(context
, &src_data
, 0, NULL
);
325 struct wined3d_box src_box
= {0, 0, desc
.width
, desc
.height
, 0, 1};
327 TRACE("Using upload conversion.\n");
329 wined3d_texture_prepare_location(dst_texture
, 0, context
, WINED3D_LOCATION_TEXTURE_RGB
);
330 dst_texture
->texture_ops
->texture_upload_data(context
, wined3d_const_bo_address(&src_data
),
331 src_format
, &src_box
, src_row_pitch
, src_slice_pitch
,
332 dst_texture
, 0, WINED3D_LOCATION_TEXTURE_RGB
, 0, 0, 0);
334 wined3d_texture_validate_location(dst_texture
, 0, WINED3D_LOCATION_TEXTURE_RGB
);
335 wined3d_texture_invalidate_location(dst_texture
, 0, ~WINED3D_LOCATION_TEXTURE_RGB
);
338 context_release(context
);
343 void texture2d_read_from_framebuffer(struct wined3d_texture
*texture
, unsigned int sub_resource_idx
,
344 struct wined3d_context
*context
, DWORD src_location
, DWORD dst_location
)
346 struct wined3d_resource
*resource
= &texture
->resource
;
347 struct wined3d_device
*device
= resource
->device
;
348 const struct wined3d_format_gl
*format_gl
;
349 struct wined3d_texture
*restore_texture
;
350 const struct wined3d_gl_info
*gl_info
;
351 struct wined3d_context_gl
*context_gl
;
352 unsigned int row_pitch
, slice_pitch
;
353 unsigned int width
, height
, level
;
354 struct wined3d_bo_address data
;
355 unsigned int restore_idx
;
356 BYTE
*row
, *top
, *bottom
;
357 BOOL src_is_upside_down
;
362 TRACE("texture %p, sub_resource_idx %u, context %p, src_location %s, dst_location %s.\n",
363 texture
, sub_resource_idx
, context
, wined3d_debug_location(src_location
), wined3d_debug_location(dst_location
));
365 /* dst_location was already prepared by the caller. */
366 wined3d_texture_get_bo_address(texture
, sub_resource_idx
, &data
, dst_location
);
369 restore_texture
= context
->current_rt
.texture
;
370 restore_idx
= context
->current_rt
.sub_resource_idx
;
371 if (!wined3d_resource_is_offscreen(resource
) && (restore_texture
!= texture
|| restore_idx
!= sub_resource_idx
))
372 context
= context_acquire(device
, texture
, sub_resource_idx
);
374 restore_texture
= NULL
;
375 context_gl
= wined3d_context_gl(context
);
376 gl_info
= context_gl
->gl_info
;
378 if (resource
->format
->depth_size
|| resource
->format
->stencil_size
)
379 wined3d_context_gl_apply_fbo_state_explicit(context_gl
, GL_READ_FRAMEBUFFER
,
380 NULL
, 0, resource
, sub_resource_idx
, src_location
);
382 wined3d_context_gl_apply_fbo_state_explicit(context_gl
, GL_READ_FRAMEBUFFER
,
383 resource
, sub_resource_idx
, NULL
, 0, src_location
);
385 /* Select the correct read buffer, and give some debug output. There is no
386 * need to keep track of the current read buffer or reset it, every part
387 * of the code that reads pixels sets the read buffer as desired. */
388 if (src_location
!= WINED3D_LOCATION_DRAWABLE
|| wined3d_resource_is_offscreen(resource
))
390 /* Mapping the primary render target which is not on a swapchain.
391 * Read from the back buffer. */
392 TRACE("Mapping offscreen render target.\n");
393 gl_info
->gl_ops
.gl
.p_glReadBuffer(wined3d_context_gl_get_offscreen_gl_buffer(context_gl
));
394 src_is_upside_down
= TRUE
;
398 /* Onscreen surfaces are always part of a swapchain */
399 GLenum buffer
= wined3d_texture_get_gl_buffer(texture
);
400 TRACE("Mapping %#x buffer.\n", buffer
);
401 gl_info
->gl_ops
.gl
.p_glReadBuffer(buffer
);
402 src_is_upside_down
= FALSE
;
404 checkGLcall("glReadBuffer");
405 wined3d_context_gl_check_fbo_status(context_gl
, GL_READ_FRAMEBUFFER
);
407 if (data
.buffer_object
)
409 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, wined3d_bo_gl(data
.buffer_object
)->id
));
410 checkGLcall("glBindBuffer");
411 offset
+= data
.buffer_object
->buffer_offset
;
415 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, 0));
416 checkGLcall("glBindBuffer");
419 level
= sub_resource_idx
% texture
->level_count
;
420 wined3d_texture_get_pitch(texture
, level
, &row_pitch
, &slice_pitch
);
421 format_gl
= wined3d_format_gl(resource
->format
);
423 /* Setup pixel store pack state -- to glReadPixels into the correct place */
424 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_PACK_ROW_LENGTH
, row_pitch
/ format_gl
->f
.byte_count
);
425 checkGLcall("glPixelStorei");
427 width
= wined3d_texture_get_level_width(texture
, level
);
428 height
= wined3d_texture_get_level_height(texture
, level
);
429 gl_info
->gl_ops
.gl
.p_glReadPixels(0, 0, width
, height
,
430 format_gl
->format
, format_gl
->type
, offset
);
431 checkGLcall("glReadPixels");
433 /* Reset previous pixel store pack state */
434 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_PACK_ROW_LENGTH
, 0);
435 checkGLcall("glPixelStorei");
437 if (!src_is_upside_down
)
439 /* glReadPixels returns the image upside down, and there is no way to
440 * prevent this. Flip the lines in software. */
442 if (!(row
= malloc(row_pitch
)))
445 if (data
.buffer_object
)
447 mem
= GL_EXTCALL(glMapBuffer(GL_PIXEL_PACK_BUFFER
, GL_READ_WRITE
));
448 checkGLcall("glMapBuffer");
450 mem
+= (uintptr_t)offset
;
453 bottom
= mem
+ row_pitch
* (height
- 1);
454 for (i
= 0; i
< height
/ 2; i
++)
456 memcpy(row
, top
, row_pitch
);
457 memcpy(top
, bottom
, row_pitch
);
458 memcpy(bottom
, row
, row_pitch
);
464 if (data
.buffer_object
)
465 GL_EXTCALL(glUnmapBuffer(GL_PIXEL_PACK_BUFFER
));
469 if (data
.buffer_object
)
471 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, 0));
472 wined3d_context_gl_reference_bo(context_gl
, wined3d_bo_gl(data
.buffer_object
));
473 checkGLcall("glBindBuffer");
477 context_restore(context
, restore_texture
, restore_idx
);
480 /* Context activation is done by the caller. */
481 static void cpu_blitter_destroy(struct wined3d_blitter
*blitter
, struct wined3d_context
*context
)
483 struct wined3d_blitter
*next
;
485 if ((next
= blitter
->next
))
486 next
->ops
->blitter_destroy(next
, context
);
491 static HRESULT
surface_cpu_blt_compressed(const BYTE
*src_data
, BYTE
*dst_data
,
492 UINT src_pitch
, UINT dst_pitch
, UINT update_w
, UINT update_h
,
493 const struct wined3d_format
*format
, uint32_t flags
, const struct wined3d_blt_fx
*fx
)
495 UINT row_block_count
;
503 row_block_count
= (update_w
+ format
->block_width
- 1) / format
->block_width
;
507 for (y
= 0; y
< update_h
; y
+= format
->block_height
)
509 memcpy(dst_row
, src_row
, row_block_count
* format
->block_byte_count
);
510 src_row
+= src_pitch
;
511 dst_row
+= dst_pitch
;
517 if (flags
== WINED3D_BLT_FX
&& fx
->fx
== WINEDDBLTFX_MIRRORUPDOWN
)
519 src_row
+= (((update_h
/ format
->block_height
) - 1) * src_pitch
);
523 case WINED3DFMT_DXT1
:
524 for (y
= 0; y
< update_h
; y
+= format
->block_height
)
532 const struct block
*s
= (const struct block
*)src_row
;
533 struct block
*d
= (struct block
*)dst_row
;
535 for (x
= 0; x
< row_block_count
; ++x
)
537 d
[x
].color
[0] = s
[x
].color
[0];
538 d
[x
].color
[1] = s
[x
].color
[1];
539 d
[x
].control_row
[0] = s
[x
].control_row
[3];
540 d
[x
].control_row
[1] = s
[x
].control_row
[2];
541 d
[x
].control_row
[2] = s
[x
].control_row
[1];
542 d
[x
].control_row
[3] = s
[x
].control_row
[0];
544 src_row
-= src_pitch
;
545 dst_row
+= dst_pitch
;
549 case WINED3DFMT_DXT2
:
550 case WINED3DFMT_DXT3
:
551 for (y
= 0; y
< update_h
; y
+= format
->block_height
)
560 const struct block
*s
= (const struct block
*)src_row
;
561 struct block
*d
= (struct block
*)dst_row
;
563 for (x
= 0; x
< row_block_count
; ++x
)
565 d
[x
].alpha_row
[0] = s
[x
].alpha_row
[3];
566 d
[x
].alpha_row
[1] = s
[x
].alpha_row
[2];
567 d
[x
].alpha_row
[2] = s
[x
].alpha_row
[1];
568 d
[x
].alpha_row
[3] = s
[x
].alpha_row
[0];
569 d
[x
].color
[0] = s
[x
].color
[0];
570 d
[x
].color
[1] = s
[x
].color
[1];
571 d
[x
].control_row
[0] = s
[x
].control_row
[3];
572 d
[x
].control_row
[1] = s
[x
].control_row
[2];
573 d
[x
].control_row
[2] = s
[x
].control_row
[1];
574 d
[x
].control_row
[3] = s
[x
].control_row
[0];
576 src_row
-= src_pitch
;
577 dst_row
+= dst_pitch
;
582 FIXME("Compressed flip not implemented for format %s.\n",
583 debug_d3dformat(format
->id
));
588 FIXME("Unsupported blit on compressed surface (format %s, flags %#x, DDFX %#x).\n",
589 debug_d3dformat(format
->id
), flags
, flags
& WINED3D_BLT_FX
? fx
->fx
: 0);
594 static HRESULT
surface_cpu_blt(struct wined3d_texture
*dst_texture
, unsigned int dst_sub_resource_idx
,
595 const struct wined3d_box
*dst_box
, struct wined3d_texture
*src_texture
, unsigned int src_sub_resource_idx
,
596 const struct wined3d_box
*src_box
, uint32_t flags
, const struct wined3d_blt_fx
*fx
,
597 enum wined3d_texture_filter_type filter
)
599 unsigned int bpp
, src_height
, src_width
, dst_height
, dst_width
, row_byte_count
;
600 struct wined3d_device
*device
= dst_texture
->resource
.device
;
601 const struct wined3d_format
*src_format
, *dst_format
;
602 struct wined3d_texture
*converted_texture
= NULL
;
603 struct wined3d_bo_address src_data
, dst_data
;
604 unsigned int src_fmt_attrs
, dst_fmt_attrs
;
605 struct wined3d_map_desc dst_map
, src_map
;
606 unsigned int x
, sx
, xinc
, y
, sy
, yinc
;
607 struct wined3d_context
*context
;
608 struct wined3d_range dst_range
;
609 unsigned int texture_level
;
610 HRESULT hr
= WINED3D_OK
;
611 BOOL same_sub_resource
;
618 TRACE("dst_texture %p, dst_sub_resource_idx %u, dst_box %s, src_texture %p, "
619 "src_sub_resource_idx %u, src_box %s, flags %#x, fx %p, filter %s.\n",
620 dst_texture
, dst_sub_resource_idx
, debug_box(dst_box
), src_texture
,
621 src_sub_resource_idx
, debug_box(src_box
), flags
, fx
, debug_d3dtexturefiltertype(filter
));
623 context
= context_acquire(device
, NULL
, 0);
625 src_format
= src_texture
->resource
.format
;
626 dst_format
= dst_texture
->resource
.format
;
628 if (wined3d_format_is_typeless(src_format
) && src_format
->id
== dst_format
->typeless_id
)
629 src_format
= dst_format
;
630 if (wined3d_format_is_typeless(dst_format
) && dst_format
->id
== src_format
->typeless_id
)
631 dst_format
= src_format
;
633 src_height
= src_box
->bottom
- src_box
->top
;
634 src_width
= src_box
->right
- src_box
->left
;
635 dst_height
= dst_box
->bottom
- dst_box
->top
;
636 dst_width
= dst_box
->right
- dst_box
->left
;
638 dst_range
.offset
= 0;
639 dst_range
.size
= dst_texture
->sub_resources
[dst_sub_resource_idx
].size
;
640 if (src_texture
== dst_texture
&& src_sub_resource_idx
== dst_sub_resource_idx
)
642 same_sub_resource
= TRUE
;
644 map_binding
= dst_texture
->resource
.map_binding
;
645 texture_level
= dst_sub_resource_idx
% dst_texture
->level_count
;
646 if (!wined3d_texture_load_location(dst_texture
, dst_sub_resource_idx
, context
, map_binding
))
647 ERR("Failed to load the destination sub-resource into %s.\n", wined3d_debug_location(map_binding
));
648 wined3d_texture_invalidate_location(dst_texture
, dst_sub_resource_idx
, ~map_binding
);
649 wined3d_texture_get_pitch(dst_texture
, texture_level
, &dst_map
.row_pitch
, &dst_map
.slice_pitch
);
650 wined3d_texture_get_bo_address(dst_texture
, dst_sub_resource_idx
, &dst_data
, map_binding
);
651 dst_map
.data
= wined3d_context_map_bo_address(context
, &dst_data
,
652 dst_texture
->sub_resources
[dst_sub_resource_idx
].size
, WINED3D_MAP_READ
| WINED3D_MAP_WRITE
);
658 same_sub_resource
= FALSE
;
659 upload
= dst_format
->attrs
& WINED3D_FORMAT_ATTR_BLOCKS
660 && (dst_width
!= src_width
|| dst_height
!= src_height
);
664 dst_format
= src_format
->attrs
& WINED3D_FORMAT_ATTR_BLOCKS
665 ? wined3d_get_format(device
->adapter
, WINED3DFMT_B8G8R8A8_UNORM
, 0) : src_format
;
668 if (!(flags
& WINED3D_BLT_RAW
) && dst_format
->id
!= src_format
->id
)
670 if (!(converted_texture
= surface_convert_format(src_texture
, src_sub_resource_idx
, dst_format
)))
672 FIXME("Cannot convert %s to %s.\n", debug_d3dformat(src_format
->id
),
673 debug_d3dformat(dst_format
->id
));
674 context_release(context
);
675 return WINED3DERR_NOTAVAILABLE
;
677 src_texture
= converted_texture
;
678 src_sub_resource_idx
= 0;
679 src_format
= src_texture
->resource
.format
;
682 map_binding
= src_texture
->resource
.map_binding
;
683 texture_level
= src_sub_resource_idx
% src_texture
->level_count
;
684 if (!wined3d_texture_load_location(src_texture
, src_sub_resource_idx
, context
, map_binding
))
685 ERR("Failed to load the source sub-resource into %s.\n", wined3d_debug_location(map_binding
));
686 wined3d_texture_get_pitch(src_texture
, texture_level
, &src_map
.row_pitch
, &src_map
.slice_pitch
);
687 wined3d_texture_get_bo_address(src_texture
, src_sub_resource_idx
, &src_data
, map_binding
);
688 src_map
.data
= wined3d_context_map_bo_address(context
, &src_data
,
689 src_texture
->sub_resources
[src_sub_resource_idx
].size
, WINED3D_MAP_READ
);
693 wined3d_format_calculate_pitch(dst_format
, 1, dst_box
->right
, dst_box
->bottom
,
694 &dst_map
.row_pitch
, &dst_map
.slice_pitch
);
695 dst_map
.data
= malloc(dst_map
.slice_pitch
);
699 map_binding
= dst_texture
->resource
.map_binding
;
700 texture_level
= dst_sub_resource_idx
% dst_texture
->level_count
;
701 if (!wined3d_texture_load_location(dst_texture
, dst_sub_resource_idx
, context
, map_binding
))
702 ERR("Failed to load the destination sub-resource into %s.\n", wined3d_debug_location(map_binding
));
704 wined3d_texture_invalidate_location(dst_texture
, dst_sub_resource_idx
, ~map_binding
);
705 wined3d_texture_get_pitch(dst_texture
, texture_level
, &dst_map
.row_pitch
, &dst_map
.slice_pitch
);
706 wined3d_texture_get_bo_address(dst_texture
, dst_sub_resource_idx
, &dst_data
, map_binding
);
707 dst_map
.data
= wined3d_context_map_bo_address(context
, &dst_data
,
708 dst_texture
->sub_resources
[dst_sub_resource_idx
].size
, WINED3D_MAP_WRITE
);
711 src_fmt_attrs
= src_format
->attrs
;
712 dst_fmt_attrs
= dst_format
->attrs
;
713 flags
&= ~WINED3D_BLT_RAW
;
715 bpp
= dst_format
->byte_count
;
716 row_byte_count
= dst_width
* bpp
;
718 sbase
= (BYTE
*)src_map
.data
719 + ((src_box
->top
/ src_format
->block_height
) * src_map
.row_pitch
)
720 + ((src_box
->left
/ src_format
->block_width
) * src_format
->block_byte_count
);
721 dbuf
= (BYTE
*)dst_map
.data
722 + ((dst_box
->top
/ dst_format
->block_height
) * dst_map
.row_pitch
)
723 + ((dst_box
->left
/ dst_format
->block_width
) * dst_format
->block_byte_count
);
725 if (src_fmt_attrs
& dst_fmt_attrs
& WINED3D_FORMAT_ATTR_BLOCKS
)
727 TRACE("%s -> %s copy.\n", debug_d3dformat(src_format
->id
), debug_d3dformat(dst_format
->id
));
729 if (same_sub_resource
)
731 FIXME("Only plain blits supported on compressed surfaces.\n");
736 hr
= surface_cpu_blt_compressed(sbase
, dbuf
,
737 src_map
.row_pitch
, dst_map
.row_pitch
, dst_width
, dst_height
,
738 src_format
, flags
, fx
);
742 if ((src_fmt_attrs
| dst_fmt_attrs
) & WINED3D_FORMAT_ATTR_HEIGHT_SCALE
)
744 FIXME("Unsupported blit between height-scaled formats (src %s, dst %s).\n",
745 debug_d3dformat(src_format
->id
), debug_d3dformat(dst_format
->id
));
750 if (filter
!= WINED3D_TEXF_NONE
&& filter
!= WINED3D_TEXF_POINT
751 && (src_width
!= dst_width
|| src_height
!= dst_height
))
753 /* Can happen when d3d9 apps do a StretchRect() call which isn't handled in GL. */
754 FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(filter
));
757 xinc
= (src_width
<< 16) / dst_width
;
758 yinc
= (src_height
<< 16) / dst_height
;
762 /* No effects, we can cheat here. */
763 if (dst_width
== src_width
)
765 if (dst_height
== src_height
)
767 /* No stretching in either direction. This needs to be as fast
771 /* Check for overlapping surfaces. */
772 if (!same_sub_resource
|| dst_box
->top
< src_box
->top
773 || dst_box
->right
<= src_box
->left
|| src_box
->right
<= dst_box
->left
)
775 /* No overlap, or dst above src, so copy from top downwards. */
776 for (y
= 0; y
< dst_height
; ++y
)
778 memcpy(dbuf
, sbuf
, row_byte_count
);
779 sbuf
+= src_map
.row_pitch
;
780 dbuf
+= dst_map
.row_pitch
;
783 else if (dst_box
->top
> src_box
->top
)
785 /* Copy from bottom upwards. */
786 sbuf
+= src_map
.row_pitch
* dst_height
;
787 dbuf
+= dst_map
.row_pitch
* dst_height
;
788 for (y
= 0; y
< dst_height
; ++y
)
790 sbuf
-= src_map
.row_pitch
;
791 dbuf
-= dst_map
.row_pitch
;
792 memcpy(dbuf
, sbuf
, row_byte_count
);
797 /* Src and dst overlapping on the same line, use memmove. */
798 for (y
= 0; y
< dst_height
; ++y
)
800 memmove(dbuf
, sbuf
, row_byte_count
);
801 sbuf
+= src_map
.row_pitch
;
802 dbuf
+= dst_map
.row_pitch
;
808 /* Stretching in y direction only. */
809 for (y
= sy
= 0; y
< dst_height
; ++y
, sy
+= yinc
)
811 sbuf
= sbase
+ (sy
>> 16) * src_map
.row_pitch
;
812 memcpy(dbuf
, sbuf
, row_byte_count
);
813 dbuf
+= dst_map
.row_pitch
;
819 /* Stretching in X direction. */
820 unsigned int last_sy
= ~0u;
821 for (y
= sy
= 0; y
< dst_height
; ++y
, sy
+= yinc
)
823 sbuf
= sbase
+ (sy
>> 16) * src_map
.row_pitch
;
825 if ((sy
>> 16) == (last_sy
>> 16))
827 /* This source row is the same as last source row -
828 * Copy the already stretched row. */
829 memcpy(dbuf
, dbuf
- dst_map
.row_pitch
, row_byte_count
);
833 #define STRETCH_ROW(type) \
835 const type *s = (const type *)sbuf; \
836 type *d = (type *)dbuf; \
837 for (x = sx = 0; x < dst_width; ++x, sx += xinc) \
838 d[x] = s[sx >> 16]; \
856 for (x
= sx
= 0; x
< dst_width
; x
++, sx
+= xinc
)
860 s
= sbuf
+ 3 * (sx
>> 16);
861 pixel
= s
[0] | (s
[1] << 8) | (s
[2] << 16);
862 d
[0] = (pixel
) & 0xff;
863 d
[1] = (pixel
>> 8) & 0xff;
864 d
[2] = (pixel
>> 16) & 0xff;
870 FIXME("Stretched blit not implemented for bpp %u.\n", bpp
* 8);
871 hr
= WINED3DERR_NOTAVAILABLE
;
876 dbuf
+= dst_map
.row_pitch
;
883 LONG dstyinc
= dst_map
.row_pitch
, dstxinc
= bpp
;
884 DWORD keylow
= 0xffffffff, keyhigh
= 0, keymask
= 0xffffffff;
885 DWORD destkeylow
= 0x0, destkeyhigh
= 0xffffffff, destkeymask
= 0xffffffff;
886 if (flags
& (WINED3D_BLT_SRC_CKEY
| WINED3D_BLT_DST_CKEY
887 | WINED3D_BLT_SRC_CKEY_OVERRIDE
| WINED3D_BLT_DST_CKEY_OVERRIDE
))
889 /* The color keying flags are checked for correctness in ddraw. */
890 if (flags
& WINED3D_BLT_SRC_CKEY
)
892 keylow
= src_texture
->async
.src_blt_color_key
.color_space_low_value
;
893 keyhigh
= src_texture
->async
.src_blt_color_key
.color_space_high_value
;
895 else if (flags
& WINED3D_BLT_SRC_CKEY_OVERRIDE
)
897 keylow
= fx
->src_color_key
.color_space_low_value
;
898 keyhigh
= fx
->src_color_key
.color_space_high_value
;
901 if (flags
& WINED3D_BLT_DST_CKEY
)
903 /* Destination color keys are taken from the source surface! */
904 destkeylow
= src_texture
->async
.dst_blt_color_key
.color_space_low_value
;
905 destkeyhigh
= src_texture
->async
.dst_blt_color_key
.color_space_high_value
;
907 else if (flags
& WINED3D_BLT_DST_CKEY_OVERRIDE
)
909 destkeylow
= fx
->dst_color_key
.color_space_low_value
;
910 destkeyhigh
= fx
->dst_color_key
.color_space_high_value
;
920 get_color_masks(src_format
, masks
);
921 keymask
= masks
[0] | masks
[1] | masks
[2];
923 flags
&= ~(WINED3D_BLT_SRC_CKEY
| WINED3D_BLT_DST_CKEY
924 | WINED3D_BLT_SRC_CKEY_OVERRIDE
| WINED3D_BLT_DST_CKEY_OVERRIDE
);
927 if (flags
& WINED3D_BLT_FX
)
929 BYTE
*dTopLeft
, *dTopRight
, *dBottomLeft
, *dBottomRight
, *tmp
;
932 dTopRight
= dbuf
+ ((dst_width
- 1) * bpp
);
933 dBottomLeft
= dTopLeft
+ ((dst_height
- 1) * dst_map
.row_pitch
);
934 dBottomRight
= dBottomLeft
+ ((dst_width
- 1) * bpp
);
936 if (fx
->fx
& WINEDDBLTFX_ARITHSTRETCHY
)
938 /* I don't think we need to do anything about this flag. */
939 WARN("Nothing done for WINEDDBLTFX_ARITHSTRETCHY.\n");
941 if (fx
->fx
& WINEDDBLTFX_MIRRORLEFTRIGHT
)
944 dTopRight
= dTopLeft
;
947 dBottomRight
= dBottomLeft
;
949 dstxinc
= dstxinc
* -1;
951 if (fx
->fx
& WINEDDBLTFX_MIRRORUPDOWN
)
954 dTopLeft
= dBottomLeft
;
957 dTopRight
= dBottomRight
;
959 dstyinc
= dstyinc
* -1;
961 if (fx
->fx
& WINEDDBLTFX_NOTEARING
)
963 /* I don't think we need to do anything about this flag. */
964 WARN("Nothing done for WINEDDBLTFX_NOTEARING.\n");
966 if (fx
->fx
& WINEDDBLTFX_ROTATE180
)
969 dBottomRight
= dTopLeft
;
972 dBottomLeft
= dTopRight
;
974 dstxinc
= dstxinc
* -1;
975 dstyinc
= dstyinc
* -1;
977 if (fx
->fx
& WINEDDBLTFX_ROTATE270
)
980 dTopLeft
= dBottomLeft
;
981 dBottomLeft
= dBottomRight
;
982 dBottomRight
= dTopRight
;
987 dstxinc
= dstxinc
* -1;
989 if (fx
->fx
& WINEDDBLTFX_ROTATE90
)
992 dTopLeft
= dTopRight
;
993 dTopRight
= dBottomRight
;
994 dBottomRight
= dBottomLeft
;
999 dstyinc
= dstyinc
* -1;
1001 if (fx
->fx
& WINEDDBLTFX_ZBUFFERBASEDEST
)
1003 /* I don't think we need to do anything about this flag. */
1004 WARN("Nothing done for WINEDDBLTFX_ZBUFFERBASEDEST.\n");
1007 flags
&= ~(WINED3D_BLT_FX
);
1010 #define COPY_COLORKEY_FX(type) \
1013 type *d = (type *)dbuf, *dx, tmp; \
1014 for (y = sy = 0; y < dst_height; ++y, sy += yinc) \
1016 s = (const type *)(sbase + (sy >> 16) * src_map.row_pitch); \
1018 for (x = sx = 0; x < dst_width; ++x, sx += xinc) \
1020 tmp = s[sx >> 16]; \
1021 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) \
1022 && ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) \
1026 dx = (type *)(((BYTE *)dx) + dstxinc); \
1028 d = (type *)(((BYTE *)d) + dstyinc); \
1035 COPY_COLORKEY_FX(BYTE
);
1038 COPY_COLORKEY_FX(WORD
);
1041 COPY_COLORKEY_FX(DWORD
);
1046 BYTE
*d
= dbuf
, *dx
;
1047 for (y
= sy
= 0; y
< dst_height
; ++y
, sy
+= yinc
)
1049 sbuf
= sbase
+ (sy
>> 16) * src_map
.row_pitch
;
1051 for (x
= sx
= 0; x
< dst_width
; ++x
, sx
+= xinc
)
1053 DWORD pixel
, dpixel
= 0;
1054 s
= sbuf
+ 3 * (sx
>>16);
1055 pixel
= s
[0] | (s
[1] << 8) | (s
[2] << 16);
1056 dpixel
= dx
[0] | (dx
[1] << 8 ) | (dx
[2] << 16);
1057 if (((pixel
& keymask
) < keylow
|| (pixel
& keymask
) > keyhigh
)
1058 && ((dpixel
& keymask
) >= destkeylow
|| (dpixel
& keymask
) <= keyhigh
))
1060 dx
[0] = (pixel
) & 0xff;
1061 dx
[1] = (pixel
>> 8) & 0xff;
1062 dx
[2] = (pixel
>> 16) & 0xff;
1071 FIXME("%s color-keyed blit not implemented for bpp %u.\n",
1072 (flags
& WINED3D_BLT_SRC_CKEY
) ? "Source" : "Destination", bpp
* 8);
1073 hr
= WINED3DERR_NOTAVAILABLE
;
1075 #undef COPY_COLORKEY_FX
1081 FIXME(" Unsupported flags %#x.\n", flags
);
1084 if (upload
&& hr
== WINED3D_OK
)
1086 struct wined3d_bo_address data
;
1088 data
.buffer_object
= 0;
1089 data
.addr
= dst_map
.data
;
1091 texture_level
= dst_sub_resource_idx
% dst_texture
->level_count
;
1093 wined3d_texture_prepare_location(dst_texture
, texture_level
, context
, WINED3D_LOCATION_TEXTURE_RGB
);
1094 dst_texture
->texture_ops
->texture_upload_data(context
, wined3d_const_bo_address(&data
), dst_format
,
1095 dst_box
, dst_map
.row_pitch
, dst_map
.slice_pitch
, dst_texture
, texture_level
,
1096 WINED3D_LOCATION_TEXTURE_RGB
, dst_box
->left
, dst_box
->top
, 0);
1098 wined3d_texture_validate_location(dst_texture
, texture_level
, WINED3D_LOCATION_TEXTURE_RGB
);
1099 wined3d_texture_invalidate_location(dst_texture
, texture_level
, ~WINED3D_LOCATION_TEXTURE_RGB
);
1108 wined3d_context_unmap_bo_address(context
, &dst_data
, 1, &dst_range
);
1111 if (!same_sub_resource
)
1112 wined3d_context_unmap_bo_address(context
, &src_data
, 0, NULL
);
1113 if (SUCCEEDED(hr
) && dst_texture
->swapchain
&& dst_texture
->swapchain
->front_buffer
== dst_texture
)
1115 SetRect(&dst_texture
->swapchain
->front_buffer_update
,
1116 dst_box
->left
, dst_box
->top
, dst_box
->right
, dst_box
->bottom
);
1117 dst_texture
->swapchain
->swapchain_ops
->swapchain_frontbuffer_updated(dst_texture
->swapchain
);
1119 if (converted_texture
)
1120 wined3d_texture_decref(converted_texture
);
1121 context_release(context
);
1126 static void surface_cpu_blt_colour_fill(struct wined3d_rendertarget_view
*view
,
1127 const struct wined3d_box
*box
, const struct wined3d_color
*colour
)
1129 struct wined3d_device
*device
= view
->resource
->device
;
1130 struct wined3d_context
*context
;
1131 struct wined3d_texture
*texture
;
1132 struct wined3d_bo_address data
;
1133 struct wined3d_box level_box
;
1134 struct wined3d_map_desc map
;
1135 struct wined3d_range range
;
1136 bool full_subresource
;
1140 TRACE("view %p, box %s, colour %s.\n", view
, debug_box(box
), debug_color(colour
));
1142 if (view
->format_attrs
& WINED3D_FORMAT_ATTR_BLOCKS
)
1144 FIXME("Not implemented for format %s.\n", debug_d3dformat(view
->format
->id
));
1148 if (view
->format
->id
!= view
->resource
->format
->id
)
1149 FIXME("View format %s doesn't match resource format %s.\n",
1150 debug_d3dformat(view
->format
->id
), debug_d3dformat(view
->resource
->format
->id
));
1152 if (view
->resource
->type
== WINED3D_RTYPE_BUFFER
)
1154 FIXME("Not implemented for buffers.\n");
1158 context
= context_acquire(device
, NULL
, 0);
1160 texture
= texture_from_resource(view
->resource
);
1161 level
= view
->sub_resource_idx
% texture
->level_count
;
1162 wined3d_texture_get_level_box(texture_from_resource(view
->resource
), level
, &level_box
);
1163 full_subresource
= !memcmp(box
, &level_box
, sizeof(*box
));
1165 map_binding
= texture
->resource
.map_binding
;
1166 if (!wined3d_texture_load_location(texture
, view
->sub_resource_idx
, context
, map_binding
))
1167 ERR("Failed to load the sub-resource into %s.\n", wined3d_debug_location(map_binding
));
1168 wined3d_texture_invalidate_location(texture
, view
->sub_resource_idx
, ~map_binding
);
1169 wined3d_texture_get_pitch(texture
, level
, &map
.row_pitch
, &map
.slice_pitch
);
1170 wined3d_texture_get_bo_address(texture
, view
->sub_resource_idx
, &data
, map_binding
);
1171 map
.data
= wined3d_context_map_bo_address(context
, &data
,
1172 texture
->sub_resources
[view
->sub_resource_idx
].size
, WINED3D_MAP_WRITE
);
1174 range
.size
= texture
->sub_resources
[view
->sub_resource_idx
].size
;
1176 wined3d_resource_memory_colour_fill(view
->resource
, &map
, colour
, box
, full_subresource
);
1178 wined3d_context_unmap_bo_address(context
, &data
, 1, &range
);
1179 context_release(context
);
1182 static bool wined3d_box_intersect(struct wined3d_box
*ret
, const struct wined3d_box
*b1
,
1183 const struct wined3d_box
*b2
)
1185 wined3d_box_set(ret
, max(b1
->left
, b2
->left
), max(b1
->top
, b2
->top
),
1186 min(b1
->right
, b2
->right
), min(b1
->bottom
, b2
->bottom
),
1187 max(b1
->front
, b2
->front
), min(b1
->back
, b2
->back
));
1188 return ret
->right
> ret
->left
&& ret
->bottom
> ret
->top
&& ret
->back
> ret
->front
;
1191 static void cpu_blitter_clear(struct wined3d_blitter
*blitter
, struct wined3d_device
*device
,
1192 unsigned int rt_count
, const struct wined3d_fb_state
*fb
, unsigned int rect_count
, const RECT
*clear_rects
,
1193 const RECT
*draw_rect
, uint32_t flags
, const struct wined3d_color
*colour
, float depth
, unsigned int stencil
)
1195 struct wined3d_color c
= {depth
, 0.0f
, 0.0f
, 0.0f
};
1196 struct wined3d_box box
, box_clip
, box_view
;
1197 struct wined3d_rendertarget_view
*view
;
1203 clear_rects
= draw_rect
;
1206 for (i
= 0; i
< rect_count
; ++i
)
1208 box
.left
= max(clear_rects
[i
].left
, draw_rect
->left
);
1209 box
.top
= max(clear_rects
[i
].top
, draw_rect
->top
);
1210 box
.right
= min(clear_rects
[i
].right
, draw_rect
->right
);
1211 box
.bottom
= min(clear_rects
[i
].bottom
, draw_rect
->bottom
);
1215 if (box
.left
>= box
.right
|| box
.top
>= box
.bottom
)
1218 if (flags
& WINED3DCLEAR_TARGET
)
1220 for (j
= 0; j
< rt_count
; ++j
)
1222 if ((view
= fb
->render_targets
[j
]))
1224 wined3d_rendertarget_view_get_box(view
, &box_view
);
1225 if (wined3d_box_intersect(&box_clip
, &box_view
, &box
))
1226 surface_cpu_blt_colour_fill(view
, &box_clip
, colour
);
1231 if ((flags
& (WINED3DCLEAR_ZBUFFER
| WINED3DCLEAR_STENCIL
)) && (view
= fb
->depth_stencil
))
1233 if ((view
->format
->depth_size
&& !(flags
& WINED3DCLEAR_ZBUFFER
))
1234 || (view
->format
->stencil_size
&& !(flags
& WINED3DCLEAR_STENCIL
)))
1235 FIXME("Clearing %#x on %s.\n", flags
, debug_d3dformat(view
->format
->id
));
1237 wined3d_rendertarget_view_get_box(view
, &box_view
);
1238 if (wined3d_box_intersect(&box_clip
, &box_view
, &box
))
1239 surface_cpu_blt_colour_fill(view
, &box_clip
, &c
);
1244 static DWORD
cpu_blitter_blit(struct wined3d_blitter
*blitter
, enum wined3d_blit_op op
,
1245 struct wined3d_context
*context
, struct wined3d_texture
*src_texture
, unsigned int src_sub_resource_idx
,
1246 DWORD src_location
, const RECT
*src_rect
, struct wined3d_texture
*dst_texture
,
1247 unsigned int dst_sub_resource_idx
, DWORD dst_location
, const RECT
*dst_rect
,
1248 const struct wined3d_color_key
*color_key
, enum wined3d_texture_filter_type filter
,
1249 const struct wined3d_format
*resolve_format
)
1251 struct wined3d_box dst_box
= {dst_rect
->left
, dst_rect
->top
, dst_rect
->right
, dst_rect
->bottom
, 0, 1};
1252 struct wined3d_box src_box
= {src_rect
->left
, src_rect
->top
, src_rect
->right
, src_rect
->bottom
, 0, 1};
1253 struct wined3d_blt_fx fx
;
1256 memset(&fx
, 0, sizeof(fx
));
1259 case WINED3D_BLIT_OP_COLOR_BLIT
:
1260 case WINED3D_BLIT_OP_DEPTH_BLIT
:
1262 case WINED3D_BLIT_OP_RAW_BLIT
:
1263 flags
|= WINED3D_BLT_RAW
;
1265 case WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST
:
1266 flags
|= WINED3D_BLT_ALPHA_TEST
;
1268 case WINED3D_BLIT_OP_COLOR_BLIT_CKEY
:
1269 flags
|= WINED3D_BLT_SRC_CKEY_OVERRIDE
| WINED3D_BLT_FX
;
1270 fx
.src_color_key
= *color_key
;
1273 FIXME("Unhandled op %#x.\n", op
);
1277 if (FAILED(surface_cpu_blt(dst_texture
, dst_sub_resource_idx
, &dst_box
,
1278 src_texture
, src_sub_resource_idx
, &src_box
, flags
, &fx
, filter
)))
1279 ERR("Failed to blit.\n");
1280 wined3d_texture_load_location(dst_texture
, dst_sub_resource_idx
, context
, dst_location
);
1282 return dst_location
| (dst_texture
->sub_resources
[dst_sub_resource_idx
].locations
1283 & dst_texture
->resource
.map_binding
);
1286 static const struct wined3d_blitter_ops cpu_blitter_ops
=
1288 cpu_blitter_destroy
,
1293 struct wined3d_blitter
*wined3d_cpu_blitter_create(void)
1295 struct wined3d_blitter
*blitter
;
1297 if (!(blitter
= malloc(sizeof(*blitter
))))
1300 TRACE("Created blitter %p.\n", blitter
);
1302 blitter
->ops
= &cpu_blitter_ops
;
1303 blitter
->next
= NULL
;
1308 static bool wined3d_is_colour_blit(enum wined3d_blit_op blit_op
)
1312 case WINED3D_BLIT_OP_COLOR_BLIT
:
1313 case WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST
:
1314 case WINED3D_BLIT_OP_COLOR_BLIT_CKEY
:
1322 static bool sub_resource_is_on_cpu(const struct wined3d_texture
*texture
, unsigned int sub_resource_idx
)
1324 DWORD locations
= texture
->sub_resources
[sub_resource_idx
].locations
;
1326 if (locations
& (WINED3D_LOCATION_BUFFER
| WINED3D_LOCATION_SYSMEM
))
1329 if (!(texture
->resource
.access
& WINED3D_RESOURCE_ACCESS_GPU
) && (locations
& WINED3D_LOCATION_CLEARED
))
1335 HRESULT
texture2d_blt(struct wined3d_texture
*dst_texture
, unsigned int dst_sub_resource_idx
,
1336 const struct wined3d_box
*dst_box
, struct wined3d_texture
*src_texture
, unsigned int src_sub_resource_idx
,
1337 const struct wined3d_box
*src_box
, uint32_t flags
, const struct wined3d_blt_fx
*fx
,
1338 enum wined3d_texture_filter_type filter
)
1340 struct wined3d_texture_sub_resource
*src_sub_resource
, *dst_sub_resource
;
1341 struct wined3d_device
*device
= dst_texture
->resource
.device
;
1342 struct wined3d_swapchain
*src_swapchain
, *dst_swapchain
;
1343 BOOL scale
, convert
, resolve
, resolve_typeless
= FALSE
;
1344 const struct wined3d_format
*resolve_format
= NULL
;
1345 const struct wined3d_color_key
*colour_key
= NULL
;
1346 DWORD src_location
, dst_location
, valid_locations
;
1347 struct wined3d_context
*context
;
1348 enum wined3d_blit_op blit_op
;
1349 RECT src_rect
, dst_rect
;
1350 bool src_ds
, dst_ds
;
1352 static const DWORD simple_blit
= WINED3D_BLT_SRC_CKEY
1353 | WINED3D_BLT_SRC_CKEY_OVERRIDE
1354 | WINED3D_BLT_ALPHA_TEST
1357 TRACE("dst_texture %p, dst_sub_resource_idx %u, dst_box %s, src_texture %p, "
1358 "src_sub_resource_idx %u, src_box %s, flags %#x, fx %p, filter %s.\n",
1359 dst_texture
, dst_sub_resource_idx
, debug_box(dst_box
), src_texture
, src_sub_resource_idx
,
1360 debug_box(src_box
), flags
, fx
, debug_d3dtexturefiltertype(filter
));
1361 TRACE("Usage is %s.\n", debug_d3dusage(dst_texture
->resource
.usage
));
1365 TRACE("fx %#x.\n", fx
->fx
);
1366 TRACE("dst_color_key {0x%08x, 0x%08x}.\n",
1367 fx
->dst_color_key
.color_space_low_value
,
1368 fx
->dst_color_key
.color_space_high_value
);
1369 TRACE("src_color_key {0x%08x, 0x%08x}.\n",
1370 fx
->src_color_key
.color_space_low_value
,
1371 fx
->src_color_key
.color_space_high_value
);
1372 TRACE("resolve_format_id %s.\n", debug_d3dformat(fx
->resolve_format_id
));
1374 if (fx
->resolve_format_id
!= WINED3DFMT_UNKNOWN
)
1375 resolve_format
= wined3d_get_format(device
->adapter
, fx
->resolve_format_id
, 0);
1378 dst_sub_resource
= &dst_texture
->sub_resources
[dst_sub_resource_idx
];
1379 src_sub_resource
= &src_texture
->sub_resources
[src_sub_resource_idx
];
1381 if (src_sub_resource
->locations
& WINED3D_LOCATION_DISCARDED
)
1383 WARN("Source sub-resource is discarded, nothing to do.\n");
1387 SetRect(&src_rect
, src_box
->left
, src_box
->top
, src_box
->right
, src_box
->bottom
);
1388 SetRect(&dst_rect
, dst_box
->left
, dst_box
->top
, dst_box
->right
, dst_box
->bottom
);
1390 if (!fx
|| !(fx
->fx
))
1391 flags
&= ~WINED3D_BLT_FX
;
1393 /* WINED3D_BLT_DO_NOT_WAIT appeared in DX7. */
1394 if (flags
& WINED3D_BLT_DO_NOT_WAIT
)
1396 static unsigned int once
;
1399 FIXME("Can't handle WINED3D_BLT_DO_NOT_WAIT flag.\n");
1402 flags
&= ~(WINED3D_BLT_SYNCHRONOUS
| WINED3D_BLT_DO_NOT_WAIT
| WINED3D_BLT_WAIT
);
1404 if (flags
& ~simple_blit
)
1406 WARN_(d3d_perf
)("Using CPU fallback for complex blit (%#x).\n", flags
);
1410 src_swapchain
= src_texture
->swapchain
;
1411 dst_swapchain
= dst_texture
->swapchain
;
1413 if (src_swapchain
&& dst_swapchain
&& src_swapchain
!= dst_swapchain
1414 && src_texture
== src_swapchain
->front_buffer
)
1416 /* TODO: We could support cross-swapchain blits by first downloading
1417 * the source to a texture. */
1418 FIXME("Cross-swapchain blit not supported.\n");
1419 return WINED3DERR_INVALIDCALL
;
1422 scale
= src_box
->right
- src_box
->left
!= dst_box
->right
- dst_box
->left
1423 || src_box
->bottom
- src_box
->top
!= dst_box
->bottom
- dst_box
->top
;
1424 convert
= src_texture
->resource
.format
->id
!= dst_texture
->resource
.format
->id
;
1425 resolve
= src_texture
->resource
.multisample_type
!= dst_texture
->resource
.multisample_type
;
1428 resolve_typeless
= (wined3d_format_is_typeless(src_texture
->resource
.format
)
1429 || wined3d_format_is_typeless(dst_texture
->resource
.format
))
1430 && (src_texture
->resource
.format
->typeless_id
== dst_texture
->resource
.format
->typeless_id
);
1431 if (resolve_typeless
&& !resolve_format
)
1432 WARN("Resolve format for typeless resolve not specified.\n");
1435 dst_ds
= dst_texture
->resource
.format
->depth_size
|| dst_texture
->resource
.format
->stencil_size
;
1436 src_ds
= src_texture
->resource
.format
->depth_size
|| src_texture
->resource
.format
->stencil_size
;
1438 if (src_ds
|| dst_ds
)
1440 TRACE("Depth/stencil blit.\n");
1442 if (dst_texture
->resource
.access
& WINED3D_RESOURCE_ACCESS_GPU
)
1443 dst_location
= dst_texture
->resource
.draw_binding
;
1445 dst_location
= dst_texture
->resource
.map_binding
;
1447 if ((flags
& WINED3D_BLT_RAW
) || (!scale
&& !convert
&& !resolve
))
1448 blit_op
= WINED3D_BLIT_OP_RAW_BLIT
;
1450 blit_op
= WINED3D_BLIT_OP_DEPTH_BLIT
;
1452 context
= context_acquire(device
, dst_texture
, dst_sub_resource_idx
);
1453 valid_locations
= device
->blitter
->ops
->blitter_blit(device
->blitter
, blit_op
, context
,
1454 src_texture
, src_sub_resource_idx
, src_texture
->resource
.draw_binding
, &src_rect
,
1455 dst_texture
, dst_sub_resource_idx
, dst_location
, &dst_rect
, NULL
, filter
, resolve_format
);
1456 context_release(context
);
1458 wined3d_texture_validate_location(dst_texture
, dst_sub_resource_idx
, valid_locations
);
1459 wined3d_texture_invalidate_location(dst_texture
, dst_sub_resource_idx
, ~valid_locations
);
1464 TRACE("Colour blit.\n");
1466 /* In principle this would apply to depth blits as well, but we don't
1467 * implement those in the CPU blitter at the moment. */
1468 if ((dst_sub_resource
->locations
& dst_texture
->resource
.map_binding
)
1469 && (src_sub_resource
->locations
& src_texture
->resource
.map_binding
))
1472 TRACE("Not doing sysmem blit because of scaling.\n");
1474 TRACE("Not doing sysmem blit because of format conversion.\n");
1479 blit_op
= WINED3D_BLIT_OP_COLOR_BLIT
;
1480 if (flags
& WINED3D_BLT_SRC_CKEY_OVERRIDE
)
1482 colour_key
= &fx
->src_color_key
;
1483 blit_op
= WINED3D_BLIT_OP_COLOR_BLIT_CKEY
;
1485 else if (flags
& WINED3D_BLT_SRC_CKEY
)
1487 colour_key
= &src_texture
->async
.src_blt_color_key
;
1488 blit_op
= WINED3D_BLIT_OP_COLOR_BLIT_CKEY
;
1490 else if (flags
& WINED3D_BLT_ALPHA_TEST
)
1492 blit_op
= WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST
;
1494 else if (sub_resource_is_on_cpu(src_texture
, src_sub_resource_idx
)
1495 && !sub_resource_is_on_cpu(dst_texture
, dst_sub_resource_idx
)
1496 && (dst_texture
->resource
.access
& WINED3D_RESOURCE_ACCESS_GPU
))
1500 TRACE("Not doing upload because of scaling.\n");
1502 TRACE("Not doing upload because of format conversion.\n");
1503 else if (dst_texture
->resource
.format
->conv_byte_count
)
1504 TRACE("Not doing upload because the destination format needs conversion.\n");
1507 wined3d_texture_upload_from_texture(dst_texture
, dst_sub_resource_idx
, dst_box
->left
,
1508 dst_box
->top
, dst_box
->front
, src_texture
, src_sub_resource_idx
, src_box
);
1509 if (!wined3d_resource_is_offscreen(&dst_texture
->resource
))
1511 context
= context_acquire(device
, dst_texture
, dst_sub_resource_idx
);
1512 wined3d_texture_load_location(dst_texture
, dst_sub_resource_idx
,
1513 context
, dst_texture
->resource
.draw_binding
);
1514 context_release(context
);
1519 else if (!sub_resource_is_on_cpu(src_texture
, src_sub_resource_idx
)
1520 && (dst_sub_resource
->locations
& dst_texture
->resource
.map_binding
)
1521 && !(dst_texture
->resource
.access
& WINED3D_RESOURCE_ACCESS_GPU
))
1525 TRACE("Not doing download because of scaling.\n");
1527 TRACE("Not doing download because of format conversion.\n");
1528 else if (src_texture
->resource
.format
->conv_byte_count
)
1529 TRACE("Not doing download because the source format needs conversion.\n");
1530 else if (!(src_texture
->flags
& WINED3D_TEXTURE_DOWNLOADABLE
))
1531 TRACE("Not doing download because texture is not downloadable.\n");
1532 else if (!wined3d_texture_is_full_rect(src_texture
, src_sub_resource_idx
% src_texture
->level_count
, &src_rect
))
1533 TRACE("Not doing download because of partial download (src).\n");
1534 else if (!wined3d_texture_is_full_rect(dst_texture
, dst_sub_resource_idx
% dst_texture
->level_count
, &dst_rect
))
1535 TRACE("Not doing download because of partial download (dst).\n");
1538 wined3d_texture_download_from_texture(dst_texture
, dst_sub_resource_idx
, src_texture
,
1539 src_sub_resource_idx
);
1543 else if (dst_swapchain
&& dst_swapchain
->back_buffers
1544 && dst_texture
== dst_swapchain
->front_buffer
1545 && src_texture
== dst_swapchain
->back_buffers
[0])
1547 /* Use present for back -> front blits. The idea behind this is that
1548 * present is potentially faster than a blit, in particular when FBO
1549 * blits aren't available. Some ddraw applications like Half-Life and
1550 * Prince of Persia 3D use Blt() from the backbuffer to the
1551 * frontbuffer instead of doing a Flip(). D3d8 and d3d9 applications
1552 * can't blit directly to the frontbuffer. */
1553 enum wined3d_swap_effect swap_effect
= dst_swapchain
->state
.desc
.swap_effect
;
1555 TRACE("Using present for backbuffer -> frontbuffer blit.\n");
1557 /* Set the swap effect to COPY, we don't want the backbuffer to become
1559 dst_swapchain
->state
.desc
.swap_effect
= WINED3D_SWAP_EFFECT_COPY
;
1560 wined3d_swapchain_present(dst_swapchain
, NULL
, NULL
,
1561 dst_swapchain
->win_handle
, dst_swapchain
->swap_interval
, 0);
1562 dst_swapchain
->state
.desc
.swap_effect
= swap_effect
;
1567 if ((flags
& WINED3D_BLT_RAW
) || (blit_op
== WINED3D_BLIT_OP_COLOR_BLIT
&& !scale
&& !convert
&& !resolve
))
1568 blit_op
= WINED3D_BLIT_OP_RAW_BLIT
;
1570 context
= context_acquire(device
, dst_texture
, dst_sub_resource_idx
);
1572 if (src_texture
->resource
.multisample_type
!= WINED3D_MULTISAMPLE_NONE
&& !resolve_typeless
1573 && ((scale
&& !context
->d3d_info
->scaled_resolve
)
1574 || convert
|| !wined3d_is_colour_blit(blit_op
)))
1575 src_location
= WINED3D_LOCATION_RB_RESOLVED
;
1577 src_location
= src_texture
->resource
.draw_binding
;
1579 if (!(dst_texture
->resource
.access
& WINED3D_RESOURCE_ACCESS_GPU
))
1580 dst_location
= dst_texture
->resource
.map_binding
;
1581 else if (dst_texture
->resource
.multisample_type
!= WINED3D_MULTISAMPLE_NONE
1582 && (scale
|| convert
|| !wined3d_is_colour_blit(blit_op
)))
1583 dst_location
= WINED3D_LOCATION_RB_RESOLVED
;
1585 dst_location
= dst_texture
->resource
.draw_binding
;
1587 valid_locations
= device
->blitter
->ops
->blitter_blit(device
->blitter
, blit_op
, context
,
1588 src_texture
, src_sub_resource_idx
, src_location
, &src_rect
,
1589 dst_texture
, dst_sub_resource_idx
, dst_location
, &dst_rect
, colour_key
, filter
, resolve_format
);
1591 context_release(context
);
1593 wined3d_texture_validate_location(dst_texture
, dst_sub_resource_idx
, valid_locations
);
1594 wined3d_texture_invalidate_location(dst_texture
, dst_sub_resource_idx
, ~valid_locations
);
1599 return surface_cpu_blt(dst_texture
, dst_sub_resource_idx
, dst_box
,
1600 src_texture
, src_sub_resource_idx
, src_box
, flags
, fx
, filter
);