1 /* 2 * Copyright 2002-2005 Jason Edmeades 3 * Copyright 2002-2005 Raphael Junqueira 4 * Copyright 2005 Oliver Stieber 5 * Copyright 2007-2009, 2013 Stefan Dösinger for CodeWeavers 6 * Copyright 2009-2011 Henri Verbeet for CodeWeavers 7 * 8 * This library is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Lesser General Public 10 * License as published by the Free Software Foundation; either 11 * version 2.1 of the License, or (at your option) any later version. 12 * 13 * This library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public 19 * License along with this library; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 21 */ 22 23 #include "config.h" 24 #include "wine/port.h" 25 #include "wined3d_private.h" 26 27 WINE_DEFAULT_DEBUG_CHANNEL(d3d); 28 WINE_DECLARE_DEBUG_CHANNEL(d3d_perf); 29 WINE_DECLARE_DEBUG_CHANNEL(winediag); 30 31 #define WINED3D_TEXTURE_DYNAMIC_MAP_THRESHOLD 50 32 33 struct wined3d_texture_idx 34 { 35 struct wined3d_texture *texture; 36 unsigned int sub_resource_idx; 37 }; 38 39 struct wined3d_rect_f 40 { 41 float l; 42 float t; 43 float r; 44 float b; 45 }; 46 47 static BOOL wined3d_texture_use_pbo(const struct wined3d_texture *texture, const struct wined3d_gl_info *gl_info) 48 { 49 return !(texture->resource.access & WINED3D_RESOURCE_ACCESS_CPU) 50 && texture->resource.usage & WINED3DUSAGE_DYNAMIC 51 && gl_info->supported[ARB_PIXEL_BUFFER_OBJECT] 52 && !texture->resource.format->conv_byte_count 53 && !(texture->flags & (WINED3D_TEXTURE_PIN_SYSMEM | WINED3D_TEXTURE_COND_NP2_EMULATED)); 54 } 55 56 static BOOL wined3d_texture_use_immutable_storage(const struct wined3d_texture *texture, 57 const struct wined3d_gl_info *gl_info) 58 { 59 /* We don't expect to create texture views for textures with height-scaled formats. 60 * Besides, ARB_texture_storage doesn't allow specifying exact sizes for all levels. */ 61 return gl_info->supported[ARB_TEXTURE_STORAGE] 62 && !(texture->resource.format_flags & WINED3DFMT_FLAG_HEIGHT_SCALE); 63 } 64 65 /* Front buffer coordinates are always full screen coordinates, but our GL 66 * drawable is limited to the window's client area. The sysmem and texture 67 * copies do have the full screen size. Note that GL has a bottom-left 68 * origin, while D3D has a top-left origin. */ 69 void wined3d_texture_translate_drawable_coords(const struct wined3d_texture *texture, HWND window, RECT *rect) 70 { 71 unsigned int drawable_height; 72 POINT offset = {0, 0}; 73 RECT windowsize; 74 75 if (!texture->swapchain) 76 return; 77 78 if (texture == texture->swapchain->front_buffer) 79 { 80 ScreenToClient(window, &offset); 81 OffsetRect(rect, offset.x, offset.y); 82 } 83 84 GetClientRect(window, &windowsize); 85 drawable_height = windowsize.bottom - windowsize.top; 86 87 rect->top = drawable_height - rect->top; 88 rect->bottom = drawable_height - rect->bottom; 89 } 90 91 GLenum wined3d_texture_get_gl_buffer(const struct wined3d_texture *texture) 92 { 93 const struct wined3d_swapchain *swapchain = texture->swapchain; 94 95 TRACE("texture %p.\n", texture); 96 97 if (!swapchain) 98 { 99 ERR("Texture %p is not part of a swapchain.\n", texture); 100 return GL_NONE; 101 } 102 103 if (texture == swapchain->front_buffer) 104 { 105 TRACE("Returning GL_FRONT.\n"); 106 return GL_FRONT; 107 } 108 109 if (texture == swapchain->back_buffers[0]) 110 { 111 TRACE("Returning GL_BACK.\n"); 112 return GL_BACK; 113 } 114 115 FIXME("Higher back buffer, returning GL_BACK.\n"); 116 return GL_BACK; 117 } 118 119 static DWORD wined3d_resource_access_from_location(DWORD location) 120 { 121 switch (location) 122 { 123 case WINED3D_LOCATION_DISCARDED: 124 return 0; 125 126 case WINED3D_LOCATION_SYSMEM: 127 case WINED3D_LOCATION_USER_MEMORY: 128 return WINED3D_RESOURCE_ACCESS_CPU; 129 130 case WINED3D_LOCATION_BUFFER: 131 case WINED3D_LOCATION_DRAWABLE: 132 case WINED3D_LOCATION_TEXTURE_RGB: 133 case WINED3D_LOCATION_TEXTURE_SRGB: 134 case WINED3D_LOCATION_RB_MULTISAMPLE: 135 case WINED3D_LOCATION_RB_RESOLVED: 136 return WINED3D_RESOURCE_ACCESS_GPU; 137 138 default: 139 FIXME("Unhandled location %#x.\n", location); 140 return 0; 141 } 142 } 143 144 static inline void cube_coords_float(const RECT *r, UINT w, UINT h, struct wined3d_rect_f *f) 145 { 146 f->l = ((r->left * 2.0f) / w) - 1.0f; 147 f->t = ((r->top * 2.0f) / h) - 1.0f; 148 f->r = ((r->right * 2.0f) / w) - 1.0f; 149 f->b = ((r->bottom * 2.0f) / h) - 1.0f; 150 } 151 152 void texture2d_get_blt_info(const struct wined3d_texture *texture, 153 unsigned int sub_resource_idx, const RECT *rect, struct wined3d_blt_info *info) 154 { 155 struct wined3d_vec3 *coords = info->texcoords; 156 struct wined3d_rect_f f; 157 unsigned int level; 158 GLenum target; 159 GLsizei w, h; 160 161 level = sub_resource_idx % texture->level_count; 162 w = wined3d_texture_get_level_pow2_width(texture, level); 163 h = wined3d_texture_get_level_pow2_height(texture, level); 164 target = wined3d_texture_get_sub_resource_target(texture, sub_resource_idx); 165 166 switch (target) 167 { 168 default: 169 FIXME("Unsupported texture target %#x.\n", target); 170 /* Fall back to GL_TEXTURE_2D */ 171 case GL_TEXTURE_2D: 172 info->bind_target = GL_TEXTURE_2D; 173 coords[0].x = (float)rect->left / w; 174 coords[0].y = (float)rect->top / h; 175 coords[0].z = 0.0f; 176 177 coords[1].x = (float)rect->right / w; 178 coords[1].y = (float)rect->top / h; 179 coords[1].z = 0.0f; 180 181 coords[2].x = (float)rect->left / w; 182 coords[2].y = (float)rect->bottom / h; 183 coords[2].z = 0.0f; 184 185 coords[3].x = (float)rect->right / w; 186 coords[3].y = (float)rect->bottom / h; 187 coords[3].z = 0.0f; 188 break; 189 190 case GL_TEXTURE_RECTANGLE_ARB: 191 info->bind_target = GL_TEXTURE_RECTANGLE_ARB; 192 coords[0].x = rect->left; coords[0].y = rect->top; coords[0].z = 0.0f; 193 coords[1].x = rect->right; coords[1].y = rect->top; coords[1].z = 0.0f; 194 coords[2].x = rect->left; coords[2].y = rect->bottom; coords[2].z = 0.0f; 195 coords[3].x = rect->right; coords[3].y = rect->bottom; coords[3].z = 0.0f; 196 break; 197 198 case GL_TEXTURE_CUBE_MAP_POSITIVE_X: 199 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB; 200 cube_coords_float(rect, w, h, &f); 201 202 coords[0].x = 1.0f; coords[0].y = -f.t; coords[0].z = -f.l; 203 coords[1].x = 1.0f; coords[1].y = -f.t; coords[1].z = -f.r; 204 coords[2].x = 1.0f; coords[2].y = -f.b; coords[2].z = -f.l; 205 coords[3].x = 1.0f; coords[3].y = -f.b; coords[3].z = -f.r; 206 break; 207 208 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: 209 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB; 210 cube_coords_float(rect, w, h, &f); 211 212 coords[0].x = -1.0f; coords[0].y = -f.t; coords[0].z = f.l; 213 coords[1].x = -1.0f; coords[1].y = -f.t; coords[1].z = f.r; 214 coords[2].x = -1.0f; coords[2].y = -f.b; coords[2].z = f.l; 215 coords[3].x = -1.0f; coords[3].y = -f.b; coords[3].z = f.r; 216 break; 217 218 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: 219 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB; 220 cube_coords_float(rect, w, h, &f); 221 222 coords[0].x = f.l; coords[0].y = 1.0f; coords[0].z = f.t; 223 coords[1].x = f.r; coords[1].y = 1.0f; coords[1].z = f.t; 224 coords[2].x = f.l; coords[2].y = 1.0f; coords[2].z = f.b; 225 coords[3].x = f.r; coords[3].y = 1.0f; coords[3].z = f.b; 226 break; 227 228 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: 229 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB; 230 cube_coords_float(rect, w, h, &f); 231 232 coords[0].x = f.l; coords[0].y = -1.0f; coords[0].z = -f.t; 233 coords[1].x = f.r; coords[1].y = -1.0f; coords[1].z = -f.t; 234 coords[2].x = f.l; coords[2].y = -1.0f; coords[2].z = -f.b; 235 coords[3].x = f.r; coords[3].y = -1.0f; coords[3].z = -f.b; 236 break; 237 238 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: 239 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB; 240 cube_coords_float(rect, w, h, &f); 241 242 coords[0].x = f.l; coords[0].y = -f.t; coords[0].z = 1.0f; 243 coords[1].x = f.r; coords[1].y = -f.t; coords[1].z = 1.0f; 244 coords[2].x = f.l; coords[2].y = -f.b; coords[2].z = 1.0f; 245 coords[3].x = f.r; coords[3].y = -f.b; coords[3].z = 1.0f; 246 break; 247 248 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: 249 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB; 250 cube_coords_float(rect, w, h, &f); 251 252 coords[0].x = -f.l; coords[0].y = -f.t; coords[0].z = -1.0f; 253 coords[1].x = -f.r; coords[1].y = -f.t; coords[1].z = -1.0f; 254 coords[2].x = -f.l; coords[2].y = -f.b; coords[2].z = -1.0f; 255 coords[3].x = -f.r; coords[3].y = -f.b; coords[3].z = -1.0f; 256 break; 257 } 258 } 259 260 static void wined3d_texture_evict_sysmem(struct wined3d_texture *texture) 261 { 262 struct wined3d_texture_sub_resource *sub_resource; 263 unsigned int i, sub_count; 264 265 if (texture->flags & (WINED3D_TEXTURE_CONVERTED | WINED3D_TEXTURE_PIN_SYSMEM) 266 || texture->download_count > WINED3D_TEXTURE_DYNAMIC_MAP_THRESHOLD) 267 { 268 TRACE("Not evicting system memory for texture %p.\n", texture); 269 return; 270 } 271 272 TRACE("Evicting system memory for texture %p.\n", texture); 273 274 sub_count = texture->level_count * texture->layer_count; 275 for (i = 0; i < sub_count; ++i) 276 { 277 sub_resource = &texture->sub_resources[i]; 278 if (sub_resource->locations == WINED3D_LOCATION_SYSMEM) 279 ERR("WINED3D_LOCATION_SYSMEM is the only location for sub-resource %u of texture %p.\n", 280 i, texture); 281 sub_resource->locations &= ~WINED3D_LOCATION_SYSMEM; 282 } 283 wined3d_resource_free_sysmem(&texture->resource); 284 } 285 286 void wined3d_texture_validate_location(struct wined3d_texture *texture, 287 unsigned int sub_resource_idx, DWORD location) 288 { 289 struct wined3d_texture_sub_resource *sub_resource; 290 DWORD previous_locations; 291 292 TRACE("texture %p, sub_resource_idx %u, location %s.\n", 293 texture, sub_resource_idx, wined3d_debug_location(location)); 294 295 sub_resource = &texture->sub_resources[sub_resource_idx]; 296 previous_locations = sub_resource->locations; 297 sub_resource->locations |= location; 298 if (previous_locations == WINED3D_LOCATION_SYSMEM && location != WINED3D_LOCATION_SYSMEM 299 && !--texture->sysmem_count) 300 wined3d_texture_evict_sysmem(texture); 301 302 TRACE("New locations flags are %s.\n", wined3d_debug_location(sub_resource->locations)); 303 } 304 305 static void wined3d_texture_set_dirty(struct wined3d_texture *texture) 306 { 307 texture->flags &= ~(WINED3D_TEXTURE_RGB_VALID | WINED3D_TEXTURE_SRGB_VALID); 308 } 309 310 void wined3d_texture_invalidate_location(struct wined3d_texture *texture, 311 unsigned int sub_resource_idx, DWORD location) 312 { 313 struct wined3d_texture_sub_resource *sub_resource; 314 DWORD previous_locations; 315 316 TRACE("texture %p, sub_resource_idx %u, location %s.\n", 317 texture, sub_resource_idx, wined3d_debug_location(location)); 318 319 if (location & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB)) 320 wined3d_texture_set_dirty(texture); 321 322 sub_resource = &texture->sub_resources[sub_resource_idx]; 323 previous_locations = sub_resource->locations; 324 sub_resource->locations &= ~location; 325 if (previous_locations != WINED3D_LOCATION_SYSMEM && sub_resource->locations == WINED3D_LOCATION_SYSMEM) 326 ++texture->sysmem_count; 327 328 TRACE("New locations flags are %s.\n", wined3d_debug_location(sub_resource->locations)); 329 330 if (!sub_resource->locations) 331 ERR("Sub-resource %u of texture %p does not have any up to date location.\n", 332 sub_resource_idx, texture); 333 } 334 335 static BOOL wined3d_texture_copy_sysmem_location(struct wined3d_texture *texture, 336 unsigned int sub_resource_idx, struct wined3d_context *context, DWORD location) 337 { 338 unsigned int size = texture->sub_resources[sub_resource_idx].size; 339 struct wined3d_device *device = texture->resource.device; 340 const struct wined3d_gl_info *gl_info; 341 struct wined3d_bo_address dst, src; 342 343 if (!wined3d_texture_prepare_location(texture, sub_resource_idx, context, location)) 344 return FALSE; 345 346 wined3d_texture_get_memory(texture, sub_resource_idx, &dst, location); 347 wined3d_texture_get_memory(texture, sub_resource_idx, &src, 348 texture->sub_resources[sub_resource_idx].locations); 349 350 if (dst.buffer_object) 351 { 352 context = context_acquire(device, NULL, 0); 353 gl_info = context->gl_info; 354 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, dst.buffer_object)); 355 GL_EXTCALL(glBufferSubData(GL_PIXEL_UNPACK_BUFFER, 0, size, src.addr)); 356 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0)); 357 checkGLcall("PBO upload"); 358 context_release(context); 359 return TRUE; 360 } 361 362 if (src.buffer_object) 363 { 364 context = context_acquire(device, NULL, 0); 365 gl_info = context->gl_info; 366 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, src.buffer_object)); 367 GL_EXTCALL(glGetBufferSubData(GL_PIXEL_PACK_BUFFER, 0, size, dst.addr)); 368 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0)); 369 checkGLcall("PBO download"); 370 context_release(context); 371 return TRUE; 372 } 373 374 memcpy(dst.addr, src.addr, size); 375 return TRUE; 376 } 377 378 /* Context activation is done by the caller. Context may be NULL in 379 * WINED3D_NO3D mode. */ 380 BOOL wined3d_texture_load_location(struct wined3d_texture *texture, 381 unsigned int sub_resource_idx, struct wined3d_context *context, DWORD location) 382 { 383 static const DWORD sysmem_locations = WINED3D_LOCATION_SYSMEM | WINED3D_LOCATION_USER_MEMORY 384 | WINED3D_LOCATION_BUFFER; 385 DWORD current = texture->sub_resources[sub_resource_idx].locations; 386 BOOL ret; 387 388 TRACE("texture %p, sub_resource_idx %u, context %p, location %s.\n", 389 texture, sub_resource_idx, context, wined3d_debug_location(location)); 390 391 TRACE("Current resource location %s.\n", wined3d_debug_location(current)); 392 393 if (current & location) 394 { 395 TRACE("Location %s is already up to date.\n", wined3d_debug_location(location)); 396 return TRUE; 397 } 398 399 if (WARN_ON(d3d)) 400 { 401 DWORD required_access = wined3d_resource_access_from_location(location); 402 if ((texture->resource.access & required_access) != required_access) 403 WARN("Operation requires %#x access, but texture only has %#x.\n", 404 required_access, texture->resource.access); 405 } 406 407 if (current & WINED3D_LOCATION_DISCARDED) 408 { 409 TRACE("Sub-resource previously discarded, nothing to do.\n"); 410 if (!wined3d_texture_prepare_location(texture, sub_resource_idx, context, location)) 411 return FALSE; 412 wined3d_texture_validate_location(texture, sub_resource_idx, location); 413 wined3d_texture_invalidate_location(texture, sub_resource_idx, WINED3D_LOCATION_DISCARDED); 414 return TRUE; 415 } 416 417 if (!current) 418 { 419 ERR("Sub-resource %u of texture %p does not have any up to date location.\n", 420 sub_resource_idx, texture); 421 wined3d_texture_validate_location(texture, sub_resource_idx, WINED3D_LOCATION_DISCARDED); 422 return wined3d_texture_load_location(texture, sub_resource_idx, context, location); 423 } 424 425 if ((location & sysmem_locations) && (current & sysmem_locations)) 426 ret = wined3d_texture_copy_sysmem_location(texture, sub_resource_idx, context, location); 427 else 428 ret = texture->texture_ops->texture_load_location(texture, sub_resource_idx, context, location); 429 430 if (ret) 431 wined3d_texture_validate_location(texture, sub_resource_idx, location); 432 433 return ret; 434 } 435 436 void wined3d_texture_get_memory(struct wined3d_texture *texture, unsigned int sub_resource_idx, 437 struct wined3d_bo_address *data, DWORD locations) 438 { 439 struct wined3d_texture_sub_resource *sub_resource; 440 441 TRACE("texture %p, sub_resource_idx %u, data %p, locations %s.\n", 442 texture, sub_resource_idx, data, wined3d_debug_location(locations)); 443 444 sub_resource = &texture->sub_resources[sub_resource_idx]; 445 if (locations & WINED3D_LOCATION_BUFFER) 446 { 447 data->addr = NULL; 448 data->buffer_object = sub_resource->buffer_object; 449 return; 450 } 451 if (locations & WINED3D_LOCATION_USER_MEMORY) 452 { 453 data->addr = texture->user_memory; 454 data->buffer_object = 0; 455 return; 456 } 457 if (locations & WINED3D_LOCATION_SYSMEM) 458 { 459 data->addr = texture->resource.heap_memory; 460 data->addr += sub_resource->offset; 461 data->buffer_object = 0; 462 return; 463 } 464 465 ERR("Unexpected locations %s.\n", wined3d_debug_location(locations)); 466 data->addr = NULL; 467 data->buffer_object = 0; 468 } 469 470 /* Context activation is done by the caller. */ 471 static void wined3d_texture_remove_buffer_object(struct wined3d_texture *texture, 472 unsigned int sub_resource_idx, const struct wined3d_gl_info *gl_info) 473 { 474 GLuint *buffer_object = &texture->sub_resources[sub_resource_idx].buffer_object; 475 476 GL_EXTCALL(glDeleteBuffers(1, buffer_object)); 477 checkGLcall("glDeleteBuffers"); 478 479 TRACE("Deleted buffer object %u for texture %p, sub-resource %u.\n", 480 *buffer_object, texture, sub_resource_idx); 481 482 wined3d_texture_invalidate_location(texture, sub_resource_idx, WINED3D_LOCATION_BUFFER); 483 *buffer_object = 0; 484 } 485 486 static void wined3d_texture_update_map_binding(struct wined3d_texture *texture) 487 { 488 unsigned int sub_count = texture->level_count * texture->layer_count; 489 const struct wined3d_device *device = texture->resource.device; 490 DWORD map_binding = texture->update_map_binding; 491 struct wined3d_context *context = NULL; 492 unsigned int i; 493 494 if (device->d3d_initialized) 495 context = context_acquire(device, NULL, 0); 496 497 for (i = 0; i < sub_count; ++i) 498 { 499 if (texture->sub_resources[i].locations == texture->resource.map_binding 500 && !wined3d_texture_load_location(texture, i, context, map_binding)) 501 ERR("Failed to load location %s.\n", wined3d_debug_location(map_binding)); 502 if (texture->resource.map_binding == WINED3D_LOCATION_BUFFER) 503 wined3d_texture_remove_buffer_object(texture, i, context->gl_info); 504 } 505 506 if (context) 507 context_release(context); 508 509 texture->resource.map_binding = map_binding; 510 texture->update_map_binding = 0; 511 } 512 513 void wined3d_texture_set_map_binding(struct wined3d_texture *texture, DWORD map_binding) 514 { 515 texture->update_map_binding = map_binding; 516 if (!texture->resource.map_count) 517 wined3d_texture_update_map_binding(texture); 518 } 519 520 /* A GL context is provided by the caller */ 521 static void gltexture_delete(struct wined3d_device *device, const struct wined3d_gl_info *gl_info, 522 struct gl_texture *tex) 523 { 524 context_gl_resource_released(device, tex->name, FALSE); 525 gl_info->gl_ops.gl.p_glDeleteTextures(1, &tex->name); 526 tex->name = 0; 527 } 528 529 static unsigned int wined3d_texture_get_gl_sample_count(const struct wined3d_texture *texture) 530 { 531 const struct wined3d_format *format = texture->resource.format; 532 533 /* TODO: NVIDIA expose their Coverage Sample Anti-Aliasing (CSAA) 534 * feature through type == MULTISAMPLE_XX and quality != 0. This could 535 * be mapped to GL_NV_framebuffer_multisample_coverage. 536 * 537 * AMD have a similar feature called Enhanced Quality Anti-Aliasing 538 * (EQAA), but it does not have an equivalent OpenGL extension. */ 539 540 /* We advertise as many WINED3D_MULTISAMPLE_NON_MASKABLE quality 541 * levels as the count of advertised multisample types for the texture 542 * format. */ 543 if (texture->resource.multisample_type == WINED3D_MULTISAMPLE_NON_MASKABLE) 544 { 545 unsigned int i, count = 0; 546 547 for (i = 0; i < sizeof(format->multisample_types) * CHAR_BIT; ++i) 548 { 549 if (format->multisample_types & 1u << i) 550 { 551 if (texture->resource.multisample_quality == count++) 552 break; 553 } 554 } 555 return i + 1; 556 } 557 558 return texture->resource.multisample_type; 559 } 560 561 /* Context activation is done by the caller. */ 562 /* The caller is responsible for binding the correct texture. */ 563 static void wined3d_texture_allocate_gl_mutable_storage(struct wined3d_texture *texture, 564 GLenum gl_internal_format, const struct wined3d_format *format, 565 const struct wined3d_gl_info *gl_info) 566 { 567 unsigned int level, level_count, layer, layer_count; 568 GLsizei width, height, depth; 569 GLenum target; 570 571 level_count = texture->level_count; 572 if (texture->target == GL_TEXTURE_1D_ARRAY || texture->target == GL_TEXTURE_2D_ARRAY) 573 layer_count = 1; 574 else 575 layer_count = texture->layer_count; 576 577 for (layer = 0; layer < layer_count; ++layer) 578 { 579 target = wined3d_texture_get_sub_resource_target(texture, layer * level_count); 580 581 for (level = 0; level < level_count; ++level) 582 { 583 width = wined3d_texture_get_level_pow2_width(texture, level); 584 height = wined3d_texture_get_level_pow2_height(texture, level); 585 if (texture->resource.format_flags & WINED3DFMT_FLAG_HEIGHT_SCALE) 586 { 587 height *= format->height_scale.numerator; 588 height /= format->height_scale.denominator; 589 } 590 591 TRACE("texture %p, layer %u, level %u, target %#x, width %u, height %u.\n", 592 texture, layer, level, target, width, height); 593 594 if (target == GL_TEXTURE_3D || target == GL_TEXTURE_2D_ARRAY) 595 { 596 depth = wined3d_texture_get_level_depth(texture, level); 597 GL_EXTCALL(glTexImage3D(target, level, gl_internal_format, width, height, 598 target == GL_TEXTURE_2D_ARRAY ? texture->layer_count : depth, 0, 599 format->glFormat, format->glType, NULL)); 600 checkGLcall("glTexImage3D"); 601 } 602 else if (target == GL_TEXTURE_1D) 603 { 604 gl_info->gl_ops.gl.p_glTexImage1D(target, level, gl_internal_format, 605 width, 0, format->glFormat, format->glType, NULL); 606 } 607 else 608 { 609 gl_info->gl_ops.gl.p_glTexImage2D(target, level, gl_internal_format, width, 610 target == GL_TEXTURE_1D_ARRAY ? texture->layer_count : height, 0, 611 format->glFormat, format->glType, NULL); 612 checkGLcall("glTexImage2D"); 613 } 614 } 615 } 616 } 617 618 /* Context activation is done by the caller. */ 619 /* The caller is responsible for binding the correct texture. */ 620 static void wined3d_texture_allocate_gl_immutable_storage(struct wined3d_texture *texture, 621 GLenum gl_internal_format, const struct wined3d_gl_info *gl_info) 622 { 623 unsigned int samples = wined3d_texture_get_gl_sample_count(texture); 624 GLsizei height = wined3d_texture_get_level_pow2_height(texture, 0); 625 GLsizei width = wined3d_texture_get_level_pow2_width(texture, 0); 626 627 switch (texture->target) 628 { 629 case GL_TEXTURE_3D: 630 GL_EXTCALL(glTexStorage3D(texture->target, texture->level_count, 631 gl_internal_format, width, height, wined3d_texture_get_level_depth(texture, 0))); 632 break; 633 case GL_TEXTURE_2D_ARRAY: 634 GL_EXTCALL(glTexStorage3D(texture->target, texture->level_count, 635 gl_internal_format, width, height, texture->layer_count)); 636 break; 637 case GL_TEXTURE_2D_MULTISAMPLE: 638 GL_EXTCALL(glTexStorage2DMultisample(texture->target, samples, 639 gl_internal_format, width, height, GL_FALSE)); 640 break; 641 case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: 642 GL_EXTCALL(glTexStorage3DMultisample(texture->target, samples, 643 gl_internal_format, width, height, texture->layer_count, GL_FALSE)); 644 break; 645 case GL_TEXTURE_1D_ARRAY: 646 GL_EXTCALL(glTexStorage2D(texture->target, texture->level_count, 647 gl_internal_format, width, texture->layer_count)); 648 break; 649 case GL_TEXTURE_1D: 650 GL_EXTCALL(glTexStorage1D(texture->target, texture->level_count, gl_internal_format, width)); 651 break; 652 default: 653 GL_EXTCALL(glTexStorage2D(texture->target, texture->level_count, 654 gl_internal_format, width, height)); 655 break; 656 } 657 658 checkGLcall("allocate immutable storage"); 659 } 660 661 static void wined3d_texture_unload_gl_texture(struct wined3d_texture *texture) 662 { 663 struct wined3d_device *device = texture->resource.device; 664 const struct wined3d_gl_info *gl_info = NULL; 665 struct wined3d_context *context = NULL; 666 667 if (texture->texture_rgb.name || texture->texture_srgb.name 668 || texture->rb_multisample || texture->rb_resolved) 669 { 670 context = context_acquire(device, NULL, 0); 671 gl_info = context->gl_info; 672 } 673 674 if (texture->texture_rgb.name) 675 gltexture_delete(device, context->gl_info, &texture->texture_rgb); 676 677 if (texture->texture_srgb.name) 678 gltexture_delete(device, context->gl_info, &texture->texture_srgb); 679 680 if (texture->rb_multisample) 681 { 682 TRACE("Deleting multisample renderbuffer %u.\n", texture->rb_multisample); 683 context_gl_resource_released(device, texture->rb_multisample, TRUE); 684 gl_info->fbo_ops.glDeleteRenderbuffers(1, &texture->rb_multisample); 685 texture->rb_multisample = 0; 686 } 687 688 if (texture->rb_resolved) 689 { 690 TRACE("Deleting resolved renderbuffer %u.\n", texture->rb_resolved); 691 context_gl_resource_released(device, texture->rb_resolved, TRUE); 692 gl_info->fbo_ops.glDeleteRenderbuffers(1, &texture->rb_resolved); 693 texture->rb_resolved = 0; 694 } 695 696 if (context) context_release(context); 697 698 wined3d_texture_set_dirty(texture); 699 700 resource_unload(&texture->resource); 701 } 702 703 static void wined3d_texture_sub_resources_destroyed(struct wined3d_texture *texture) 704 { 705 unsigned int sub_count = texture->level_count * texture->layer_count; 706 struct wined3d_texture_sub_resource *sub_resource; 707 unsigned int i; 708 709 for (i = 0; i < sub_count; ++i) 710 { 711 sub_resource = &texture->sub_resources[i]; 712 if (sub_resource->parent) 713 { 714 TRACE("sub-resource %u.\n", i); 715 sub_resource->parent_ops->wined3d_object_destroyed(sub_resource->parent); 716 sub_resource->parent = NULL; 717 } 718 } 719 } 720 721 static void wined3d_texture_create_dc(void *object) 722 { 723 const struct wined3d_texture_idx *idx = object; 724 struct wined3d_context *context = NULL; 725 unsigned int sub_resource_idx, level; 726 const struct wined3d_format *format; 727 unsigned int row_pitch, slice_pitch; 728 struct wined3d_texture *texture; 729 struct wined3d_dc_info *dc_info; 730 struct wined3d_bo_address data; 731 D3DKMT_CREATEDCFROMMEMORY desc; 732 struct wined3d_device *device; 733 NTSTATUS status; 734 735 TRACE("texture %p, sub_resource_idx %u.\n", idx->texture, idx->sub_resource_idx); 736 737 texture = idx->texture; 738 sub_resource_idx = idx->sub_resource_idx; 739 level = sub_resource_idx % texture->level_count; 740 device = texture->resource.device; 741 742 format = texture->resource.format; 743 if (!format->ddi_format) 744 { 745 WARN("Cannot create a DC for format %s.\n", debug_d3dformat(format->id)); 746 return; 747 } 748 749 if (!texture->dc_info) 750 { 751 unsigned int sub_count = texture->level_count * texture->layer_count; 752 753 if (!(texture->dc_info = heap_calloc(sub_count, sizeof(*texture->dc_info)))) 754 { 755 ERR("Failed to allocate DC info.\n"); 756 return; 757 } 758 } 759 760 if (device->d3d_initialized) 761 context = context_acquire(device, NULL, 0); 762 763 wined3d_texture_load_location(texture, sub_resource_idx, context, texture->resource.map_binding); 764 wined3d_texture_invalidate_location(texture, sub_resource_idx, ~texture->resource.map_binding); 765 wined3d_texture_get_pitch(texture, level, &row_pitch, &slice_pitch); 766 wined3d_texture_get_memory(texture, sub_resource_idx, &data, texture->resource.map_binding); 767 desc.pMemory = context_map_bo_address(context, &data, 768 texture->sub_resources[sub_resource_idx].size, 769 GL_PIXEL_UNPACK_BUFFER, WINED3D_MAP_READ | WINED3D_MAP_WRITE); 770 771 if (context) 772 context_release(context); 773 774 desc.Format = format->ddi_format; 775 desc.Width = wined3d_texture_get_level_width(texture, level); 776 desc.Height = wined3d_texture_get_level_height(texture, level); 777 desc.Pitch = row_pitch; 778 desc.hDeviceDc = CreateCompatibleDC(NULL); 779 desc.pColorTable = NULL; 780 781 status = D3DKMTCreateDCFromMemory(&desc); 782 DeleteDC(desc.hDeviceDc); 783 if (status) 784 { 785 WARN("Failed to create DC, status %#x.\n", status); 786 return; 787 } 788 789 dc_info = &texture->dc_info[sub_resource_idx]; 790 dc_info->dc = desc.hDc; 791 dc_info->bitmap = desc.hBitmap; 792 793 TRACE("Created DC %p, bitmap %p for texture %p, %u.\n", dc_info->dc, dc_info->bitmap, texture, sub_resource_idx); 794 } 795 796 static void wined3d_texture_destroy_dc(void *object) 797 { 798 const struct wined3d_texture_idx *idx = object; 799 D3DKMT_DESTROYDCFROMMEMORY destroy_desc; 800 struct wined3d_context *context = NULL; 801 struct wined3d_texture *texture; 802 struct wined3d_dc_info *dc_info; 803 struct wined3d_bo_address data; 804 unsigned int sub_resource_idx; 805 struct wined3d_device *device; 806 NTSTATUS status; 807 808 texture = idx->texture; 809 sub_resource_idx = idx->sub_resource_idx; 810 device = texture->resource.device; 811 dc_info = &texture->dc_info[sub_resource_idx]; 812 813 if (!dc_info->dc) 814 { 815 ERR("Sub-resource {%p, %u} has no DC.\n", texture, sub_resource_idx); 816 return; 817 } 818 819 TRACE("dc %p, bitmap %p.\n", dc_info->dc, dc_info->bitmap); 820 821 destroy_desc.hDc = dc_info->dc; 822 destroy_desc.hBitmap = dc_info->bitmap; 823 if ((status = D3DKMTDestroyDCFromMemory(&destroy_desc))) 824 ERR("Failed to destroy dc, status %#x.\n", status); 825 dc_info->dc = NULL; 826 dc_info->bitmap = NULL; 827 828 if (device->d3d_initialized) 829 context = context_acquire(device, NULL, 0); 830 831 wined3d_texture_get_memory(texture, sub_resource_idx, &data, texture->resource.map_binding); 832 context_unmap_bo_address(context, &data, GL_PIXEL_UNPACK_BUFFER); 833 834 if (context) 835 context_release(context); 836 } 837 838 static void wined3d_texture_cleanup(struct wined3d_texture *texture) 839 { 840 unsigned int sub_count = texture->level_count * texture->layer_count; 841 struct wined3d_device *device = texture->resource.device; 842 struct wined3d_renderbuffer_entry *entry, *entry2; 843 const struct wined3d_gl_info *gl_info = NULL; 844 struct wined3d_context *context = NULL; 845 struct wined3d_dc_info *dc_info; 846 GLuint buffer_object; 847 unsigned int i; 848 849 TRACE("texture %p.\n", texture); 850 851 for (i = 0; i < sub_count; ++i) 852 { 853 if (!(buffer_object = texture->sub_resources[i].buffer_object)) 854 continue; 855 856 TRACE("Deleting buffer object %u.\n", buffer_object); 857 858 /* We may not be able to get a context in wined3d_texture_cleanup() in 859 * general, but if a buffer object was previously created we can. */ 860 if (!context) 861 { 862 context = context_acquire(device, NULL, 0); 863 gl_info = context->gl_info; 864 } 865 866 GL_EXTCALL(glDeleteBuffers(1, &buffer_object)); 867 } 868 869 if (!context && !list_empty(&texture->renderbuffers)) 870 { 871 context = context_acquire(device, NULL, 0); 872 gl_info = context->gl_info; 873 } 874 875 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &texture->renderbuffers, struct wined3d_renderbuffer_entry, entry) 876 { 877 TRACE("Deleting renderbuffer %u.\n", entry->id); 878 context_gl_resource_released(device, entry->id, TRUE); 879 gl_info->fbo_ops.glDeleteRenderbuffers(1, &entry->id); 880 heap_free(entry); 881 } 882 883 if (context) 884 context_release(context); 885 886 if ((dc_info = texture->dc_info)) 887 { 888 for (i = 0; i < sub_count; ++i) 889 { 890 if (dc_info[i].dc) 891 { 892 struct wined3d_texture_idx texture_idx = {texture, i}; 893 894 wined3d_texture_destroy_dc(&texture_idx); 895 } 896 } 897 heap_free(dc_info); 898 } 899 900 if (texture->overlay_info) 901 { 902 for (i = 0; i < sub_count; ++i) 903 { 904 struct wined3d_overlay_info *info = &texture->overlay_info[i]; 905 struct wined3d_overlay_info *overlay, *cur; 906 907 list_remove(&info->entry); 908 LIST_FOR_EACH_ENTRY_SAFE(overlay, cur, &info->overlays, struct wined3d_overlay_info, entry) 909 { 910 list_remove(&overlay->entry); 911 } 912 } 913 heap_free(texture->overlay_info); 914 } 915 wined3d_texture_unload_gl_texture(texture); 916 } 917 918 void wined3d_texture_set_swapchain(struct wined3d_texture *texture, struct wined3d_swapchain *swapchain) 919 { 920 texture->swapchain = swapchain; 921 wined3d_resource_update_draw_binding(&texture->resource); 922 } 923 924 /* Context activation is done by the caller. */ 925 void wined3d_texture_bind(struct wined3d_texture *texture, 926 struct wined3d_context *context, BOOL srgb) 927 { 928 const struct wined3d_gl_info *gl_info = context->gl_info; 929 const struct wined3d_format *format = texture->resource.format; 930 const struct color_fixup_desc fixup = format->color_fixup; 931 struct gl_texture *gl_tex; 932 GLenum target; 933 934 TRACE("texture %p, context %p, srgb %#x.\n", texture, context, srgb); 935 936 if (!needs_separate_srgb_gl_texture(context, texture)) 937 srgb = FALSE; 938 939 /* sRGB mode cache for preload() calls outside drawprim. */ 940 if (srgb) 941 texture->flags |= WINED3D_TEXTURE_IS_SRGB; 942 else 943 texture->flags &= ~WINED3D_TEXTURE_IS_SRGB; 944 945 gl_tex = wined3d_texture_get_gl_texture(texture, srgb); 946 target = texture->target; 947 948 if (gl_tex->name) 949 { 950 context_bind_texture(context, target, gl_tex->name); 951 return; 952 } 953 954 gl_info->gl_ops.gl.p_glGenTextures(1, &gl_tex->name); 955 checkGLcall("glGenTextures"); 956 TRACE("Generated texture %d.\n", gl_tex->name); 957 958 if (!gl_tex->name) 959 { 960 ERR("Failed to generate a texture name.\n"); 961 return; 962 } 963 964 /* Initialise the state of the texture object to the OpenGL defaults, not 965 * the wined3d defaults. */ 966 gl_tex->sampler_desc.address_u = WINED3D_TADDRESS_WRAP; 967 gl_tex->sampler_desc.address_v = WINED3D_TADDRESS_WRAP; 968 gl_tex->sampler_desc.address_w = WINED3D_TADDRESS_WRAP; 969 memset(gl_tex->sampler_desc.border_color, 0, sizeof(gl_tex->sampler_desc.border_color)); 970 gl_tex->sampler_desc.mag_filter = WINED3D_TEXF_LINEAR; 971 gl_tex->sampler_desc.min_filter = WINED3D_TEXF_POINT; /* GL_NEAREST_MIPMAP_LINEAR */ 972 gl_tex->sampler_desc.mip_filter = WINED3D_TEXF_LINEAR; /* GL_NEAREST_MIPMAP_LINEAR */ 973 gl_tex->sampler_desc.lod_bias = 0.0f; 974 gl_tex->sampler_desc.min_lod = -1000.0f; 975 gl_tex->sampler_desc.max_lod = 1000.0f; 976 gl_tex->sampler_desc.max_anisotropy = 1; 977 gl_tex->sampler_desc.compare = FALSE; 978 gl_tex->sampler_desc.comparison_func = WINED3D_CMP_LESSEQUAL; 979 if (context->gl_info->supported[EXT_TEXTURE_SRGB_DECODE]) 980 gl_tex->sampler_desc.srgb_decode = TRUE; 981 else 982 gl_tex->sampler_desc.srgb_decode = srgb; 983 gl_tex->base_level = 0; 984 wined3d_texture_set_dirty(texture); 985 986 context_bind_texture(context, target, gl_tex->name); 987 988 /* For a new texture we have to set the texture levels after binding the 989 * texture. Beware that texture rectangles do not support mipmapping, but 990 * set the maxmiplevel if we're relying on the partial 991 * GL_ARB_texture_non_power_of_two emulation with texture rectangles. 992 * (I.e., do not care about cond_np2 here, just look for 993 * GL_TEXTURE_RECTANGLE_ARB.) */ 994 if (target != GL_TEXTURE_RECTANGLE_ARB) 995 { 996 TRACE("Setting GL_TEXTURE_MAX_LEVEL to %u.\n", texture->level_count - 1); 997 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, texture->level_count - 1); 998 checkGLcall("glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, texture->level_count)"); 999 } 1000 1001 if (target == GL_TEXTURE_CUBE_MAP_ARB) 1002 { 1003 /* Cubemaps are always set to clamp, regardless of the sampler state. */ 1004 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 1005 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 1006 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); 1007 } 1008 1009 if (texture->flags & WINED3D_TEXTURE_COND_NP2) 1010 { 1011 /* Conditinal non power of two textures use a different clamping 1012 * default. If we're using the GL_WINE_normalized_texrect partial 1013 * driver emulation, we're dealing with a GL_TEXTURE_2D texture which 1014 * has the address mode set to repeat - something that prevents us 1015 * from hitting the accelerated codepath. Thus manually set the GL 1016 * state. The same applies to filtering. Even if the texture has only 1017 * one mip level, the default LINEAR_MIPMAP_LINEAR filter causes a SW 1018 * fallback on macos. */ 1019 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 1020 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 1021 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 1022 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 1023 checkGLcall("glTexParameteri"); 1024 gl_tex->sampler_desc.address_u = WINED3D_TADDRESS_CLAMP; 1025 gl_tex->sampler_desc.address_v = WINED3D_TADDRESS_CLAMP; 1026 gl_tex->sampler_desc.mag_filter = WINED3D_TEXF_POINT; 1027 gl_tex->sampler_desc.min_filter = WINED3D_TEXF_POINT; 1028 gl_tex->sampler_desc.mip_filter = WINED3D_TEXF_NONE; 1029 } 1030 1031 if (gl_info->supported[WINED3D_GL_LEGACY_CONTEXT] && gl_info->supported[ARB_DEPTH_TEXTURE]) 1032 { 1033 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_INTENSITY); 1034 checkGLcall("glTexParameteri(GL_DEPTH_TEXTURE_MODE_ARB, GL_INTENSITY)"); 1035 } 1036 1037 if (!is_identity_fixup(fixup) && can_use_texture_swizzle(gl_info, format)) 1038 { 1039 static const GLenum swizzle_source[] = 1040 { 1041 GL_ZERO, /* CHANNEL_SOURCE_ZERO */ 1042 GL_ONE, /* CHANNEL_SOURCE_ONE */ 1043 GL_RED, /* CHANNEL_SOURCE_X */ 1044 GL_GREEN, /* CHANNEL_SOURCE_Y */ 1045 GL_BLUE, /* CHANNEL_SOURCE_Z */ 1046 GL_ALPHA, /* CHANNEL_SOURCE_W */ 1047 }; 1048 struct 1049 { 1050 GLint x, y, z, w; 1051 } 1052 swizzle; 1053 1054 swizzle.x = swizzle_source[fixup.x_source]; 1055 swizzle.y = swizzle_source[fixup.y_source]; 1056 swizzle.z = swizzle_source[fixup.z_source]; 1057 swizzle.w = swizzle_source[fixup.w_source]; 1058 gl_info->gl_ops.gl.p_glTexParameteriv(target, GL_TEXTURE_SWIZZLE_RGBA, &swizzle.x); 1059 checkGLcall("glTexParameteriv(GL_TEXTURE_SWIZZLE_RGBA)"); 1060 } 1061 } 1062 1063 /* Context activation is done by the caller. */ 1064 void wined3d_texture_bind_and_dirtify(struct wined3d_texture *texture, 1065 struct wined3d_context *context, BOOL srgb) 1066 { 1067 /* We don't need a specific texture unit, but after binding the texture 1068 * the current unit is dirty. Read the unit back instead of switching to 1069 * 0, this avoids messing around with the state manager's GL states. The 1070 * current texture unit should always be a valid one. 1071 * 1072 * To be more specific, this is tricky because we can implicitly be 1073 * called from sampler() in state.c. This means we can't touch anything 1074 * other than whatever happens to be the currently active texture, or we 1075 * would risk marking already applied sampler states dirty again. */ 1076 if (context->active_texture < ARRAY_SIZE(context->rev_tex_unit_map)) 1077 { 1078 DWORD active_sampler = context->rev_tex_unit_map[context->active_texture]; 1079 if (active_sampler != WINED3D_UNMAPPED_STAGE) 1080 context_invalidate_state(context, STATE_SAMPLER(active_sampler)); 1081 } 1082 /* FIXME: Ideally we'd only do this when touching a binding that's used by 1083 * a shader. */ 1084 context_invalidate_compute_state(context, STATE_COMPUTE_SHADER_RESOURCE_BINDING); 1085 context_invalidate_state(context, STATE_GRAPHICS_SHADER_RESOURCE_BINDING); 1086 1087 wined3d_texture_bind(texture, context, srgb); 1088 } 1089 1090 /* Context activation is done by the caller (state handler). */ 1091 /* This function relies on the correct texture being bound and loaded. */ 1092 void wined3d_texture_apply_sampler_desc(struct wined3d_texture *texture, 1093 const struct wined3d_sampler_desc *sampler_desc, const struct wined3d_context *context) 1094 { 1095 const struct wined3d_gl_info *gl_info = context->gl_info; 1096 GLenum target = texture->target; 1097 struct gl_texture *gl_tex; 1098 DWORD state; 1099 1100 TRACE("texture %p, sampler_desc %p, context %p.\n", texture, sampler_desc, context); 1101 1102 gl_tex = wined3d_texture_get_gl_texture(texture, texture->flags & WINED3D_TEXTURE_IS_SRGB); 1103 1104 state = sampler_desc->address_u; 1105 if (state != gl_tex->sampler_desc.address_u) 1106 { 1107 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_S, 1108 gl_info->wrap_lookup[state - WINED3D_TADDRESS_WRAP]); 1109 gl_tex->sampler_desc.address_u = state; 1110 } 1111 1112 state = sampler_desc->address_v; 1113 if (state != gl_tex->sampler_desc.address_v) 1114 { 1115 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_T, 1116 gl_info->wrap_lookup[state - WINED3D_TADDRESS_WRAP]); 1117 gl_tex->sampler_desc.address_v = state; 1118 } 1119 1120 state = sampler_desc->address_w; 1121 if (state != gl_tex->sampler_desc.address_w) 1122 { 1123 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_R, 1124 gl_info->wrap_lookup[state - WINED3D_TADDRESS_WRAP]); 1125 gl_tex->sampler_desc.address_w = state; 1126 } 1127 1128 if (memcmp(gl_tex->sampler_desc.border_color, sampler_desc->border_color, 1129 sizeof(gl_tex->sampler_desc.border_color))) 1130 { 1131 gl_info->gl_ops.gl.p_glTexParameterfv(target, GL_TEXTURE_BORDER_COLOR, &sampler_desc->border_color[0]); 1132 memcpy(gl_tex->sampler_desc.border_color, sampler_desc->border_color, 1133 sizeof(gl_tex->sampler_desc.border_color)); 1134 } 1135 1136 state = sampler_desc->mag_filter; 1137 if (state != gl_tex->sampler_desc.mag_filter) 1138 { 1139 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_MAG_FILTER, wined3d_gl_mag_filter(state)); 1140 gl_tex->sampler_desc.mag_filter = state; 1141 } 1142 1143 if (sampler_desc->min_filter != gl_tex->sampler_desc.min_filter 1144 || sampler_desc->mip_filter != gl_tex->sampler_desc.mip_filter) 1145 { 1146 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_MIN_FILTER, 1147 wined3d_gl_min_mip_filter(sampler_desc->min_filter, sampler_desc->mip_filter)); 1148 gl_tex->sampler_desc.min_filter = sampler_desc->min_filter; 1149 gl_tex->sampler_desc.mip_filter = sampler_desc->mip_filter; 1150 } 1151 1152 state = sampler_desc->max_anisotropy; 1153 if (state != gl_tex->sampler_desc.max_anisotropy) 1154 { 1155 if (gl_info->supported[ARB_TEXTURE_FILTER_ANISOTROPIC]) 1156 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_MAX_ANISOTROPY, state); 1157 else 1158 WARN("Anisotropic filtering not supported.\n"); 1159 gl_tex->sampler_desc.max_anisotropy = state; 1160 } 1161 1162 if (!sampler_desc->srgb_decode != !gl_tex->sampler_desc.srgb_decode 1163 && (context->d3d_info->wined3d_creation_flags & WINED3D_SRGB_READ_WRITE_CONTROL) 1164 && gl_info->supported[EXT_TEXTURE_SRGB_DECODE]) 1165 { 1166 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_SRGB_DECODE_EXT, 1167 sampler_desc->srgb_decode ? GL_DECODE_EXT : GL_SKIP_DECODE_EXT); 1168 gl_tex->sampler_desc.srgb_decode = sampler_desc->srgb_decode; 1169 } 1170 1171 if (!sampler_desc->compare != !gl_tex->sampler_desc.compare) 1172 { 1173 if (sampler_desc->compare) 1174 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB); 1175 else 1176 gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE); 1177 gl_tex->sampler_desc.compare = sampler_desc->compare; 1178 } 1179 1180 checkGLcall("Texture parameter application"); 1181 1182 if (gl_info->supported[EXT_TEXTURE_LOD_BIAS]) 1183 { 1184 gl_info->gl_ops.gl.p_glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, 1185 GL_TEXTURE_LOD_BIAS_EXT, sampler_desc->lod_bias); 1186 checkGLcall("glTexEnvf(GL_TEXTURE_LOD_BIAS_EXT, ...)"); 1187 } 1188 } 1189 1190 ULONG CDECL wined3d_texture_incref(struct wined3d_texture *texture) 1191 { 1192 ULONG refcount; 1193 1194 TRACE("texture %p, swapchain %p.\n", texture, texture->swapchain); 1195 1196 if (texture->swapchain) 1197 return wined3d_swapchain_incref(texture->swapchain); 1198 1199 refcount = InterlockedIncrement(&texture->resource.ref); 1200 TRACE("%p increasing refcount to %u.\n", texture, refcount); 1201 1202 return refcount; 1203 } 1204 1205 static void wined3d_texture_cleanup_sync(struct wined3d_texture *texture) 1206 { 1207 wined3d_texture_sub_resources_destroyed(texture); 1208 resource_cleanup(&texture->resource); 1209 wined3d_resource_wait_idle(&texture->resource); 1210 wined3d_texture_cleanup(texture); 1211 } 1212 1213 static void wined3d_texture_destroy_object(void *object) 1214 { 1215 wined3d_texture_cleanup(object); 1216 heap_free(object); 1217 } 1218 1219 ULONG CDECL wined3d_texture_decref(struct wined3d_texture *texture) 1220 { 1221 ULONG refcount; 1222 1223 TRACE("texture %p, swapchain %p.\n", texture, texture->swapchain); 1224 1225 if (texture->swapchain) 1226 return wined3d_swapchain_decref(texture->swapchain); 1227 1228 refcount = InterlockedDecrement(&texture->resource.ref); 1229 TRACE("%p decreasing refcount to %u.\n", texture, refcount); 1230 1231 if (!refcount) 1232 { 1233 /* Wait for the texture to become idle if it's using user memory, 1234 * since the application is allowed to free that memory once the 1235 * texture is destroyed. Note that this implies that 1236 * wined3d_texture_destroy_object() can't access that memory either. */ 1237 if (texture->user_memory) 1238 wined3d_resource_wait_idle(&texture->resource); 1239 wined3d_texture_sub_resources_destroyed(texture); 1240 texture->resource.parent_ops->wined3d_object_destroyed(texture->resource.parent); 1241 resource_cleanup(&texture->resource); 1242 wined3d_cs_destroy_object(texture->resource.device->cs, wined3d_texture_destroy_object, texture); 1243 } 1244 1245 return refcount; 1246 } 1247 1248 struct wined3d_resource * CDECL wined3d_texture_get_resource(struct wined3d_texture *texture) 1249 { 1250 TRACE("texture %p.\n", texture); 1251 1252 return &texture->resource; 1253 } 1254 1255 static BOOL color_key_equal(const struct wined3d_color_key *c1, struct wined3d_color_key *c2) 1256 { 1257 return c1->color_space_low_value == c2->color_space_low_value 1258 && c1->color_space_high_value == c2->color_space_high_value; 1259 } 1260 1261 /* Context activation is done by the caller */ 1262 void wined3d_texture_load(struct wined3d_texture *texture, 1263 struct wined3d_context *context, BOOL srgb) 1264 { 1265 UINT sub_count = texture->level_count * texture->layer_count; 1266 const struct wined3d_d3d_info *d3d_info = context->d3d_info; 1267 DWORD flag; 1268 UINT i; 1269 1270 TRACE("texture %p, context %p, srgb %#x.\n", texture, context, srgb); 1271 1272 if (!needs_separate_srgb_gl_texture(context, texture)) 1273 srgb = FALSE; 1274 1275 if (srgb) 1276 flag = WINED3D_TEXTURE_SRGB_VALID; 1277 else 1278 flag = WINED3D_TEXTURE_RGB_VALID; 1279 1280 if (!d3d_info->shader_color_key 1281 && (!(texture->async.flags & WINED3D_TEXTURE_ASYNC_COLOR_KEY) 1282 != !(texture->async.color_key_flags & WINED3D_CKEY_SRC_BLT) 1283 || (texture->async.flags & WINED3D_TEXTURE_ASYNC_COLOR_KEY 1284 && !color_key_equal(&texture->async.gl_color_key, &texture->async.src_blt_color_key)))) 1285 { 1286 unsigned int sub_count = texture->level_count * texture->layer_count; 1287 unsigned int i; 1288 1289 TRACE("Reloading because of color key value change.\n"); 1290 for (i = 0; i < sub_count; i++) 1291 { 1292 if (!wined3d_texture_load_location(texture, i, context, texture->resource.map_binding)) 1293 ERR("Failed to load location %s.\n", wined3d_debug_location(texture->resource.map_binding)); 1294 else 1295 wined3d_texture_invalidate_location(texture, i, ~texture->resource.map_binding); 1296 } 1297 1298 texture->async.gl_color_key = texture->async.src_blt_color_key; 1299 } 1300 1301 if (texture->flags & flag) 1302 { 1303 TRACE("Texture %p not dirty, nothing to do.\n", texture); 1304 return; 1305 } 1306 1307 /* Reload the surfaces if the texture is marked dirty. */ 1308 for (i = 0; i < sub_count; ++i) 1309 { 1310 if (!wined3d_texture_load_location(texture, i, context, 1311 srgb ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB)) 1312 ERR("Failed to load location (srgb %#x).\n", srgb); 1313 } 1314 texture->flags |= flag; 1315 } 1316 1317 void * CDECL wined3d_texture_get_parent(const struct wined3d_texture *texture) 1318 { 1319 TRACE("texture %p.\n", texture); 1320 1321 return texture->resource.parent; 1322 } 1323 1324 HRESULT wined3d_texture_check_box_dimensions(const struct wined3d_texture *texture, 1325 unsigned int level, const struct wined3d_box *box) 1326 { 1327 const struct wined3d_format *format = texture->resource.format; 1328 unsigned int width_mask, height_mask, width, height, depth; 1329 1330 width = wined3d_texture_get_level_width(texture, level); 1331 height = wined3d_texture_get_level_height(texture, level); 1332 depth = wined3d_texture_get_level_depth(texture, level); 1333 1334 if (box->left >= box->right || box->right > width 1335 || box->top >= box->bottom || box->bottom > height 1336 || box->front >= box->back || box->back > depth) 1337 { 1338 WARN("Box %s is invalid.\n", debug_box(box)); 1339 return WINEDDERR_INVALIDRECT; 1340 } 1341 1342 if (texture->resource.format_flags & WINED3DFMT_FLAG_BLOCKS) 1343 { 1344 /* This assumes power of two block sizes, but NPOT block sizes would 1345 * be silly anyway. 1346 * 1347 * This also assumes that the format's block depth is 1. */ 1348 width_mask = format->block_width - 1; 1349 height_mask = format->block_height - 1; 1350 1351 if ((box->left & width_mask) || (box->top & height_mask) 1352 || (box->right & width_mask && box->right != width) 1353 || (box->bottom & height_mask && box->bottom != height)) 1354 { 1355 WARN("Box %s is misaligned for %ux%u blocks.\n", 1356 debug_box(box), format->block_width, format->block_height); 1357 return WINED3DERR_INVALIDCALL; 1358 } 1359 } 1360 1361 return WINED3D_OK; 1362 } 1363 1364 void CDECL wined3d_texture_get_pitch(const struct wined3d_texture *texture, 1365 unsigned int level, unsigned int *row_pitch, unsigned int *slice_pitch) 1366 { 1367 const struct wined3d_resource *resource = &texture->resource; 1368 unsigned int width = wined3d_texture_get_level_width(texture, level); 1369 unsigned int height = wined3d_texture_get_level_height(texture, level); 1370 1371 if (texture->row_pitch) 1372 { 1373 *row_pitch = texture->row_pitch; 1374 *slice_pitch = texture->slice_pitch; 1375 return; 1376 } 1377 1378 wined3d_format_calculate_pitch(resource->format, resource->device->surface_alignment, 1379 width, height, row_pitch, slice_pitch); 1380 } 1381 1382 DWORD CDECL wined3d_texture_set_lod(struct wined3d_texture *texture, DWORD lod) 1383 { 1384 DWORD old = texture->lod; 1385 1386 TRACE("texture %p, lod %u.\n", texture, lod); 1387 1388 /* The d3d9:texture test shows that SetLOD is ignored on non-managed 1389 * textures. The call always returns 0, and GetLOD always returns 0. */ 1390 if (!wined3d_resource_access_is_managed(texture->resource.access)) 1391 { 1392 TRACE("Ignoring LOD on texture with resource access %s.\n", 1393 wined3d_debug_resource_access(texture->resource.access)); 1394 return 0; 1395 } 1396 1397 if (lod >= texture->level_count) 1398 lod = texture->level_count - 1; 1399 1400 if (texture->lod != lod) 1401 { 1402 struct wined3d_device *device = texture->resource.device; 1403 1404 wined3d_resource_wait_idle(&texture->resource); 1405 texture->lod = lod; 1406 1407 texture->texture_rgb.base_level = ~0u; 1408 texture->texture_srgb.base_level = ~0u; 1409 if (texture->resource.bind_count) 1410 wined3d_cs_emit_set_sampler_state(device->cs, texture->sampler, WINED3D_SAMP_MAX_MIP_LEVEL, 1411 device->state.sampler_states[texture->sampler][WINED3D_SAMP_MAX_MIP_LEVEL]); 1412 } 1413 1414 return old; 1415 } 1416 1417 DWORD CDECL wined3d_texture_get_lod(const struct wined3d_texture *texture) 1418 { 1419 TRACE("texture %p, returning %u.\n", texture, texture->lod); 1420 1421 return texture->lod; 1422 } 1423 1424 DWORD CDECL wined3d_texture_get_level_count(const struct wined3d_texture *texture) 1425 { 1426 TRACE("texture %p, returning %u.\n", texture, texture->level_count); 1427 1428 return texture->level_count; 1429 } 1430 1431 HRESULT CDECL wined3d_texture_set_color_key(struct wined3d_texture *texture, 1432 DWORD flags, const struct wined3d_color_key *color_key) 1433 { 1434 struct wined3d_device *device = texture->resource.device; 1435 static const DWORD all_flags = WINED3D_CKEY_DST_BLT | WINED3D_CKEY_DST_OVERLAY 1436 | WINED3D_CKEY_SRC_BLT | WINED3D_CKEY_SRC_OVERLAY; 1437 1438 TRACE("texture %p, flags %#x, color_key %p.\n", texture, flags, color_key); 1439 1440 if (flags & ~all_flags) 1441 { 1442 WARN("Invalid flags passed, returning WINED3DERR_INVALIDCALL.\n"); 1443 return WINED3DERR_INVALIDCALL; 1444 } 1445 1446 wined3d_cs_emit_set_color_key(device->cs, texture, flags, color_key); 1447 1448 return WINED3D_OK; 1449 } 1450 1451 /* In D3D the depth stencil dimensions have to be greater than or equal to the 1452 * render target dimensions. With FBOs, the dimensions have to be an exact match. */ 1453 /* TODO: We should synchronize the renderbuffer's content with the texture's content. */ 1454 /* Context activation is done by the caller. */ 1455 void wined3d_texture_set_compatible_renderbuffer(struct wined3d_texture *texture, 1456 unsigned int level, const struct wined3d_rendertarget_info *rt) 1457 { 1458 struct wined3d_renderbuffer_entry *entry; 1459 const struct wined3d_gl_info *gl_info; 1460 unsigned int src_width, src_height; 1461 unsigned int width, height; 1462 GLuint renderbuffer = 0; 1463 1464 gl_info = &texture->resource.device->adapter->gl_info; 1465 if (gl_info->supported[ARB_FRAMEBUFFER_OBJECT]) 1466 return; 1467 1468 if (rt && rt->resource->format->id != WINED3DFMT_NULL) 1469 { 1470 struct wined3d_texture *rt_texture; 1471 unsigned int rt_level; 1472 1473 if (rt->resource->type == WINED3D_RTYPE_BUFFER) 1474 { 1475 FIXME("Unsupported resource type %s.\n", debug_d3dresourcetype(rt->resource->type)); 1476 return; 1477 } 1478 rt_texture = wined3d_texture_from_resource(rt->resource); 1479 rt_level = rt->sub_resource_idx % rt_texture->level_count; 1480 1481 width = wined3d_texture_get_level_pow2_width(rt_texture, rt_level); 1482 height = wined3d_texture_get_level_pow2_height(rt_texture, rt_level); 1483 } 1484 else 1485 { 1486 width = wined3d_texture_get_level_pow2_width(texture, level); 1487 height = wined3d_texture_get_level_pow2_height(texture, level); 1488 } 1489 1490 src_width = wined3d_texture_get_level_pow2_width(texture, level); 1491 src_height = wined3d_texture_get_level_pow2_height(texture, level); 1492 1493 /* A depth stencil smaller than the render target is not valid */ 1494 if (width > src_width || height > src_height) 1495 return; 1496 1497 /* Remove any renderbuffer set if the sizes match */ 1498 if (width == src_width && height == src_height) 1499 { 1500 texture->current_renderbuffer = NULL; 1501 return; 1502 } 1503 1504 /* Look if we've already got a renderbuffer of the correct dimensions */ 1505 LIST_FOR_EACH_ENTRY(entry, &texture->renderbuffers, struct wined3d_renderbuffer_entry, entry) 1506 { 1507 if (entry->width == width && entry->height == height) 1508 { 1509 renderbuffer = entry->id; 1510 texture->current_renderbuffer = entry; 1511 break; 1512 } 1513 } 1514 1515 if (!renderbuffer) 1516 { 1517 gl_info->fbo_ops.glGenRenderbuffers(1, &renderbuffer); 1518 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer); 1519 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER, 1520 texture->resource.format->glInternal, width, height); 1521 1522 entry = heap_alloc(sizeof(*entry)); 1523 entry->width = width; 1524 entry->height = height; 1525 entry->id = renderbuffer; 1526 list_add_head(&texture->renderbuffers, &entry->entry); 1527 1528 texture->current_renderbuffer = entry; 1529 } 1530 1531 checkGLcall("set_compatible_renderbuffer"); 1532 } 1533 1534 HRESULT CDECL wined3d_texture_update_desc(struct wined3d_texture *texture, UINT width, UINT height, 1535 enum wined3d_format_id format_id, enum wined3d_multisample_type multisample_type, 1536 UINT multisample_quality, void *mem, UINT pitch) 1537 { 1538 struct wined3d_device *device = texture->resource.device; 1539 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; 1540 const struct wined3d_format *format = wined3d_get_format(gl_info, format_id, texture->resource.usage); 1541 UINT resource_size = wined3d_format_calculate_size(format, device->surface_alignment, width, height, 1); 1542 struct wined3d_texture_sub_resource *sub_resource; 1543 DWORD valid_location = 0; 1544 BOOL create_dib = FALSE; 1545 1546 TRACE("texture %p, width %u, height %u, format %s, multisample_type %#x, multisample_quality %u, " 1547 "mem %p, pitch %u.\n", 1548 texture, width, height, debug_d3dformat(format_id), multisample_type, multisample_quality, mem, pitch); 1549 1550 if (!resource_size) 1551 return WINED3DERR_INVALIDCALL; 1552 1553 if (texture->level_count * texture->layer_count > 1) 1554 { 1555 WARN("Texture has multiple sub-resources, not supported.\n"); 1556 return WINED3DERR_INVALIDCALL; 1557 } 1558 1559 if (texture->resource.type != WINED3D_RTYPE_TEXTURE_2D) 1560 { 1561 WARN("Not supported on %s.\n", debug_d3dresourcetype(texture->resource.type)); 1562 return WINED3DERR_INVALIDCALL; 1563 } 1564 1565 if (texture->resource.map_count) 1566 { 1567 WARN("Texture is mapped.\n"); 1568 return WINED3DERR_INVALIDCALL; 1569 } 1570 1571 /* We have no way of supporting a pitch that is not a multiple of the pixel 1572 * byte width short of uploading the texture row-by-row. 1573 * Fortunately that's not an issue since D3D9Ex doesn't allow a custom pitch 1574 * for user-memory textures (it always expects packed data) while DirectDraw 1575 * requires a 4-byte aligned pitch and doesn't support texture formats 1576 * larger than 4 bytes per pixel nor any format using 3 bytes per pixel. 1577 * This check is here to verify that the assumption holds. */ 1578 if (pitch % texture->resource.format->byte_count) 1579 { 1580 WARN("Pitch unsupported, not a multiple of the texture format byte width.\n"); 1581 return WINED3DERR_INVALIDCALL; 1582 } 1583 1584 if (device->d3d_initialized) 1585 wined3d_cs_emit_unload_resource(device->cs, &texture->resource); 1586 wined3d_resource_wait_idle(&texture->resource); 1587 1588 sub_resource = &texture->sub_resources[0]; 1589 if (texture->dc_info && texture->dc_info[0].dc) 1590 { 1591 struct wined3d_texture_idx texture_idx = {texture, 0}; 1592 1593 wined3d_cs_destroy_object(device->cs, wined3d_texture_destroy_dc, &texture_idx); 1594 device->cs->ops->finish(device->cs, WINED3D_CS_QUEUE_DEFAULT); 1595 create_dib = TRUE; 1596 } 1597 1598 wined3d_resource_free_sysmem(&texture->resource); 1599 1600 if ((texture->row_pitch = pitch)) 1601 texture->slice_pitch = height * pitch; 1602 else 1603 /* User memory surfaces don't have the regular surface alignment. */ 1604 wined3d_format_calculate_pitch(format, 1, width, height, 1605 &texture->row_pitch, &texture->slice_pitch); 1606 1607 texture->resource.format = format; 1608 texture->resource.multisample_type = multisample_type; 1609 texture->resource.multisample_quality = multisample_quality; 1610 texture->resource.width = width; 1611 texture->resource.height = height; 1612 texture->resource.size = texture->slice_pitch; 1613 sub_resource->size = texture->slice_pitch; 1614 sub_resource->locations = WINED3D_LOCATION_DISCARDED; 1615 1616 if (multisample_type && gl_info->supported[ARB_TEXTURE_MULTISAMPLE]) 1617 texture->target = GL_TEXTURE_2D_MULTISAMPLE; 1618 else 1619 texture->target = GL_TEXTURE_2D; 1620 1621 if (((width & (width - 1)) || (height & (height - 1))) && !gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] 1622 && !gl_info->supported[ARB_TEXTURE_RECTANGLE] && !gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT]) 1623 { 1624 texture->flags |= WINED3D_TEXTURE_COND_NP2_EMULATED; 1625 texture->pow2_width = texture->pow2_height = 1; 1626 while (texture->pow2_width < width) 1627 texture->pow2_width <<= 1; 1628 while (texture->pow2_height < height) 1629 texture->pow2_height <<= 1; 1630 } 1631 else 1632 { 1633 texture->flags &= ~WINED3D_TEXTURE_COND_NP2_EMULATED; 1634 texture->pow2_width = width; 1635 texture->pow2_height = height; 1636 } 1637 1638 if ((texture->user_memory = mem)) 1639 { 1640 texture->resource.map_binding = WINED3D_LOCATION_USER_MEMORY; 1641 valid_location = WINED3D_LOCATION_USER_MEMORY; 1642 } 1643 else 1644 { 1645 wined3d_texture_prepare_location(texture, 0, NULL, WINED3D_LOCATION_SYSMEM); 1646 valid_location = WINED3D_LOCATION_SYSMEM; 1647 } 1648 1649 /* The format might be changed to a format that needs conversion. 1650 * If the surface didn't use PBOs previously but could now, don't 1651 * change it - whatever made us not use PBOs might come back, e.g. 1652 * color keys. */ 1653 if (texture->resource.map_binding == WINED3D_LOCATION_BUFFER && !wined3d_texture_use_pbo(texture, gl_info)) 1654 texture->resource.map_binding = WINED3D_LOCATION_SYSMEM; 1655 1656 wined3d_texture_validate_location(texture, 0, valid_location); 1657 wined3d_texture_invalidate_location(texture, 0, ~valid_location); 1658 1659 if (create_dib) 1660 { 1661 struct wined3d_texture_idx texture_idx = {texture, 0}; 1662 1663 wined3d_cs_init_object(device->cs, wined3d_texture_create_dc, &texture_idx); 1664 device->cs->ops->finish(device->cs, WINED3D_CS_QUEUE_DEFAULT); 1665 } 1666 1667 return WINED3D_OK; 1668 } 1669 1670 /* Context activation is done by the caller. */ 1671 static void wined3d_texture_prepare_buffer_object(struct wined3d_texture *texture, 1672 unsigned int sub_resource_idx, const struct wined3d_gl_info *gl_info) 1673 { 1674 struct wined3d_texture_sub_resource *sub_resource; 1675 1676 sub_resource = &texture->sub_resources[sub_resource_idx]; 1677 if (sub_resource->buffer_object) 1678 return; 1679 1680 GL_EXTCALL(glGenBuffers(1, &sub_resource->buffer_object)); 1681 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, sub_resource->buffer_object)); 1682 GL_EXTCALL(glBufferData(GL_PIXEL_UNPACK_BUFFER, sub_resource->size, NULL, GL_STREAM_DRAW)); 1683 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0)); 1684 checkGLcall("Create buffer object"); 1685 1686 TRACE("Created buffer object %u for texture %p, sub-resource %u.\n", 1687 sub_resource->buffer_object, texture, sub_resource_idx); 1688 } 1689 1690 static void wined3d_texture_force_reload(struct wined3d_texture *texture) 1691 { 1692 unsigned int sub_count = texture->level_count * texture->layer_count; 1693 unsigned int i; 1694 1695 texture->flags &= ~(WINED3D_TEXTURE_RGB_ALLOCATED | WINED3D_TEXTURE_SRGB_ALLOCATED 1696 | WINED3D_TEXTURE_CONVERTED); 1697 texture->async.flags &= ~WINED3D_TEXTURE_ASYNC_COLOR_KEY; 1698 for (i = 0; i < sub_count; ++i) 1699 { 1700 wined3d_texture_invalidate_location(texture, i, 1701 WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB); 1702 } 1703 } 1704 1705 /* Context activation is done by the caller. */ 1706 void wined3d_texture_prepare_texture(struct wined3d_texture *texture, struct wined3d_context *context, BOOL srgb) 1707 { 1708 DWORD alloc_flag = srgb ? WINED3D_TEXTURE_SRGB_ALLOCATED : WINED3D_TEXTURE_RGB_ALLOCATED; 1709 const struct wined3d_format *format = texture->resource.format; 1710 const struct wined3d_d3d_info *d3d_info = context->d3d_info; 1711 const struct wined3d_gl_info *gl_info = context->gl_info; 1712 const struct wined3d_color_key_conversion *conversion; 1713 GLenum internal; 1714 1715 TRACE("texture %p, context %p, format %s.\n", texture, context, debug_d3dformat(format->id)); 1716 1717 if (!d3d_info->shader_color_key 1718 && !(texture->async.flags & WINED3D_TEXTURE_ASYNC_COLOR_KEY) 1719 != !(texture->async.color_key_flags & WINED3D_CKEY_SRC_BLT)) 1720 { 1721 wined3d_texture_force_reload(texture); 1722 1723 if (texture->async.color_key_flags & WINED3D_CKEY_SRC_BLT) 1724 texture->async.flags |= WINED3D_TEXTURE_ASYNC_COLOR_KEY; 1725 } 1726 1727 if (texture->flags & alloc_flag) 1728 return; 1729 1730 if (format->conv_byte_count) 1731 { 1732 texture->flags |= WINED3D_TEXTURE_CONVERTED; 1733 } 1734 else if ((conversion = wined3d_format_get_color_key_conversion(texture, TRUE))) 1735 { 1736 texture->flags |= WINED3D_TEXTURE_CONVERTED; 1737 format = wined3d_get_format(gl_info, conversion->dst_format, texture->resource.usage); 1738 TRACE("Using format %s for color key conversion.\n", debug_d3dformat(format->id)); 1739 } 1740 1741 wined3d_texture_bind_and_dirtify(texture, context, srgb); 1742 1743 if (srgb) 1744 internal = format->glGammaInternal; 1745 else if (texture->resource.usage & WINED3DUSAGE_RENDERTARGET 1746 && wined3d_resource_is_offscreen(&texture->resource)) 1747 internal = format->rtInternal; 1748 else 1749 internal = format->glInternal; 1750 1751 if (!internal) 1752 FIXME("No GL internal format for format %s.\n", debug_d3dformat(format->id)); 1753 1754 TRACE("internal %#x, format %#x, type %#x.\n", internal, format->glFormat, format->glType); 1755 1756 if (wined3d_texture_use_immutable_storage(texture, gl_info)) 1757 wined3d_texture_allocate_gl_immutable_storage(texture, internal, gl_info); 1758 else 1759 wined3d_texture_allocate_gl_mutable_storage(texture, internal, format, gl_info); 1760 texture->flags |= alloc_flag; 1761 } 1762 1763 static void wined3d_texture_prepare_rb(struct wined3d_texture *texture, 1764 const struct wined3d_gl_info *gl_info, BOOL multisample) 1765 { 1766 const struct wined3d_format *format = texture->resource.format; 1767 1768 if (multisample) 1769 { 1770 DWORD samples; 1771 1772 if (texture->rb_multisample) 1773 return; 1774 1775 samples = wined3d_texture_get_gl_sample_count(texture); 1776 1777 gl_info->fbo_ops.glGenRenderbuffers(1, &texture->rb_multisample); 1778 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, texture->rb_multisample); 1779 gl_info->fbo_ops.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, 1780 format->glInternal, texture->resource.width, texture->resource.height); 1781 checkGLcall("glRenderbufferStorageMultisample()"); 1782 TRACE("Created multisample rb %u.\n", texture->rb_multisample); 1783 } 1784 else 1785 { 1786 if (texture->rb_resolved) 1787 return; 1788 1789 gl_info->fbo_ops.glGenRenderbuffers(1, &texture->rb_resolved); 1790 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, texture->rb_resolved); 1791 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER, format->glInternal, 1792 texture->resource.width, texture->resource.height); 1793 checkGLcall("glRenderbufferStorage()"); 1794 TRACE("Created resolved rb %u.\n", texture->rb_resolved); 1795 } 1796 } 1797 1798 /* Context activation is done by the caller. Context may be NULL in 1799 * WINED3D_NO3D mode. */ 1800 BOOL wined3d_texture_prepare_location(struct wined3d_texture *texture, unsigned int sub_resource_idx, 1801 struct wined3d_context *context, DWORD location) 1802 { 1803 switch (location) 1804 { 1805 case WINED3D_LOCATION_SYSMEM: 1806 if (texture->resource.heap_memory) 1807 return TRUE; 1808 1809 if (!wined3d_resource_allocate_sysmem(&texture->resource)) 1810 return FALSE; 1811 return TRUE; 1812 1813 case WINED3D_LOCATION_USER_MEMORY: 1814 if (!texture->user_memory) 1815 ERR("Map binding is set to WINED3D_LOCATION_USER_MEMORY but surface->user_memory is NULL.\n"); 1816 return TRUE; 1817 1818 case WINED3D_LOCATION_BUFFER: 1819 wined3d_texture_prepare_buffer_object(texture, sub_resource_idx, context->gl_info); 1820 return TRUE; 1821 1822 case WINED3D_LOCATION_TEXTURE_RGB: 1823 wined3d_texture_prepare_texture(texture, context, FALSE); 1824 return TRUE; 1825 1826 case WINED3D_LOCATION_TEXTURE_SRGB: 1827 wined3d_texture_prepare_texture(texture, context, TRUE); 1828 return TRUE; 1829 1830 case WINED3D_LOCATION_DRAWABLE: 1831 if (!texture->swapchain && wined3d_settings.offscreen_rendering_mode != ORM_BACKBUFFER) 1832 ERR("Texture %p does not have a drawable.\n", texture); 1833 return TRUE; 1834 1835 case WINED3D_LOCATION_RB_MULTISAMPLE: 1836 wined3d_texture_prepare_rb(texture, context->gl_info, TRUE); 1837 return TRUE; 1838 1839 case WINED3D_LOCATION_RB_RESOLVED: 1840 wined3d_texture_prepare_rb(texture, context->gl_info, FALSE); 1841 return TRUE; 1842 1843 default: 1844 ERR("Invalid location %s.\n", wined3d_debug_location(location)); 1845 return FALSE; 1846 } 1847 } 1848 1849 static struct wined3d_texture_sub_resource *wined3d_texture_get_sub_resource(struct wined3d_texture *texture, 1850 unsigned int sub_resource_idx) 1851 { 1852 UINT sub_count = texture->level_count * texture->layer_count; 1853 1854 TRACE("texture %p, sub_resource_idx %u.\n", texture, sub_resource_idx); 1855 1856 if (sub_resource_idx >= sub_count) 1857 { 1858 WARN("sub_resource_idx %u >= sub_count %u.\n", sub_resource_idx, sub_count); 1859 return NULL; 1860 } 1861 1862 return &texture->sub_resources[sub_resource_idx]; 1863 } 1864 1865 HRESULT CDECL wined3d_texture_add_dirty_region(struct wined3d_texture *texture, 1866 UINT layer, const struct wined3d_box *dirty_region) 1867 { 1868 TRACE("texture %p, layer %u, dirty_region %s.\n", texture, layer, debug_box(dirty_region)); 1869 1870 if (layer >= texture->layer_count) 1871 { 1872 WARN("Invalid layer %u specified.\n", layer); 1873 return WINED3DERR_INVALIDCALL; 1874 } 1875 1876 if (dirty_region) 1877 WARN("Ignoring dirty_region %s.\n", debug_box(dirty_region)); 1878 1879 wined3d_cs_emit_add_dirty_texture_region(texture->resource.device->cs, texture, layer); 1880 1881 return WINED3D_OK; 1882 } 1883 1884 /* This call just uploads data, the caller is responsible for binding the 1885 * correct texture. */ 1886 /* Context activation is done by the caller. */ 1887 void wined3d_texture_upload_data(struct wined3d_texture *texture, unsigned int sub_resource_idx, 1888 struct wined3d_context *context, const struct wined3d_format *format, const struct wined3d_box *src_box, 1889 const struct wined3d_const_bo_address *data, unsigned int src_row_pitch, unsigned int src_slice_pitch, 1890 unsigned int dst_x, unsigned int dst_y, unsigned int dst_z, BOOL srgb) 1891 { 1892 const struct wined3d_gl_info *gl_info = context->gl_info; 1893 unsigned int update_w = src_box->right - src_box->left; 1894 unsigned int update_h = src_box->bottom - src_box->top; 1895 unsigned int update_d = src_box->back - src_box->front; 1896 struct wined3d_bo_address bo; 1897 void *converted_mem = NULL; 1898 struct wined3d_format f; 1899 unsigned int level; 1900 GLenum target; 1901 1902 TRACE("texture %p, sub_resource_idx %u, context %p, format %s, src_box %s, data {%#x:%p}, " 1903 "src_row_pitch %#x, src_slice_pitch %#x, dst_x %u, dst_y %u, dst_z %u, srgb %#x.\n", 1904 texture, sub_resource_idx, context, debug_d3dformat(format->id), debug_box(src_box), 1905 data->buffer_object, data->addr, src_row_pitch, src_slice_pitch, dst_x, dst_y, dst_z, srgb); 1906 1907 if (texture->sub_resources[sub_resource_idx].map_count) 1908 { 1909 WARN("Uploading a texture that is currently mapped, setting WINED3D_TEXTURE_PIN_SYSMEM.\n"); 1910 texture->flags |= WINED3D_TEXTURE_PIN_SYSMEM; 1911 } 1912 1913 if (format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_HEIGHT_SCALE) 1914 { 1915 update_h *= format->height_scale.numerator; 1916 update_h /= format->height_scale.denominator; 1917 } 1918 1919 target = wined3d_texture_get_sub_resource_target(texture, sub_resource_idx); 1920 level = sub_resource_idx % texture->level_count; 1921 1922 switch (target) 1923 { 1924 case GL_TEXTURE_1D_ARRAY: 1925 dst_y = sub_resource_idx / texture->level_count; 1926 update_h = 1; 1927 break; 1928 case GL_TEXTURE_2D_ARRAY: 1929 dst_z = sub_resource_idx / texture->level_count; 1930 update_d = 1; 1931 break; 1932 case GL_TEXTURE_2D_MULTISAMPLE: 1933 case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: 1934 FIXME("Not supported for multisample textures.\n"); 1935 return; 1936 } 1937 1938 bo.buffer_object = data->buffer_object; 1939 bo.addr = (BYTE *)data->addr + src_box->front * src_slice_pitch; 1940 if (texture->resource.format_flags & WINED3DFMT_FLAG_BLOCKS) 1941 { 1942 bo.addr += (src_box->top / format->block_height) * src_row_pitch; 1943 bo.addr += (src_box->left / format->block_width) * format->block_byte_count; 1944 } 1945 else 1946 { 1947 bo.addr += src_box->top * src_row_pitch; 1948 bo.addr += src_box->left * format->byte_count; 1949 } 1950 1951 if (format->upload) 1952 { 1953 unsigned int dst_row_pitch, dst_slice_pitch; 1954 void *src_mem; 1955 1956 if (texture->resource.format_flags & WINED3DFMT_FLAG_BLOCKS) 1957 ERR("Converting a block-based format.\n"); 1958 1959 f = *format; 1960 f.byte_count = format->conv_byte_count; 1961 format = &f; 1962 1963 wined3d_format_calculate_pitch(format, 1, update_w, update_h, &dst_row_pitch, &dst_slice_pitch); 1964 1965 if (!(converted_mem = heap_calloc(update_d, dst_slice_pitch))) 1966 { 1967 ERR("Failed to allocate upload buffer.\n"); 1968 return; 1969 } 1970 1971 src_mem = context_map_bo_address(context, &bo, src_slice_pitch, 1972 GL_PIXEL_UNPACK_BUFFER, WINED3D_MAP_READ); 1973 format->upload(src_mem, converted_mem, src_row_pitch, src_slice_pitch, 1974 dst_row_pitch, dst_slice_pitch, update_w, update_h, update_d); 1975 context_unmap_bo_address(context, &bo, GL_PIXEL_UNPACK_BUFFER); 1976 1977 bo.buffer_object = 0; 1978 bo.addr = converted_mem; 1979 src_row_pitch = dst_row_pitch; 1980 src_slice_pitch = dst_slice_pitch; 1981 } 1982 1983 if (bo.buffer_object) 1984 { 1985 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, bo.buffer_object)); 1986 checkGLcall("glBindBuffer"); 1987 } 1988 1989 if (format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_COMPRESSED) 1990 { 1991 unsigned int dst_row_pitch, dst_slice_pitch; 1992 const BYTE *addr = bo.addr; 1993 GLenum internal; 1994 1995 if (srgb) 1996 internal = format->glGammaInternal; 1997 else if (texture->resource.usage & WINED3DUSAGE_RENDERTARGET 1998 && wined3d_resource_is_offscreen(&texture->resource)) 1999 internal = format->rtInternal; 2000 else 2001 internal = format->glInternal; 2002 2003 wined3d_format_calculate_pitch(format, 1, update_w, update_h, &dst_row_pitch, &dst_slice_pitch); 2004 2005 TRACE("Uploading compressed data, target %#x, level %u, x %u, y %u, z %u, " 2006 "w %u, h %u, d %u, format %#x, image_size %#x, addr %p.\n", 2007 target, level, dst_x, dst_y, dst_z, update_w, update_h, 2008 update_d, internal, dst_slice_pitch, addr); 2009 2010 if (target == GL_TEXTURE_1D) 2011 { 2012 GL_EXTCALL(glCompressedTexSubImage1D(target, level, dst_x, 2013 update_w, internal, dst_row_pitch, addr)); 2014 } 2015 else if (dst_row_pitch == src_row_pitch) 2016 { 2017 if (target == GL_TEXTURE_2D_ARRAY || target == GL_TEXTURE_3D) 2018 { 2019 GL_EXTCALL(glCompressedTexSubImage3D(target, level, dst_x, dst_y, dst_z, 2020 update_w, update_h, update_d, internal, dst_slice_pitch * update_d, addr)); 2021 } 2022 else 2023 { 2024 GL_EXTCALL(glCompressedTexSubImage2D(target, level, dst_x, dst_y, 2025 update_w, update_h, internal, dst_slice_pitch, addr)); 2026 } 2027 } 2028 else 2029 { 2030 unsigned int row_count = (update_h + format->block_height - 1) / format->block_height; 2031 unsigned int row, y, z; 2032 2033 /* glCompressedTexSubImage2D() ignores pixel store state, so we 2034 * can't use the unpack row length like for glTexSubImage2D. */ 2035 for (z = dst_z; z < dst_z + update_d; ++z) 2036 { 2037 for (row = 0, y = dst_y; row < row_count; ++row) 2038 { 2039 if (target == GL_TEXTURE_2D_ARRAY || target == GL_TEXTURE_3D) 2040 { 2041 GL_EXTCALL(glCompressedTexSubImage3D(target, level, dst_x, y, z, 2042 update_w, format->block_height, 1, internal, dst_row_pitch, addr)); 2043 } 2044 else 2045 { 2046 GL_EXTCALL(glCompressedTexSubImage2D(target, level, dst_x, y, 2047 update_w, format->block_height, internal, dst_row_pitch, addr)); 2048 } 2049 2050 y += format->block_height; 2051 addr += src_row_pitch; 2052 } 2053 } 2054 } 2055 checkGLcall("Upload compressed texture data"); 2056 } 2057 else 2058 { 2059 TRACE("Uploading data, target %#x, level %u, x %u, y %u, z %u, " 2060 "w %u, h %u, d %u, format %#x, type %#x, addr %p.\n", 2061 target, level, dst_x, dst_y, dst_z, update_w, update_h, 2062 update_d, format->glFormat, format->glType, bo.addr); 2063 2064 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, src_row_pitch / format->byte_count); 2065 if (target == GL_TEXTURE_2D_ARRAY || target == GL_TEXTURE_3D) 2066 { 2067 GL_EXTCALL(glTexSubImage3D(target, level, dst_x, dst_y, dst_z, 2068 update_w, update_h, update_d, format->glFormat, format->glType, bo.addr)); 2069 } 2070 else if (target == GL_TEXTURE_1D) 2071 { 2072 gl_info->gl_ops.gl.p_glTexSubImage1D(target, level, dst_x, 2073 update_w, format->glFormat, format->glType, bo.addr); 2074 } 2075 else 2076 { 2077 gl_info->gl_ops.gl.p_glTexSubImage2D(target, level, dst_x, dst_y, 2078 update_w, update_h, format->glFormat, format->glType, bo.addr); 2079 } 2080 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); 2081 checkGLcall("Upload texture data"); 2082 } 2083 2084 if (bo.buffer_object) 2085 { 2086 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0)); 2087 checkGLcall("glBindBuffer"); 2088 } 2089 heap_free(converted_mem); 2090 2091 if (gl_info->quirks & WINED3D_QUIRK_FBO_TEX_UPDATE) 2092 { 2093 struct wined3d_device *device = texture->resource.device; 2094 unsigned int i; 2095 2096 for (i = 0; i < device->context_count; ++i) 2097 { 2098 context_texture_update(device->contexts[i], texture); 2099 } 2100 } 2101 } 2102 2103 /* Context activation is done by the caller. Context may be NULL in ddraw-only mode. */ 2104 static BOOL texture2d_load_location(struct wined3d_texture *texture, unsigned int sub_resource_idx, 2105 struct wined3d_context *context, DWORD location) 2106 { 2107 TRACE("texture %p, sub_resource_idx %u, context %p, location %s.\n", 2108 texture, sub_resource_idx, context, wined3d_debug_location(location)); 2109 2110 switch (location) 2111 { 2112 case WINED3D_LOCATION_USER_MEMORY: 2113 case WINED3D_LOCATION_SYSMEM: 2114 case WINED3D_LOCATION_BUFFER: 2115 return texture2d_load_sysmem(texture, sub_resource_idx, context, location); 2116 2117 case WINED3D_LOCATION_DRAWABLE: 2118 return texture2d_load_drawable(texture, sub_resource_idx, context); 2119 2120 case WINED3D_LOCATION_RB_RESOLVED: 2121 case WINED3D_LOCATION_RB_MULTISAMPLE: 2122 return texture2d_load_renderbuffer(texture, sub_resource_idx, context, location); 2123 2124 case WINED3D_LOCATION_TEXTURE_RGB: 2125 case WINED3D_LOCATION_TEXTURE_SRGB: 2126 return texture2d_load_texture(texture, sub_resource_idx, context, 2127 location == WINED3D_LOCATION_TEXTURE_SRGB); 2128 2129 default: 2130 ERR("Don't know how to handle location %#x.\n", location); 2131 return FALSE; 2132 } 2133 } 2134 2135 static const struct wined3d_texture_ops texture2d_ops = 2136 { 2137 texture2d_load_location, 2138 }; 2139 2140 struct wined3d_texture * __cdecl wined3d_texture_from_resource(struct wined3d_resource *resource) 2141 { 2142 return texture_from_resource(resource); 2143 } 2144 2145 static ULONG texture_resource_incref(struct wined3d_resource *resource) 2146 { 2147 return wined3d_texture_incref(texture_from_resource(resource)); 2148 } 2149 2150 static ULONG texture_resource_decref(struct wined3d_resource *resource) 2151 { 2152 return wined3d_texture_decref(texture_from_resource(resource)); 2153 } 2154 2155 static void texture_resource_preload(struct wined3d_resource *resource) 2156 { 2157 struct wined3d_texture *texture = texture_from_resource(resource); 2158 struct wined3d_context *context; 2159 2160 context = context_acquire(resource->device, NULL, 0); 2161 wined3d_texture_load(texture, context, texture->flags & WINED3D_TEXTURE_IS_SRGB); 2162 context_release(context); 2163 } 2164 2165 static void wined3d_texture_unload(struct wined3d_resource *resource) 2166 { 2167 struct wined3d_texture *texture = texture_from_resource(resource); 2168 UINT sub_count = texture->level_count * texture->layer_count; 2169 struct wined3d_renderbuffer_entry *entry, *entry2; 2170 struct wined3d_device *device = resource->device; 2171 const struct wined3d_gl_info *gl_info; 2172 struct wined3d_context *context; 2173 UINT i; 2174 2175 TRACE("texture %p.\n", texture); 2176 2177 context = context_acquire(device, NULL, 0); 2178 gl_info = context->gl_info; 2179 2180 for (i = 0; i < sub_count; ++i) 2181 { 2182 struct wined3d_texture_sub_resource *sub_resource = &texture->sub_resources[i]; 2183 2184 if (resource->access & WINED3D_RESOURCE_ACCESS_CPU 2185 && wined3d_texture_load_location(texture, i, context, resource->map_binding)) 2186 { 2187 wined3d_texture_invalidate_location(texture, i, ~resource->map_binding); 2188 } 2189 else 2190 { 2191 /* We should only get here on device reset/teardown for implicit 2192 * resources. */ 2193 if (resource->access & WINED3D_RESOURCE_ACCESS_CPU 2194 || resource->type != WINED3D_RTYPE_TEXTURE_2D) 2195 ERR("Discarding %s %p sub-resource %u with resource access %s.\n", 2196 debug_d3dresourcetype(resource->type), resource, i, 2197 wined3d_debug_resource_access(resource->access)); 2198 wined3d_texture_validate_location(texture, i, WINED3D_LOCATION_DISCARDED); 2199 wined3d_texture_invalidate_location(texture, i, ~WINED3D_LOCATION_DISCARDED); 2200 } 2201 2202 if (sub_resource->buffer_object) 2203 wined3d_texture_remove_buffer_object(texture, i, context->gl_info); 2204 } 2205 2206 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &texture->renderbuffers, struct wined3d_renderbuffer_entry, entry) 2207 { 2208 context_gl_resource_released(device, entry->id, TRUE); 2209 gl_info->fbo_ops.glDeleteRenderbuffers(1, &entry->id); 2210 list_remove(&entry->entry); 2211 heap_free(entry); 2212 } 2213 list_init(&texture->renderbuffers); 2214 texture->current_renderbuffer = NULL; 2215 2216 context_release(context); 2217 2218 wined3d_texture_force_reload(texture); 2219 wined3d_texture_unload_gl_texture(texture); 2220 } 2221 2222 static HRESULT texture_resource_sub_resource_map(struct wined3d_resource *resource, unsigned int sub_resource_idx, 2223 struct wined3d_map_desc *map_desc, const struct wined3d_box *box, DWORD flags) 2224 { 2225 const struct wined3d_format *format = resource->format; 2226 struct wined3d_texture_sub_resource *sub_resource; 2227 struct wined3d_device *device = resource->device; 2228 unsigned int fmt_flags = resource->format_flags; 2229 struct wined3d_context *context = NULL; 2230 struct wined3d_texture *texture; 2231 struct wined3d_bo_address data; 2232 unsigned int texture_level; 2233 BYTE *base_memory; 2234 BOOL ret; 2235 2236 TRACE("resource %p, sub_resource_idx %u, map_desc %p, box %s, flags %#x.\n", 2237 resource, sub_resource_idx, map_desc, debug_box(box), flags); 2238 2239 texture = texture_from_resource(resource); 2240 if (!(sub_resource = wined3d_texture_get_sub_resource(texture, sub_resource_idx))) 2241 return E_INVALIDARG; 2242 2243 texture_level = sub_resource_idx % texture->level_count; 2244 if (box && FAILED(wined3d_texture_check_box_dimensions(texture, texture_level, box))) 2245 { 2246 WARN("Map box is invalid.\n"); 2247 if (((fmt_flags & WINED3DFMT_FLAG_BLOCKS) && !(resource->access & WINED3D_RESOURCE_ACCESS_CPU)) 2248 || resource->type != WINED3D_RTYPE_TEXTURE_2D) 2249 return WINED3DERR_INVALIDCALL; 2250 } 2251 2252 if (texture->flags & WINED3D_TEXTURE_DC_IN_USE) 2253 { 2254 WARN("DC is in use.\n"); 2255 return WINED3DERR_INVALIDCALL; 2256 } 2257 2258 if (sub_resource->map_count) 2259 { 2260 WARN("Sub-resource is already mapped.\n"); 2261 return WINED3DERR_INVALIDCALL; 2262 } 2263 2264 if (device->d3d_initialized) 2265 context = context_acquire(device, NULL, 0); 2266 2267 if (flags & WINED3D_MAP_DISCARD) 2268 { 2269 TRACE("WINED3D_MAP_DISCARD flag passed, marking %s as up to date.\n", 2270 wined3d_debug_location(resource->map_binding)); 2271 if ((ret = wined3d_texture_prepare_location(texture, sub_resource_idx, context, resource->map_binding))) 2272 wined3d_texture_validate_location(texture, sub_resource_idx, resource->map_binding); 2273 } 2274 else 2275 { 2276 if (resource->usage & WINED3DUSAGE_DYNAMIC) 2277 WARN_(d3d_perf)("Mapping a dynamic texture without WINED3D_MAP_DISCARD.\n"); 2278 ret = wined3d_texture_load_location(texture, sub_resource_idx, context, resource->map_binding); 2279 } 2280 2281 if (!ret) 2282 { 2283 ERR("Failed to prepare location.\n"); 2284 context_release(context); 2285 return E_OUTOFMEMORY; 2286 } 2287 2288 if (flags & WINED3D_MAP_WRITE 2289 && (!(flags & WINED3D_MAP_NO_DIRTY_UPDATE) || (resource->usage & WINED3DUSAGE_DYNAMIC))) 2290 wined3d_texture_invalidate_location(texture, sub_resource_idx, ~resource->map_binding); 2291 2292 wined3d_texture_get_memory(texture, sub_resource_idx, &data, resource->map_binding); 2293 base_memory = context_map_bo_address(context, &data, sub_resource->size, GL_PIXEL_UNPACK_BUFFER, flags); 2294 TRACE("Base memory pointer %p.\n", base_memory); 2295 2296 if (context) 2297 context_release(context); 2298 2299 if (fmt_flags & WINED3DFMT_FLAG_BROKEN_PITCH) 2300 { 2301 map_desc->row_pitch = wined3d_texture_get_level_width(texture, texture_level) * format->byte_count; 2302 map_desc->slice_pitch = wined3d_texture_get_level_height(texture, texture_level) * map_desc->row_pitch; 2303 } 2304 else 2305 { 2306 wined3d_texture_get_pitch(texture, texture_level, &map_desc->row_pitch, &map_desc->slice_pitch); 2307 } 2308 2309 if (!box) 2310 { 2311 map_desc->data = base_memory; 2312 } 2313 else 2314 { 2315 if ((fmt_flags & (WINED3DFMT_FLAG_BLOCKS | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_BLOCKS) 2316 { 2317 /* Compressed textures are block based, so calculate the offset of 2318 * the block that contains the top-left pixel of the mapped box. */ 2319 map_desc->data = base_memory 2320 + (box->front * map_desc->slice_pitch) 2321 + ((box->top / format->block_height) * map_desc->row_pitch) 2322 + ((box->left / format->block_width) * format->block_byte_count); 2323 } 2324 else 2325 { 2326 map_desc->data = base_memory 2327 + (box->front * map_desc->slice_pitch) 2328 + (box->top * map_desc->row_pitch) 2329 + (box->left * format->byte_count); 2330 } 2331 } 2332 2333 if (texture->swapchain && texture->swapchain->front_buffer == texture) 2334 { 2335 RECT *r = &texture->swapchain->front_buffer_update; 2336 2337 if (!box) 2338 SetRect(r, 0, 0, resource->width, resource->height); 2339 else 2340 SetRect(r, box->left, box->top, box->right, box->bottom); 2341 TRACE("Mapped front buffer %s.\n", wine_dbgstr_rect(r)); 2342 } 2343 2344 ++resource->map_count; 2345 ++sub_resource->map_count; 2346 2347 TRACE("Returning memory %p, row pitch %u, slice pitch %u.\n", 2348 map_desc->data, map_desc->row_pitch, map_desc->slice_pitch); 2349 2350 return WINED3D_OK; 2351 } 2352 2353 static HRESULT texture_resource_sub_resource_map_info(struct wined3d_resource *resource, unsigned int sub_resource_idx, 2354 struct wined3d_map_info *info, DWORD flags) 2355 { 2356 const struct wined3d_format *format = resource->format; 2357 struct wined3d_texture_sub_resource *sub_resource; 2358 unsigned int fmt_flags = resource->format_flags; 2359 struct wined3d_texture *texture; 2360 unsigned int texture_level; 2361 2362 texture = texture_from_resource(resource); 2363 if (!(sub_resource = wined3d_texture_get_sub_resource(texture, sub_resource_idx))) 2364 return E_INVALIDARG; 2365 2366 texture_level = sub_resource_idx % texture->level_count; 2367 2368 if (fmt_flags & WINED3DFMT_FLAG_BROKEN_PITCH) 2369 { 2370 info->row_pitch = wined3d_texture_get_level_width(texture, texture_level) * format->byte_count; 2371 info->slice_pitch = wined3d_texture_get_level_height(texture, texture_level) * info->row_pitch; 2372 } 2373 else 2374 { 2375 wined3d_texture_get_pitch(texture, texture_level, &info->row_pitch, &info->slice_pitch); 2376 } 2377 2378 info->size = info->slice_pitch * wined3d_texture_get_level_depth(texture, texture_level); 2379 2380 return WINED3D_OK; 2381 } 2382 2383 static HRESULT texture_resource_sub_resource_unmap(struct wined3d_resource *resource, unsigned int sub_resource_idx) 2384 { 2385 struct wined3d_texture_sub_resource *sub_resource; 2386 struct wined3d_device *device = resource->device; 2387 struct wined3d_context *context = NULL; 2388 struct wined3d_texture *texture; 2389 struct wined3d_bo_address data; 2390 2391 TRACE("resource %p, sub_resource_idx %u.\n", resource, sub_resource_idx); 2392 2393 texture = texture_from_resource(resource); 2394 if (!(sub_resource = wined3d_texture_get_sub_resource(texture, sub_resource_idx))) 2395 return E_INVALIDARG; 2396 2397 if (!sub_resource->map_count) 2398 { 2399 WARN("Trying to unmap unmapped sub-resource.\n"); 2400 if (texture->flags & WINED3D_TEXTURE_DC_IN_USE) 2401 return WINED3D_OK; 2402 return WINEDDERR_NOTLOCKED; 2403 } 2404 2405 if (device->d3d_initialized) 2406 context = context_acquire(device, NULL, 0); 2407 2408 wined3d_texture_get_memory(texture, sub_resource_idx, &data, texture->resource.map_binding); 2409 context_unmap_bo_address(context, &data, GL_PIXEL_UNPACK_BUFFER); 2410 2411 if (context) 2412 context_release(context); 2413 2414 if (texture->swapchain && texture->swapchain->front_buffer == texture) 2415 { 2416 if (!(sub_resource->locations & (WINED3D_LOCATION_DRAWABLE | WINED3D_LOCATION_TEXTURE_RGB))) 2417 texture->swapchain->swapchain_ops->swapchain_frontbuffer_updated(texture->swapchain); 2418 } 2419 2420 --sub_resource->map_count; 2421 if (!--resource->map_count && texture->update_map_binding) 2422 wined3d_texture_update_map_binding(texture); 2423 2424 return WINED3D_OK; 2425 } 2426 2427 static const struct wined3d_resource_ops texture_resource_ops = 2428 { 2429 texture_resource_incref, 2430 texture_resource_decref, 2431 texture_resource_preload, 2432 wined3d_texture_unload, 2433 texture_resource_sub_resource_map, 2434 texture_resource_sub_resource_map_info, 2435 texture_resource_sub_resource_unmap, 2436 }; 2437 2438 /* Context activation is done by the caller. */ 2439 static void texture1d_download_data(struct wined3d_texture *texture, unsigned int sub_resource_idx, 2440 const struct wined3d_context *context, const struct wined3d_bo_address *data) 2441 { 2442 const struct wined3d_format *format = texture->resource.format; 2443 const struct wined3d_gl_info *gl_info = context->gl_info; 2444 2445 if (format->conv_byte_count) 2446 { 2447 FIXME("Attempting to download a converted texture, format %s.\n", 2448 debug_d3dformat(format->id)); 2449 return; 2450 } 2451 2452 if (data->buffer_object) 2453 { 2454 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, data->buffer_object)); 2455 checkGLcall("glBindBuffer"); 2456 } 2457 2458 gl_info->gl_ops.gl.p_glGetTexImage(texture->target, sub_resource_idx, 2459 format->glFormat, format->glType, data->addr); 2460 checkGLcall("glGetTexImage"); 2461 2462 if (data->buffer_object) 2463 { 2464 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0)); 2465 checkGLcall("glBindBuffer"); 2466 } 2467 } 2468 2469 /* Context activation is done by the caller. */ 2470 static BOOL texture1d_load_location(struct wined3d_texture *texture, unsigned int sub_resource_idx, 2471 struct wined3d_context *context, DWORD location) 2472 { 2473 struct wined3d_texture_sub_resource *sub_resource = &texture->sub_resources[sub_resource_idx]; 2474 unsigned int row_pitch, slice_pitch; 2475 2476 TRACE("texture %p, sub_resource_idx %u, context %p, location %s.\n", 2477 texture, sub_resource_idx, context, wined3d_debug_location(location)); 2478 2479 if (!wined3d_texture_prepare_location(texture, sub_resource_idx, context, location)) 2480 return FALSE; 2481 2482 switch (location) 2483 { 2484 case WINED3D_LOCATION_TEXTURE_RGB: 2485 case WINED3D_LOCATION_TEXTURE_SRGB: 2486 if (sub_resource->locations & WINED3D_LOCATION_SYSMEM) 2487 { 2488 struct wined3d_const_bo_address data = {0, texture->resource.heap_memory}; 2489 struct wined3d_box src_box; 2490 2491 data.addr += sub_resource->offset; 2492 wined3d_texture_bind_and_dirtify(texture, context, 2493 location == WINED3D_LOCATION_TEXTURE_SRGB); 2494 wined3d_texture_get_pitch(texture, sub_resource_idx, &row_pitch, &slice_pitch); 2495 wined3d_texture_get_level_box(texture, sub_resource_idx % texture->level_count, &src_box); 2496 wined3d_texture_upload_data(texture, sub_resource_idx, context, texture->resource.format, 2497 &src_box, &data, row_pitch, slice_pitch, 0, 0, 0, FALSE); 2498 } 2499 else if (sub_resource->locations & WINED3D_LOCATION_BUFFER) 2500 { 2501 struct wined3d_const_bo_address data = {sub_resource->buffer_object, NULL}; 2502 struct wined3d_box src_box; 2503 2504 wined3d_texture_bind_and_dirtify(texture, context, 2505 location == WINED3D_LOCATION_TEXTURE_SRGB); 2506 wined3d_texture_get_pitch(texture, sub_resource_idx, &row_pitch, &slice_pitch); 2507 wined3d_texture_get_level_box(texture, sub_resource_idx % texture->level_count, &src_box); 2508 wined3d_texture_upload_data(texture, sub_resource_idx, context, texture->resource.format, 2509 &src_box, &data, row_pitch, slice_pitch, 0, 0, 0, FALSE); 2510 } 2511 else 2512 { 2513 FIXME("Implement texture loading from %s.\n", wined3d_debug_location(sub_resource->locations)); 2514 return FALSE; 2515 } 2516 break; 2517 2518 case WINED3D_LOCATION_SYSMEM: 2519 if (sub_resource->locations & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB)) 2520 { 2521 struct wined3d_bo_address data = {0, texture->resource.heap_memory}; 2522 2523 data.addr += sub_resource->offset; 2524 if (sub_resource->locations & WINED3D_LOCATION_TEXTURE_RGB) 2525 wined3d_texture_bind_and_dirtify(texture, context, FALSE); 2526 else 2527 wined3d_texture_bind_and_dirtify(texture, context, TRUE); 2528 2529 texture1d_download_data(texture, sub_resource_idx, context, &data); 2530 ++texture->download_count; 2531 } 2532 else 2533 { 2534 FIXME("Implement WINED3D_LOCATION_SYSMEM loading from %s.\n", 2535 wined3d_debug_location(sub_resource->locations)); 2536 return FALSE; 2537 } 2538 break; 2539 2540 case WINED3D_LOCATION_BUFFER: 2541 if (sub_resource->locations & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB)) 2542 { 2543 struct wined3d_bo_address data = {sub_resource->buffer_object, NULL}; 2544 2545 if (sub_resource->locations & WINED3D_LOCATION_TEXTURE_RGB) 2546 wined3d_texture_bind_and_dirtify(texture, context, FALSE); 2547 else 2548 wined3d_texture_bind_and_dirtify(texture, context, TRUE); 2549 2550 texture1d_download_data(texture, sub_resource_idx, context, &data); 2551 } 2552 else 2553 { 2554 FIXME("Implement WINED3D_LOCATION_BUFFER loading from %s.\n", 2555 wined3d_debug_location(sub_resource->locations)); 2556 return FALSE; 2557 } 2558 break; 2559 2560 default: 2561 FIXME("Implement %s loading from %s.\n", wined3d_debug_location(location), 2562 wined3d_debug_location(sub_resource->locations)); 2563 return FALSE; 2564 } 2565 2566 return TRUE; 2567 } 2568 2569 static const struct wined3d_texture_ops texture1d_ops = 2570 { 2571 texture1d_load_location, 2572 }; 2573 2574 static HRESULT wined3d_texture_init(struct wined3d_texture *texture, const struct wined3d_resource_desc *desc, 2575 unsigned int layer_count, unsigned int level_count, DWORD flags, struct wined3d_device *device, 2576 void *parent, const struct wined3d_parent_ops *parent_ops, const struct wined3d_texture_ops *texture_ops) 2577 { 2578 struct wined3d_device_parent *device_parent = device->device_parent; 2579 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; 2580 unsigned int sub_count, i, j, size, offset = 0; 2581 unsigned int pow2_width, pow2_height; 2582 const struct wined3d_format *format; 2583 HRESULT hr; 2584 2585 TRACE("texture %p, resource_type %s, format %s, multisample_type %#x, multisample_quality %#x, " 2586 "usage %s, access %s, width %u, height %u, depth %u, layer_count %u, level_count %u, " 2587 "flags %#x, device %p, parent %p, parent_ops %p, texture_ops %p.\n", 2588 texture, debug_d3dresourcetype(desc->resource_type), debug_d3dformat(desc->format), 2589 desc->multisample_type, desc->multisample_quality, debug_d3dusage(desc->usage), 2590 wined3d_debug_resource_access(desc->access), desc->width, desc->height, desc->depth, 2591 layer_count, level_count, flags, device, parent, parent_ops, texture_ops); 2592 2593 if (!desc->width || !desc->height || !desc->depth) 2594 return WINED3DERR_INVALIDCALL; 2595 2596 if (desc->resource_type == WINED3D_RTYPE_TEXTURE_3D) 2597 { 2598 if (layer_count != 1) 2599 { 2600 ERR("Invalid layer count for volume texture.\n"); 2601 return E_INVALIDARG; 2602 } 2603 2604 if (!gl_info->supported[EXT_TEXTURE3D]) 2605 { 2606 WARN("OpenGL implementation does not support 3D textures.\n"); 2607 return WINED3DERR_INVALIDCALL; 2608 } 2609 } 2610 2611 if (!(desc->usage & WINED3DUSAGE_LEGACY_CUBEMAP) && layer_count > 1 2612 && !gl_info->supported[EXT_TEXTURE_ARRAY]) 2613 { 2614 WARN("OpenGL implementation does not support array textures.\n"); 2615 return WINED3DERR_INVALIDCALL; 2616 } 2617 2618 /* TODO: It should only be possible to create textures for formats 2619 * that are reported as supported. */ 2620 if (WINED3DFMT_UNKNOWN >= desc->format) 2621 { 2622 WARN("Texture cannot be created with a format of WINED3DFMT_UNKNOWN.\n"); 2623 return WINED3DERR_INVALIDCALL; 2624 } 2625 2626 if (desc->usage & WINED3DUSAGE_DYNAMIC && (wined3d_resource_access_is_managed(desc->access) 2627 || desc->usage & WINED3DUSAGE_SCRATCH)) 2628 { 2629 WARN("Attempted to create a dynamic texture with access %s and usage %s.\n", 2630 wined3d_debug_resource_access(desc->access), debug_d3dusage(desc->usage)); 2631 return WINED3DERR_INVALIDCALL; 2632 } 2633 2634 if (!(desc->usage & (WINED3DUSAGE_DYNAMIC | WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL)) 2635 && (flags & WINED3D_TEXTURE_CREATE_MAPPABLE)) 2636 WARN("Creating a mappable texture that doesn't specify dynamic usage.\n"); 2637 if (desc->usage & WINED3DUSAGE_RENDERTARGET && desc->access & WINED3D_RESOURCE_ACCESS_CPU) 2638 FIXME("Trying to create a CPU accessible render target.\n"); 2639 2640 pow2_width = desc->width; 2641 pow2_height = desc->height; 2642 if (((desc->width & (desc->width - 1)) || (desc->height & (desc->height - 1)) || (desc->depth & (desc->depth - 1))) 2643 && !gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO]) 2644 { 2645 /* level_count == 0 returns an error as well. */ 2646 if (level_count != 1 || layer_count != 1 || desc->resource_type == WINED3D_RTYPE_TEXTURE_3D) 2647 { 2648 if (!(desc->usage & WINED3DUSAGE_SCRATCH)) 2649 { 2650 WARN("Attempted to create a mipmapped/cube/array/volume NPOT " 2651 "texture without unconditional NPOT support.\n"); 2652 return WINED3DERR_INVALIDCALL; 2653 } 2654 2655 WARN("Creating a scratch mipmapped/cube/array NPOT texture despite lack of HW support.\n"); 2656 } 2657 texture->flags |= WINED3D_TEXTURE_COND_NP2; 2658 2659 if (desc->resource_type != WINED3D_RTYPE_TEXTURE_3D && !gl_info->supported[ARB_TEXTURE_RECTANGLE] 2660 && !gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT]) 2661 { 2662 const struct wined3d_format *format = wined3d_get_format(gl_info, desc->format, desc->usage); 2663 2664 /* TODO: Add support for non-power-of-two compressed textures. */ 2665 if (format->flags[WINED3D_GL_RES_TYPE_TEX_2D] 2666 & (WINED3DFMT_FLAG_COMPRESSED | WINED3DFMT_FLAG_HEIGHT_SCALE)) 2667 { 2668 FIXME("Compressed or height scaled non-power-of-two (%ux%u) textures are not supported.\n", 2669 desc->width, desc->height); 2670 return WINED3DERR_NOTAVAILABLE; 2671 } 2672 2673 /* Find the nearest pow2 match. */ 2674 pow2_width = pow2_height = 1; 2675 while (pow2_width < desc->width) 2676 pow2_width <<= 1; 2677 while (pow2_height < desc->height) 2678 pow2_height <<= 1; 2679 texture->flags |= WINED3D_TEXTURE_COND_NP2_EMULATED; 2680 } 2681 } 2682 texture->pow2_width = pow2_width; 2683 texture->pow2_height = pow2_height; 2684 2685 if ((pow2_width > gl_info->limits.texture_size || pow2_height > gl_info->limits.texture_size) 2686 && (desc->usage & WINED3DUSAGE_TEXTURE)) 2687 { 2688 /* One of four options: 2689 * 1: Do the same as we do with NPOT and scale the texture. (Any 2690 * texture ops would require the texture to be scaled which is 2691 * potentially slow.) 2692 * 2: Set the texture to the maximum size (bad idea). 2693 * 3: WARN and return WINED3DERR_NOTAVAILABLE. 2694 * 4: Create the surface, but allow it to be used only for DirectDraw 2695 * Blts. Some apps (e.g. Swat 3) create textures with a height of 2696 * 16 and a width > 3000 and blt 16x16 letter areas from them to 2697 * the render target. */ 2698 if (desc->access & WINED3D_RESOURCE_ACCESS_GPU) 2699 { 2700 WARN("Dimensions (%ux%u) exceed the maximum texture size.\n", pow2_width, pow2_height); 2701 return WINED3DERR_NOTAVAILABLE; 2702 } 2703 2704 /* We should never use this surface in combination with OpenGL. */ 2705 TRACE("Creating an oversized (%ux%u) surface.\n", pow2_width, pow2_height); 2706 } 2707 2708 format = wined3d_get_format(&device->adapter->gl_info, desc->format, desc->usage); 2709 for (i = 0; i < layer_count; ++i) 2710 { 2711 for (j = 0; j < level_count; ++j) 2712 { 2713 unsigned int idx = i * level_count + j; 2714 2715 size = wined3d_format_calculate_size(format, device->surface_alignment, 2716 max(1, desc->width >> j), max(1, desc->height >> j), max(1, desc->depth >> j)); 2717 texture->sub_resources[idx].offset = offset; 2718 texture->sub_resources[idx].size = size; 2719 offset += size; 2720 } 2721 offset = (offset + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1); 2722 } 2723 2724 if (!offset) 2725 return WINED3DERR_INVALIDCALL; 2726 2727 if (FAILED(hr = resource_init(&texture->resource, device, desc->resource_type, format, 2728 desc->multisample_type, desc->multisample_quality, desc->usage, desc->access, 2729 desc->width, desc->height, desc->depth, offset, parent, parent_ops, &texture_resource_ops))) 2730 { 2731 static unsigned int once; 2732 2733 /* DXTn 3D textures are not supported. Do not write the ERR for them. */ 2734 if ((desc->format == WINED3DFMT_DXT1 || desc->format == WINED3DFMT_DXT2 || desc->format == WINED3DFMT_DXT3 2735 || desc->format == WINED3DFMT_DXT4 || desc->format == WINED3DFMT_DXT5) 2736 && !(format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_TEXTURE) 2737 && desc->resource_type != WINED3D_RTYPE_TEXTURE_3D && !once++) 2738 ERR_(winediag)("The application tried to create a DXTn texture, but the driver does not support them.\n"); 2739 2740 WARN("Failed to initialize resource, returning %#x\n", hr); 2741 return hr; 2742 } 2743 wined3d_resource_update_draw_binding(&texture->resource); 2744 if ((flags & WINED3D_TEXTURE_CREATE_MAPPABLE) || desc->format == WINED3DFMT_D16_LOCKABLE) 2745 texture->resource.access |= WINED3D_RESOURCE_ACCESS_MAP_R | WINED3D_RESOURCE_ACCESS_MAP_W; 2746 2747 texture->texture_ops = texture_ops; 2748 2749 texture->layer_count = layer_count; 2750 texture->level_count = level_count; 2751 texture->lod = 0; 2752 texture->flags |= WINED3D_TEXTURE_POW2_MAT_IDENT | WINED3D_TEXTURE_NORMALIZED_COORDS; 2753 if (flags & WINED3D_TEXTURE_CREATE_GET_DC_LENIENT) 2754 texture->flags |= WINED3D_TEXTURE_PIN_SYSMEM | WINED3D_TEXTURE_GET_DC_LENIENT; 2755 if (flags & (WINED3D_TEXTURE_CREATE_GET_DC | WINED3D_TEXTURE_CREATE_GET_DC_LENIENT)) 2756 texture->flags |= WINED3D_TEXTURE_GET_DC; 2757 if (flags & WINED3D_TEXTURE_CREATE_DISCARD) 2758 texture->flags |= WINED3D_TEXTURE_DISCARD; 2759 if (flags & WINED3D_TEXTURE_CREATE_GENERATE_MIPMAPS) 2760 { 2761 if (!(texture->resource.format_flags & WINED3DFMT_FLAG_GEN_MIPMAP)) 2762 WARN("Format doesn't support mipmaps generation, " 2763 "ignoring WINED3D_TEXTURE_CREATE_GENERATE_MIPMAPS flag.\n"); 2764 else 2765 texture->flags |= WINED3D_TEXTURE_GENERATE_MIPMAPS; 2766 } 2767 2768 list_init(&texture->renderbuffers); 2769 2770 switch (desc->resource_type) 2771 { 2772 case WINED3D_RTYPE_TEXTURE_1D: 2773 if (layer_count > 1) 2774 texture->target = GL_TEXTURE_1D_ARRAY; 2775 else 2776 texture->target = GL_TEXTURE_1D; 2777 break; 2778 2779 case WINED3D_RTYPE_TEXTURE_2D: 2780 if (desc->usage & WINED3DUSAGE_LEGACY_CUBEMAP) 2781 { 2782 texture->target = GL_TEXTURE_CUBE_MAP_ARB; 2783 } 2784 else if (desc->multisample_type && gl_info->supported[ARB_TEXTURE_MULTISAMPLE]) 2785 { 2786 if (layer_count > 1) 2787 texture->target = GL_TEXTURE_2D_MULTISAMPLE_ARRAY; 2788 else 2789 texture->target = GL_TEXTURE_2D_MULTISAMPLE; 2790 } 2791 else 2792 { 2793 if (layer_count > 1) 2794 texture->target = GL_TEXTURE_2D_ARRAY; 2795 else 2796 texture->target = GL_TEXTURE_2D; 2797 } 2798 break; 2799 2800 case WINED3D_RTYPE_TEXTURE_3D: 2801 texture->target = GL_TEXTURE_3D; 2802 break; 2803 2804 default: 2805 ERR("Invalid resource type %s.\n", debug_d3dresourcetype(desc->resource_type)); 2806 wined3d_texture_cleanup_sync(texture); 2807 return WINED3DERR_INVALIDCALL; 2808 } 2809 2810 /* Precalculated scaling for 'faked' non power of two texture coords. */ 2811 if (texture->resource.gl_type == WINED3D_GL_RES_TYPE_TEX_RECT) 2812 { 2813 texture->pow2_matrix[0] = (float)desc->width; 2814 texture->pow2_matrix[5] = (float)desc->height; 2815 texture->flags &= ~(WINED3D_TEXTURE_POW2_MAT_IDENT | WINED3D_TEXTURE_NORMALIZED_COORDS); 2816 texture->target = GL_TEXTURE_RECTANGLE_ARB; 2817 } 2818 else if (texture->flags & WINED3D_TEXTURE_COND_NP2_EMULATED) 2819 { 2820 texture->pow2_matrix[0] = (((float)desc->width) / ((float)pow2_width)); 2821 texture->pow2_matrix[5] = (((float)desc->height) / ((float)pow2_height)); 2822 texture->flags &= ~WINED3D_TEXTURE_POW2_MAT_IDENT; 2823 } 2824 else 2825 { 2826 texture->pow2_matrix[0] = 1.0f; 2827 texture->pow2_matrix[5] = 1.0f; 2828 } 2829 texture->pow2_matrix[10] = 1.0f; 2830 texture->pow2_matrix[15] = 1.0f; 2831 TRACE("x scale %.8e, y scale %.8e.\n", texture->pow2_matrix[0], texture->pow2_matrix[5]); 2832 2833 if (wined3d_texture_use_pbo(texture, gl_info)) 2834 texture->resource.map_binding = WINED3D_LOCATION_BUFFER; 2835 2836 if ((desc->resource_type != WINED3D_RTYPE_TEXTURE_3D 2837 && !(texture->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)) 2838 || !wined3d_texture_use_pbo(texture, gl_info)) 2839 { 2840 if (!wined3d_resource_allocate_sysmem(&texture->resource)) 2841 { 2842 wined3d_texture_cleanup_sync(texture); 2843 return E_OUTOFMEMORY; 2844 } 2845 } 2846 2847 sub_count = level_count * layer_count; 2848 if (sub_count / layer_count != level_count) 2849 { 2850 wined3d_texture_cleanup_sync(texture); 2851 return E_OUTOFMEMORY; 2852 } 2853 2854 if (desc->usage & WINED3DUSAGE_OVERLAY) 2855 { 2856 if (!(texture->overlay_info = heap_calloc(sub_count, sizeof(*texture->overlay_info)))) 2857 { 2858 wined3d_texture_cleanup_sync(texture); 2859 return E_OUTOFMEMORY; 2860 } 2861 2862 for (i = 0; i < sub_count; ++i) 2863 { 2864 list_init(&texture->overlay_info[i].entry); 2865 list_init(&texture->overlay_info[i].overlays); 2866 } 2867 } 2868 2869 /* Generate all sub-resources. */ 2870 for (i = 0; i < sub_count; ++i) 2871 { 2872 struct wined3d_texture_sub_resource *sub_resource; 2873 2874 sub_resource = &texture->sub_resources[i]; 2875 sub_resource->locations = WINED3D_LOCATION_DISCARDED; 2876 if (desc->resource_type != WINED3D_RTYPE_TEXTURE_3D 2877 && !(texture->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)) 2878 { 2879 wined3d_texture_validate_location(texture, i, WINED3D_LOCATION_SYSMEM); 2880 wined3d_texture_invalidate_location(texture, i, ~WINED3D_LOCATION_SYSMEM); 2881 } 2882 2883 if (FAILED(hr = device_parent->ops->texture_sub_resource_created(device_parent, 2884 desc->resource_type, texture, i, &sub_resource->parent, &sub_resource->parent_ops))) 2885 { 2886 WARN("Failed to create sub-resource parent, hr %#x.\n", hr); 2887 sub_resource->parent = NULL; 2888 wined3d_texture_cleanup_sync(texture); 2889 return hr; 2890 } 2891 2892 TRACE("parent %p, parent_ops %p.\n", sub_resource->parent, sub_resource->parent_ops); 2893 2894 TRACE("Created sub-resource %u (level %u, layer %u).\n", 2895 i, i % texture->level_count, i / texture->level_count); 2896 2897 if ((desc->usage & WINED3DUSAGE_OWNDC) || (device->wined3d->flags & WINED3D_NO3D)) 2898 { 2899 struct wined3d_texture_idx texture_idx = {texture, i}; 2900 2901 wined3d_cs_init_object(device->cs, wined3d_texture_create_dc, &texture_idx); 2902 device->cs->ops->finish(device->cs, WINED3D_CS_QUEUE_DEFAULT); 2903 if (!texture->dc_info || !texture->dc_info[i].dc) 2904 { 2905 wined3d_texture_cleanup_sync(texture); 2906 return WINED3DERR_INVALIDCALL; 2907 } 2908 } 2909 } 2910 2911 return WINED3D_OK; 2912 } 2913 2914 /* Context activation is done by the caller. */ 2915 static void texture3d_download_data(struct wined3d_texture *texture, unsigned int sub_resource_idx, 2916 const struct wined3d_context *context, const struct wined3d_bo_address *data) 2917 { 2918 const struct wined3d_format *format = texture->resource.format; 2919 const struct wined3d_gl_info *gl_info = context->gl_info; 2920 2921 if (format->conv_byte_count) 2922 { 2923 FIXME("Attempting to download a converted volume, format %s.\n", 2924 debug_d3dformat(format->id)); 2925 return; 2926 } 2927 2928 if (data->buffer_object) 2929 { 2930 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, data->buffer_object)); 2931 checkGLcall("glBindBuffer"); 2932 } 2933 2934 gl_info->gl_ops.gl.p_glGetTexImage(GL_TEXTURE_3D, sub_resource_idx, 2935 format->glFormat, format->glType, data->addr); 2936 checkGLcall("glGetTexImage"); 2937 2938 if (data->buffer_object) 2939 { 2940 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0)); 2941 checkGLcall("glBindBuffer"); 2942 } 2943 2944 } 2945 2946 /* Context activation is done by the caller. */ 2947 static void texture3d_srgb_transfer(struct wined3d_texture *texture, unsigned int sub_resource_idx, 2948 struct wined3d_context *context, BOOL dest_is_srgb) 2949 { 2950 struct wined3d_texture_sub_resource *sub_resource = &texture->sub_resources[sub_resource_idx]; 2951 unsigned int row_pitch, slice_pitch; 2952 struct wined3d_bo_address data; 2953 struct wined3d_box src_box; 2954 2955 /* Optimisations are possible, but the effort should be put into either 2956 * implementing EXT_SRGB_DECODE in the driver or finding out why we 2957 * picked the wrong copy for the original upload and fixing that. 2958 * 2959 * Also keep in mind that we want to avoid using resource.heap_memory 2960 * for DEFAULT pool surfaces. */ 2961 WARN_(d3d_perf)("Performing slow rgb/srgb volume transfer.\n"); 2962 data.buffer_object = 0; 2963 if (!(data.addr = heap_alloc(sub_resource->size))) 2964 return; 2965 2966 wined3d_texture_get_pitch(texture, sub_resource_idx, &row_pitch, &slice_pitch); 2967 wined3d_texture_get_level_box(texture, sub_resource_idx % texture->level_count, &src_box); 2968 wined3d_texture_bind_and_dirtify(texture, context, !dest_is_srgb); 2969 texture3d_download_data(texture, sub_resource_idx, context, &data); 2970 wined3d_texture_bind_and_dirtify(texture, context, dest_is_srgb); 2971 wined3d_texture_upload_data(texture, sub_resource_idx, context, texture->resource.format, 2972 &src_box, wined3d_const_bo_address(&data), row_pitch, slice_pitch, 0, 0, 0, FALSE); 2973 2974 heap_free(data.addr); 2975 } 2976 2977 /* Context activation is done by the caller. */ 2978 static BOOL texture3d_load_location(struct wined3d_texture *texture, unsigned int sub_resource_idx, 2979 struct wined3d_context *context, DWORD location) 2980 { 2981 struct wined3d_texture_sub_resource *sub_resource = &texture->sub_resources[sub_resource_idx]; 2982 unsigned int row_pitch, slice_pitch; 2983 2984 if (!wined3d_texture_prepare_location(texture, sub_resource_idx, context, location)) 2985 return FALSE; 2986 2987 switch (location) 2988 { 2989 case WINED3D_LOCATION_TEXTURE_RGB: 2990 case WINED3D_LOCATION_TEXTURE_SRGB: 2991 if (sub_resource->locations & WINED3D_LOCATION_SYSMEM) 2992 { 2993 struct wined3d_const_bo_address data = {0, texture->resource.heap_memory}; 2994 struct wined3d_box src_box; 2995 2996 data.addr += sub_resource->offset; 2997 wined3d_texture_bind_and_dirtify(texture, context, 2998 location == WINED3D_LOCATION_TEXTURE_SRGB); 2999 wined3d_texture_get_pitch(texture, sub_resource_idx, &row_pitch, &slice_pitch); 3000 wined3d_texture_get_level_box(texture, sub_resource_idx % texture->level_count, &src_box); 3001 wined3d_texture_upload_data(texture, sub_resource_idx, context, texture->resource.format, 3002 &src_box, &data, row_pitch, slice_pitch, 0, 0, 0, FALSE); 3003 } 3004 else if (sub_resource->locations & WINED3D_LOCATION_BUFFER) 3005 { 3006 struct wined3d_const_bo_address data = {sub_resource->buffer_object, NULL}; 3007 struct wined3d_box src_box; 3008 3009 wined3d_texture_bind_and_dirtify(texture, context, 3010 location == WINED3D_LOCATION_TEXTURE_SRGB); 3011 wined3d_texture_get_pitch(texture, sub_resource_idx, &row_pitch, &slice_pitch); 3012 wined3d_texture_get_level_box(texture, sub_resource_idx % texture->level_count, &src_box); 3013 wined3d_texture_upload_data(texture, sub_resource_idx, context, texture->resource.format, 3014 &src_box, &data, row_pitch, slice_pitch, 0, 0, 0, FALSE); 3015 } 3016 else if (sub_resource->locations & WINED3D_LOCATION_TEXTURE_RGB) 3017 { 3018 texture3d_srgb_transfer(texture, sub_resource_idx, context, TRUE); 3019 } 3020 else if (sub_resource->locations & WINED3D_LOCATION_TEXTURE_SRGB) 3021 { 3022 texture3d_srgb_transfer(texture, sub_resource_idx, context, FALSE); 3023 } 3024 else 3025 { 3026 FIXME("Implement texture loading from %s.\n", wined3d_debug_location(sub_resource->locations)); 3027 return FALSE; 3028 } 3029 break; 3030 3031 case WINED3D_LOCATION_SYSMEM: 3032 if (sub_resource->locations & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB)) 3033 { 3034 struct wined3d_bo_address data = {0, texture->resource.heap_memory}; 3035 3036 data.addr += sub_resource->offset; 3037 if (sub_resource->locations & WINED3D_LOCATION_TEXTURE_RGB) 3038 wined3d_texture_bind_and_dirtify(texture, context, FALSE); 3039 else 3040 wined3d_texture_bind_and_dirtify(texture, context, TRUE); 3041 3042 texture3d_download_data(texture, sub_resource_idx, context, &data); 3043 ++texture->download_count; 3044 } 3045 else 3046 { 3047 FIXME("Implement WINED3D_LOCATION_SYSMEM loading from %s.\n", 3048 wined3d_debug_location(sub_resource->locations)); 3049 return FALSE; 3050 } 3051 break; 3052 3053 case WINED3D_LOCATION_BUFFER: 3054 if (sub_resource->locations & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB)) 3055 { 3056 struct wined3d_bo_address data = {sub_resource->buffer_object, NULL}; 3057 3058 if (sub_resource->locations & WINED3D_LOCATION_TEXTURE_RGB) 3059 wined3d_texture_bind_and_dirtify(texture, context, FALSE); 3060 else 3061 wined3d_texture_bind_and_dirtify(texture, context, TRUE); 3062 3063 texture3d_download_data(texture, sub_resource_idx, context, &data); 3064 } 3065 else 3066 { 3067 FIXME("Implement WINED3D_LOCATION_BUFFER loading from %s.\n", 3068 wined3d_debug_location(sub_resource->locations)); 3069 return FALSE; 3070 } 3071 break; 3072 3073 default: 3074 FIXME("Implement %s loading from %s.\n", wined3d_debug_location(location), 3075 wined3d_debug_location(sub_resource->locations)); 3076 return FALSE; 3077 } 3078 3079 return TRUE; 3080 } 3081 3082 static const struct wined3d_texture_ops texture3d_ops = 3083 { 3084 texture3d_load_location, 3085 }; 3086 3087 HRESULT CDECL wined3d_texture_blt(struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx, 3088 const RECT *dst_rect, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx, 3089 const RECT *src_rect, DWORD flags, const struct wined3d_blt_fx *fx, enum wined3d_texture_filter_type filter) 3090 { 3091 struct wined3d_box src_box = {src_rect->left, src_rect->top, src_rect->right, src_rect->bottom, 0, 1}; 3092 struct wined3d_box dst_box = {dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, 0, 1}; 3093 unsigned int dst_format_flags, src_format_flags = 0; 3094 HRESULT hr; 3095 3096 TRACE("dst_texture %p, dst_sub_resource_idx %u, dst_rect %s, src_texture %p, " 3097 "src_sub_resource_idx %u, src_rect %s, flags %#x, fx %p, filter %s.\n", 3098 dst_texture, dst_sub_resource_idx, wine_dbgstr_rect(dst_rect), src_texture, 3099 src_sub_resource_idx, wine_dbgstr_rect(src_rect), flags, fx, debug_d3dtexturefiltertype(filter)); 3100 3101 if (dst_sub_resource_idx >= dst_texture->level_count * dst_texture->layer_count 3102 || dst_texture->resource.type != WINED3D_RTYPE_TEXTURE_2D) 3103 return WINED3DERR_INVALIDCALL; 3104 3105 if (src_sub_resource_idx >= src_texture->level_count * src_texture->layer_count 3106 || src_texture->resource.type != WINED3D_RTYPE_TEXTURE_2D) 3107 return WINED3DERR_INVALIDCALL; 3108 3109 dst_format_flags = dst_texture->resource.format_flags; 3110 if (FAILED(hr = wined3d_texture_check_box_dimensions(dst_texture, 3111 dst_sub_resource_idx % dst_texture->level_count, &dst_box))) 3112 return hr; 3113 3114 src_format_flags = src_texture->resource.format_flags; 3115 if (FAILED(hr = wined3d_texture_check_box_dimensions(src_texture, 3116 src_sub_resource_idx % src_texture->level_count, &src_box))) 3117 return hr; 3118 3119 if (dst_texture->sub_resources[dst_sub_resource_idx].map_count 3120 || src_texture->sub_resources[src_sub_resource_idx].map_count) 3121 { 3122 WARN("Sub-resource is busy, returning WINEDDERR_SURFACEBUSY.\n"); 3123 return WINEDDERR_SURFACEBUSY; 3124 } 3125 3126 if ((src_format_flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL)) 3127 != (dst_format_flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL))) 3128 { 3129 WARN("Rejecting depth/stencil blit between incompatible formats.\n"); 3130 return WINED3DERR_INVALIDCALL; 3131 } 3132 3133 wined3d_cs_emit_blt_sub_resource(dst_texture->resource.device->cs, &dst_texture->resource, dst_sub_resource_idx, 3134 &dst_box, &src_texture->resource, src_sub_resource_idx, &src_box, flags, fx, filter); 3135 3136 return WINED3D_OK; 3137 } 3138 3139 HRESULT CDECL wined3d_texture_get_overlay_position(const struct wined3d_texture *texture, 3140 unsigned int sub_resource_idx, LONG *x, LONG *y) 3141 { 3142 struct wined3d_overlay_info *overlay; 3143 3144 TRACE("texture %p, sub_resource_idx %u, x %p, y %p.\n", texture, sub_resource_idx, x, y); 3145 3146 if (!(texture->resource.usage & WINED3DUSAGE_OVERLAY) 3147 || sub_resource_idx >= texture->level_count * texture->layer_count) 3148 { 3149 WARN("Invalid sub-resource specified.\n"); 3150 return WINEDDERR_NOTAOVERLAYSURFACE; 3151 } 3152 3153 overlay = &texture->overlay_info[sub_resource_idx]; 3154 if (!overlay->dst_texture) 3155 { 3156 TRACE("Overlay not visible.\n"); 3157 *x = 0; 3158 *y = 0; 3159 return WINEDDERR_OVERLAYNOTVISIBLE; 3160 } 3161 3162 *x = overlay->dst_rect.left; 3163 *y = overlay->dst_rect.top; 3164 3165 TRACE("Returning position %d, %d.\n", *x, *y); 3166 3167 return WINED3D_OK; 3168 } 3169 3170 HRESULT CDECL wined3d_texture_set_overlay_position(struct wined3d_texture *texture, 3171 unsigned int sub_resource_idx, LONG x, LONG y) 3172 { 3173 struct wined3d_overlay_info *overlay; 3174 LONG w, h; 3175 3176 TRACE("texture %p, sub_resource_idx %u, x %d, y %d.\n", texture, sub_resource_idx, x, y); 3177 3178 if (!(texture->resource.usage & WINED3DUSAGE_OVERLAY) 3179 || sub_resource_idx >= texture->level_count * texture->layer_count) 3180 { 3181 WARN("Invalid sub-resource specified.\n"); 3182 return WINEDDERR_NOTAOVERLAYSURFACE; 3183 } 3184 3185 overlay = &texture->overlay_info[sub_resource_idx]; 3186 w = overlay->dst_rect.right - overlay->dst_rect.left; 3187 h = overlay->dst_rect.bottom - overlay->dst_rect.top; 3188 SetRect(&overlay->dst_rect, x, y, x + w, y + h); 3189 3190 return WINED3D_OK; 3191 } 3192 3193 HRESULT CDECL wined3d_texture_update_overlay(struct wined3d_texture *texture, unsigned int sub_resource_idx, 3194 const RECT *src_rect, struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx, 3195 const RECT *dst_rect, DWORD flags) 3196 { 3197 struct wined3d_overlay_info *overlay; 3198 unsigned int level, dst_level; 3199 3200 TRACE("texture %p, sub_resource_idx %u, src_rect %s, dst_texture %p, " 3201 "dst_sub_resource_idx %u, dst_rect %s, flags %#x.\n", 3202 texture, sub_resource_idx, wine_dbgstr_rect(src_rect), dst_texture, 3203 dst_sub_resource_idx, wine_dbgstr_rect(dst_rect), flags); 3204 3205 if (!(texture->resource.usage & WINED3DUSAGE_OVERLAY) || texture->resource.type != WINED3D_RTYPE_TEXTURE_2D 3206 || sub_resource_idx >= texture->level_count * texture->layer_count) 3207 { 3208 WARN("Invalid sub-resource specified.\n"); 3209 return WINEDDERR_NOTAOVERLAYSURFACE; 3210 } 3211 3212 if (!dst_texture || dst_texture->resource.type != WINED3D_RTYPE_TEXTURE_2D 3213 || dst_sub_resource_idx >= dst_texture->level_count * dst_texture->layer_count) 3214 { 3215 WARN("Invalid destination sub-resource specified.\n"); 3216 return WINED3DERR_INVALIDCALL; 3217 } 3218 3219 overlay = &texture->overlay_info[sub_resource_idx]; 3220 3221 level = sub_resource_idx % texture->level_count; 3222 if (src_rect) 3223 overlay->src_rect = *src_rect; 3224 else 3225 SetRect(&overlay->src_rect, 0, 0, 3226 wined3d_texture_get_level_width(texture, level), 3227 wined3d_texture_get_level_height(texture, level)); 3228 3229 dst_level = dst_sub_resource_idx % dst_texture->level_count; 3230 if (dst_rect) 3231 overlay->dst_rect = *dst_rect; 3232 else 3233 SetRect(&overlay->dst_rect, 0, 0, 3234 wined3d_texture_get_level_width(dst_texture, dst_level), 3235 wined3d_texture_get_level_height(dst_texture, dst_level)); 3236 3237 if (overlay->dst_texture && (overlay->dst_texture != dst_texture 3238 || overlay->dst_sub_resource_idx != dst_sub_resource_idx || flags & WINEDDOVER_HIDE)) 3239 { 3240 overlay->dst_texture = NULL; 3241 list_remove(&overlay->entry); 3242 } 3243 3244 if (flags & WINEDDOVER_SHOW) 3245 { 3246 if (overlay->dst_texture != dst_texture || overlay->dst_sub_resource_idx != dst_sub_resource_idx) 3247 { 3248 overlay->dst_texture = dst_texture; 3249 overlay->dst_sub_resource_idx = dst_sub_resource_idx; 3250 list_add_tail(&texture->overlay_info[dst_sub_resource_idx].overlays, &overlay->entry); 3251 } 3252 } 3253 else if (flags & WINEDDOVER_HIDE) 3254 { 3255 /* Tests show that the rectangles are erased on hide. */ 3256 SetRectEmpty(&overlay->src_rect); 3257 SetRectEmpty(&overlay->dst_rect); 3258 overlay->dst_texture = NULL; 3259 } 3260 3261 return WINED3D_OK; 3262 } 3263 3264 void * CDECL wined3d_texture_get_sub_resource_parent(struct wined3d_texture *texture, unsigned int sub_resource_idx) 3265 { 3266 unsigned int sub_count = texture->level_count * texture->layer_count; 3267 3268 TRACE("texture %p, sub_resource_idx %u.\n", texture, sub_resource_idx); 3269 3270 if (sub_resource_idx >= sub_count) 3271 { 3272 WARN("sub_resource_idx %u >= sub_count %u.\n", sub_resource_idx, sub_count); 3273 return NULL; 3274 } 3275 3276 return texture->sub_resources[sub_resource_idx].parent; 3277 } 3278 3279 void CDECL wined3d_texture_set_sub_resource_parent(struct wined3d_texture *texture, 3280 unsigned int sub_resource_idx, void *parent) 3281 { 3282 unsigned int sub_count = texture->level_count * texture->layer_count; 3283 3284 TRACE("texture %p, sub_resource_idx %u, parent %p.\n", texture, sub_resource_idx, parent); 3285 3286 if (sub_resource_idx >= sub_count) 3287 { 3288 WARN("sub_resource_idx %u >= sub_count %u.\n", sub_resource_idx, sub_count); 3289 return; 3290 } 3291 3292 texture->sub_resources[sub_resource_idx].parent = parent; 3293 } 3294 3295 HRESULT CDECL wined3d_texture_get_sub_resource_desc(const struct wined3d_texture *texture, 3296 unsigned int sub_resource_idx, struct wined3d_sub_resource_desc *desc) 3297 { 3298 unsigned int sub_count = texture->level_count * texture->layer_count; 3299 const struct wined3d_resource *resource; 3300 unsigned int level_idx; 3301 3302 TRACE("texture %p, sub_resource_idx %u, desc %p.\n", texture, sub_resource_idx, desc); 3303 3304 if (sub_resource_idx >= sub_count) 3305 { 3306 WARN("sub_resource_idx %u >= sub_count %u.\n", sub_resource_idx, sub_count); 3307 return WINED3DERR_INVALIDCALL; 3308 } 3309 3310 resource = &texture->resource; 3311 desc->format = resource->format->id; 3312 desc->multisample_type = resource->multisample_type; 3313 desc->multisample_quality = resource->multisample_quality; 3314 desc->usage = resource->usage; 3315 desc->access = resource->access; 3316 3317 level_idx = sub_resource_idx % texture->level_count; 3318 desc->width = wined3d_texture_get_level_width(texture, level_idx); 3319 desc->height = wined3d_texture_get_level_height(texture, level_idx); 3320 desc->depth = wined3d_texture_get_level_depth(texture, level_idx); 3321 desc->size = texture->sub_resources[sub_resource_idx].size; 3322 3323 return WINED3D_OK; 3324 } 3325 3326 HRESULT CDECL wined3d_texture_create(struct wined3d_device *device, const struct wined3d_resource_desc *desc, 3327 UINT layer_count, UINT level_count, DWORD flags, const struct wined3d_sub_resource_data *data, 3328 void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_texture **texture) 3329 { 3330 const struct wined3d_texture_ops *texture_ops; 3331 struct wined3d_texture *object; 3332 HRESULT hr; 3333 3334 TRACE("device %p, desc %p, layer_count %u, level_count %u, flags %#x, data %p, " 3335 "parent %p, parent_ops %p, texture %p.\n", 3336 device, desc, layer_count, level_count, flags, data, parent, parent_ops, texture); 3337 3338 if (!layer_count) 3339 { 3340 WARN("Invalid layer count.\n"); 3341 return E_INVALIDARG; 3342 } 3343 if ((desc->usage & WINED3DUSAGE_LEGACY_CUBEMAP) && layer_count != 6) 3344 { 3345 ERR("Invalid layer count %u for legacy cubemap.\n", layer_count); 3346 layer_count = 6; 3347 } 3348 3349 if (!level_count) 3350 { 3351 WARN("Invalid level count.\n"); 3352 return WINED3DERR_INVALIDCALL; 3353 } 3354 3355 if (desc->multisample_type != WINED3D_MULTISAMPLE_NONE) 3356 { 3357 const struct wined3d_format *format = wined3d_get_format(&device->adapter->gl_info, 3358 desc->format, desc->usage); 3359 3360 if (desc->multisample_type == WINED3D_MULTISAMPLE_NON_MASKABLE 3361 && desc->multisample_quality >= wined3d_popcount(format->multisample_types)) 3362 { 3363 WARN("Unsupported quality level %u requested for WINED3D_MULTISAMPLE_NON_MASKABLE.\n", 3364 desc->multisample_quality); 3365 return WINED3DERR_NOTAVAILABLE; 3366 } 3367 if (desc->multisample_type != WINED3D_MULTISAMPLE_NON_MASKABLE 3368 && (!(format->multisample_types & 1u << (desc->multisample_type - 1)) 3369 || desc->multisample_quality)) 3370 { 3371 WARN("Unsupported multisample type %u quality %u requested.\n", desc->multisample_type, 3372 desc->multisample_quality); 3373 return WINED3DERR_NOTAVAILABLE; 3374 } 3375 } 3376 3377 switch (desc->resource_type) 3378 { 3379 case WINED3D_RTYPE_TEXTURE_1D: 3380 texture_ops = &texture1d_ops; 3381 break; 3382 case WINED3D_RTYPE_TEXTURE_2D: 3383 texture_ops = &texture2d_ops; 3384 break; 3385 case WINED3D_RTYPE_TEXTURE_3D: 3386 texture_ops = &texture3d_ops; 3387 break; 3388 default: 3389 ERR("Invalid resource type %s.\n", debug_d3dresourcetype(desc->resource_type)); 3390 return WINED3DERR_INVALIDCALL; 3391 } 3392 3393 if (!(object = heap_alloc_zero(FIELD_OFFSET(struct wined3d_texture, 3394 sub_resources[level_count * layer_count])))) 3395 return E_OUTOFMEMORY; 3396 3397 if (FAILED(hr = wined3d_texture_init(object, desc, layer_count, 3398 level_count, flags, device, parent, parent_ops, texture_ops))) 3399 { 3400 WARN("Failed to initialize texture, returning %#x.\n", hr); 3401 heap_free(object); 3402 return hr; 3403 } 3404 3405 /* FIXME: We'd like to avoid ever allocating system memory for the texture 3406 * in this case. */ 3407 if (data) 3408 { 3409 unsigned int sub_count = level_count * layer_count; 3410 unsigned int i; 3411 3412 for (i = 0; i < sub_count; ++i) 3413 { 3414 if (!data[i].data) 3415 { 3416 WARN("Invalid sub-resource data specified for sub-resource %u.\n", i); 3417 wined3d_texture_cleanup_sync(object); 3418 heap_free(object); 3419 return E_INVALIDARG; 3420 } 3421 } 3422 3423 for (i = 0; i < sub_count; ++i) 3424 { 3425 wined3d_device_update_sub_resource(device, &object->resource, 3426 i, NULL, data[i].data, data[i].row_pitch, data[i].slice_pitch, 0); 3427 } 3428 } 3429 3430 TRACE("Created texture %p.\n", object); 3431 *texture = object; 3432 3433 return WINED3D_OK; 3434 } 3435 3436 HRESULT CDECL wined3d_texture_get_dc(struct wined3d_texture *texture, unsigned int sub_resource_idx, HDC *dc) 3437 { 3438 struct wined3d_device *device = texture->resource.device; 3439 struct wined3d_texture_sub_resource *sub_resource; 3440 struct wined3d_dc_info *dc_info; 3441 3442 TRACE("texture %p, sub_resource_idx %u, dc %p.\n", texture, sub_resource_idx, dc); 3443 3444 if (!(texture->flags & WINED3D_TEXTURE_GET_DC)) 3445 { 3446 WARN("Texture does not support GetDC\n"); 3447 /* Don't touch the DC */ 3448 return WINED3DERR_INVALIDCALL; 3449 } 3450 3451 if (!(sub_resource = wined3d_texture_get_sub_resource(texture, sub_resource_idx))) 3452 return WINED3DERR_INVALIDCALL; 3453 3454 if (texture->resource.type != WINED3D_RTYPE_TEXTURE_2D) 3455 { 3456 WARN("Not supported on %s resources.\n", debug_d3dresourcetype(texture->resource.type)); 3457 return WINED3DERR_INVALIDCALL; 3458 } 3459 3460 if (texture->resource.map_count && !(texture->flags & WINED3D_TEXTURE_GET_DC_LENIENT)) 3461 return WINED3DERR_INVALIDCALL; 3462 3463 if (!(dc_info = texture->dc_info) || !dc_info[sub_resource_idx].dc) 3464 { 3465 struct wined3d_texture_idx texture_idx = {texture, sub_resource_idx}; 3466 3467 wined3d_cs_init_object(device->cs, wined3d_texture_create_dc, &texture_idx); 3468 device->cs->ops->finish(device->cs, WINED3D_CS_QUEUE_DEFAULT); 3469 if (!(dc_info = texture->dc_info) || !dc_info[sub_resource_idx].dc) 3470 return WINED3DERR_INVALIDCALL; 3471 } 3472 3473 if (!(texture->flags & WINED3D_TEXTURE_GET_DC_LENIENT)) 3474 texture->flags |= WINED3D_TEXTURE_DC_IN_USE; 3475 ++texture->resource.map_count; 3476 ++sub_resource->map_count; 3477 3478 *dc = dc_info[sub_resource_idx].dc; 3479 TRACE("Returning dc %p.\n", *dc); 3480 3481 return WINED3D_OK; 3482 } 3483 3484 HRESULT CDECL wined3d_texture_release_dc(struct wined3d_texture *texture, unsigned int sub_resource_idx, HDC dc) 3485 { 3486 struct wined3d_device *device = texture->resource.device; 3487 struct wined3d_texture_sub_resource *sub_resource; 3488 struct wined3d_dc_info *dc_info; 3489 3490 TRACE("texture %p, sub_resource_idx %u, dc %p.\n", texture, sub_resource_idx, dc); 3491 3492 if (!(sub_resource = wined3d_texture_get_sub_resource(texture, sub_resource_idx))) 3493 return WINED3DERR_INVALIDCALL; 3494 3495 if (texture->resource.type != WINED3D_RTYPE_TEXTURE_2D) 3496 { 3497 WARN("Not supported on %s resources.\n", debug_d3dresourcetype(texture->resource.type)); 3498 return WINED3DERR_INVALIDCALL; 3499 } 3500 3501 if (!(texture->flags & (WINED3D_TEXTURE_GET_DC_LENIENT | WINED3D_TEXTURE_DC_IN_USE))) 3502 return WINED3DERR_INVALIDCALL; 3503 3504 if (!(dc_info = texture->dc_info) || dc_info[sub_resource_idx].dc != dc) 3505 { 3506 WARN("Application tries to release invalid DC %p, sub-resource DC is %p.\n", 3507 dc, dc_info ? dc_info[sub_resource_idx].dc : NULL); 3508 return WINED3DERR_INVALIDCALL; 3509 } 3510 3511 if (!(texture->resource.usage & WINED3DUSAGE_OWNDC) && !(device->wined3d->flags & WINED3D_NO3D)) 3512 { 3513 struct wined3d_texture_idx texture_idx = {texture, sub_resource_idx}; 3514 3515 wined3d_cs_destroy_object(device->cs, wined3d_texture_destroy_dc, &texture_idx); 3516 device->cs->ops->finish(device->cs, WINED3D_CS_QUEUE_DEFAULT); 3517 } 3518 3519 --sub_resource->map_count; 3520 if (!--texture->resource.map_count && texture->update_map_binding) 3521 wined3d_texture_update_map_binding(texture); 3522 if (!(texture->flags & WINED3D_TEXTURE_GET_DC_LENIENT)) 3523 texture->flags &= ~WINED3D_TEXTURE_DC_IN_USE; 3524 3525 return WINED3D_OK; 3526 } 3527 3528 void wined3d_texture_upload_from_texture(struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx, 3529 unsigned int dst_x, unsigned int dst_y, unsigned int dst_z, struct wined3d_texture *src_texture, 3530 unsigned int src_sub_resource_idx, const struct wined3d_box *src_box) 3531 { 3532 unsigned int src_row_pitch, src_slice_pitch; 3533 unsigned int update_w, update_h, update_d; 3534 unsigned int src_level, dst_level; 3535 struct wined3d_context *context; 3536 struct wined3d_bo_address data; 3537 3538 TRACE("dst_texture %p, dst_sub_resource_idx %u, dst_x %u, dst_y %u, dst_z %u, " 3539 "src_texture %p, src_sub_resource_idx %u, src_box %s.\n", 3540 dst_texture, dst_sub_resource_idx, dst_x, dst_y, dst_z, 3541 src_texture, src_sub_resource_idx, debug_box(src_box)); 3542 3543 context = context_acquire(dst_texture->resource.device, NULL, 0); 3544 3545 /* Only load the sub-resource for partial updates. For newly allocated 3546 * textures the texture wouldn't be the current location, and we'd upload 3547 * zeroes just to overwrite them again. */ 3548 update_w = src_box->right - src_box->left; 3549 update_h = src_box->bottom - src_box->top; 3550 update_d = src_box->back - src_box->front; 3551 dst_level = dst_sub_resource_idx % dst_texture->level_count; 3552 if (update_w == wined3d_texture_get_level_width(dst_texture, dst_level) 3553 && update_h == wined3d_texture_get_level_height(dst_texture, dst_level) 3554 && update_d == wined3d_texture_get_level_depth(dst_texture, dst_level)) 3555 wined3d_texture_prepare_texture(dst_texture, context, FALSE); 3556 else 3557 wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, WINED3D_LOCATION_TEXTURE_RGB); 3558 wined3d_texture_bind_and_dirtify(dst_texture, context, FALSE); 3559 3560 src_level = src_sub_resource_idx % src_texture->level_count; 3561 wined3d_texture_get_memory(src_texture, src_sub_resource_idx, &data, 3562 src_texture->sub_resources[src_sub_resource_idx].locations); 3563 wined3d_texture_get_pitch(src_texture, src_level, &src_row_pitch, &src_slice_pitch); 3564 3565 wined3d_texture_upload_data(dst_texture, dst_sub_resource_idx, context, src_texture->resource.format, 3566 src_box, wined3d_const_bo_address(&data), src_row_pitch, src_slice_pitch, dst_x, dst_y, dst_z, FALSE); 3567 3568 context_release(context); 3569 3570 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB); 3571 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB); 3572 } 3573