1 /* 2 * Copyright 2009, 2011 Henri Verbeet for CodeWeavers 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 17 * 18 */ 19 20 #include "config.h" 21 #include "wine/port.h" 22 23 #include "wined3d_private.h" 24 25 WINE_DEFAULT_DEBUG_CHANNEL(d3d); 26 27 #define WINED3D_VIEW_CUBE_ARRAY (WINED3D_VIEW_TEXTURE_CUBE | WINED3D_VIEW_TEXTURE_ARRAY) 28 29 static BOOL is_stencil_view_format(const struct wined3d_format *format) 30 { 31 return format->id == WINED3DFMT_X24_TYPELESS_G8_UINT 32 || format->id == WINED3DFMT_X32_TYPELESS_G8X24_UINT; 33 } 34 35 static GLenum get_texture_view_target(const struct wined3d_gl_info *gl_info, 36 const struct wined3d_view_desc *desc, const struct wined3d_texture *texture) 37 { 38 static const struct 39 { 40 GLenum texture_target; 41 unsigned int view_flags; 42 GLenum view_target; 43 enum wined3d_gl_extension extension; 44 } 45 view_types[] = 46 { 47 {GL_TEXTURE_CUBE_MAP, 0, GL_TEXTURE_CUBE_MAP}, 48 {GL_TEXTURE_RECTANGLE, 0, GL_TEXTURE_RECTANGLE}, 49 {GL_TEXTURE_3D, 0, GL_TEXTURE_3D}, 50 51 {GL_TEXTURE_1D, 0, GL_TEXTURE_1D}, 52 {GL_TEXTURE_1D, WINED3D_VIEW_TEXTURE_ARRAY, GL_TEXTURE_1D_ARRAY}, 53 {GL_TEXTURE_1D_ARRAY, 0, GL_TEXTURE_1D}, 54 {GL_TEXTURE_1D_ARRAY, WINED3D_VIEW_TEXTURE_ARRAY, GL_TEXTURE_1D_ARRAY}, 55 56 {GL_TEXTURE_2D, 0, GL_TEXTURE_2D}, 57 {GL_TEXTURE_2D, WINED3D_VIEW_TEXTURE_ARRAY, GL_TEXTURE_2D_ARRAY}, 58 {GL_TEXTURE_2D_ARRAY, 0, GL_TEXTURE_2D}, 59 {GL_TEXTURE_2D_ARRAY, WINED3D_VIEW_TEXTURE_ARRAY, GL_TEXTURE_2D_ARRAY}, 60 {GL_TEXTURE_2D_ARRAY, WINED3D_VIEW_TEXTURE_CUBE, GL_TEXTURE_CUBE_MAP}, 61 {GL_TEXTURE_2D_ARRAY, WINED3D_VIEW_CUBE_ARRAY, GL_TEXTURE_CUBE_MAP_ARRAY, ARB_TEXTURE_CUBE_MAP_ARRAY}, 62 63 {GL_TEXTURE_2D_MULTISAMPLE, 0, GL_TEXTURE_2D_MULTISAMPLE}, 64 {GL_TEXTURE_2D_MULTISAMPLE, WINED3D_VIEW_TEXTURE_ARRAY, GL_TEXTURE_2D_MULTISAMPLE_ARRAY}, 65 {GL_TEXTURE_2D_MULTISAMPLE_ARRAY, 0, GL_TEXTURE_2D_MULTISAMPLE}, 66 {GL_TEXTURE_2D_MULTISAMPLE_ARRAY, WINED3D_VIEW_TEXTURE_ARRAY, GL_TEXTURE_2D_MULTISAMPLE_ARRAY}, 67 }; 68 unsigned int i; 69 70 for (i = 0; i < ARRAY_SIZE(view_types); ++i) 71 { 72 if (view_types[i].texture_target != texture->target || view_types[i].view_flags != desc->flags) 73 continue; 74 if (gl_info->supported[view_types[i].extension]) 75 return view_types[i].view_target; 76 77 FIXME("Extension %#x not supported.\n", view_types[i].extension); 78 } 79 80 FIXME("Unhandled view flags %#x for texture target %#x.\n", desc->flags, texture->target); 81 return texture->target; 82 } 83 84 static const struct wined3d_format *validate_resource_view(const struct wined3d_view_desc *desc, 85 struct wined3d_resource *resource, BOOL mip_slice, BOOL allow_srgb_toggle) 86 { 87 const struct wined3d_gl_info *gl_info = &resource->device->adapter->gl_info; 88 const struct wined3d_format *format; 89 90 format = wined3d_get_format(gl_info, desc->format_id, resource->usage); 91 if (resource->type == WINED3D_RTYPE_BUFFER && (desc->flags & WINED3D_VIEW_BUFFER_RAW)) 92 { 93 if (format->id != WINED3DFMT_R32_TYPELESS) 94 { 95 WARN("Invalid format %s for raw buffer view.\n", debug_d3dformat(format->id)); 96 return NULL; 97 } 98 99 format = wined3d_get_format(gl_info, WINED3DFMT_R32_UINT, resource->usage); 100 } 101 102 if (wined3d_format_is_typeless(format)) 103 { 104 WARN("Trying to create view for typeless format %s.\n", debug_d3dformat(format->id)); 105 return NULL; 106 } 107 108 if (resource->type == WINED3D_RTYPE_BUFFER) 109 { 110 struct wined3d_buffer *buffer = buffer_from_resource(resource); 111 unsigned int buffer_size, element_size; 112 113 if (buffer->desc.structure_byte_stride) 114 { 115 if (desc->format_id != WINED3DFMT_UNKNOWN) 116 { 117 WARN("Invalid format %s for structured buffer view.\n", debug_d3dformat(desc->format_id)); 118 return NULL; 119 } 120 121 format = wined3d_get_format(gl_info, WINED3DFMT_R32_UINT, resource->usage); 122 element_size = buffer->desc.structure_byte_stride; 123 } 124 else 125 { 126 element_size = format->byte_count; 127 } 128 129 if (!element_size) 130 return NULL; 131 132 buffer_size = buffer->resource.size / element_size; 133 if (desc->u.buffer.start_idx >= buffer_size 134 || desc->u.buffer.count > buffer_size - desc->u.buffer.start_idx) 135 return NULL; 136 } 137 else 138 { 139 struct wined3d_texture *texture = texture_from_resource(resource); 140 unsigned int depth_or_layer_count; 141 142 if (resource->format->id != format->id && !wined3d_format_is_typeless(resource->format) 143 && (!allow_srgb_toggle || !wined3d_formats_are_srgb_variants(resource->format->id, format->id))) 144 { 145 WARN("Trying to create incompatible view for non typeless format %s.\n", 146 debug_d3dformat(format->id)); 147 return NULL; 148 } 149 150 if (mip_slice && resource->type == WINED3D_RTYPE_TEXTURE_3D) 151 depth_or_layer_count = wined3d_texture_get_level_depth(texture, desc->u.texture.level_idx); 152 else 153 depth_or_layer_count = texture->layer_count; 154 155 if (!desc->u.texture.level_count 156 || (mip_slice && desc->u.texture.level_count != 1) 157 || desc->u.texture.level_idx >= texture->level_count 158 || desc->u.texture.level_count > texture->level_count - desc->u.texture.level_idx 159 || !desc->u.texture.layer_count 160 || desc->u.texture.layer_idx >= depth_or_layer_count 161 || desc->u.texture.layer_count > depth_or_layer_count - desc->u.texture.layer_idx) 162 return NULL; 163 } 164 165 return format; 166 } 167 168 static void create_texture_view(struct wined3d_gl_view *view, GLenum view_target, 169 const struct wined3d_view_desc *desc, struct wined3d_texture *texture, 170 const struct wined3d_format *view_format) 171 { 172 const struct wined3d_gl_info *gl_info; 173 unsigned int layer_idx, layer_count; 174 struct wined3d_context *context; 175 GLuint texture_name; 176 177 view->target = view_target; 178 179 context = context_acquire(texture->resource.device, NULL, 0); 180 gl_info = context->gl_info; 181 182 if (!gl_info->supported[ARB_TEXTURE_VIEW]) 183 { 184 context_release(context); 185 FIXME("OpenGL implementation does not support texture views.\n"); 186 return; 187 } 188 189 wined3d_texture_prepare_texture(texture, context, FALSE); 190 texture_name = wined3d_texture_get_texture_name(texture, context, FALSE); 191 192 layer_idx = desc->u.texture.layer_idx; 193 layer_count = desc->u.texture.layer_count; 194 if (view_target == GL_TEXTURE_3D && (layer_idx || layer_count != 1)) 195 { 196 FIXME("Depth slice (%u-%u) not supported.\n", layer_idx, layer_count); 197 layer_idx = 0; 198 layer_count = 1; 199 } 200 201 gl_info->gl_ops.gl.p_glGenTextures(1, &view->name); 202 GL_EXTCALL(glTextureView(view->name, view->target, texture_name, view_format->glInternal, 203 desc->u.texture.level_idx, desc->u.texture.level_count, 204 layer_idx, layer_count)); 205 checkGLcall("Create texture view"); 206 207 if (is_stencil_view_format(view_format)) 208 { 209 static const GLint swizzle[] = {GL_ZERO, GL_RED, GL_ZERO, GL_ZERO}; 210 211 if (!gl_info->supported[ARB_STENCIL_TEXTURING]) 212 { 213 context_release(context); 214 FIXME("OpenGL implementation does not support stencil texturing.\n"); 215 return; 216 } 217 218 context_bind_texture(context, view->target, view->name); 219 gl_info->gl_ops.gl.p_glTexParameteriv(view->target, GL_TEXTURE_SWIZZLE_RGBA, swizzle); 220 gl_info->gl_ops.gl.p_glTexParameteri(view->target, GL_DEPTH_STENCIL_TEXTURE_MODE, GL_STENCIL_INDEX); 221 checkGLcall("Initialize stencil view"); 222 223 context_invalidate_compute_state(context, STATE_COMPUTE_SHADER_RESOURCE_BINDING); 224 context_invalidate_state(context, STATE_GRAPHICS_SHADER_RESOURCE_BINDING); 225 } 226 227 context_release(context); 228 } 229 230 static void create_buffer_texture(struct wined3d_gl_view *view, struct wined3d_context *context, 231 struct wined3d_buffer *buffer, const struct wined3d_format *view_format, 232 unsigned int offset, unsigned int size) 233 { 234 const struct wined3d_gl_info *gl_info = context->gl_info; 235 236 if (!gl_info->supported[ARB_TEXTURE_BUFFER_OBJECT]) 237 { 238 FIXME("OpenGL implementation does not support buffer textures.\n"); 239 return; 240 } 241 242 if ((offset & (gl_info->limits.texture_buffer_offset_alignment - 1))) 243 { 244 FIXME("Buffer offset %u is not %u byte aligned.\n", 245 offset, gl_info->limits.texture_buffer_offset_alignment); 246 return; 247 } 248 249 wined3d_buffer_load_location(buffer, context, WINED3D_LOCATION_BUFFER); 250 251 view->target = GL_TEXTURE_BUFFER; 252 gl_info->gl_ops.gl.p_glGenTextures(1, &view->name); 253 254 context_bind_texture(context, GL_TEXTURE_BUFFER, view->name); 255 if (gl_info->supported[ARB_TEXTURE_BUFFER_RANGE]) 256 { 257 GL_EXTCALL(glTexBufferRange(GL_TEXTURE_BUFFER, view_format->glInternal, 258 buffer->buffer_object, offset, size)); 259 } 260 else 261 { 262 if (offset || size != buffer->resource.size) 263 FIXME("OpenGL implementation does not support ARB_texture_buffer_range.\n"); 264 GL_EXTCALL(glTexBuffer(GL_TEXTURE_BUFFER, view_format->glInternal, buffer->buffer_object)); 265 } 266 checkGLcall("Create buffer texture"); 267 268 context_invalidate_compute_state(context, STATE_COMPUTE_SHADER_RESOURCE_BINDING); 269 context_invalidate_state(context, STATE_GRAPHICS_SHADER_RESOURCE_BINDING); 270 } 271 272 static void get_buffer_view_range(const struct wined3d_buffer *buffer, 273 const struct wined3d_view_desc *desc, const struct wined3d_format *view_format, 274 unsigned int *offset, unsigned int *size) 275 { 276 if (desc->format_id == WINED3DFMT_UNKNOWN) 277 { 278 *offset = desc->u.buffer.start_idx * buffer->desc.structure_byte_stride; 279 *size = desc->u.buffer.count * buffer->desc.structure_byte_stride; 280 } 281 else 282 { 283 *offset = desc->u.buffer.start_idx * view_format->byte_count; 284 *size = desc->u.buffer.count * view_format->byte_count; 285 } 286 } 287 288 static void create_buffer_view(struct wined3d_gl_view *view, struct wined3d_context *context, 289 const struct wined3d_view_desc *desc, struct wined3d_buffer *buffer, 290 const struct wined3d_format *view_format) 291 { 292 unsigned int offset, size; 293 294 get_buffer_view_range(buffer, desc, view_format, &offset, &size); 295 create_buffer_texture(view, context, buffer, view_format, offset, size); 296 } 297 298 static void wined3d_view_invalidate_location(struct wined3d_resource *resource, 299 const struct wined3d_view_desc *desc, DWORD location) 300 { 301 unsigned int i, sub_resource_idx, layer_count; 302 struct wined3d_texture *texture; 303 304 if (resource->type == WINED3D_RTYPE_BUFFER) 305 { 306 wined3d_buffer_invalidate_location(buffer_from_resource(resource), location); 307 return; 308 } 309 310 texture = texture_from_resource(resource); 311 312 sub_resource_idx = desc->u.texture.layer_idx * texture->level_count + desc->u.texture.level_idx; 313 layer_count = resource->type != WINED3D_RTYPE_TEXTURE_3D ? desc->u.texture.layer_count : 1; 314 for (i = 0; i < layer_count; ++i, sub_resource_idx += texture->level_count) 315 wined3d_texture_invalidate_location(texture, sub_resource_idx, location); 316 } 317 318 ULONG CDECL wined3d_rendertarget_view_incref(struct wined3d_rendertarget_view *view) 319 { 320 ULONG refcount = InterlockedIncrement(&view->refcount); 321 322 TRACE("%p increasing refcount to %u.\n", view, refcount); 323 324 return refcount; 325 } 326 327 static void wined3d_rendertarget_view_destroy_object(void *object) 328 { 329 struct wined3d_rendertarget_view *view = object; 330 struct wined3d_device *device = view->resource->device; 331 332 if (view->gl_view.name) 333 { 334 const struct wined3d_gl_info *gl_info; 335 struct wined3d_context *context; 336 337 context = context_acquire(device, NULL, 0); 338 gl_info = context->gl_info; 339 context_gl_resource_released(device, view->gl_view.name, FALSE); 340 gl_info->gl_ops.gl.p_glDeleteTextures(1, &view->gl_view.name); 341 checkGLcall("glDeleteTextures"); 342 context_release(context); 343 } 344 345 heap_free(view); 346 } 347 348 ULONG CDECL wined3d_rendertarget_view_decref(struct wined3d_rendertarget_view *view) 349 { 350 ULONG refcount = InterlockedDecrement(&view->refcount); 351 352 TRACE("%p decreasing refcount to %u.\n", view, refcount); 353 354 if (!refcount) 355 { 356 struct wined3d_resource *resource = view->resource; 357 struct wined3d_device *device = resource->device; 358 359 /* Call wined3d_object_destroyed() before releasing the resource, 360 * since releasing the resource may end up destroying the parent. */ 361 view->parent_ops->wined3d_object_destroyed(view->parent); 362 wined3d_cs_destroy_object(device->cs, wined3d_rendertarget_view_destroy_object, view); 363 wined3d_resource_decref(resource); 364 } 365 366 return refcount; 367 } 368 369 void * CDECL wined3d_rendertarget_view_get_parent(const struct wined3d_rendertarget_view *view) 370 { 371 TRACE("view %p.\n", view); 372 373 return view->parent; 374 } 375 376 void * CDECL wined3d_rendertarget_view_get_sub_resource_parent(const struct wined3d_rendertarget_view *view) 377 { 378 struct wined3d_texture *texture; 379 380 TRACE("view %p.\n", view); 381 382 if (view->resource->type == WINED3D_RTYPE_BUFFER) 383 return wined3d_buffer_get_parent(buffer_from_resource(view->resource)); 384 385 texture = texture_from_resource(view->resource); 386 387 return texture->sub_resources[view->sub_resource_idx].parent; 388 } 389 390 void CDECL wined3d_rendertarget_view_set_parent(struct wined3d_rendertarget_view *view, void *parent) 391 { 392 TRACE("view %p, parent %p.\n", view, parent); 393 394 view->parent = parent; 395 } 396 397 struct wined3d_resource * CDECL wined3d_rendertarget_view_get_resource(const struct wined3d_rendertarget_view *view) 398 { 399 TRACE("view %p.\n", view); 400 401 return view->resource; 402 } 403 404 void wined3d_rendertarget_view_get_drawable_size(const struct wined3d_rendertarget_view *view, 405 const struct wined3d_context *context, unsigned int *width, unsigned int *height) 406 { 407 const struct wined3d_texture *texture; 408 409 if (view->resource->type != WINED3D_RTYPE_TEXTURE_2D) 410 { 411 *width = view->width; 412 *height = view->height; 413 return; 414 } 415 416 texture = texture_from_resource(view->resource); 417 if (texture->swapchain) 418 { 419 /* The drawable size of an onscreen drawable is the surface size. 420 * (Actually: The window size, but the surface is created in window 421 * size.) */ 422 *width = texture->resource.width; 423 *height = texture->resource.height; 424 } 425 else if (wined3d_settings.offscreen_rendering_mode == ORM_BACKBUFFER) 426 { 427 const struct wined3d_swapchain *swapchain = context->swapchain; 428 429 /* The drawable size of a backbuffer / aux buffer offscreen target is 430 * the size of the current context's drawable, which is the size of 431 * the back buffer of the swapchain the active context belongs to. */ 432 *width = swapchain->desc.backbuffer_width; 433 *height = swapchain->desc.backbuffer_height; 434 } 435 else 436 { 437 unsigned int level_idx = view->sub_resource_idx % texture->level_count; 438 439 /* The drawable size of an FBO target is the OpenGL texture size, 440 * which is the power of two size. */ 441 *width = wined3d_texture_get_level_pow2_width(texture, level_idx); 442 *height = wined3d_texture_get_level_pow2_height(texture, level_idx); 443 } 444 } 445 446 void wined3d_rendertarget_view_prepare_location(struct wined3d_rendertarget_view *view, 447 struct wined3d_context *context, DWORD location) 448 { 449 struct wined3d_resource *resource = view->resource; 450 unsigned int i, sub_resource_idx, layer_count; 451 struct wined3d_texture *texture; 452 453 if (resource->type == WINED3D_RTYPE_BUFFER) 454 { 455 FIXME("Not implemented for resources %s.\n", debug_d3dresourcetype(resource->type)); 456 return; 457 } 458 459 texture = texture_from_resource(resource); 460 sub_resource_idx = view->sub_resource_idx; 461 layer_count = resource->type != WINED3D_RTYPE_TEXTURE_3D ? view->layer_count : 1; 462 for (i = 0; i < layer_count; ++i, sub_resource_idx += texture->level_count) 463 wined3d_texture_prepare_location(texture, sub_resource_idx, context, location); 464 } 465 466 void wined3d_rendertarget_view_load_location(struct wined3d_rendertarget_view *view, 467 struct wined3d_context *context, DWORD location) 468 { 469 struct wined3d_resource *resource = view->resource; 470 unsigned int i, sub_resource_idx, layer_count; 471 struct wined3d_texture *texture; 472 473 if (resource->type == WINED3D_RTYPE_BUFFER) 474 { 475 wined3d_buffer_load_location(buffer_from_resource(resource), context, location); 476 return; 477 } 478 479 texture = texture_from_resource(resource); 480 sub_resource_idx = view->sub_resource_idx; 481 layer_count = resource->type != WINED3D_RTYPE_TEXTURE_3D ? view->layer_count : 1; 482 for (i = 0; i < layer_count; ++i, sub_resource_idx += texture->level_count) 483 wined3d_texture_load_location(texture, sub_resource_idx, context, location); 484 } 485 486 void wined3d_rendertarget_view_validate_location(struct wined3d_rendertarget_view *view, DWORD location) 487 { 488 struct wined3d_resource *resource = view->resource; 489 unsigned int i, sub_resource_idx, layer_count; 490 struct wined3d_texture *texture; 491 492 if (resource->type == WINED3D_RTYPE_BUFFER) 493 { 494 FIXME("Not implemented for resources %s.\n", debug_d3dresourcetype(resource->type)); 495 return; 496 } 497 498 texture = texture_from_resource(resource); 499 sub_resource_idx = view->sub_resource_idx; 500 layer_count = resource->type != WINED3D_RTYPE_TEXTURE_3D ? view->layer_count : 1; 501 for (i = 0; i < layer_count; ++i, sub_resource_idx += texture->level_count) 502 wined3d_texture_validate_location(texture, sub_resource_idx, location); 503 } 504 505 void wined3d_rendertarget_view_invalidate_location(struct wined3d_rendertarget_view *view, DWORD location) 506 { 507 wined3d_view_invalidate_location(view->resource, &view->desc, location); 508 } 509 510 static void wined3d_render_target_view_cs_init(void *object) 511 { 512 struct wined3d_rendertarget_view *view = object; 513 struct wined3d_resource *resource = view->resource; 514 const struct wined3d_view_desc *desc = &view->desc; 515 516 if (resource->type == WINED3D_RTYPE_BUFFER) 517 { 518 FIXME("Not implemented for resources %s.\n", debug_d3dresourcetype(resource->type)); 519 } 520 else 521 { 522 struct wined3d_texture *texture = texture_from_resource(resource); 523 unsigned int depth_or_layer_count; 524 525 if (resource->type == WINED3D_RTYPE_TEXTURE_3D) 526 depth_or_layer_count = wined3d_texture_get_level_depth(texture, desc->u.texture.level_idx); 527 else 528 depth_or_layer_count = texture->layer_count; 529 530 if (resource->format->id != view->format->id 531 || (view->layer_count != 1 && view->layer_count != depth_or_layer_count)) 532 { 533 if (resource->format->gl_view_class != view->format->gl_view_class) 534 { 535 FIXME("Render target view not supported, resource format %s, view format %s.\n", 536 debug_d3dformat(resource->format->id), debug_d3dformat(view->format->id)); 537 return; 538 } 539 if (texture->swapchain && texture->swapchain->desc.backbuffer_count > 1) 540 { 541 FIXME("Swapchain views not supported.\n"); 542 return; 543 } 544 545 create_texture_view(&view->gl_view, texture->target, desc, texture, view->format); 546 } 547 } 548 } 549 550 static HRESULT wined3d_rendertarget_view_init(struct wined3d_rendertarget_view *view, 551 const struct wined3d_view_desc *desc, struct wined3d_resource *resource, 552 void *parent, const struct wined3d_parent_ops *parent_ops) 553 { 554 BOOL allow_srgb_toggle = FALSE; 555 556 view->refcount = 1; 557 view->parent = parent; 558 view->parent_ops = parent_ops; 559 560 if (resource->type != WINED3D_RTYPE_BUFFER) 561 { 562 struct wined3d_texture *texture = texture_from_resource(resource); 563 564 if (texture->swapchain) 565 allow_srgb_toggle = TRUE; 566 } 567 if (!(view->format = validate_resource_view(desc, resource, TRUE, allow_srgb_toggle))) 568 return E_INVALIDARG; 569 view->format_flags = view->format->flags[resource->gl_type]; 570 view->desc = *desc; 571 572 if (resource->type == WINED3D_RTYPE_BUFFER) 573 { 574 view->sub_resource_idx = 0; 575 view->layer_count = 1; 576 view->width = desc->u.buffer.count; 577 view->height = 1; 578 } 579 else 580 { 581 struct wined3d_texture *texture = texture_from_resource(resource); 582 583 view->sub_resource_idx = desc->u.texture.level_idx; 584 if (resource->type != WINED3D_RTYPE_TEXTURE_3D) 585 view->sub_resource_idx += desc->u.texture.layer_idx * texture->level_count; 586 view->layer_count = desc->u.texture.layer_count; 587 view->width = wined3d_texture_get_level_width(texture, desc->u.texture.level_idx); 588 view->height = wined3d_texture_get_level_height(texture, desc->u.texture.level_idx); 589 } 590 591 wined3d_resource_incref(view->resource = resource); 592 593 wined3d_cs_init_object(resource->device->cs, wined3d_render_target_view_cs_init, view); 594 595 return WINED3D_OK; 596 } 597 598 HRESULT CDECL wined3d_rendertarget_view_create(const struct wined3d_view_desc *desc, 599 struct wined3d_resource *resource, void *parent, const struct wined3d_parent_ops *parent_ops, 600 struct wined3d_rendertarget_view **view) 601 { 602 struct wined3d_rendertarget_view *object; 603 HRESULT hr; 604 605 TRACE("desc %p, resource %p, parent %p, parent_ops %p, view %p.\n", 606 desc, resource, parent, parent_ops, view); 607 608 if (!(object = heap_alloc_zero(sizeof(*object)))) 609 return E_OUTOFMEMORY; 610 611 if (FAILED(hr = wined3d_rendertarget_view_init(object, desc, resource, parent, parent_ops))) 612 { 613 heap_free(object); 614 WARN("Failed to initialise view, hr %#x.\n", hr); 615 return hr; 616 } 617 618 TRACE("Created render target view %p.\n", object); 619 *view = object; 620 621 return hr; 622 } 623 624 HRESULT CDECL wined3d_rendertarget_view_create_from_sub_resource(struct wined3d_texture *texture, 625 unsigned int sub_resource_idx, void *parent, const struct wined3d_parent_ops *parent_ops, 626 struct wined3d_rendertarget_view **view) 627 { 628 struct wined3d_view_desc desc; 629 630 TRACE("texture %p, sub_resource_idx %u, parent %p, parent_ops %p, view %p.\n", 631 texture, sub_resource_idx, parent, parent_ops, view); 632 633 desc.format_id = texture->resource.format->id; 634 desc.flags = 0; 635 desc.u.texture.level_idx = sub_resource_idx % texture->level_count; 636 desc.u.texture.level_count = 1; 637 desc.u.texture.layer_idx = sub_resource_idx / texture->level_count; 638 desc.u.texture.layer_count = 1; 639 640 return wined3d_rendertarget_view_create(&desc, &texture->resource, parent, parent_ops, view); 641 } 642 643 ULONG CDECL wined3d_shader_resource_view_incref(struct wined3d_shader_resource_view *view) 644 { 645 ULONG refcount = InterlockedIncrement(&view->refcount); 646 647 TRACE("%p increasing refcount to %u.\n", view, refcount); 648 649 return refcount; 650 } 651 652 static void wined3d_shader_resource_view_destroy_object(void *object) 653 { 654 struct wined3d_shader_resource_view *view = object; 655 656 if (view->gl_view.name) 657 { 658 const struct wined3d_gl_info *gl_info; 659 struct wined3d_context *context; 660 661 context = context_acquire(view->resource->device, NULL, 0); 662 gl_info = context->gl_info; 663 gl_info->gl_ops.gl.p_glDeleteTextures(1, &view->gl_view.name); 664 checkGLcall("glDeleteTextures"); 665 context_release(context); 666 } 667 668 heap_free(view); 669 } 670 671 ULONG CDECL wined3d_shader_resource_view_decref(struct wined3d_shader_resource_view *view) 672 { 673 ULONG refcount = InterlockedDecrement(&view->refcount); 674 675 TRACE("%p decreasing refcount to %u.\n", view, refcount); 676 677 if (!refcount) 678 { 679 struct wined3d_resource *resource = view->resource; 680 struct wined3d_device *device = resource->device; 681 682 /* Call wined3d_object_destroyed() before releasing the resource, 683 * since releasing the resource may end up destroying the parent. */ 684 view->parent_ops->wined3d_object_destroyed(view->parent); 685 wined3d_cs_destroy_object(device->cs, wined3d_shader_resource_view_destroy_object, view); 686 wined3d_resource_decref(resource); 687 } 688 689 return refcount; 690 } 691 692 void * CDECL wined3d_shader_resource_view_get_parent(const struct wined3d_shader_resource_view *view) 693 { 694 TRACE("view %p.\n", view); 695 696 return view->parent; 697 } 698 699 static void wined3d_shader_resource_view_cs_init(void *object) 700 { 701 struct wined3d_shader_resource_view *view = object; 702 struct wined3d_resource *resource = view->resource; 703 const struct wined3d_format *view_format; 704 const struct wined3d_gl_info *gl_info; 705 const struct wined3d_view_desc *desc; 706 GLenum view_target; 707 708 view_format = view->format; 709 gl_info = &resource->device->adapter->gl_info; 710 desc = &view->desc; 711 712 if (resource->type == WINED3D_RTYPE_BUFFER) 713 { 714 struct wined3d_buffer *buffer = buffer_from_resource(resource); 715 struct wined3d_context *context; 716 717 context = context_acquire(resource->device, NULL, 0); 718 create_buffer_view(&view->gl_view, context, desc, buffer, view_format); 719 context_release(context); 720 } 721 else 722 { 723 struct wined3d_texture *texture = texture_from_resource(resource); 724 725 view_target = get_texture_view_target(gl_info, desc, texture); 726 727 if (resource->format->id == view_format->id && texture->target == view_target 728 && !desc->u.texture.level_idx && desc->u.texture.level_count == texture->level_count 729 && !desc->u.texture.layer_idx && desc->u.texture.layer_count == texture->layer_count 730 && !is_stencil_view_format(view_format)) 731 { 732 TRACE("Creating identity shader resource view.\n"); 733 } 734 else if (texture->swapchain && texture->swapchain->desc.backbuffer_count > 1) 735 { 736 FIXME("Swapchain shader resource views not supported.\n"); 737 } 738 else if (resource->format->typeless_id == view_format->typeless_id 739 && resource->format->gl_view_class == view_format->gl_view_class) 740 { 741 create_texture_view(&view->gl_view, view_target, desc, texture, view_format); 742 } 743 else if (wined3d_format_is_depth_view(resource->format->id, view_format->id)) 744 { 745 create_texture_view(&view->gl_view, view_target, desc, texture, resource->format); 746 } 747 else 748 { 749 FIXME("Shader resource view not supported, resource format %s, view format %s.\n", 750 debug_d3dformat(resource->format->id), debug_d3dformat(view_format->id)); 751 } 752 } 753 #if defined(STAGING_CSMT) 754 755 wined3d_resource_release(resource); 756 #endif /* STAGING_CSMT */ 757 } 758 759 static HRESULT wined3d_shader_resource_view_init(struct wined3d_shader_resource_view *view, 760 const struct wined3d_view_desc *desc, struct wined3d_resource *resource, 761 void *parent, const struct wined3d_parent_ops *parent_ops) 762 { 763 view->refcount = 1; 764 view->parent = parent; 765 view->parent_ops = parent_ops; 766 767 if (!(view->format = validate_resource_view(desc, resource, FALSE, FALSE))) 768 return E_INVALIDARG; 769 view->desc = *desc; 770 771 wined3d_resource_incref(view->resource = resource); 772 773 #if defined(STAGING_CSMT) 774 wined3d_resource_acquire(resource); 775 #endif /* STAGING_CSMT */ 776 wined3d_cs_init_object(resource->device->cs, wined3d_shader_resource_view_cs_init, view); 777 778 return WINED3D_OK; 779 } 780 781 HRESULT CDECL wined3d_shader_resource_view_create(const struct wined3d_view_desc *desc, 782 struct wined3d_resource *resource, void *parent, const struct wined3d_parent_ops *parent_ops, 783 struct wined3d_shader_resource_view **view) 784 { 785 struct wined3d_shader_resource_view *object; 786 HRESULT hr; 787 788 TRACE("desc %p, resource %p, parent %p, parent_ops %p, view %p.\n", 789 desc, resource, parent, parent_ops, view); 790 791 if (!(object = heap_alloc_zero(sizeof(*object)))) 792 return E_OUTOFMEMORY; 793 794 if (FAILED(hr = wined3d_shader_resource_view_init(object, desc, resource, parent, parent_ops))) 795 { 796 heap_free(object); 797 WARN("Failed to initialise view, hr %#x.\n", hr); 798 return hr; 799 } 800 801 TRACE("Created shader resource view %p.\n", object); 802 *view = object; 803 804 return WINED3D_OK; 805 } 806 807 void wined3d_shader_resource_view_bind(struct wined3d_shader_resource_view *view, 808 unsigned int unit, struct wined3d_sampler *sampler, struct wined3d_context *context) 809 { 810 const struct wined3d_gl_info *gl_info = context->gl_info; 811 struct wined3d_texture *texture; 812 813 context_active_texture(context, gl_info, unit); 814 815 if (view->gl_view.name) 816 { 817 context_bind_texture(context, view->gl_view.target, view->gl_view.name); 818 wined3d_sampler_bind(sampler, unit, NULL, context); 819 return; 820 } 821 822 if (view->resource->type == WINED3D_RTYPE_BUFFER) 823 { 824 FIXME("Buffer shader resources not supported.\n"); 825 return; 826 } 827 828 texture = wined3d_texture_from_resource(view->resource); 829 wined3d_texture_bind(texture, context, FALSE); 830 wined3d_sampler_bind(sampler, unit, texture, context); 831 } 832 833 /* Context activation is done by the caller. */ 834 static void shader_resource_view_bind_and_dirtify(struct wined3d_shader_resource_view *view, 835 struct wined3d_context *context) 836 { 837 if (context->active_texture < ARRAY_SIZE(context->rev_tex_unit_map)) 838 { 839 DWORD active_sampler = context->rev_tex_unit_map[context->active_texture]; 840 if (active_sampler != WINED3D_UNMAPPED_STAGE) 841 context_invalidate_state(context, STATE_SAMPLER(active_sampler)); 842 } 843 /* FIXME: Ideally we'd only do this when touching a binding that's used by 844 * a shader. */ 845 context_invalidate_compute_state(context, STATE_COMPUTE_SHADER_RESOURCE_BINDING); 846 context_invalidate_state(context, STATE_GRAPHICS_SHADER_RESOURCE_BINDING); 847 848 context_bind_texture(context, view->gl_view.target, view->gl_view.name); 849 } 850 851 void shader_resource_view_generate_mipmaps(struct wined3d_shader_resource_view *view) 852 { 853 struct wined3d_texture *texture = texture_from_resource(view->resource); 854 unsigned int i, j, layer_count, level_count, base_level, max_level; 855 const struct wined3d_gl_info *gl_info; 856 struct wined3d_context *context; 857 struct gl_texture *gl_tex; 858 DWORD location; 859 BOOL srgb; 860 861 TRACE("view %p.\n", view); 862 863 context = context_acquire(view->resource->device, NULL, 0); 864 gl_info = context->gl_info; 865 layer_count = view->desc.u.texture.layer_count; 866 level_count = view->desc.u.texture.level_count; 867 base_level = view->desc.u.texture.level_idx; 868 max_level = base_level + level_count - 1; 869 870 srgb = !!(texture->flags & WINED3D_TEXTURE_IS_SRGB); 871 location = srgb ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB; 872 for (i = 0; i < layer_count; ++i) 873 wined3d_texture_load_location(texture, i * level_count + base_level, context, location); 874 875 if (view->gl_view.name) 876 { 877 shader_resource_view_bind_and_dirtify(view, context); 878 } 879 else 880 { 881 wined3d_texture_bind_and_dirtify(texture, context, srgb); 882 gl_info->gl_ops.gl.p_glTexParameteri(texture->target, GL_TEXTURE_BASE_LEVEL, base_level); 883 gl_info->gl_ops.gl.p_glTexParameteri(texture->target, GL_TEXTURE_MAX_LEVEL, max_level); 884 } 885 886 if (gl_info->supported[ARB_SAMPLER_OBJECTS]) 887 GL_EXTCALL(glBindSampler(context->active_texture, 0)); 888 gl_tex = wined3d_texture_get_gl_texture(texture, srgb); 889 if (context->d3d_info->wined3d_creation_flags & WINED3D_SRGB_READ_WRITE_CONTROL) 890 { 891 gl_info->gl_ops.gl.p_glTexParameteri(texture->target, GL_TEXTURE_SRGB_DECODE_EXT, 892 GL_SKIP_DECODE_EXT); 893 gl_tex->sampler_desc.srgb_decode = FALSE; 894 } 895 896 gl_info->fbo_ops.glGenerateMipmap(texture->target); 897 checkGLcall("glGenerateMipMap()"); 898 899 for (i = 0; i < layer_count; ++i) 900 { 901 for (j = base_level + 1; j <= max_level; ++j) 902 { 903 wined3d_texture_validate_location(texture, i * level_count + j, location); 904 wined3d_texture_invalidate_location(texture, i * level_count + j, ~location); 905 } 906 } 907 908 if (!view->gl_view.name) 909 { 910 gl_tex->base_level = base_level; 911 gl_info->gl_ops.gl.p_glTexParameteri(texture->target, GL_TEXTURE_MAX_LEVEL, texture->level_count - 1); 912 } 913 914 context_release(context); 915 } 916 917 void CDECL wined3d_shader_resource_view_generate_mipmaps(struct wined3d_shader_resource_view *view) 918 { 919 struct wined3d_texture *texture; 920 921 TRACE("view %p.\n", view); 922 923 if (view->resource->type == WINED3D_RTYPE_BUFFER) 924 { 925 WARN("Called on buffer resource %p.\n", view->resource); 926 return; 927 } 928 929 texture = texture_from_resource(view->resource); 930 if (!(texture->flags & WINED3D_TEXTURE_GENERATE_MIPMAPS)) 931 { 932 WARN("Texture without the WINED3D_TEXTURE_GENERATE_MIPMAPS flag, ignoring.\n"); 933 return; 934 } 935 936 wined3d_cs_emit_generate_mipmaps(view->resource->device->cs, view); 937 } 938 939 ULONG CDECL wined3d_unordered_access_view_incref(struct wined3d_unordered_access_view *view) 940 { 941 ULONG refcount = InterlockedIncrement(&view->refcount); 942 943 TRACE("%p increasing refcount to %u.\n", view, refcount); 944 945 return refcount; 946 } 947 948 static void wined3d_unordered_access_view_destroy_object(void *object) 949 { 950 struct wined3d_unordered_access_view *view = object; 951 952 if (view->gl_view.name || view->counter_bo) 953 { 954 const struct wined3d_gl_info *gl_info; 955 struct wined3d_context *context; 956 957 context = context_acquire(view->resource->device, NULL, 0); 958 gl_info = context->gl_info; 959 if (view->gl_view.name) 960 gl_info->gl_ops.gl.p_glDeleteTextures(1, &view->gl_view.name); 961 if (view->counter_bo) 962 GL_EXTCALL(glDeleteBuffers(1, &view->counter_bo)); 963 checkGLcall("delete resources"); 964 context_release(context); 965 } 966 967 heap_free(view); 968 } 969 970 ULONG CDECL wined3d_unordered_access_view_decref(struct wined3d_unordered_access_view *view) 971 { 972 ULONG refcount = InterlockedDecrement(&view->refcount); 973 974 TRACE("%p decreasing refcount to %u.\n", view, refcount); 975 976 if (!refcount) 977 { 978 struct wined3d_resource *resource = view->resource; 979 struct wined3d_device *device = resource->device; 980 981 /* Call wined3d_object_destroyed() before releasing the resource, 982 * since releasing the resource may end up destroying the parent. */ 983 view->parent_ops->wined3d_object_destroyed(view->parent); 984 wined3d_cs_destroy_object(device->cs, wined3d_unordered_access_view_destroy_object, view); 985 wined3d_resource_decref(resource); 986 } 987 988 return refcount; 989 } 990 991 void * CDECL wined3d_unordered_access_view_get_parent(const struct wined3d_unordered_access_view *view) 992 { 993 TRACE("view %p.\n", view); 994 995 return view->parent; 996 } 997 998 void wined3d_unordered_access_view_invalidate_location(struct wined3d_unordered_access_view *view, 999 DWORD location) 1000 { 1001 wined3d_view_invalidate_location(view->resource, &view->desc, location); 1002 } 1003 1004 void wined3d_unordered_access_view_clear_uint(struct wined3d_unordered_access_view *view, 1005 const struct wined3d_uvec4 *clear_value, struct wined3d_context *context) 1006 { 1007 const struct wined3d_gl_info *gl_info = context->gl_info; 1008 const struct wined3d_format *format; 1009 struct wined3d_resource *resource; 1010 struct wined3d_buffer *buffer; 1011 unsigned int offset, size; 1012 1013 resource = view->resource; 1014 if (resource->type != WINED3D_RTYPE_BUFFER) 1015 { 1016 FIXME("Not implemented for %s resources.\n", debug_d3dresourcetype(resource->type)); 1017 return; 1018 } 1019 1020 if (!gl_info->supported[ARB_CLEAR_BUFFER_OBJECT]) 1021 { 1022 FIXME("OpenGL implementation does not support ARB_clear_buffer_object.\n"); 1023 return; 1024 } 1025 1026 format = view->format; 1027 if (format->id != WINED3DFMT_R32_UINT && format->id != WINED3DFMT_R32_SINT 1028 && format->id != WINED3DFMT_R32G32B32A32_UINT 1029 && format->id != WINED3DFMT_R32G32B32A32_SINT) 1030 { 1031 FIXME("Not implemented for format %s.\n", debug_d3dformat(format->id)); 1032 return; 1033 } 1034 1035 buffer = buffer_from_resource(resource); 1036 wined3d_buffer_load_location(buffer, context, WINED3D_LOCATION_BUFFER); 1037 wined3d_unordered_access_view_invalidate_location(view, ~WINED3D_LOCATION_BUFFER); 1038 1039 get_buffer_view_range(buffer, &view->desc, format, &offset, &size); 1040 context_bind_bo(context, buffer->buffer_type_hint, buffer->buffer_object); 1041 GL_EXTCALL(glClearBufferSubData(buffer->buffer_type_hint, format->glInternal, 1042 offset, size, format->glFormat, format->glType, clear_value)); 1043 checkGLcall("clear unordered access view"); 1044 } 1045 1046 void wined3d_unordered_access_view_set_counter(struct wined3d_unordered_access_view *view, 1047 unsigned int value) 1048 { 1049 const struct wined3d_gl_info *gl_info; 1050 struct wined3d_context *context; 1051 1052 if (!view->counter_bo) 1053 return; 1054 1055 context = context_acquire(view->resource->device, NULL, 0); 1056 gl_info = context->gl_info; 1057 GL_EXTCALL(glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, view->counter_bo)); 1058 GL_EXTCALL(glBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(value), &value)); 1059 checkGLcall("set atomic counter"); 1060 context_release(context); 1061 } 1062 1063 void wined3d_unordered_access_view_copy_counter(struct wined3d_unordered_access_view *view, 1064 struct wined3d_buffer *buffer, unsigned int offset, struct wined3d_context *context) 1065 { 1066 struct wined3d_bo_address dst, src; 1067 DWORD dst_location; 1068 1069 if (!view->counter_bo) 1070 return; 1071 1072 dst_location = wined3d_buffer_get_memory(buffer, &dst, buffer->locations); 1073 dst.addr += offset; 1074 1075 src.buffer_object = view->counter_bo; 1076 src.addr = NULL; 1077 1078 context_copy_bo_address(context, &dst, buffer->buffer_type_hint, 1079 &src, GL_ATOMIC_COUNTER_BUFFER, sizeof(GLuint)); 1080 1081 wined3d_buffer_invalidate_location(buffer, ~dst_location); 1082 } 1083 1084 static void wined3d_unordered_access_view_cs_init(void *object) 1085 { 1086 struct wined3d_unordered_access_view *view = object; 1087 struct wined3d_resource *resource = view->resource; 1088 struct wined3d_view_desc *desc = &view->desc; 1089 const struct wined3d_gl_info *gl_info; 1090 1091 gl_info = &resource->device->adapter->gl_info; 1092 1093 if (resource->type == WINED3D_RTYPE_BUFFER) 1094 { 1095 struct wined3d_buffer *buffer = buffer_from_resource(resource); 1096 struct wined3d_context *context; 1097 1098 context = context_acquire(resource->device, NULL, 0); 1099 gl_info = context->gl_info; 1100 create_buffer_view(&view->gl_view, context, desc, buffer, view->format); 1101 if (desc->flags & (WINED3D_VIEW_BUFFER_COUNTER | WINED3D_VIEW_BUFFER_APPEND)) 1102 { 1103 static const GLuint initial_value = 0; 1104 GL_EXTCALL(glGenBuffers(1, &view->counter_bo)); 1105 GL_EXTCALL(glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, view->counter_bo)); 1106 GL_EXTCALL(glBufferData(GL_ATOMIC_COUNTER_BUFFER, 1107 sizeof(initial_value), &initial_value, GL_STATIC_DRAW)); 1108 checkGLcall("create atomic counter buffer"); 1109 } 1110 context_release(context); 1111 } 1112 else 1113 { 1114 struct wined3d_texture *texture = texture_from_resource(resource); 1115 unsigned int depth_or_layer_count; 1116 1117 if (resource->type == WINED3D_RTYPE_TEXTURE_3D) 1118 depth_or_layer_count = wined3d_texture_get_level_depth(texture, desc->u.texture.level_idx); 1119 else 1120 depth_or_layer_count = texture->layer_count; 1121 1122 if (desc->u.texture.layer_idx || desc->u.texture.layer_count != depth_or_layer_count) 1123 { 1124 create_texture_view(&view->gl_view, get_texture_view_target(gl_info, desc, texture), 1125 desc, texture, view->format); 1126 } 1127 } 1128 #if defined(STAGING_CSMT) 1129 1130 wined3d_resource_release(resource); 1131 #endif /* STAGING_CSMT */ 1132 } 1133 1134 static HRESULT wined3d_unordered_access_view_init(struct wined3d_unordered_access_view *view, 1135 const struct wined3d_view_desc *desc, struct wined3d_resource *resource, 1136 void *parent, const struct wined3d_parent_ops *parent_ops) 1137 { 1138 view->refcount = 1; 1139 view->parent = parent; 1140 view->parent_ops = parent_ops; 1141 1142 if (!(view->format = validate_resource_view(desc, resource, TRUE, FALSE))) 1143 return E_INVALIDARG; 1144 view->desc = *desc; 1145 1146 wined3d_resource_incref(view->resource = resource); 1147 1148 #if defined(STAGING_CSMT) 1149 wined3d_resource_acquire(resource); 1150 #endif /* STAGING_CSMT */ 1151 wined3d_cs_init_object(resource->device->cs, wined3d_unordered_access_view_cs_init, view); 1152 1153 return WINED3D_OK; 1154 } 1155 1156 HRESULT CDECL wined3d_unordered_access_view_create(const struct wined3d_view_desc *desc, 1157 struct wined3d_resource *resource, void *parent, const struct wined3d_parent_ops *parent_ops, 1158 struct wined3d_unordered_access_view **view) 1159 { 1160 struct wined3d_unordered_access_view *object; 1161 HRESULT hr; 1162 1163 TRACE("desc %p, resource %p, parent %p, parent_ops %p, view %p.\n", 1164 desc, resource, parent, parent_ops, view); 1165 1166 if (!(object = heap_alloc_zero(sizeof(*object)))) 1167 return E_OUTOFMEMORY; 1168 1169 if (FAILED(hr = wined3d_unordered_access_view_init(object, desc, resource, parent, parent_ops))) 1170 { 1171 heap_free(object); 1172 WARN("Failed to initialise view, hr %#x.\n", hr); 1173 return hr; 1174 } 1175 1176 TRACE("Created unordered access view %p.\n", object); 1177 *view = object; 1178 1179 return WINED3D_OK; 1180 } 1181