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