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