mstask: Implement ITask::DeleteTrigger().
[wine.git] / dlls / wined3d / view.c
blobc98ebfb7ee8e8d74f65686faa4fa24d1c4675b49
1 /*
2 * Copyright 2009, 2011 Henri Verbeet for CodeWeavers
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.
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.
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
20 #include "config.h"
21 #include "wine/port.h"
23 #include "wined3d_private.h"
25 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
27 #define WINED3D_VIEW_CUBE_ARRAY (WINED3D_VIEW_TEXTURE_CUBE | WINED3D_VIEW_TEXTURE_ARRAY)
29 static BOOL is_stencil_view_format(const struct wined3d_format *format)
31 return format->id == WINED3DFMT_X24_TYPELESS_G8_UINT
32 || format->id == WINED3DFMT_X32_TYPELESS_G8X24_UINT;
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)
38 static const struct
40 GLenum texture_target;
41 unsigned int view_flags;
42 GLenum view_target;
43 enum wined3d_gl_extension extension;
45 view_types[] =
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},
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},
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},
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},
68 unsigned int i;
70 for (i = 0; i < ARRAY_SIZE(view_types); ++i)
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;
77 FIXME("Extension %#x not supported.\n", view_types[i].extension);
80 FIXME("Unhandled view flags %#x for texture target %#x.\n", desc->flags, texture->target);
81 return texture->target;
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)
87 const struct wined3d_gl_info *gl_info = &resource->device->adapter->gl_info;
88 const struct wined3d_format *format;
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))
93 if (format->id != WINED3DFMT_R32_TYPELESS)
95 WARN("Invalid format %s for raw buffer view.\n", debug_d3dformat(format->id));
96 return NULL;
99 format = wined3d_get_format(gl_info, WINED3DFMT_R32_UINT, resource->usage);
102 if (wined3d_format_is_typeless(format))
104 WARN("Trying to create view for typeless format %s.\n", debug_d3dformat(format->id));
105 return NULL;
108 if (resource->type == WINED3D_RTYPE_BUFFER)
110 struct wined3d_buffer *buffer = buffer_from_resource(resource);
111 unsigned int buffer_size, element_size;
113 if (buffer->desc.structure_byte_stride)
115 if (desc->format_id != WINED3DFMT_UNKNOWN)
117 WARN("Invalid format %s for structured buffer view.\n", debug_d3dformat(desc->format_id));
118 return NULL;
121 format = wined3d_get_format(gl_info, WINED3DFMT_R32_UINT, resource->usage);
122 element_size = buffer->desc.structure_byte_stride;
124 else
126 element_size = format->byte_count;
129 if (!element_size)
130 return NULL;
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;
137 else
139 struct wined3d_texture *texture = texture_from_resource(resource);
140 unsigned int depth_or_layer_count;
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)))
145 WARN("Trying to create incompatible view for non typeless format %s.\n",
146 debug_d3dformat(format->id));
147 return NULL;
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;
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;
165 return format;
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)
172 const struct wined3d_gl_info *gl_info;
173 unsigned int layer_idx, layer_count;
174 struct wined3d_context *context;
175 GLuint texture_name;
177 view->target = view_target;
179 context = context_acquire(texture->resource.device, NULL, 0);
180 gl_info = context->gl_info;
182 if (!gl_info->supported[ARB_TEXTURE_VIEW])
184 context_release(context);
185 FIXME("OpenGL implementation does not support texture views.\n");
186 return;
189 wined3d_texture_prepare_texture(texture, context, FALSE);
190 texture_name = wined3d_texture_get_texture_name(texture, context, FALSE);
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))
196 FIXME("Depth slice (%u-%u) not supported.\n", layer_idx, layer_count);
197 layer_idx = 0;
198 layer_count = 1;
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");
207 if (is_stencil_view_format(view_format))
209 static const GLint swizzle[] = {GL_ZERO, GL_RED, GL_ZERO, GL_ZERO};
211 if (!gl_info->supported[ARB_STENCIL_TEXTURING])
213 context_release(context);
214 FIXME("OpenGL implementation does not support stencil texturing.\n");
215 return;
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");
223 context_invalidate_compute_state(context, STATE_COMPUTE_SHADER_RESOURCE_BINDING);
224 context_invalidate_state(context, STATE_GRAPHICS_SHADER_RESOURCE_BINDING);
227 context_release(context);
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)
234 const struct wined3d_gl_info *gl_info = context->gl_info;
236 if (!gl_info->supported[ARB_TEXTURE_BUFFER_OBJECT])
238 FIXME("OpenGL implementation does not support buffer textures.\n");
239 return;
242 if ((offset & (gl_info->limits.texture_buffer_offset_alignment - 1)))
244 FIXME("Buffer offset %u is not %u byte aligned.\n",
245 offset, gl_info->limits.texture_buffer_offset_alignment);
246 return;
249 wined3d_buffer_load_location(buffer, context, WINED3D_LOCATION_BUFFER);
251 view->target = GL_TEXTURE_BUFFER;
252 gl_info->gl_ops.gl.p_glGenTextures(1, &view->name);
254 context_bind_texture(context, GL_TEXTURE_BUFFER, view->name);
255 if (gl_info->supported[ARB_TEXTURE_BUFFER_RANGE])
257 GL_EXTCALL(glTexBufferRange(GL_TEXTURE_BUFFER, view_format->glInternal,
258 buffer->buffer_object, offset, size));
260 else
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));
266 checkGLcall("Create buffer texture");
268 context_invalidate_compute_state(context, STATE_COMPUTE_SHADER_RESOURCE_BINDING);
269 context_invalidate_state(context, STATE_GRAPHICS_SHADER_RESOURCE_BINDING);
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)
276 if (desc->format_id == WINED3DFMT_UNKNOWN)
278 *offset = desc->u.buffer.start_idx * buffer->desc.structure_byte_stride;
279 *size = desc->u.buffer.count * buffer->desc.structure_byte_stride;
281 else
283 *offset = desc->u.buffer.start_idx * view_format->byte_count;
284 *size = desc->u.buffer.count * view_format->byte_count;
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)
292 unsigned int offset, size;
294 get_buffer_view_range(buffer, desc, view_format, &offset, &size);
295 create_buffer_texture(view, context, buffer, view_format, offset, size);
298 static void wined3d_view_invalidate_location(struct wined3d_resource *resource,
299 const struct wined3d_view_desc *desc, DWORD location)
301 unsigned int i, sub_resource_idx, layer_count;
302 struct wined3d_texture *texture;
304 if (resource->type == WINED3D_RTYPE_BUFFER)
306 wined3d_buffer_invalidate_location(buffer_from_resource(resource), location);
307 return;
310 texture = texture_from_resource(resource);
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);
318 ULONG CDECL wined3d_rendertarget_view_incref(struct wined3d_rendertarget_view *view)
320 ULONG refcount = InterlockedIncrement(&view->refcount);
322 TRACE("%p increasing refcount to %u.\n", view, refcount);
324 return refcount;
327 static void wined3d_rendertarget_view_destroy_object(void *object)
329 struct wined3d_rendertarget_view *view = object;
330 struct wined3d_device *device = view->resource->device;
332 if (view->gl_view.name)
334 const struct wined3d_gl_info *gl_info;
335 struct wined3d_context *context;
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);
345 heap_free(view);
348 ULONG CDECL wined3d_rendertarget_view_decref(struct wined3d_rendertarget_view *view)
350 ULONG refcount = InterlockedDecrement(&view->refcount);
352 TRACE("%p decreasing refcount to %u.\n", view, refcount);
354 if (!refcount)
356 struct wined3d_resource *resource = view->resource;
357 struct wined3d_device *device = resource->device;
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);
366 return refcount;
369 void * CDECL wined3d_rendertarget_view_get_parent(const struct wined3d_rendertarget_view *view)
371 TRACE("view %p.\n", view);
373 return view->parent;
376 void * CDECL wined3d_rendertarget_view_get_sub_resource_parent(const struct wined3d_rendertarget_view *view)
378 struct wined3d_texture *texture;
380 TRACE("view %p.\n", view);
382 if (view->resource->type == WINED3D_RTYPE_BUFFER)
383 return wined3d_buffer_get_parent(buffer_from_resource(view->resource));
385 texture = texture_from_resource(view->resource);
387 return texture->sub_resources[view->sub_resource_idx].parent;
390 void CDECL wined3d_rendertarget_view_set_parent(struct wined3d_rendertarget_view *view, void *parent)
392 TRACE("view %p, parent %p.\n", view, parent);
394 view->parent = parent;
397 struct wined3d_resource * CDECL wined3d_rendertarget_view_get_resource(const struct wined3d_rendertarget_view *view)
399 TRACE("view %p.\n", view);
401 return view->resource;
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)
407 const struct wined3d_texture *texture;
409 if (view->resource->type != WINED3D_RTYPE_TEXTURE_2D)
411 *width = view->width;
412 *height = view->height;
413 return;
416 texture = texture_from_resource(view->resource);
417 if (texture->swapchain)
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;
425 else if (wined3d_settings.offscreen_rendering_mode == ORM_BACKBUFFER)
427 const struct wined3d_swapchain *swapchain = context->swapchain;
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;
435 else
437 unsigned int level_idx = view->sub_resource_idx % texture->level_count;
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);
446 void wined3d_rendertarget_view_prepare_location(struct wined3d_rendertarget_view *view,
447 struct wined3d_context *context, DWORD location)
449 struct wined3d_resource *resource = view->resource;
450 unsigned int i, sub_resource_idx, layer_count;
451 struct wined3d_texture *texture;
453 if (resource->type == WINED3D_RTYPE_BUFFER)
455 FIXME("Not implemented for resources %s.\n", debug_d3dresourcetype(resource->type));
456 return;
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);
466 void wined3d_rendertarget_view_load_location(struct wined3d_rendertarget_view *view,
467 struct wined3d_context *context, DWORD location)
469 struct wined3d_resource *resource = view->resource;
470 unsigned int i, sub_resource_idx, layer_count;
471 struct wined3d_texture *texture;
473 if (resource->type == WINED3D_RTYPE_BUFFER)
475 wined3d_buffer_load_location(buffer_from_resource(resource), context, location);
476 return;
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);
486 void wined3d_rendertarget_view_validate_location(struct wined3d_rendertarget_view *view, DWORD location)
488 struct wined3d_resource *resource = view->resource;
489 unsigned int i, sub_resource_idx, layer_count;
490 struct wined3d_texture *texture;
492 if (resource->type == WINED3D_RTYPE_BUFFER)
494 FIXME("Not implemented for resources %s.\n", debug_d3dresourcetype(resource->type));
495 return;
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);
505 void wined3d_rendertarget_view_invalidate_location(struct wined3d_rendertarget_view *view, DWORD location)
507 wined3d_view_invalidate_location(view->resource, &view->desc, location);
510 static void wined3d_render_target_view_cs_init(void *object)
512 struct wined3d_rendertarget_view *view = object;
513 struct wined3d_resource *resource = view->resource;
514 const struct wined3d_view_desc *desc = &view->desc;
516 if (resource->type == WINED3D_RTYPE_BUFFER)
518 FIXME("Not implemented for resources %s.\n", debug_d3dresourcetype(resource->type));
520 else
522 struct wined3d_texture *texture = texture_from_resource(resource);
523 unsigned int depth_or_layer_count;
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;
530 if (resource->format->id != view->format->id
531 || (view->layer_count != 1 && view->layer_count != depth_or_layer_count))
533 if (resource->format->gl_view_class != view->format->gl_view_class)
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;
539 if (texture->swapchain && texture->swapchain->desc.backbuffer_count > 1)
541 FIXME("Swapchain views not supported.\n");
542 return;
545 create_texture_view(&view->gl_view, texture->target, desc, texture, view->format);
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)
554 BOOL allow_srgb_toggle = FALSE;
556 view->refcount = 1;
557 view->parent = parent;
558 view->parent_ops = parent_ops;
560 if (resource->type != WINED3D_RTYPE_BUFFER)
562 struct wined3d_texture *texture = texture_from_resource(resource);
564 if (texture->swapchain)
565 allow_srgb_toggle = TRUE;
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;
572 if (resource->type == WINED3D_RTYPE_BUFFER)
574 view->sub_resource_idx = 0;
575 view->layer_count = 1;
576 view->width = desc->u.buffer.count;
577 view->height = 1;
579 else
581 struct wined3d_texture *texture = texture_from_resource(resource);
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);
591 wined3d_resource_incref(view->resource = resource);
593 wined3d_cs_init_object(resource->device->cs, wined3d_render_target_view_cs_init, view);
595 return WINED3D_OK;
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)
602 struct wined3d_rendertarget_view *object;
603 HRESULT hr;
605 TRACE("desc %p, resource %p, parent %p, parent_ops %p, view %p.\n",
606 desc, resource, parent, parent_ops, view);
608 if (!(object = heap_alloc_zero(sizeof(*object))))
609 return E_OUTOFMEMORY;
611 if (FAILED(hr = wined3d_rendertarget_view_init(object, desc, resource, parent, parent_ops)))
613 heap_free(object);
614 WARN("Failed to initialise view, hr %#x.\n", hr);
615 return hr;
618 TRACE("Created render target view %p.\n", object);
619 *view = object;
621 return hr;
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)
628 struct wined3d_view_desc desc;
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);
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;
640 return wined3d_rendertarget_view_create(&desc, &texture->resource, parent, parent_ops, view);
643 ULONG CDECL wined3d_shader_resource_view_incref(struct wined3d_shader_resource_view *view)
645 ULONG refcount = InterlockedIncrement(&view->refcount);
647 TRACE("%p increasing refcount to %u.\n", view, refcount);
649 return refcount;
652 static void wined3d_shader_resource_view_destroy_object(void *object)
654 struct wined3d_shader_resource_view *view = object;
656 if (view->gl_view.name)
658 const struct wined3d_gl_info *gl_info;
659 struct wined3d_context *context;
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);
668 heap_free(view);
671 ULONG CDECL wined3d_shader_resource_view_decref(struct wined3d_shader_resource_view *view)
673 ULONG refcount = InterlockedDecrement(&view->refcount);
675 TRACE("%p decreasing refcount to %u.\n", view, refcount);
677 if (!refcount)
679 struct wined3d_resource *resource = view->resource;
680 struct wined3d_device *device = resource->device;
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);
689 return refcount;
692 void * CDECL wined3d_shader_resource_view_get_parent(const struct wined3d_shader_resource_view *view)
694 TRACE("view %p.\n", view);
696 return view->parent;
699 static void wined3d_shader_resource_view_cs_init(void *object)
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;
708 view_format = view->format;
709 gl_info = &resource->device->adapter->gl_info;
710 desc = &view->desc;
712 if (resource->type == WINED3D_RTYPE_BUFFER)
714 struct wined3d_buffer *buffer = buffer_from_resource(resource);
715 struct wined3d_context *context;
717 context = context_acquire(resource->device, NULL, 0);
718 create_buffer_view(&view->gl_view, context, desc, buffer, view_format);
719 context_release(context);
721 else
723 struct wined3d_texture *texture = texture_from_resource(resource);
725 view_target = get_texture_view_target(gl_info, desc, texture);
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))
732 TRACE("Creating identity shader resource view.\n");
734 else if (texture->swapchain && texture->swapchain->desc.backbuffer_count > 1)
736 FIXME("Swapchain shader resource views not supported.\n");
738 else if (resource->format->typeless_id == view_format->typeless_id
739 && resource->format->gl_view_class == view_format->gl_view_class)
741 create_texture_view(&view->gl_view, view_target, desc, texture, view_format);
743 else if (wined3d_format_is_depth_view(resource->format->id, view_format->id))
745 create_texture_view(&view->gl_view, view_target, desc, texture, resource->format);
747 else
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));
755 static HRESULT wined3d_shader_resource_view_init(struct wined3d_shader_resource_view *view,
756 const struct wined3d_view_desc *desc, struct wined3d_resource *resource,
757 void *parent, const struct wined3d_parent_ops *parent_ops)
759 view->refcount = 1;
760 view->parent = parent;
761 view->parent_ops = parent_ops;
763 if (!(view->format = validate_resource_view(desc, resource, FALSE, FALSE)))
764 return E_INVALIDARG;
765 view->desc = *desc;
767 wined3d_resource_incref(view->resource = resource);
769 wined3d_cs_init_object(resource->device->cs, wined3d_shader_resource_view_cs_init, view);
771 return WINED3D_OK;
774 HRESULT CDECL wined3d_shader_resource_view_create(const struct wined3d_view_desc *desc,
775 struct wined3d_resource *resource, void *parent, const struct wined3d_parent_ops *parent_ops,
776 struct wined3d_shader_resource_view **view)
778 struct wined3d_shader_resource_view *object;
779 HRESULT hr;
781 TRACE("desc %p, resource %p, parent %p, parent_ops %p, view %p.\n",
782 desc, resource, parent, parent_ops, view);
784 if (!(object = heap_alloc_zero(sizeof(*object))))
785 return E_OUTOFMEMORY;
787 if (FAILED(hr = wined3d_shader_resource_view_init(object, desc, resource, parent, parent_ops)))
789 heap_free(object);
790 WARN("Failed to initialise view, hr %#x.\n", hr);
791 return hr;
794 TRACE("Created shader resource view %p.\n", object);
795 *view = object;
797 return WINED3D_OK;
800 void wined3d_shader_resource_view_bind(struct wined3d_shader_resource_view *view,
801 unsigned int unit, struct wined3d_sampler *sampler, struct wined3d_context *context)
803 const struct wined3d_gl_info *gl_info = context->gl_info;
804 struct wined3d_texture *texture;
806 context_active_texture(context, gl_info, unit);
808 if (view->gl_view.name)
810 context_bind_texture(context, view->gl_view.target, view->gl_view.name);
811 wined3d_sampler_bind(sampler, unit, NULL, context);
812 return;
815 if (view->resource->type == WINED3D_RTYPE_BUFFER)
817 FIXME("Buffer shader resources not supported.\n");
818 return;
821 texture = wined3d_texture_from_resource(view->resource);
822 wined3d_texture_bind(texture, context, FALSE);
823 wined3d_sampler_bind(sampler, unit, texture, context);
826 /* Context activation is done by the caller. */
827 static void shader_resource_view_bind_and_dirtify(struct wined3d_shader_resource_view *view,
828 struct wined3d_context *context)
830 if (context->active_texture < ARRAY_SIZE(context->rev_tex_unit_map))
832 DWORD active_sampler = context->rev_tex_unit_map[context->active_texture];
833 if (active_sampler != WINED3D_UNMAPPED_STAGE)
834 context_invalidate_state(context, STATE_SAMPLER(active_sampler));
836 /* FIXME: Ideally we'd only do this when touching a binding that's used by
837 * a shader. */
838 context_invalidate_compute_state(context, STATE_COMPUTE_SHADER_RESOURCE_BINDING);
839 context_invalidate_state(context, STATE_GRAPHICS_SHADER_RESOURCE_BINDING);
841 context_bind_texture(context, view->gl_view.target, view->gl_view.name);
844 void shader_resource_view_generate_mipmaps(struct wined3d_shader_resource_view *view)
846 struct wined3d_texture *texture = texture_from_resource(view->resource);
847 unsigned int i, j, layer_count, level_count, base_level, max_level;
848 const struct wined3d_gl_info *gl_info;
849 struct wined3d_context *context;
850 struct gl_texture *gl_tex;
851 DWORD location;
852 BOOL srgb;
854 TRACE("view %p.\n", view);
856 context = context_acquire(view->resource->device, NULL, 0);
857 gl_info = context->gl_info;
858 layer_count = view->desc.u.texture.layer_count;
859 level_count = view->desc.u.texture.level_count;
860 base_level = view->desc.u.texture.level_idx;
861 max_level = base_level + level_count - 1;
863 srgb = !!(texture->flags & WINED3D_TEXTURE_IS_SRGB);
864 location = srgb ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB;
865 for (i = 0; i < layer_count; ++i)
866 wined3d_texture_load_location(texture, i * level_count + base_level, context, location);
868 if (view->gl_view.name)
870 shader_resource_view_bind_and_dirtify(view, context);
872 else
874 wined3d_texture_bind_and_dirtify(texture, context, srgb);
875 gl_info->gl_ops.gl.p_glTexParameteri(texture->target, GL_TEXTURE_BASE_LEVEL, base_level);
876 gl_info->gl_ops.gl.p_glTexParameteri(texture->target, GL_TEXTURE_MAX_LEVEL, max_level);
879 if (gl_info->supported[ARB_SAMPLER_OBJECTS])
880 GL_EXTCALL(glBindSampler(context->active_texture, 0));
881 gl_tex = wined3d_texture_get_gl_texture(texture, srgb);
882 if (context->d3d_info->wined3d_creation_flags & WINED3D_SRGB_READ_WRITE_CONTROL)
884 gl_info->gl_ops.gl.p_glTexParameteri(texture->target, GL_TEXTURE_SRGB_DECODE_EXT,
885 GL_SKIP_DECODE_EXT);
886 gl_tex->sampler_desc.srgb_decode = FALSE;
889 gl_info->fbo_ops.glGenerateMipmap(texture->target);
890 checkGLcall("glGenerateMipMap()");
892 for (i = 0; i < layer_count; ++i)
894 for (j = base_level + 1; j <= max_level; ++j)
896 wined3d_texture_validate_location(texture, i * level_count + j, location);
897 wined3d_texture_invalidate_location(texture, i * level_count + j, ~location);
901 if (!view->gl_view.name)
903 gl_tex->base_level = base_level;
904 gl_info->gl_ops.gl.p_glTexParameteri(texture->target, GL_TEXTURE_MAX_LEVEL, texture->level_count - 1);
907 context_release(context);
910 void CDECL wined3d_shader_resource_view_generate_mipmaps(struct wined3d_shader_resource_view *view)
912 struct wined3d_texture *texture;
914 TRACE("view %p.\n", view);
916 if (view->resource->type == WINED3D_RTYPE_BUFFER)
918 WARN("Called on buffer resource %p.\n", view->resource);
919 return;
922 texture = texture_from_resource(view->resource);
923 if (!(texture->flags & WINED3D_TEXTURE_GENERATE_MIPMAPS))
925 WARN("Texture without the WINED3D_TEXTURE_GENERATE_MIPMAPS flag, ignoring.\n");
926 return;
929 wined3d_cs_emit_generate_mipmaps(view->resource->device->cs, view);
932 ULONG CDECL wined3d_unordered_access_view_incref(struct wined3d_unordered_access_view *view)
934 ULONG refcount = InterlockedIncrement(&view->refcount);
936 TRACE("%p increasing refcount to %u.\n", view, refcount);
938 return refcount;
941 static void wined3d_unordered_access_view_destroy_object(void *object)
943 struct wined3d_unordered_access_view *view = object;
945 if (view->gl_view.name || view->counter_bo)
947 const struct wined3d_gl_info *gl_info;
948 struct wined3d_context *context;
950 context = context_acquire(view->resource->device, NULL, 0);
951 gl_info = context->gl_info;
952 if (view->gl_view.name)
953 gl_info->gl_ops.gl.p_glDeleteTextures(1, &view->gl_view.name);
954 if (view->counter_bo)
955 GL_EXTCALL(glDeleteBuffers(1, &view->counter_bo));
956 checkGLcall("delete resources");
957 context_release(context);
960 heap_free(view);
963 ULONG CDECL wined3d_unordered_access_view_decref(struct wined3d_unordered_access_view *view)
965 ULONG refcount = InterlockedDecrement(&view->refcount);
967 TRACE("%p decreasing refcount to %u.\n", view, refcount);
969 if (!refcount)
971 struct wined3d_resource *resource = view->resource;
972 struct wined3d_device *device = resource->device;
974 /* Call wined3d_object_destroyed() before releasing the resource,
975 * since releasing the resource may end up destroying the parent. */
976 view->parent_ops->wined3d_object_destroyed(view->parent);
977 wined3d_cs_destroy_object(device->cs, wined3d_unordered_access_view_destroy_object, view);
978 wined3d_resource_decref(resource);
981 return refcount;
984 void * CDECL wined3d_unordered_access_view_get_parent(const struct wined3d_unordered_access_view *view)
986 TRACE("view %p.\n", view);
988 return view->parent;
991 void wined3d_unordered_access_view_invalidate_location(struct wined3d_unordered_access_view *view,
992 DWORD location)
994 wined3d_view_invalidate_location(view->resource, &view->desc, location);
997 void wined3d_unordered_access_view_clear_uint(struct wined3d_unordered_access_view *view,
998 const struct wined3d_uvec4 *clear_value, struct wined3d_context *context)
1000 const struct wined3d_gl_info *gl_info = context->gl_info;
1001 const struct wined3d_format *format;
1002 struct wined3d_resource *resource;
1003 struct wined3d_buffer *buffer;
1004 unsigned int offset, size;
1006 resource = view->resource;
1007 if (resource->type != WINED3D_RTYPE_BUFFER)
1009 FIXME("Not implemented for %s resources.\n", debug_d3dresourcetype(resource->type));
1010 return;
1013 if (!gl_info->supported[ARB_CLEAR_BUFFER_OBJECT])
1015 FIXME("OpenGL implementation does not support ARB_clear_buffer_object.\n");
1016 return;
1019 format = view->format;
1020 if (format->id != WINED3DFMT_R32_UINT && format->id != WINED3DFMT_R32_SINT
1021 && format->id != WINED3DFMT_R32G32B32A32_UINT
1022 && format->id != WINED3DFMT_R32G32B32A32_SINT)
1024 FIXME("Not implemented for format %s.\n", debug_d3dformat(format->id));
1025 return;
1028 buffer = buffer_from_resource(resource);
1029 wined3d_buffer_load_location(buffer, context, WINED3D_LOCATION_BUFFER);
1030 wined3d_unordered_access_view_invalidate_location(view, ~WINED3D_LOCATION_BUFFER);
1032 get_buffer_view_range(buffer, &view->desc, format, &offset, &size);
1033 context_bind_bo(context, buffer->buffer_type_hint, buffer->buffer_object);
1034 GL_EXTCALL(glClearBufferSubData(buffer->buffer_type_hint, format->glInternal,
1035 offset, size, format->glFormat, format->glType, clear_value));
1036 checkGLcall("clear unordered access view");
1039 void wined3d_unordered_access_view_set_counter(struct wined3d_unordered_access_view *view,
1040 unsigned int value)
1042 const struct wined3d_gl_info *gl_info;
1043 struct wined3d_context *context;
1045 if (!view->counter_bo)
1046 return;
1048 context = context_acquire(view->resource->device, NULL, 0);
1049 gl_info = context->gl_info;
1050 GL_EXTCALL(glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, view->counter_bo));
1051 GL_EXTCALL(glBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(value), &value));
1052 checkGLcall("set atomic counter");
1053 context_release(context);
1056 void wined3d_unordered_access_view_copy_counter(struct wined3d_unordered_access_view *view,
1057 struct wined3d_buffer *buffer, unsigned int offset, struct wined3d_context *context)
1059 struct wined3d_bo_address dst, src;
1060 DWORD dst_location;
1062 if (!view->counter_bo)
1063 return;
1065 dst_location = wined3d_buffer_get_memory(buffer, &dst, buffer->locations);
1066 dst.addr += offset;
1068 src.buffer_object = view->counter_bo;
1069 src.addr = NULL;
1071 context_copy_bo_address(context, &dst, buffer->buffer_type_hint,
1072 &src, GL_ATOMIC_COUNTER_BUFFER, sizeof(GLuint));
1074 wined3d_buffer_invalidate_location(buffer, ~dst_location);
1077 static void wined3d_unordered_access_view_cs_init(void *object)
1079 struct wined3d_unordered_access_view *view = object;
1080 struct wined3d_resource *resource = view->resource;
1081 struct wined3d_view_desc *desc = &view->desc;
1082 const struct wined3d_gl_info *gl_info;
1084 gl_info = &resource->device->adapter->gl_info;
1086 if (resource->type == WINED3D_RTYPE_BUFFER)
1088 struct wined3d_buffer *buffer = buffer_from_resource(resource);
1089 struct wined3d_context *context;
1091 context = context_acquire(resource->device, NULL, 0);
1092 gl_info = context->gl_info;
1093 create_buffer_view(&view->gl_view, context, desc, buffer, view->format);
1094 if (desc->flags & (WINED3D_VIEW_BUFFER_COUNTER | WINED3D_VIEW_BUFFER_APPEND))
1096 static const GLuint initial_value = 0;
1097 GL_EXTCALL(glGenBuffers(1, &view->counter_bo));
1098 GL_EXTCALL(glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, view->counter_bo));
1099 GL_EXTCALL(glBufferData(GL_ATOMIC_COUNTER_BUFFER,
1100 sizeof(initial_value), &initial_value, GL_STATIC_DRAW));
1101 checkGLcall("create atomic counter buffer");
1103 context_release(context);
1105 else
1107 struct wined3d_texture *texture = texture_from_resource(resource);
1108 unsigned int depth_or_layer_count;
1110 if (resource->type == WINED3D_RTYPE_TEXTURE_3D)
1111 depth_or_layer_count = wined3d_texture_get_level_depth(texture, desc->u.texture.level_idx);
1112 else
1113 depth_or_layer_count = texture->layer_count;
1115 if (desc->u.texture.layer_idx || desc->u.texture.layer_count != depth_or_layer_count)
1117 create_texture_view(&view->gl_view, get_texture_view_target(gl_info, desc, texture),
1118 desc, texture, view->format);
1123 static HRESULT wined3d_unordered_access_view_init(struct wined3d_unordered_access_view *view,
1124 const struct wined3d_view_desc *desc, struct wined3d_resource *resource,
1125 void *parent, const struct wined3d_parent_ops *parent_ops)
1127 view->refcount = 1;
1128 view->parent = parent;
1129 view->parent_ops = parent_ops;
1131 if (!(view->format = validate_resource_view(desc, resource, TRUE, FALSE)))
1132 return E_INVALIDARG;
1133 view->desc = *desc;
1135 wined3d_resource_incref(view->resource = resource);
1137 wined3d_cs_init_object(resource->device->cs, wined3d_unordered_access_view_cs_init, view);
1139 return WINED3D_OK;
1142 HRESULT CDECL wined3d_unordered_access_view_create(const struct wined3d_view_desc *desc,
1143 struct wined3d_resource *resource, void *parent, const struct wined3d_parent_ops *parent_ops,
1144 struct wined3d_unordered_access_view **view)
1146 struct wined3d_unordered_access_view *object;
1147 HRESULT hr;
1149 TRACE("desc %p, resource %p, parent %p, parent_ops %p, view %p.\n",
1150 desc, resource, parent, parent_ops, view);
1152 if (!(object = heap_alloc_zero(sizeof(*object))))
1153 return E_OUTOFMEMORY;
1155 if (FAILED(hr = wined3d_unordered_access_view_init(object, desc, resource, parent, parent_ops)))
1157 heap_free(object);
1158 WARN("Failed to initialise view, hr %#x.\n", hr);
1159 return hr;
1162 TRACE("Created unordered access view %p.\n", object);
1163 *view = object;
1165 return WINED3D_OK;