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_2D, 0, GL_TEXTURE_2D}, 52 {GL_TEXTURE_2D, WINED3D_VIEW_TEXTURE_ARRAY, GL_TEXTURE_2D_ARRAY}, 53 {GL_TEXTURE_2D_ARRAY, 0, GL_TEXTURE_2D}, 54 {GL_TEXTURE_2D_ARRAY, WINED3D_VIEW_TEXTURE_ARRAY, GL_TEXTURE_2D_ARRAY}, 55 {GL_TEXTURE_2D_ARRAY, WINED3D_VIEW_TEXTURE_CUBE, GL_TEXTURE_CUBE_MAP}, 56 {GL_TEXTURE_2D_ARRAY, WINED3D_VIEW_CUBE_ARRAY, GL_TEXTURE_CUBE_MAP_ARRAY, ARB_TEXTURE_CUBE_MAP_ARRAY}, 57 58 {GL_TEXTURE_2D_MULTISAMPLE, 0, GL_TEXTURE_2D_MULTISAMPLE}, 59 {GL_TEXTURE_2D_MULTISAMPLE, WINED3D_VIEW_TEXTURE_ARRAY, GL_TEXTURE_2D_MULTISAMPLE_ARRAY}, 60 {GL_TEXTURE_2D_MULTISAMPLE_ARRAY, 0, GL_TEXTURE_2D_MULTISAMPLE}, 61 {GL_TEXTURE_2D_MULTISAMPLE_ARRAY, WINED3D_VIEW_TEXTURE_ARRAY, GL_TEXTURE_2D_MULTISAMPLE_ARRAY}, 62 63 {GL_TEXTURE_1D, 0, GL_TEXTURE_1D}, 64 {GL_TEXTURE_1D, WINED3D_VIEW_TEXTURE_ARRAY, GL_TEXTURE_1D_ARRAY}, 65 {GL_TEXTURE_1D_ARRAY, 0, GL_TEXTURE_1D}, 66 {GL_TEXTURE_1D_ARRAY, WINED3D_VIEW_TEXTURE_ARRAY, GL_TEXTURE_1D_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 754 wined3d_resource_release(resource); 755 } 756 757 static HRESULT wined3d_shader_resource_view_init(struct wined3d_shader_resource_view *view, 758 const struct wined3d_view_desc *desc, struct wined3d_resource *resource, 759 void *parent, const struct wined3d_parent_ops *parent_ops) 760 { 761 view->refcount = 1; 762 view->parent = parent; 763 view->parent_ops = parent_ops; 764 765 if (!(view->format = validate_resource_view(desc, resource, FALSE, FALSE))) 766 return E_INVALIDARG; 767 view->desc = *desc; 768 769 wined3d_resource_incref(view->resource = resource); 770 771 wined3d_resource_acquire(resource); 772 wined3d_cs_init_object(resource->device->cs, wined3d_shader_resource_view_cs_init, view); 773 774 return WINED3D_OK; 775 } 776 777 HRESULT CDECL wined3d_shader_resource_view_create(const struct wined3d_view_desc *desc, 778 struct wined3d_resource *resource, void *parent, const struct wined3d_parent_ops *parent_ops, 779 struct wined3d_shader_resource_view **view) 780 { 781 struct wined3d_shader_resource_view *object; 782 HRESULT hr; 783 784 TRACE("desc %p, resource %p, parent %p, parent_ops %p, view %p.\n", 785 desc, resource, parent, parent_ops, view); 786 787 if (!(object = heap_alloc_zero(sizeof(*object)))) 788 return E_OUTOFMEMORY; 789 790 if (FAILED(hr = wined3d_shader_resource_view_init(object, desc, resource, parent, parent_ops))) 791 { 792 heap_free(object); 793 WARN("Failed to initialise view, hr %#x.\n", hr); 794 return hr; 795 } 796 797 TRACE("Created shader resource view %p.\n", object); 798 *view = object; 799 800 return WINED3D_OK; 801 } 802 803 void wined3d_shader_resource_view_bind(struct wined3d_shader_resource_view *view, 804 unsigned int unit, struct wined3d_sampler *sampler, struct wined3d_context *context) 805 { 806 const struct wined3d_gl_info *gl_info = context->gl_info; 807 struct wined3d_texture *texture; 808 809 context_active_texture(context, gl_info, unit); 810 811 if (view->gl_view.name) 812 { 813 context_bind_texture(context, view->gl_view.target, view->gl_view.name); 814 wined3d_sampler_bind(sampler, unit, NULL, context); 815 return; 816 } 817 818 if (view->resource->type == WINED3D_RTYPE_BUFFER) 819 { 820 FIXME("Buffer shader resources not supported.\n"); 821 return; 822 } 823 824 texture = wined3d_texture_from_resource(view->resource); 825 wined3d_texture_bind(texture, context, FALSE); 826 wined3d_sampler_bind(sampler, unit, texture, context); 827 } 828 829 /* Context activation is done by the caller. */ 830 static void shader_resource_view_bind_and_dirtify(struct wined3d_shader_resource_view *view, 831 struct wined3d_context *context) 832 { 833 if (context->active_texture < ARRAY_SIZE(context->rev_tex_unit_map)) 834 { 835 DWORD active_sampler = context->rev_tex_unit_map[context->active_texture]; 836 if (active_sampler != WINED3D_UNMAPPED_STAGE) 837 context_invalidate_state(context, STATE_SAMPLER(active_sampler)); 838 } 839 /* FIXME: Ideally we'd only do this when touching a binding that's used by 840 * a shader. */ 841 context_invalidate_compute_state(context, STATE_COMPUTE_SHADER_RESOURCE_BINDING); 842 context_invalidate_state(context, STATE_GRAPHICS_SHADER_RESOURCE_BINDING); 843 844 context_bind_texture(context, view->gl_view.target, view->gl_view.name); 845 } 846 847 void shader_resource_view_generate_mipmaps(struct wined3d_shader_resource_view *view) 848 { 849 struct wined3d_texture *texture = texture_from_resource(view->resource); 850 unsigned int i, j, layer_count, level_count, base_level, max_level; 851 const struct wined3d_gl_info *gl_info; 852 struct wined3d_context *context; 853 struct gl_texture *gl_tex; 854 DWORD location; 855 BOOL srgb; 856 857 TRACE("view %p.\n", view); 858 859 context = context_acquire(view->resource->device, NULL, 0); 860 gl_info = context->gl_info; 861 layer_count = view->desc.u.texture.layer_count; 862 level_count = view->desc.u.texture.level_count; 863 base_level = view->desc.u.texture.level_idx; 864 max_level = base_level + level_count - 1; 865 866 srgb = !!(texture->flags & WINED3D_TEXTURE_IS_SRGB); 867 location = srgb ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB; 868 for (i = 0; i < layer_count; ++i) 869 wined3d_texture_load_location(texture, i * level_count + base_level, context, location); 870 871 if (view->gl_view.name) 872 { 873 shader_resource_view_bind_and_dirtify(view, context); 874 } 875 else 876 { 877 wined3d_texture_bind_and_dirtify(texture, context, srgb); 878 gl_info->gl_ops.gl.p_glTexParameteri(texture->target, GL_TEXTURE_BASE_LEVEL, base_level); 879 gl_info->gl_ops.gl.p_glTexParameteri(texture->target, GL_TEXTURE_MAX_LEVEL, max_level); 880 } 881 882 if (gl_info->supported[ARB_SAMPLER_OBJECTS]) 883 GL_EXTCALL(glBindSampler(context->active_texture, 0)); 884 gl_tex = wined3d_texture_get_gl_texture(texture, srgb); 885 if (context->d3d_info->wined3d_creation_flags & WINED3D_SRGB_READ_WRITE_CONTROL) 886 { 887 gl_info->gl_ops.gl.p_glTexParameteri(texture->target, GL_TEXTURE_SRGB_DECODE_EXT, 888 GL_SKIP_DECODE_EXT); 889 gl_tex->sampler_desc.srgb_decode = FALSE; 890 } 891 892 gl_info->fbo_ops.glGenerateMipmap(texture->target); 893 checkGLcall("glGenerateMipMap()"); 894 895 for (i = 0; i < layer_count; ++i) 896 { 897 for (j = base_level + 1; j <= max_level; ++j) 898 { 899 wined3d_texture_validate_location(texture, i * level_count + j, location); 900 wined3d_texture_invalidate_location(texture, i * level_count + j, ~location); 901 } 902 } 903 904 if (!view->gl_view.name) 905 { 906 gl_tex->base_level = base_level; 907 gl_info->gl_ops.gl.p_glTexParameteri(texture->target, GL_TEXTURE_MAX_LEVEL, texture->level_count - 1); 908 } 909 910 context_release(context); 911 } 912 913 void CDECL wined3d_shader_resource_view_generate_mipmaps(struct wined3d_shader_resource_view *view) 914 { 915 struct wined3d_texture *texture; 916 917 TRACE("view %p.\n", view); 918 919 if (view->resource->type == WINED3D_RTYPE_BUFFER) 920 { 921 WARN("Called on buffer resource %p.\n", view->resource); 922 return; 923 } 924 925 texture = texture_from_resource(view->resource); 926 if (!(texture->flags & WINED3D_TEXTURE_GENERATE_MIPMAPS)) 927 { 928 WARN("Texture without the WINED3D_TEXTURE_GENERATE_MIPMAPS flag, ignoring.\n"); 929 return; 930 } 931 932 wined3d_cs_emit_generate_mipmaps(view->resource->device->cs, view); 933 } 934 935 ULONG CDECL wined3d_unordered_access_view_incref(struct wined3d_unordered_access_view *view) 936 { 937 ULONG refcount = InterlockedIncrement(&view->refcount); 938 939 TRACE("%p increasing refcount to %u.\n", view, refcount); 940 941 return refcount; 942 } 943 944 static void wined3d_unordered_access_view_destroy_object(void *object) 945 { 946 struct wined3d_unordered_access_view *view = object; 947 948 if (view->gl_view.name || view->counter_bo) 949 { 950 const struct wined3d_gl_info *gl_info; 951 struct wined3d_context *context; 952 953 context = context_acquire(view->resource->device, NULL, 0); 954 gl_info = context->gl_info; 955 if (view->gl_view.name) 956 gl_info->gl_ops.gl.p_glDeleteTextures(1, &view->gl_view.name); 957 if (view->counter_bo) 958 GL_EXTCALL(glDeleteBuffers(1, &view->counter_bo)); 959 checkGLcall("delete resources"); 960 context_release(context); 961 } 962 963 heap_free(view); 964 } 965 966 ULONG CDECL wined3d_unordered_access_view_decref(struct wined3d_unordered_access_view *view) 967 { 968 ULONG refcount = InterlockedDecrement(&view->refcount); 969 970 TRACE("%p decreasing refcount to %u.\n", view, refcount); 971 972 if (!refcount) 973 { 974 struct wined3d_resource *resource = view->resource; 975 struct wined3d_device *device = resource->device; 976 977 /* Call wined3d_object_destroyed() before releasing the resource, 978 * since releasing the resource may end up destroying the parent. */ 979 view->parent_ops->wined3d_object_destroyed(view->parent); 980 wined3d_cs_destroy_object(device->cs, wined3d_unordered_access_view_destroy_object, view); 981 wined3d_resource_decref(resource); 982 } 983 984 return refcount; 985 } 986 987 void * CDECL wined3d_unordered_access_view_get_parent(const struct wined3d_unordered_access_view *view) 988 { 989 TRACE("view %p.\n", view); 990 991 return view->parent; 992 } 993 994 void wined3d_unordered_access_view_invalidate_location(struct wined3d_unordered_access_view *view, 995 DWORD location) 996 { 997 wined3d_view_invalidate_location(view->resource, &view->desc, location); 998 } 999 1000 void wined3d_unordered_access_view_clear_uint(struct wined3d_unordered_access_view *view, 1001 const struct wined3d_uvec4 *clear_value, struct wined3d_context *context) 1002 { 1003 const struct wined3d_gl_info *gl_info = context->gl_info; 1004 const struct wined3d_format *format; 1005 struct wined3d_resource *resource; 1006 struct wined3d_buffer *buffer; 1007 unsigned int offset, size; 1008 1009 resource = view->resource; 1010 if (resource->type != WINED3D_RTYPE_BUFFER) 1011 { 1012 FIXME("Not implemented for %s resources.\n", debug_d3dresourcetype(resource->type)); 1013 return; 1014 } 1015 1016 if (!gl_info->supported[ARB_CLEAR_BUFFER_OBJECT]) 1017 { 1018 FIXME("OpenGL implementation does not support ARB_clear_buffer_object.\n"); 1019 return; 1020 } 1021 1022 format = view->format; 1023 if (format->id != WINED3DFMT_R32_UINT && format->id != WINED3DFMT_R32_SINT 1024 && format->id != WINED3DFMT_R32G32B32A32_UINT 1025 && format->id != WINED3DFMT_R32G32B32A32_SINT) 1026 { 1027 FIXME("Not implemented for format %s.\n", debug_d3dformat(format->id)); 1028 return; 1029 } 1030 1031 buffer = buffer_from_resource(resource); 1032 wined3d_buffer_load_location(buffer, context, WINED3D_LOCATION_BUFFER); 1033 wined3d_unordered_access_view_invalidate_location(view, ~WINED3D_LOCATION_BUFFER); 1034 1035 get_buffer_view_range(buffer, &view->desc, format, &offset, &size); 1036 context_bind_bo(context, buffer->buffer_type_hint, buffer->buffer_object); 1037 GL_EXTCALL(glClearBufferSubData(buffer->buffer_type_hint, format->glInternal, 1038 offset, size, format->glFormat, format->glType, clear_value)); 1039 checkGLcall("clear unordered access view"); 1040 } 1041 1042 void wined3d_unordered_access_view_set_counter(struct wined3d_unordered_access_view *view, 1043 unsigned int value) 1044 { 1045 const struct wined3d_gl_info *gl_info; 1046 struct wined3d_context *context; 1047 1048 if (!view->counter_bo) 1049 return; 1050 1051 context = context_acquire(view->resource->device, NULL, 0); 1052 gl_info = context->gl_info; 1053 GL_EXTCALL(glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, view->counter_bo)); 1054 GL_EXTCALL(glBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(value), &value)); 1055 checkGLcall("set atomic counter"); 1056 context_release(context); 1057 } 1058 1059 void wined3d_unordered_access_view_copy_counter(struct wined3d_unordered_access_view *view, 1060 struct wined3d_buffer *buffer, unsigned int offset, struct wined3d_context *context) 1061 { 1062 struct wined3d_bo_address dst, src; 1063 DWORD dst_location; 1064 1065 if (!view->counter_bo) 1066 return; 1067 1068 dst_location = wined3d_buffer_get_memory(buffer, &dst, buffer->locations); 1069 dst.addr += offset; 1070 1071 src.buffer_object = view->counter_bo; 1072 src.addr = NULL; 1073 1074 context_copy_bo_address(context, &dst, buffer->buffer_type_hint, 1075 &src, GL_ATOMIC_COUNTER_BUFFER, sizeof(GLuint)); 1076 1077 wined3d_buffer_invalidate_location(buffer, ~dst_location); 1078 } 1079 1080 static void wined3d_unordered_access_view_cs_init(void *object) 1081 { 1082 struct wined3d_unordered_access_view *view = object; 1083 struct wined3d_resource *resource = view->resource; 1084 struct wined3d_view_desc *desc = &view->desc; 1085 const struct wined3d_gl_info *gl_info; 1086 1087 gl_info = &resource->device->adapter->gl_info; 1088 1089 if (resource->type == WINED3D_RTYPE_BUFFER) 1090 { 1091 struct wined3d_buffer *buffer = buffer_from_resource(resource); 1092 struct wined3d_context *context; 1093 1094 context = context_acquire(resource->device, NULL, 0); 1095 gl_info = context->gl_info; 1096 create_buffer_view(&view->gl_view, context, desc, buffer, view->format); 1097 if (desc->flags & (WINED3D_VIEW_BUFFER_COUNTER | WINED3D_VIEW_BUFFER_APPEND)) 1098 { 1099 static const GLuint initial_value = 0; 1100 GL_EXTCALL(glGenBuffers(1, &view->counter_bo)); 1101 GL_EXTCALL(glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, view->counter_bo)); 1102 GL_EXTCALL(glBufferData(GL_ATOMIC_COUNTER_BUFFER, 1103 sizeof(initial_value), &initial_value, GL_STATIC_DRAW)); 1104 checkGLcall("create atomic counter buffer"); 1105 } 1106 context_release(context); 1107 } 1108 else 1109 { 1110 struct wined3d_texture *texture = texture_from_resource(resource); 1111 unsigned int depth_or_layer_count; 1112 1113 if (resource->type == WINED3D_RTYPE_TEXTURE_3D) 1114 depth_or_layer_count = wined3d_texture_get_level_depth(texture, desc->u.texture.level_idx); 1115 else 1116 depth_or_layer_count = texture->layer_count; 1117 1118 if (desc->u.texture.layer_idx || desc->u.texture.layer_count != depth_or_layer_count) 1119 { 1120 create_texture_view(&view->gl_view, get_texture_view_target(gl_info, desc, texture), 1121 desc, texture, view->format); 1122 } 1123 } 1124 1125 wined3d_resource_release(resource); 1126 } 1127 1128 static HRESULT wined3d_unordered_access_view_init(struct wined3d_unordered_access_view *view, 1129 const struct wined3d_view_desc *desc, struct wined3d_resource *resource, 1130 void *parent, const struct wined3d_parent_ops *parent_ops) 1131 { 1132 view->refcount = 1; 1133 view->parent = parent; 1134 view->parent_ops = parent_ops; 1135 1136 if (!(view->format = validate_resource_view(desc, resource, TRUE, FALSE))) 1137 return E_INVALIDARG; 1138 view->desc = *desc; 1139 1140 wined3d_resource_incref(view->resource = resource); 1141 1142 wined3d_resource_acquire(resource); 1143 wined3d_cs_init_object(resource->device->cs, wined3d_unordered_access_view_cs_init, view); 1144 1145 return WINED3D_OK; 1146 } 1147 1148 HRESULT CDECL wined3d_unordered_access_view_create(const struct wined3d_view_desc *desc, 1149 struct wined3d_resource *resource, void *parent, const struct wined3d_parent_ops *parent_ops, 1150 struct wined3d_unordered_access_view **view) 1151 { 1152 struct wined3d_unordered_access_view *object; 1153 HRESULT hr; 1154 1155 TRACE("desc %p, resource %p, parent %p, parent_ops %p, view %p.\n", 1156 desc, resource, parent, parent_ops, view); 1157 1158 if (!(object = heap_alloc_zero(sizeof(*object)))) 1159 return E_OUTOFMEMORY; 1160 1161 if (FAILED(hr = wined3d_unordered_access_view_init(object, desc, resource, parent, parent_ops))) 1162 { 1163 heap_free(object); 1164 WARN("Failed to initialise view, hr %#x.\n", hr); 1165 return hr; 1166 } 1167 1168 TRACE("Created unordered access view %p.\n", object); 1169 *view = object; 1170 1171 return WINED3D_OK; 1172 } 1173