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"
31 WINE_DEFAULT_DEBUG_CHANNEL(d3d
);
32 WINE_DECLARE_DEBUG_CHANNEL(d3d_perf
);
34 /* Works correctly only for <= 4 bpp formats. */
35 static void get_color_masks(const struct wined3d_format
*format
, uint32_t *masks
)
37 masks
[0] = wined3d_mask_from_size(format
->red_size
) << format
->red_offset
;
38 masks
[1] = wined3d_mask_from_size(format
->green_size
) << format
->green_offset
;
39 masks
[2] = wined3d_mask_from_size(format
->blue_size
) << format
->blue_offset
;
42 static void convert_r32_float_r16_float(const BYTE
*src
, BYTE
*dst
,
43 unsigned int pitch_in
, unsigned int pitch_out
, unsigned int w
, unsigned int h
)
45 unsigned short *dst_s
;
49 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
51 for (y
= 0; y
< h
; ++y
)
53 src_f
= (const float *)(src
+ y
* pitch_in
);
54 dst_s
= (unsigned short *) (dst
+ y
* pitch_out
);
55 for (x
= 0; x
< w
; ++x
)
57 dst_s
[x
] = float_32_to_16(src_f
+ x
);
62 static void convert_r5g6b5_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
63 unsigned int pitch_in
, unsigned int pitch_out
, unsigned int w
, unsigned int h
)
65 static const unsigned char convert_5to8
[] =
67 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
68 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
69 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
70 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
72 static const unsigned char convert_6to8
[] =
74 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
75 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
76 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
77 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
78 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
79 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
80 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
81 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
85 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
87 for (y
= 0; y
< h
; ++y
)
89 const WORD
*src_line
= (const WORD
*)(src
+ y
* pitch_in
);
90 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
91 for (x
= 0; x
< w
; ++x
)
93 WORD pixel
= src_line
[x
];
94 dst_line
[x
] = 0xff000000u
95 | convert_5to8
[(pixel
& 0xf800u
) >> 11] << 16
96 | convert_6to8
[(pixel
& 0x07e0u
) >> 5] << 8
97 | convert_5to8
[(pixel
& 0x001fu
)];
102 /* We use this for both B8G8R8A8 -> B8G8R8X8 and B8G8R8X8 -> B8G8R8A8, since
103 * in both cases we're just setting the X / Alpha channel to 0xff. */
104 static void convert_a8r8g8b8_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
105 unsigned int pitch_in
, unsigned int pitch_out
, unsigned int w
, unsigned int h
)
109 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
111 for (y
= 0; y
< h
; ++y
)
113 const DWORD
*src_line
= (const DWORD
*)(src
+ y
* pitch_in
);
114 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
116 for (x
= 0; x
< w
; ++x
)
118 dst_line
[x
] = 0xff000000 | (src_line
[x
] & 0xffffff);
123 static inline BYTE
cliptobyte(int x
)
125 return (BYTE
)((x
< 0) ? 0 : ((x
> 255) ? 255 : x
));
128 static void convert_yuy2_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
129 unsigned int pitch_in
, unsigned int pitch_out
, unsigned int w
, unsigned int h
)
131 int c2
, d
, e
, r2
= 0, g2
= 0, b2
= 0;
134 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
136 for (y
= 0; y
< h
; ++y
)
138 const BYTE
*src_line
= src
+ y
* pitch_in
;
139 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
140 for (x
= 0; x
< w
; ++x
)
142 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
143 * C = Y - 16; D = U - 128; E = V - 128;
144 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
145 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
146 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
147 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
148 * U and V are shared between the pixels. */
149 if (!(x
& 1)) /* For every even pixel, read new U and V. */
151 d
= (int) src_line
[1] - 128;
152 e
= (int) src_line
[3] - 128;
154 g2
= - 100 * d
- 208 * e
+ 128;
157 c2
= 298 * ((int) src_line
[0] - 16);
158 dst_line
[x
] = 0xff000000
159 | cliptobyte((c2
+ r2
) >> 8) << 16 /* red */
160 | cliptobyte((c2
+ g2
) >> 8) << 8 /* green */
161 | cliptobyte((c2
+ b2
) >> 8); /* blue */
162 /* Scale RGB values to 0..255 range,
163 * then clip them if still not in range (may be negative),
164 * then shift them within DWORD if necessary. */
170 static void convert_yuy2_r5g6b5(const BYTE
*src
, BYTE
*dst
,
171 unsigned int pitch_in
, unsigned int pitch_out
, unsigned int w
, unsigned int h
)
174 int c2
, d
, e
, r2
= 0, g2
= 0, b2
= 0;
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 BYTE
*src_line
= src
+ y
* pitch_in
;
181 WORD
*dst_line
= (WORD
*)(dst
+ y
* pitch_out
);
182 for (x
= 0; x
< w
; ++x
)
184 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
185 * C = Y - 16; D = U - 128; E = V - 128;
186 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
187 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
188 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
189 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
190 * U and V are shared between the pixels. */
191 if (!(x
& 1)) /* For every even pixel, read new U and V. */
193 d
= (int) src_line
[1] - 128;
194 e
= (int) src_line
[3] - 128;
196 g2
= - 100 * d
- 208 * e
+ 128;
199 c2
= 298 * ((int) src_line
[0] - 16);
200 dst_line
[x
] = (cliptobyte((c2
+ r2
) >> 8) >> 3) << 11 /* red */
201 | (cliptobyte((c2
+ g2
) >> 8) >> 2) << 5 /* green */
202 | (cliptobyte((c2
+ b2
) >> 8) >> 3); /* blue */
203 /* Scale RGB values to 0..255 range,
204 * then clip them if still not in range (may be negative),
205 * then shift them within DWORD if necessary. */
211 struct d3dfmt_converter_desc
213 enum wined3d_format_id from
, to
;
214 void (*convert
)(const BYTE
*src
, BYTE
*dst
,
215 unsigned int pitch_in
, unsigned int pitch_out
,
216 unsigned int w
, unsigned int h
);
219 static const struct d3dfmt_converter_desc converters
[] =
221 {WINED3DFMT_R32_FLOAT
, WINED3DFMT_R16_FLOAT
, convert_r32_float_r16_float
},
222 {WINED3DFMT_B5G6R5_UNORM
, WINED3DFMT_B8G8R8X8_UNORM
, convert_r5g6b5_x8r8g8b8
},
223 {WINED3DFMT_B8G8R8A8_UNORM
, WINED3DFMT_B8G8R8X8_UNORM
, convert_a8r8g8b8_x8r8g8b8
},
224 {WINED3DFMT_B8G8R8X8_UNORM
, WINED3DFMT_B8G8R8A8_UNORM
, convert_a8r8g8b8_x8r8g8b8
},
225 {WINED3DFMT_YUY2
, WINED3DFMT_B8G8R8X8_UNORM
, convert_yuy2_x8r8g8b8
},
226 {WINED3DFMT_YUY2
, WINED3DFMT_B5G6R5_UNORM
, convert_yuy2_r5g6b5
},
229 static inline const struct d3dfmt_converter_desc
*find_converter(enum wined3d_format_id from
,
230 enum wined3d_format_id to
)
234 for (i
= 0; i
< ARRAY_SIZE(converters
); ++i
)
236 if (converters
[i
].from
== from
&& converters
[i
].to
== to
)
237 return &converters
[i
];
243 static struct wined3d_texture
*surface_convert_format(struct wined3d_texture
*src_texture
,
244 unsigned int sub_resource_idx
, const struct wined3d_format
*dst_format
)
246 unsigned int texture_level
= sub_resource_idx
% src_texture
->level_count
;
247 const struct wined3d_format
*src_format
= src_texture
->resource
.format
;
248 struct wined3d_device
*device
= src_texture
->resource
.device
;
249 const struct d3dfmt_converter_desc
*conv
= NULL
;
250 unsigned int src_row_pitch
, src_slice_pitch
;
251 struct wined3d_texture
*dst_texture
;
252 struct wined3d_bo_address src_data
;
253 struct wined3d_resource_desc desc
;
254 struct wined3d_context
*context
;
257 if (!(conv
= find_converter(src_format
->id
, dst_format
->id
)) && ((device
->wined3d
->flags
& WINED3D_NO3D
)
258 || !is_identity_fixup(src_format
->color_fixup
) || src_format
->conv_byte_count
259 || !is_identity_fixup(dst_format
->color_fixup
) || dst_format
->conv_byte_count
260 || ((src_format
->attrs
& WINED3D_FORMAT_ATTR_COMPRESSED
)
261 && !src_format
->decompress
)))
263 FIXME("Cannot find a conversion function from format %s to %s.\n",
264 debug_d3dformat(src_format
->id
), debug_d3dformat(dst_format
->id
));
268 /* FIXME: Multisampled conversion? */
269 desc
.resource_type
= WINED3D_RTYPE_TEXTURE_2D
;
270 desc
.format
= dst_format
->id
;
271 desc
.multisample_type
= WINED3D_MULTISAMPLE_NONE
;
272 desc
.multisample_quality
= 0;
273 desc
.usage
= WINED3DUSAGE_SCRATCH
| WINED3DUSAGE_PRIVATE
;
275 desc
.access
= WINED3D_RESOURCE_ACCESS_CPU
| WINED3D_RESOURCE_ACCESS_MAP_R
| WINED3D_RESOURCE_ACCESS_MAP_W
;
276 desc
.width
= wined3d_texture_get_level_width(src_texture
, texture_level
);
277 desc
.height
= wined3d_texture_get_level_height(src_texture
, texture_level
);
280 if (FAILED(wined3d_texture_create(device
, &desc
, 1, 1, WINED3D_TEXTURE_CREATE_DISCARD
,
281 NULL
, NULL
, &wined3d_null_parent_ops
, &dst_texture
)))
283 ERR("Failed to create a destination texture for conversion.\n");
287 context
= context_acquire(device
, NULL
, 0);
289 map_binding
= src_texture
->resource
.map_binding
;
290 if (!wined3d_texture_load_location(src_texture
, sub_resource_idx
, context
, map_binding
))
291 ERR("Failed to load the source sub-resource into %s.\n", wined3d_debug_location(map_binding
));
292 wined3d_texture_get_pitch(src_texture
, texture_level
, &src_row_pitch
, &src_slice_pitch
);
293 wined3d_texture_get_bo_address(src_texture
, sub_resource_idx
, &src_data
, map_binding
);
297 unsigned int dst_row_pitch
, dst_slice_pitch
;
298 struct wined3d_bo_address dst_data
;
299 struct wined3d_range range
;
303 map_binding
= dst_texture
->resource
.map_binding
;
304 if (!wined3d_texture_load_location(dst_texture
, 0, context
, map_binding
))
305 ERR("Failed to load the destination sub-resource into %s.\n", wined3d_debug_location(map_binding
));
306 wined3d_texture_get_pitch(dst_texture
, 0, &dst_row_pitch
, &dst_slice_pitch
);
307 wined3d_texture_get_bo_address(dst_texture
, 0, &dst_data
, map_binding
);
309 src
= wined3d_context_map_bo_address(context
, &src_data
,
310 src_texture
->sub_resources
[sub_resource_idx
].size
, WINED3D_MAP_READ
);
311 dst
= wined3d_context_map_bo_address(context
, &dst_data
,
312 dst_texture
->sub_resources
[0].size
, WINED3D_MAP_WRITE
);
314 conv
->convert(src
, dst
, src_row_pitch
, dst_row_pitch
, desc
.width
, desc
.height
);
317 range
.size
= dst_texture
->sub_resources
[0].size
;
318 wined3d_texture_invalidate_location(dst_texture
, 0, ~map_binding
);
319 wined3d_context_unmap_bo_address(context
, &dst_data
, 1, &range
);
320 wined3d_context_unmap_bo_address(context
, &src_data
, 0, NULL
);
324 struct wined3d_box src_box
= {0, 0, desc
.width
, desc
.height
, 0, 1};
326 TRACE("Using upload conversion.\n");
328 wined3d_texture_prepare_location(dst_texture
, 0, context
, WINED3D_LOCATION_TEXTURE_RGB
);
329 dst_texture
->texture_ops
->texture_upload_data(context
, wined3d_const_bo_address(&src_data
),
330 src_format
, &src_box
, src_row_pitch
, src_slice_pitch
,
331 dst_texture
, 0, WINED3D_LOCATION_TEXTURE_RGB
, 0, 0, 0);
333 wined3d_texture_validate_location(dst_texture
, 0, WINED3D_LOCATION_TEXTURE_RGB
);
334 wined3d_texture_invalidate_location(dst_texture
, 0, ~WINED3D_LOCATION_TEXTURE_RGB
);
337 context_release(context
);
342 void texture2d_read_from_framebuffer(struct wined3d_texture
*texture
, unsigned int sub_resource_idx
,
343 struct wined3d_context
*context
, DWORD src_location
, DWORD dst_location
)
345 struct wined3d_resource
*resource
= &texture
->resource
;
346 struct wined3d_device
*device
= resource
->device
;
347 const struct wined3d_format_gl
*format_gl
;
348 struct wined3d_texture
*restore_texture
;
349 const struct wined3d_gl_info
*gl_info
;
350 struct wined3d_context_gl
*context_gl
;
351 unsigned int row_pitch
, slice_pitch
;
352 unsigned int width
, height
, level
;
353 struct wined3d_bo_address data
;
354 unsigned int restore_idx
;
355 BYTE
*row
, *top
, *bottom
;
356 BOOL src_is_upside_down
;
361 /* dst_location was already prepared by the caller. */
362 wined3d_texture_get_bo_address(texture
, sub_resource_idx
, &data
, dst_location
);
365 restore_texture
= context
->current_rt
.texture
;
366 restore_idx
= context
->current_rt
.sub_resource_idx
;
367 if (restore_texture
!= texture
|| restore_idx
!= sub_resource_idx
)
368 context
= context_acquire(device
, texture
, sub_resource_idx
);
370 restore_texture
= NULL
;
371 context_gl
= wined3d_context_gl(context
);
372 gl_info
= context_gl
->gl_info
;
374 if (src_location
!= resource
->draw_binding
)
376 wined3d_context_gl_apply_fbo_state_blit(context_gl
, GL_READ_FRAMEBUFFER
,
377 resource
, sub_resource_idx
, NULL
, 0, src_location
);
378 wined3d_context_gl_check_fbo_status(context_gl
, GL_READ_FRAMEBUFFER
);
379 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
383 wined3d_context_gl_apply_blit_state(context_gl
, device
);
386 /* Select the correct read buffer, and give some debug output.
387 * There is no need to keep track of the current read buffer or reset it,
388 * every part of the code that reads sets the read buffer as desired.
390 if (src_location
!= WINED3D_LOCATION_DRAWABLE
|| wined3d_resource_is_offscreen(resource
))
392 /* Mapping the primary render target which is not on a swapchain.
393 * Read from the back buffer. */
394 TRACE("Mapping offscreen render target.\n");
395 gl_info
->gl_ops
.gl
.p_glReadBuffer(wined3d_context_gl_get_offscreen_gl_buffer(context_gl
));
396 src_is_upside_down
= TRUE
;
400 /* Onscreen surfaces are always part of a swapchain */
401 GLenum buffer
= wined3d_texture_get_gl_buffer(texture
);
402 TRACE("Mapping %#x buffer.\n", buffer
);
403 gl_info
->gl_ops
.gl
.p_glReadBuffer(buffer
);
404 src_is_upside_down
= FALSE
;
406 checkGLcall("glReadBuffer");
408 if (data
.buffer_object
)
410 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, wined3d_bo_gl(data
.buffer_object
)->id
));
411 checkGLcall("glBindBuffer");
412 offset
+= data
.buffer_object
->buffer_offset
;
416 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, 0));
417 checkGLcall("glBindBuffer");
420 level
= sub_resource_idx
% texture
->level_count
;
421 wined3d_texture_get_pitch(texture
, level
, &row_pitch
, &slice_pitch
);
422 format_gl
= wined3d_format_gl(resource
->format
);
424 /* Setup pixel store pack state -- to glReadPixels into the correct place */
425 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_PACK_ROW_LENGTH
, row_pitch
/ format_gl
->f
.byte_count
);
426 checkGLcall("glPixelStorei");
428 width
= wined3d_texture_get_level_width(texture
, level
);
429 height
= wined3d_texture_get_level_height(texture
, level
);
430 gl_info
->gl_ops
.gl
.p_glReadPixels(0, 0, width
, height
,
431 format_gl
->format
, format_gl
->type
, offset
);
432 checkGLcall("glReadPixels");
434 /* Reset previous pixel store pack state */
435 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_PACK_ROW_LENGTH
, 0);
436 checkGLcall("glPixelStorei");
438 if (!src_is_upside_down
)
440 /* glReadPixels returns the image upside down, and there is no way to
441 * prevent this. Flip the lines in software. */
443 if (!(row
= heap_alloc(row_pitch
)))
446 if (data
.buffer_object
)
448 mem
= GL_EXTCALL(glMapBuffer(GL_PIXEL_PACK_BUFFER
, GL_READ_WRITE
));
449 checkGLcall("glMapBuffer");
451 mem
+= (uintptr_t)offset
;
454 bottom
= mem
+ row_pitch
* (height
- 1);
455 for (i
= 0; i
< height
/ 2; i
++)
457 memcpy(row
, top
, row_pitch
);
458 memcpy(top
, bottom
, row_pitch
);
459 memcpy(bottom
, row
, row_pitch
);
465 if (data
.buffer_object
)
466 GL_EXTCALL(glUnmapBuffer(GL_PIXEL_PACK_BUFFER
));
470 if (data
.buffer_object
)
472 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, 0));
473 wined3d_context_gl_reference_bo(context_gl
, wined3d_bo_gl(data
.buffer_object
));
474 checkGLcall("glBindBuffer");
478 context_restore(context
, restore_texture
, restore_idx
);
481 /* Read the framebuffer contents into a texture. Note that this function
482 * doesn't do any kind of flipping. Using this on an onscreen surface will
483 * result in a flipped D3D texture.
485 * Context activation is done by the caller. This function may temporarily
486 * switch to a different context and restore the original one before return. */
487 void texture2d_load_fb_texture(struct wined3d_texture_gl
*texture_gl
,
488 unsigned int sub_resource_idx
, BOOL srgb
, struct wined3d_context
*context
)
490 struct wined3d_texture
*restore_texture
;
491 const struct wined3d_gl_info
*gl_info
;
492 struct wined3d_context_gl
*context_gl
;
493 struct wined3d_resource
*resource
;
494 unsigned int restore_idx
, level
;
495 struct wined3d_device
*device
;
498 resource
= &texture_gl
->t
.resource
;
499 device
= resource
->device
;
500 restore_texture
= context
->current_rt
.texture
;
501 restore_idx
= context
->current_rt
.sub_resource_idx
;
502 if (restore_texture
!= &texture_gl
->t
|| restore_idx
!= sub_resource_idx
)
503 context
= context_acquire(device
, &texture_gl
->t
, sub_resource_idx
);
505 restore_texture
= NULL
;
506 context_gl
= wined3d_context_gl(context
);
508 gl_info
= context_gl
->gl_info
;
509 device_invalidate_state(device
, STATE_FRAMEBUFFER
);
511 wined3d_texture_gl_prepare_texture(texture_gl
, context_gl
, srgb
);
512 wined3d_texture_gl_bind_and_dirtify(texture_gl
, context_gl
, srgb
);
514 TRACE("Reading back offscreen render target %p, %u.\n", texture_gl
, sub_resource_idx
);
516 if (wined3d_resource_is_offscreen(resource
))
517 gl_info
->gl_ops
.gl
.p_glReadBuffer(wined3d_context_gl_get_offscreen_gl_buffer(context_gl
));
519 gl_info
->gl_ops
.gl
.p_glReadBuffer(wined3d_texture_get_gl_buffer(&texture_gl
->t
));
520 checkGLcall("glReadBuffer");
522 level
= sub_resource_idx
% texture_gl
->t
.level_count
;
523 target
= wined3d_texture_gl_get_sub_resource_target(texture_gl
, sub_resource_idx
);
524 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(target
, level
, 0, 0, 0, 0,
525 wined3d_texture_get_level_width(&texture_gl
->t
, level
),
526 wined3d_texture_get_level_height(&texture_gl
->t
, level
));
527 checkGLcall("glCopyTexSubImage2D");
530 context_restore(context
, restore_texture
, restore_idx
);
533 /* Context activation is done by the caller. */
534 static void cpu_blitter_destroy(struct wined3d_blitter
*blitter
, struct wined3d_context
*context
)
536 struct wined3d_blitter
*next
;
538 if ((next
= blitter
->next
))
539 next
->ops
->blitter_destroy(next
, context
);
544 static HRESULT
surface_cpu_blt_compressed(const BYTE
*src_data
, BYTE
*dst_data
,
545 UINT src_pitch
, UINT dst_pitch
, UINT update_w
, UINT update_h
,
546 const struct wined3d_format
*format
, uint32_t flags
, const struct wined3d_blt_fx
*fx
)
548 UINT row_block_count
;
556 row_block_count
= (update_w
+ format
->block_width
- 1) / format
->block_width
;
560 for (y
= 0; y
< update_h
; y
+= format
->block_height
)
562 memcpy(dst_row
, src_row
, row_block_count
* format
->block_byte_count
);
563 src_row
+= src_pitch
;
564 dst_row
+= dst_pitch
;
570 if (flags
== WINED3D_BLT_FX
&& fx
->fx
== WINEDDBLTFX_MIRRORUPDOWN
)
572 src_row
+= (((update_h
/ format
->block_height
) - 1) * src_pitch
);
576 case WINED3DFMT_DXT1
:
577 for (y
= 0; y
< update_h
; y
+= format
->block_height
)
585 const struct block
*s
= (const struct block
*)src_row
;
586 struct block
*d
= (struct block
*)dst_row
;
588 for (x
= 0; x
< row_block_count
; ++x
)
590 d
[x
].color
[0] = s
[x
].color
[0];
591 d
[x
].color
[1] = s
[x
].color
[1];
592 d
[x
].control_row
[0] = s
[x
].control_row
[3];
593 d
[x
].control_row
[1] = s
[x
].control_row
[2];
594 d
[x
].control_row
[2] = s
[x
].control_row
[1];
595 d
[x
].control_row
[3] = s
[x
].control_row
[0];
597 src_row
-= src_pitch
;
598 dst_row
+= dst_pitch
;
602 case WINED3DFMT_DXT2
:
603 case WINED3DFMT_DXT3
:
604 for (y
= 0; y
< update_h
; y
+= format
->block_height
)
613 const struct block
*s
= (const struct block
*)src_row
;
614 struct block
*d
= (struct block
*)dst_row
;
616 for (x
= 0; x
< row_block_count
; ++x
)
618 d
[x
].alpha_row
[0] = s
[x
].alpha_row
[3];
619 d
[x
].alpha_row
[1] = s
[x
].alpha_row
[2];
620 d
[x
].alpha_row
[2] = s
[x
].alpha_row
[1];
621 d
[x
].alpha_row
[3] = s
[x
].alpha_row
[0];
622 d
[x
].color
[0] = s
[x
].color
[0];
623 d
[x
].color
[1] = s
[x
].color
[1];
624 d
[x
].control_row
[0] = s
[x
].control_row
[3];
625 d
[x
].control_row
[1] = s
[x
].control_row
[2];
626 d
[x
].control_row
[2] = s
[x
].control_row
[1];
627 d
[x
].control_row
[3] = s
[x
].control_row
[0];
629 src_row
-= src_pitch
;
630 dst_row
+= dst_pitch
;
635 FIXME("Compressed flip not implemented for format %s.\n",
636 debug_d3dformat(format
->id
));
641 FIXME("Unsupported blit on compressed surface (format %s, flags %#x, DDFX %#x).\n",
642 debug_d3dformat(format
->id
), flags
, flags
& WINED3D_BLT_FX
? fx
->fx
: 0);
647 static HRESULT
surface_cpu_blt(struct wined3d_texture
*dst_texture
, unsigned int dst_sub_resource_idx
,
648 const struct wined3d_box
*dst_box
, struct wined3d_texture
*src_texture
, unsigned int src_sub_resource_idx
,
649 const struct wined3d_box
*src_box
, uint32_t flags
, const struct wined3d_blt_fx
*fx
,
650 enum wined3d_texture_filter_type filter
)
652 unsigned int bpp
, src_height
, src_width
, dst_height
, dst_width
, row_byte_count
;
653 struct wined3d_device
*device
= dst_texture
->resource
.device
;
654 const struct wined3d_format
*src_format
, *dst_format
;
655 struct wined3d_texture
*converted_texture
= NULL
;
656 struct wined3d_bo_address src_data
, dst_data
;
657 unsigned int src_fmt_attrs
, dst_fmt_attrs
;
658 struct wined3d_map_desc dst_map
, src_map
;
659 unsigned int x
, sx
, xinc
, y
, sy
, yinc
;
660 struct wined3d_context
*context
;
661 struct wined3d_range dst_range
;
662 unsigned int texture_level
;
663 HRESULT hr
= WINED3D_OK
;
664 BOOL same_sub_resource
;
671 TRACE("dst_texture %p, dst_sub_resource_idx %u, dst_box %s, src_texture %p, "
672 "src_sub_resource_idx %u, src_box %s, flags %#x, fx %p, filter %s.\n",
673 dst_texture
, dst_sub_resource_idx
, debug_box(dst_box
), src_texture
,
674 src_sub_resource_idx
, debug_box(src_box
), flags
, fx
, debug_d3dtexturefiltertype(filter
));
676 context
= context_acquire(device
, NULL
, 0);
678 src_format
= src_texture
->resource
.format
;
679 dst_format
= dst_texture
->resource
.format
;
681 if (wined3d_format_is_typeless(src_format
) && src_format
->id
== dst_format
->typeless_id
)
682 src_format
= dst_format
;
683 if (wined3d_format_is_typeless(dst_format
) && dst_format
->id
== src_format
->typeless_id
)
684 dst_format
= src_format
;
686 src_height
= src_box
->bottom
- src_box
->top
;
687 src_width
= src_box
->right
- src_box
->left
;
688 dst_height
= dst_box
->bottom
- dst_box
->top
;
689 dst_width
= dst_box
->right
- dst_box
->left
;
691 dst_range
.offset
= 0;
692 dst_range
.size
= dst_texture
->sub_resources
[dst_sub_resource_idx
].size
;
693 if (src_texture
== dst_texture
&& src_sub_resource_idx
== dst_sub_resource_idx
)
695 same_sub_resource
= TRUE
;
697 map_binding
= dst_texture
->resource
.map_binding
;
698 texture_level
= dst_sub_resource_idx
% dst_texture
->level_count
;
699 if (!wined3d_texture_load_location(dst_texture
, dst_sub_resource_idx
, context
, map_binding
))
700 ERR("Failed to load the destination sub-resource into %s.\n", wined3d_debug_location(map_binding
));
701 wined3d_texture_invalidate_location(dst_texture
, dst_sub_resource_idx
, ~map_binding
);
702 wined3d_texture_get_pitch(dst_texture
, texture_level
, &dst_map
.row_pitch
, &dst_map
.slice_pitch
);
703 wined3d_texture_get_bo_address(dst_texture
, dst_sub_resource_idx
, &dst_data
, map_binding
);
704 dst_map
.data
= wined3d_context_map_bo_address(context
, &dst_data
,
705 dst_texture
->sub_resources
[dst_sub_resource_idx
].size
, WINED3D_MAP_READ
| WINED3D_MAP_WRITE
);
711 same_sub_resource
= FALSE
;
712 upload
= dst_format
->attrs
& WINED3D_FORMAT_ATTR_BLOCKS
713 && (dst_width
!= src_width
|| dst_height
!= src_height
);
717 dst_format
= src_format
->attrs
& WINED3D_FORMAT_ATTR_BLOCKS
718 ? wined3d_get_format(device
->adapter
, WINED3DFMT_B8G8R8A8_UNORM
, 0) : src_format
;
721 if (!(flags
& WINED3D_BLT_RAW
) && dst_format
->id
!= src_format
->id
)
723 if (!(converted_texture
= surface_convert_format(src_texture
, src_sub_resource_idx
, dst_format
)))
725 FIXME("Cannot convert %s to %s.\n", debug_d3dformat(src_format
->id
),
726 debug_d3dformat(dst_format
->id
));
727 context_release(context
);
728 return WINED3DERR_NOTAVAILABLE
;
730 src_texture
= converted_texture
;
731 src_sub_resource_idx
= 0;
732 src_format
= src_texture
->resource
.format
;
735 map_binding
= src_texture
->resource
.map_binding
;
736 texture_level
= src_sub_resource_idx
% src_texture
->level_count
;
737 if (!wined3d_texture_load_location(src_texture
, src_sub_resource_idx
, context
, map_binding
))
738 ERR("Failed to load the source sub-resource into %s.\n", wined3d_debug_location(map_binding
));
739 wined3d_texture_get_pitch(src_texture
, texture_level
, &src_map
.row_pitch
, &src_map
.slice_pitch
);
740 wined3d_texture_get_bo_address(src_texture
, src_sub_resource_idx
, &src_data
, map_binding
);
741 src_map
.data
= wined3d_context_map_bo_address(context
, &src_data
,
742 src_texture
->sub_resources
[src_sub_resource_idx
].size
, WINED3D_MAP_READ
);
746 wined3d_format_calculate_pitch(dst_format
, 1, dst_box
->right
, dst_box
->bottom
,
747 &dst_map
.row_pitch
, &dst_map
.slice_pitch
);
748 dst_map
.data
= heap_alloc(dst_map
.slice_pitch
);
752 map_binding
= dst_texture
->resource
.map_binding
;
753 texture_level
= dst_sub_resource_idx
% dst_texture
->level_count
;
754 if (!wined3d_texture_load_location(dst_texture
, dst_sub_resource_idx
, context
, map_binding
))
755 ERR("Failed to load the destination sub-resource into %s.\n", wined3d_debug_location(map_binding
));
757 wined3d_texture_invalidate_location(dst_texture
, dst_sub_resource_idx
, ~map_binding
);
758 wined3d_texture_get_pitch(dst_texture
, texture_level
, &dst_map
.row_pitch
, &dst_map
.slice_pitch
);
759 wined3d_texture_get_bo_address(dst_texture
, dst_sub_resource_idx
, &dst_data
, map_binding
);
760 dst_map
.data
= wined3d_context_map_bo_address(context
, &dst_data
,
761 dst_texture
->sub_resources
[dst_sub_resource_idx
].size
, WINED3D_MAP_WRITE
);
764 src_fmt_attrs
= src_format
->attrs
;
765 dst_fmt_attrs
= dst_format
->attrs
;
766 flags
&= ~WINED3D_BLT_RAW
;
768 bpp
= dst_format
->byte_count
;
769 row_byte_count
= dst_width
* bpp
;
771 sbase
= (BYTE
*)src_map
.data
772 + ((src_box
->top
/ src_format
->block_height
) * src_map
.row_pitch
)
773 + ((src_box
->left
/ src_format
->block_width
) * src_format
->block_byte_count
);
774 dbuf
= (BYTE
*)dst_map
.data
775 + ((dst_box
->top
/ dst_format
->block_height
) * dst_map
.row_pitch
)
776 + ((dst_box
->left
/ dst_format
->block_width
) * dst_format
->block_byte_count
);
778 if (src_fmt_attrs
& dst_fmt_attrs
& WINED3D_FORMAT_ATTR_BLOCKS
)
780 TRACE("%s -> %s copy.\n", debug_d3dformat(src_format
->id
), debug_d3dformat(dst_format
->id
));
782 if (same_sub_resource
)
784 FIXME("Only plain blits supported on compressed surfaces.\n");
789 hr
= surface_cpu_blt_compressed(sbase
, dbuf
,
790 src_map
.row_pitch
, dst_map
.row_pitch
, dst_width
, dst_height
,
791 src_format
, flags
, fx
);
795 if ((src_fmt_attrs
| dst_fmt_attrs
) & WINED3D_FORMAT_ATTR_HEIGHT_SCALE
)
797 FIXME("Unsupported blit between height-scaled formats (src %s, dst %s).\n",
798 debug_d3dformat(src_format
->id
), debug_d3dformat(dst_format
->id
));
803 if (filter
!= WINED3D_TEXF_NONE
&& filter
!= WINED3D_TEXF_POINT
804 && (src_width
!= dst_width
|| src_height
!= dst_height
))
806 /* Can happen when d3d9 apps do a StretchRect() call which isn't handled in GL. */
807 FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(filter
));
810 xinc
= (src_width
<< 16) / dst_width
;
811 yinc
= (src_height
<< 16) / dst_height
;
815 /* No effects, we can cheat here. */
816 if (dst_width
== src_width
)
818 if (dst_height
== src_height
)
820 /* No stretching in either direction. This needs to be as fast
824 /* Check for overlapping surfaces. */
825 if (!same_sub_resource
|| dst_box
->top
< src_box
->top
826 || dst_box
->right
<= src_box
->left
|| src_box
->right
<= dst_box
->left
)
828 /* No overlap, or dst above src, so copy from top downwards. */
829 for (y
= 0; y
< dst_height
; ++y
)
831 memcpy(dbuf
, sbuf
, row_byte_count
);
832 sbuf
+= src_map
.row_pitch
;
833 dbuf
+= dst_map
.row_pitch
;
836 else if (dst_box
->top
> src_box
->top
)
838 /* Copy from bottom upwards. */
839 sbuf
+= src_map
.row_pitch
* dst_height
;
840 dbuf
+= dst_map
.row_pitch
* dst_height
;
841 for (y
= 0; y
< dst_height
; ++y
)
843 sbuf
-= src_map
.row_pitch
;
844 dbuf
-= dst_map
.row_pitch
;
845 memcpy(dbuf
, sbuf
, row_byte_count
);
850 /* Src and dst overlapping on the same line, use memmove. */
851 for (y
= 0; y
< dst_height
; ++y
)
853 memmove(dbuf
, sbuf
, row_byte_count
);
854 sbuf
+= src_map
.row_pitch
;
855 dbuf
+= dst_map
.row_pitch
;
861 /* Stretching in y direction only. */
862 for (y
= sy
= 0; y
< dst_height
; ++y
, sy
+= yinc
)
864 sbuf
= sbase
+ (sy
>> 16) * src_map
.row_pitch
;
865 memcpy(dbuf
, sbuf
, row_byte_count
);
866 dbuf
+= dst_map
.row_pitch
;
872 /* Stretching in X direction. */
873 unsigned int last_sy
= ~0u;
874 for (y
= sy
= 0; y
< dst_height
; ++y
, sy
+= yinc
)
876 sbuf
= sbase
+ (sy
>> 16) * src_map
.row_pitch
;
878 if ((sy
>> 16) == (last_sy
>> 16))
880 /* This source row is the same as last source row -
881 * Copy the already stretched row. */
882 memcpy(dbuf
, dbuf
- dst_map
.row_pitch
, row_byte_count
);
886 #define STRETCH_ROW(type) \
888 const type *s = (const type *)sbuf; \
889 type *d = (type *)dbuf; \
890 for (x = sx = 0; x < dst_width; ++x, sx += xinc) \
891 d[x] = s[sx >> 16]; \
909 for (x
= sx
= 0; x
< dst_width
; x
++, sx
+= xinc
)
913 s
= sbuf
+ 3 * (sx
>> 16);
914 pixel
= s
[0] | (s
[1] << 8) | (s
[2] << 16);
915 d
[0] = (pixel
) & 0xff;
916 d
[1] = (pixel
>> 8) & 0xff;
917 d
[2] = (pixel
>> 16) & 0xff;
923 FIXME("Stretched blit not implemented for bpp %u.\n", bpp
* 8);
924 hr
= WINED3DERR_NOTAVAILABLE
;
929 dbuf
+= dst_map
.row_pitch
;
936 LONG dstyinc
= dst_map
.row_pitch
, dstxinc
= bpp
;
937 DWORD keylow
= 0xffffffff, keyhigh
= 0, keymask
= 0xffffffff;
938 DWORD destkeylow
= 0x0, destkeyhigh
= 0xffffffff, destkeymask
= 0xffffffff;
939 if (flags
& (WINED3D_BLT_SRC_CKEY
| WINED3D_BLT_DST_CKEY
940 | WINED3D_BLT_SRC_CKEY_OVERRIDE
| WINED3D_BLT_DST_CKEY_OVERRIDE
))
942 /* The color keying flags are checked for correctness in ddraw. */
943 if (flags
& WINED3D_BLT_SRC_CKEY
)
945 keylow
= src_texture
->async
.src_blt_color_key
.color_space_low_value
;
946 keyhigh
= src_texture
->async
.src_blt_color_key
.color_space_high_value
;
948 else if (flags
& WINED3D_BLT_SRC_CKEY_OVERRIDE
)
950 keylow
= fx
->src_color_key
.color_space_low_value
;
951 keyhigh
= fx
->src_color_key
.color_space_high_value
;
954 if (flags
& WINED3D_BLT_DST_CKEY
)
956 /* Destination color keys are taken from the source surface! */
957 destkeylow
= src_texture
->async
.dst_blt_color_key
.color_space_low_value
;
958 destkeyhigh
= src_texture
->async
.dst_blt_color_key
.color_space_high_value
;
960 else if (flags
& WINED3D_BLT_DST_CKEY_OVERRIDE
)
962 destkeylow
= fx
->dst_color_key
.color_space_low_value
;
963 destkeyhigh
= fx
->dst_color_key
.color_space_high_value
;
973 get_color_masks(src_format
, masks
);
974 keymask
= masks
[0] | masks
[1] | masks
[2];
976 flags
&= ~(WINED3D_BLT_SRC_CKEY
| WINED3D_BLT_DST_CKEY
977 | WINED3D_BLT_SRC_CKEY_OVERRIDE
| WINED3D_BLT_DST_CKEY_OVERRIDE
);
980 if (flags
& WINED3D_BLT_FX
)
982 BYTE
*dTopLeft
, *dTopRight
, *dBottomLeft
, *dBottomRight
, *tmp
;
985 dTopRight
= dbuf
+ ((dst_width
- 1) * bpp
);
986 dBottomLeft
= dTopLeft
+ ((dst_height
- 1) * dst_map
.row_pitch
);
987 dBottomRight
= dBottomLeft
+ ((dst_width
- 1) * bpp
);
989 if (fx
->fx
& WINEDDBLTFX_ARITHSTRETCHY
)
991 /* I don't think we need to do anything about this flag. */
992 WARN("Nothing done for WINEDDBLTFX_ARITHSTRETCHY.\n");
994 if (fx
->fx
& WINEDDBLTFX_MIRRORLEFTRIGHT
)
997 dTopRight
= dTopLeft
;
1000 dBottomRight
= dBottomLeft
;
1002 dstxinc
= dstxinc
* -1;
1004 if (fx
->fx
& WINEDDBLTFX_MIRRORUPDOWN
)
1007 dTopLeft
= dBottomLeft
;
1010 dTopRight
= dBottomRight
;
1012 dstyinc
= dstyinc
* -1;
1014 if (fx
->fx
& WINEDDBLTFX_NOTEARING
)
1016 /* I don't think we need to do anything about this flag. */
1017 WARN("Nothing done for WINEDDBLTFX_NOTEARING.\n");
1019 if (fx
->fx
& WINEDDBLTFX_ROTATE180
)
1022 dBottomRight
= dTopLeft
;
1025 dBottomLeft
= dTopRight
;
1027 dstxinc
= dstxinc
* -1;
1028 dstyinc
= dstyinc
* -1;
1030 if (fx
->fx
& WINEDDBLTFX_ROTATE270
)
1033 dTopLeft
= dBottomLeft
;
1034 dBottomLeft
= dBottomRight
;
1035 dBottomRight
= dTopRight
;
1040 dstxinc
= dstxinc
* -1;
1042 if (fx
->fx
& WINEDDBLTFX_ROTATE90
)
1045 dTopLeft
= dTopRight
;
1046 dTopRight
= dBottomRight
;
1047 dBottomRight
= dBottomLeft
;
1052 dstyinc
= dstyinc
* -1;
1054 if (fx
->fx
& WINEDDBLTFX_ZBUFFERBASEDEST
)
1056 /* I don't think we need to do anything about this flag. */
1057 WARN("Nothing done for WINEDDBLTFX_ZBUFFERBASEDEST.\n");
1060 flags
&= ~(WINED3D_BLT_FX
);
1063 #define COPY_COLORKEY_FX(type) \
1066 type *d = (type *)dbuf, *dx, tmp; \
1067 for (y = sy = 0; y < dst_height; ++y, sy += yinc) \
1069 s = (const type *)(sbase + (sy >> 16) * src_map.row_pitch); \
1071 for (x = sx = 0; x < dst_width; ++x, sx += xinc) \
1073 tmp = s[sx >> 16]; \
1074 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) \
1075 && ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) \
1079 dx = (type *)(((BYTE *)dx) + dstxinc); \
1081 d = (type *)(((BYTE *)d) + dstyinc); \
1088 COPY_COLORKEY_FX(BYTE
);
1091 COPY_COLORKEY_FX(WORD
);
1094 COPY_COLORKEY_FX(DWORD
);
1099 BYTE
*d
= dbuf
, *dx
;
1100 for (y
= sy
= 0; y
< dst_height
; ++y
, sy
+= yinc
)
1102 sbuf
= sbase
+ (sy
>> 16) * src_map
.row_pitch
;
1104 for (x
= sx
= 0; x
< dst_width
; ++x
, sx
+= xinc
)
1106 DWORD pixel
, dpixel
= 0;
1107 s
= sbuf
+ 3 * (sx
>>16);
1108 pixel
= s
[0] | (s
[1] << 8) | (s
[2] << 16);
1109 dpixel
= dx
[0] | (dx
[1] << 8 ) | (dx
[2] << 16);
1110 if (((pixel
& keymask
) < keylow
|| (pixel
& keymask
) > keyhigh
)
1111 && ((dpixel
& keymask
) >= destkeylow
|| (dpixel
& keymask
) <= keyhigh
))
1113 dx
[0] = (pixel
) & 0xff;
1114 dx
[1] = (pixel
>> 8) & 0xff;
1115 dx
[2] = (pixel
>> 16) & 0xff;
1124 FIXME("%s color-keyed blit not implemented for bpp %u.\n",
1125 (flags
& WINED3D_BLT_SRC_CKEY
) ? "Source" : "Destination", bpp
* 8);
1126 hr
= WINED3DERR_NOTAVAILABLE
;
1128 #undef COPY_COLORKEY_FX
1134 FIXME(" Unsupported flags %#x.\n", flags
);
1137 if (upload
&& hr
== WINED3D_OK
)
1139 struct wined3d_bo_address data
;
1141 data
.buffer_object
= 0;
1142 data
.addr
= dst_map
.data
;
1144 texture_level
= dst_sub_resource_idx
% dst_texture
->level_count
;
1146 wined3d_texture_prepare_location(dst_texture
, texture_level
, context
, WINED3D_LOCATION_TEXTURE_RGB
);
1147 dst_texture
->texture_ops
->texture_upload_data(context
, wined3d_const_bo_address(&data
), dst_format
,
1148 dst_box
, dst_map
.row_pitch
, dst_map
.slice_pitch
, dst_texture
, texture_level
,
1149 WINED3D_LOCATION_TEXTURE_RGB
, dst_box
->left
, dst_box
->top
, 0);
1151 wined3d_texture_validate_location(dst_texture
, texture_level
, WINED3D_LOCATION_TEXTURE_RGB
);
1152 wined3d_texture_invalidate_location(dst_texture
, texture_level
, ~WINED3D_LOCATION_TEXTURE_RGB
);
1157 heap_free(dst_map
.data
);
1161 wined3d_context_unmap_bo_address(context
, &dst_data
, 1, &dst_range
);
1164 if (!same_sub_resource
)
1165 wined3d_context_unmap_bo_address(context
, &src_data
, 0, NULL
);
1166 if (SUCCEEDED(hr
) && dst_texture
->swapchain
&& dst_texture
->swapchain
->front_buffer
== dst_texture
)
1168 SetRect(&dst_texture
->swapchain
->front_buffer_update
,
1169 dst_box
->left
, dst_box
->top
, dst_box
->right
, dst_box
->bottom
);
1170 dst_texture
->swapchain
->swapchain_ops
->swapchain_frontbuffer_updated(dst_texture
->swapchain
);
1172 if (converted_texture
)
1173 wined3d_texture_decref(converted_texture
);
1174 context_release(context
);
1179 static void surface_cpu_blt_colour_fill(struct wined3d_rendertarget_view
*view
,
1180 const struct wined3d_box
*box
, const struct wined3d_color
*colour
)
1182 struct wined3d_device
*device
= view
->resource
->device
;
1183 struct wined3d_context
*context
;
1184 struct wined3d_texture
*texture
;
1185 struct wined3d_bo_address data
;
1186 struct wined3d_box level_box
;
1187 struct wined3d_map_desc map
;
1188 struct wined3d_range range
;
1189 bool full_subresource
;
1193 TRACE("view %p, box %s, colour %s.\n", view
, debug_box(box
), debug_color(colour
));
1195 if (view
->format_attrs
& WINED3D_FORMAT_ATTR_BLOCKS
)
1197 FIXME("Not implemented for format %s.\n", debug_d3dformat(view
->format
->id
));
1201 if (view
->format
->id
!= view
->resource
->format
->id
)
1202 FIXME("View format %s doesn't match resource format %s.\n",
1203 debug_d3dformat(view
->format
->id
), debug_d3dformat(view
->resource
->format
->id
));
1205 if (view
->resource
->type
== WINED3D_RTYPE_BUFFER
)
1207 FIXME("Not implemented for buffers.\n");
1211 context
= context_acquire(device
, NULL
, 0);
1213 texture
= texture_from_resource(view
->resource
);
1214 level
= view
->sub_resource_idx
% texture
->level_count
;
1215 wined3d_texture_get_level_box(texture_from_resource(view
->resource
), level
, &level_box
);
1216 full_subresource
= !memcmp(box
, &level_box
, sizeof(*box
));
1218 map_binding
= texture
->resource
.map_binding
;
1219 if (!wined3d_texture_load_location(texture
, view
->sub_resource_idx
, context
, map_binding
))
1220 ERR("Failed to load the sub-resource into %s.\n", wined3d_debug_location(map_binding
));
1221 wined3d_texture_invalidate_location(texture
, view
->sub_resource_idx
, ~map_binding
);
1222 wined3d_texture_get_pitch(texture
, level
, &map
.row_pitch
, &map
.slice_pitch
);
1223 wined3d_texture_get_bo_address(texture
, view
->sub_resource_idx
, &data
, map_binding
);
1224 map
.data
= wined3d_context_map_bo_address(context
, &data
,
1225 texture
->sub_resources
[view
->sub_resource_idx
].size
, WINED3D_MAP_WRITE
);
1227 range
.size
= texture
->sub_resources
[view
->sub_resource_idx
].size
;
1229 wined3d_resource_memory_colour_fill(view
->resource
, &map
, colour
, box
, full_subresource
);
1231 wined3d_context_unmap_bo_address(context
, &data
, 1, &range
);
1232 context_release(context
);
1235 static bool wined3d_box_intersect(struct wined3d_box
*ret
, const struct wined3d_box
*b1
,
1236 const struct wined3d_box
*b2
)
1238 wined3d_box_set(ret
, max(b1
->left
, b2
->left
), max(b1
->top
, b2
->top
),
1239 min(b1
->right
, b2
->right
), min(b1
->bottom
, b2
->bottom
),
1240 max(b1
->front
, b2
->front
), min(b1
->back
, b2
->back
));
1241 return ret
->right
> ret
->left
&& ret
->bottom
> ret
->top
&& ret
->back
> ret
->front
;
1244 static void cpu_blitter_clear(struct wined3d_blitter
*blitter
, struct wined3d_device
*device
,
1245 unsigned int rt_count
, const struct wined3d_fb_state
*fb
, unsigned int rect_count
, const RECT
*clear_rects
,
1246 const RECT
*draw_rect
, uint32_t flags
, const struct wined3d_color
*colour
, float depth
, unsigned int stencil
)
1248 struct wined3d_color c
= {depth
, 0.0f
, 0.0f
, 0.0f
};
1249 struct wined3d_box box
, box_clip
, box_view
;
1250 struct wined3d_rendertarget_view
*view
;
1256 clear_rects
= draw_rect
;
1259 for (i
= 0; i
< rect_count
; ++i
)
1261 box
.left
= max(clear_rects
[i
].left
, draw_rect
->left
);
1262 box
.top
= max(clear_rects
[i
].top
, draw_rect
->top
);
1263 box
.right
= min(clear_rects
[i
].right
, draw_rect
->right
);
1264 box
.bottom
= min(clear_rects
[i
].bottom
, draw_rect
->bottom
);
1268 if (box
.left
>= box
.right
|| box
.top
>= box
.bottom
)
1271 if (flags
& WINED3DCLEAR_TARGET
)
1273 for (j
= 0; j
< rt_count
; ++j
)
1275 if ((view
= fb
->render_targets
[j
]))
1277 wined3d_rendertarget_view_get_box(view
, &box_view
);
1278 if (wined3d_box_intersect(&box_clip
, &box_view
, &box
))
1279 surface_cpu_blt_colour_fill(view
, &box_clip
, colour
);
1284 if ((flags
& (WINED3DCLEAR_ZBUFFER
| WINED3DCLEAR_STENCIL
)) && (view
= fb
->depth_stencil
))
1286 if ((view
->format
->depth_size
&& !(flags
& WINED3DCLEAR_ZBUFFER
))
1287 || (view
->format
->stencil_size
&& !(flags
& WINED3DCLEAR_STENCIL
)))
1288 FIXME("Clearing %#x on %s.\n", flags
, debug_d3dformat(view
->format
->id
));
1290 wined3d_rendertarget_view_get_box(view
, &box_view
);
1291 if (wined3d_box_intersect(&box_clip
, &box_view
, &box
))
1292 surface_cpu_blt_colour_fill(view
, &box_clip
, &c
);
1297 static DWORD
cpu_blitter_blit(struct wined3d_blitter
*blitter
, enum wined3d_blit_op op
,
1298 struct wined3d_context
*context
, struct wined3d_texture
*src_texture
, unsigned int src_sub_resource_idx
,
1299 DWORD src_location
, const RECT
*src_rect
, struct wined3d_texture
*dst_texture
,
1300 unsigned int dst_sub_resource_idx
, DWORD dst_location
, const RECT
*dst_rect
,
1301 const struct wined3d_color_key
*color_key
, enum wined3d_texture_filter_type filter
,
1302 const struct wined3d_format
*resolve_format
)
1304 struct wined3d_box dst_box
= {dst_rect
->left
, dst_rect
->top
, dst_rect
->right
, dst_rect
->bottom
, 0, 1};
1305 struct wined3d_box src_box
= {src_rect
->left
, src_rect
->top
, src_rect
->right
, src_rect
->bottom
, 0, 1};
1306 struct wined3d_blt_fx fx
;
1309 memset(&fx
, 0, sizeof(fx
));
1312 case WINED3D_BLIT_OP_COLOR_BLIT
:
1313 case WINED3D_BLIT_OP_DEPTH_BLIT
:
1315 case WINED3D_BLIT_OP_RAW_BLIT
:
1316 flags
|= WINED3D_BLT_RAW
;
1318 case WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST
:
1319 flags
|= WINED3D_BLT_ALPHA_TEST
;
1321 case WINED3D_BLIT_OP_COLOR_BLIT_CKEY
:
1322 flags
|= WINED3D_BLT_SRC_CKEY_OVERRIDE
| WINED3D_BLT_FX
;
1323 fx
.src_color_key
= *color_key
;
1326 FIXME("Unhandled op %#x.\n", op
);
1330 if (FAILED(surface_cpu_blt(dst_texture
, dst_sub_resource_idx
, &dst_box
,
1331 src_texture
, src_sub_resource_idx
, &src_box
, flags
, &fx
, filter
)))
1332 ERR("Failed to blit.\n");
1333 wined3d_texture_load_location(dst_texture
, dst_sub_resource_idx
, context
, dst_location
);
1335 return dst_location
| (dst_texture
->sub_resources
[dst_sub_resource_idx
].locations
1336 & dst_texture
->resource
.map_binding
);
1339 static const struct wined3d_blitter_ops cpu_blitter_ops
=
1341 cpu_blitter_destroy
,
1346 struct wined3d_blitter
*wined3d_cpu_blitter_create(void)
1348 struct wined3d_blitter
*blitter
;
1350 if (!(blitter
= heap_alloc(sizeof(*blitter
))))
1353 TRACE("Created blitter %p.\n", blitter
);
1355 blitter
->ops
= &cpu_blitter_ops
;
1356 blitter
->next
= NULL
;
1361 static bool wined3d_is_colour_blit(enum wined3d_blit_op blit_op
)
1365 case WINED3D_BLIT_OP_COLOR_BLIT
:
1366 case WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST
:
1367 case WINED3D_BLIT_OP_COLOR_BLIT_CKEY
:
1375 static bool sub_resource_is_on_cpu(const struct wined3d_texture
*texture
, unsigned int sub_resource_idx
)
1377 DWORD locations
= texture
->sub_resources
[sub_resource_idx
].locations
;
1379 if (locations
& (WINED3D_LOCATION_BUFFER
| WINED3D_LOCATION_SYSMEM
))
1382 if (!(texture
->resource
.access
& WINED3D_RESOURCE_ACCESS_GPU
) && (locations
& WINED3D_LOCATION_CLEARED
))
1388 HRESULT
texture2d_blt(struct wined3d_texture
*dst_texture
, unsigned int dst_sub_resource_idx
,
1389 const struct wined3d_box
*dst_box
, struct wined3d_texture
*src_texture
, unsigned int src_sub_resource_idx
,
1390 const struct wined3d_box
*src_box
, uint32_t flags
, const struct wined3d_blt_fx
*fx
,
1391 enum wined3d_texture_filter_type filter
)
1393 struct wined3d_texture_sub_resource
*src_sub_resource
, *dst_sub_resource
;
1394 struct wined3d_device
*device
= dst_texture
->resource
.device
;
1395 struct wined3d_swapchain
*src_swapchain
, *dst_swapchain
;
1396 BOOL scale
, convert
, resolve
, resolve_typeless
= FALSE
;
1397 const struct wined3d_format
*resolve_format
= NULL
;
1398 const struct wined3d_color_key
*colour_key
= NULL
;
1399 DWORD src_location
, dst_location
, valid_locations
;
1400 struct wined3d_context
*context
;
1401 enum wined3d_blit_op blit_op
;
1402 RECT src_rect
, dst_rect
;
1403 bool src_ds
, dst_ds
;
1405 static const DWORD simple_blit
= WINED3D_BLT_SRC_CKEY
1406 | WINED3D_BLT_SRC_CKEY_OVERRIDE
1407 | WINED3D_BLT_ALPHA_TEST
1410 TRACE("dst_texture %p, dst_sub_resource_idx %u, dst_box %s, src_texture %p, "
1411 "src_sub_resource_idx %u, src_box %s, flags %#x, fx %p, filter %s.\n",
1412 dst_texture
, dst_sub_resource_idx
, debug_box(dst_box
), src_texture
, src_sub_resource_idx
,
1413 debug_box(src_box
), flags
, fx
, debug_d3dtexturefiltertype(filter
));
1414 TRACE("Usage is %s.\n", debug_d3dusage(dst_texture
->resource
.usage
));
1418 TRACE("fx %#x.\n", fx
->fx
);
1419 TRACE("dst_color_key {0x%08x, 0x%08x}.\n",
1420 fx
->dst_color_key
.color_space_low_value
,
1421 fx
->dst_color_key
.color_space_high_value
);
1422 TRACE("src_color_key {0x%08x, 0x%08x}.\n",
1423 fx
->src_color_key
.color_space_low_value
,
1424 fx
->src_color_key
.color_space_high_value
);
1425 TRACE("resolve_format_id %s.\n", debug_d3dformat(fx
->resolve_format_id
));
1427 if (fx
->resolve_format_id
!= WINED3DFMT_UNKNOWN
)
1428 resolve_format
= wined3d_get_format(device
->adapter
, fx
->resolve_format_id
, 0);
1431 dst_sub_resource
= &dst_texture
->sub_resources
[dst_sub_resource_idx
];
1432 src_sub_resource
= &src_texture
->sub_resources
[src_sub_resource_idx
];
1434 if (src_sub_resource
->locations
& WINED3D_LOCATION_DISCARDED
)
1436 WARN("Source sub-resource is discarded, nothing to do.\n");
1440 SetRect(&src_rect
, src_box
->left
, src_box
->top
, src_box
->right
, src_box
->bottom
);
1441 SetRect(&dst_rect
, dst_box
->left
, dst_box
->top
, dst_box
->right
, dst_box
->bottom
);
1443 if (!fx
|| !(fx
->fx
))
1444 flags
&= ~WINED3D_BLT_FX
;
1446 /* WINED3D_BLT_DO_NOT_WAIT appeared in DX7. */
1447 if (flags
& WINED3D_BLT_DO_NOT_WAIT
)
1449 static unsigned int once
;
1452 FIXME("Can't handle WINED3D_BLT_DO_NOT_WAIT flag.\n");
1455 flags
&= ~(WINED3D_BLT_SYNCHRONOUS
| WINED3D_BLT_DO_NOT_WAIT
| WINED3D_BLT_WAIT
);
1457 if (flags
& ~simple_blit
)
1459 WARN_(d3d_perf
)("Using CPU fallback for complex blit (%#x).\n", flags
);
1463 src_swapchain
= src_texture
->swapchain
;
1464 dst_swapchain
= dst_texture
->swapchain
;
1466 if (src_swapchain
&& dst_swapchain
&& src_swapchain
!= dst_swapchain
1467 && (wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
1468 || src_texture
== src_swapchain
->front_buffer
))
1470 /* TODO: We could support cross-swapchain blits by first downloading
1471 * the source to a texture. */
1472 FIXME("Cross-swapchain blit not supported.\n");
1473 return WINED3DERR_INVALIDCALL
;
1476 scale
= src_box
->right
- src_box
->left
!= dst_box
->right
- dst_box
->left
1477 || src_box
->bottom
- src_box
->top
!= dst_box
->bottom
- dst_box
->top
;
1478 convert
= src_texture
->resource
.format
->id
!= dst_texture
->resource
.format
->id
;
1479 resolve
= src_texture
->resource
.multisample_type
!= dst_texture
->resource
.multisample_type
;
1482 resolve_typeless
= (wined3d_format_is_typeless(src_texture
->resource
.format
)
1483 || wined3d_format_is_typeless(dst_texture
->resource
.format
))
1484 && (src_texture
->resource
.format
->typeless_id
== dst_texture
->resource
.format
->typeless_id
);
1485 if (resolve_typeless
&& !resolve_format
)
1486 WARN("Resolve format for typeless resolve not specified.\n");
1489 dst_ds
= dst_texture
->resource
.format
->depth_size
|| dst_texture
->resource
.format
->stencil_size
;
1490 src_ds
= src_texture
->resource
.format
->depth_size
|| src_texture
->resource
.format
->stencil_size
;
1492 if (src_ds
|| dst_ds
)
1494 TRACE("Depth/stencil blit.\n");
1496 if (dst_texture
->resource
.access
& WINED3D_RESOURCE_ACCESS_GPU
)
1497 dst_location
= dst_texture
->resource
.draw_binding
;
1499 dst_location
= dst_texture
->resource
.map_binding
;
1501 if ((flags
& WINED3D_BLT_RAW
) || (!scale
&& !convert
&& !resolve
))
1502 blit_op
= WINED3D_BLIT_OP_RAW_BLIT
;
1504 blit_op
= WINED3D_BLIT_OP_DEPTH_BLIT
;
1506 context
= context_acquire(device
, dst_texture
, dst_sub_resource_idx
);
1507 valid_locations
= device
->blitter
->ops
->blitter_blit(device
->blitter
, blit_op
, context
,
1508 src_texture
, src_sub_resource_idx
, src_texture
->resource
.draw_binding
, &src_rect
,
1509 dst_texture
, dst_sub_resource_idx
, dst_location
, &dst_rect
, NULL
, filter
, resolve_format
);
1510 context_release(context
);
1512 wined3d_texture_validate_location(dst_texture
, dst_sub_resource_idx
, valid_locations
);
1513 wined3d_texture_invalidate_location(dst_texture
, dst_sub_resource_idx
, ~valid_locations
);
1518 TRACE("Colour blit.\n");
1520 /* In principle this would apply to depth blits as well, but we don't
1521 * implement those in the CPU blitter at the moment. */
1522 if ((dst_sub_resource
->locations
& dst_texture
->resource
.map_binding
)
1523 && (src_sub_resource
->locations
& src_texture
->resource
.map_binding
))
1526 TRACE("Not doing sysmem blit because of scaling.\n");
1528 TRACE("Not doing sysmem blit because of format conversion.\n");
1533 blit_op
= WINED3D_BLIT_OP_COLOR_BLIT
;
1534 if (flags
& WINED3D_BLT_SRC_CKEY_OVERRIDE
)
1536 colour_key
= &fx
->src_color_key
;
1537 blit_op
= WINED3D_BLIT_OP_COLOR_BLIT_CKEY
;
1539 else if (flags
& WINED3D_BLT_SRC_CKEY
)
1541 colour_key
= &src_texture
->async
.src_blt_color_key
;
1542 blit_op
= WINED3D_BLIT_OP_COLOR_BLIT_CKEY
;
1544 else if (flags
& WINED3D_BLT_ALPHA_TEST
)
1546 blit_op
= WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST
;
1548 else if (sub_resource_is_on_cpu(src_texture
, src_sub_resource_idx
)
1549 && !sub_resource_is_on_cpu(dst_texture
, dst_sub_resource_idx
)
1550 && (dst_texture
->resource
.access
& WINED3D_RESOURCE_ACCESS_GPU
))
1554 TRACE("Not doing upload because of scaling.\n");
1556 TRACE("Not doing upload because of format conversion.\n");
1557 else if (dst_texture
->resource
.format
->conv_byte_count
)
1558 TRACE("Not doing upload because the destination format needs conversion.\n");
1561 wined3d_texture_upload_from_texture(dst_texture
, dst_sub_resource_idx
, dst_box
->left
,
1562 dst_box
->top
, dst_box
->front
, src_texture
, src_sub_resource_idx
, src_box
);
1563 if (!wined3d_resource_is_offscreen(&dst_texture
->resource
))
1565 context
= context_acquire(device
, dst_texture
, dst_sub_resource_idx
);
1566 wined3d_texture_load_location(dst_texture
, dst_sub_resource_idx
,
1567 context
, dst_texture
->resource
.draw_binding
);
1568 context_release(context
);
1573 else if (!sub_resource_is_on_cpu(src_texture
, src_sub_resource_idx
)
1574 && (dst_sub_resource
->locations
& dst_texture
->resource
.map_binding
)
1575 && !(dst_texture
->resource
.access
& WINED3D_RESOURCE_ACCESS_GPU
))
1579 TRACE("Not doing download because of scaling.\n");
1581 TRACE("Not doing download because of format conversion.\n");
1582 else if (src_texture
->resource
.format
->conv_byte_count
)
1583 TRACE("Not doing download because the source format needs conversion.\n");
1584 else if (!(src_texture
->flags
& WINED3D_TEXTURE_DOWNLOADABLE
))
1585 TRACE("Not doing download because texture is not downloadable.\n");
1586 else if (!wined3d_texture_is_full_rect(src_texture
, src_sub_resource_idx
% src_texture
->level_count
, &src_rect
))
1587 TRACE("Not doing download because of partial download (src).\n");
1588 else if (!wined3d_texture_is_full_rect(dst_texture
, dst_sub_resource_idx
% dst_texture
->level_count
, &dst_rect
))
1589 TRACE("Not doing download because of partial download (dst).\n");
1592 wined3d_texture_download_from_texture(dst_texture
, dst_sub_resource_idx
, src_texture
,
1593 src_sub_resource_idx
);
1597 else if (dst_swapchain
&& dst_swapchain
->back_buffers
1598 && dst_texture
== dst_swapchain
->front_buffer
1599 && src_texture
== dst_swapchain
->back_buffers
[0])
1601 /* Use present for back -> front blits. The idea behind this is that
1602 * present is potentially faster than a blit, in particular when FBO
1603 * blits aren't available. Some ddraw applications like Half-Life and
1604 * Prince of Persia 3D use Blt() from the backbuffer to the
1605 * frontbuffer instead of doing a Flip(). D3d8 and d3d9 applications
1606 * can't blit directly to the frontbuffer. */
1607 enum wined3d_swap_effect swap_effect
= dst_swapchain
->state
.desc
.swap_effect
;
1609 TRACE("Using present for backbuffer -> frontbuffer blit.\n");
1611 /* Set the swap effect to COPY, we don't want the backbuffer to become
1613 dst_swapchain
->state
.desc
.swap_effect
= WINED3D_SWAP_EFFECT_COPY
;
1614 wined3d_swapchain_present(dst_swapchain
, NULL
, NULL
,
1615 dst_swapchain
->win_handle
, dst_swapchain
->swap_interval
, 0);
1616 dst_swapchain
->state
.desc
.swap_effect
= swap_effect
;
1621 if ((flags
& WINED3D_BLT_RAW
) || (blit_op
== WINED3D_BLIT_OP_COLOR_BLIT
&& !scale
&& !convert
&& !resolve
))
1622 blit_op
= WINED3D_BLIT_OP_RAW_BLIT
;
1624 context
= context_acquire(device
, dst_texture
, dst_sub_resource_idx
);
1626 if (src_texture
->resource
.multisample_type
!= WINED3D_MULTISAMPLE_NONE
&& !resolve_typeless
1627 && ((scale
&& !context
->d3d_info
->scaled_resolve
)
1628 || convert
|| !wined3d_is_colour_blit(blit_op
)))
1629 src_location
= WINED3D_LOCATION_RB_RESOLVED
;
1631 src_location
= src_texture
->resource
.draw_binding
;
1633 if (!(dst_texture
->resource
.access
& WINED3D_RESOURCE_ACCESS_GPU
))
1634 dst_location
= dst_texture
->resource
.map_binding
;
1635 else if (dst_texture
->resource
.multisample_type
!= WINED3D_MULTISAMPLE_NONE
1636 && (scale
|| convert
|| !wined3d_is_colour_blit(blit_op
)))
1637 dst_location
= WINED3D_LOCATION_RB_RESOLVED
;
1639 dst_location
= dst_texture
->resource
.draw_binding
;
1641 valid_locations
= device
->blitter
->ops
->blitter_blit(device
->blitter
, blit_op
, context
,
1642 src_texture
, src_sub_resource_idx
, src_location
, &src_rect
,
1643 dst_texture
, dst_sub_resource_idx
, dst_location
, &dst_rect
, colour_key
, filter
, resolve_format
);
1645 context_release(context
);
1647 wined3d_texture_validate_location(dst_texture
, dst_sub_resource_idx
, valid_locations
);
1648 wined3d_texture_invalidate_location(dst_texture
, dst_sub_resource_idx
, ~valid_locations
);
1653 return surface_cpu_blt(dst_texture
, dst_sub_resource_idx
, dst_box
,
1654 src_texture
, src_sub_resource_idx
, src_box
, flags
, fx
, filter
);