gphoto2.ds: Set supported groups.
[wine.git] / dlls / wined3d / view.c
blob62f087b23a43d4545b2f83390d3e75f38a6deddb
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_2D, 0, GL_TEXTURE_2D},
50 {GL_TEXTURE_2D, WINED3D_VIEW_TEXTURE_ARRAY, GL_TEXTURE_2D_ARRAY},
51 {GL_TEXTURE_2D_ARRAY, 0, GL_TEXTURE_2D},
52 {GL_TEXTURE_2D_ARRAY, WINED3D_VIEW_TEXTURE_ARRAY, GL_TEXTURE_2D_ARRAY},
53 {GL_TEXTURE_2D_ARRAY, WINED3D_VIEW_TEXTURE_CUBE, GL_TEXTURE_CUBE_MAP},
54 {GL_TEXTURE_2D_ARRAY, WINED3D_VIEW_CUBE_ARRAY, GL_TEXTURE_CUBE_MAP_ARRAY, ARB_TEXTURE_CUBE_MAP_ARRAY},
55 {GL_TEXTURE_3D, 0, GL_TEXTURE_3D},
57 unsigned int i;
59 for (i = 0; i < ARRAY_SIZE(view_types); ++i)
61 if (view_types[i].texture_target != texture->target || view_types[i].view_flags != desc->flags)
62 continue;
63 if (gl_info->supported[view_types[i].extension])
64 return view_types[i].view_target;
66 FIXME("Extension %#x not supported.\n", view_types[i].extension);
69 FIXME("Unhandled view flags %#x for texture target %#x.\n", desc->flags, texture->target);
70 return texture->target;
73 static const struct wined3d_format *validate_resource_view(const struct wined3d_view_desc *desc,
74 struct wined3d_resource *resource, BOOL mip_slice)
76 const struct wined3d_gl_info *gl_info = &resource->device->adapter->gl_info;
77 const struct wined3d_format *format;
79 format = wined3d_get_format(gl_info, desc->format_id, resource->usage);
80 if (resource->type == WINED3D_RTYPE_BUFFER && (desc->flags & WINED3D_VIEW_BUFFER_RAW))
82 if (format->id != WINED3DFMT_R32_TYPELESS)
84 WARN("Invalid format %s for raw buffer view.\n", debug_d3dformat(format->id));
85 return NULL;
88 format = wined3d_get_format(gl_info, WINED3DFMT_R32_UINT, resource->usage);
91 if (wined3d_format_is_typeless(format))
93 WARN("Trying to create view for typeless format %s.\n", debug_d3dformat(format->id));
94 return NULL;
97 if (resource->type == WINED3D_RTYPE_BUFFER)
99 struct wined3d_buffer *buffer = buffer_from_resource(resource);
100 unsigned int buffer_size, element_size;
102 if (buffer->desc.structure_byte_stride)
104 if (desc->format_id != WINED3DFMT_UNKNOWN)
106 WARN("Invalid format %s for structured buffer view.\n", debug_d3dformat(desc->format_id));
107 return NULL;
110 format = wined3d_get_format(gl_info, WINED3DFMT_R32_UINT, resource->usage);
111 element_size = buffer->desc.structure_byte_stride;
113 else
115 element_size = format->byte_count;
118 if (!element_size)
119 return NULL;
121 buffer_size = buffer->resource.size / element_size;
122 if (desc->u.buffer.start_idx >= buffer_size
123 || desc->u.buffer.count > buffer_size - desc->u.buffer.start_idx)
124 return NULL;
126 else
128 struct wined3d_texture *texture = texture_from_resource(resource);
129 unsigned int depth_or_layer_count;
131 if (mip_slice && resource->type == WINED3D_RTYPE_TEXTURE_3D)
132 depth_or_layer_count = wined3d_texture_get_level_depth(texture, desc->u.texture.level_idx);
133 else
134 depth_or_layer_count = texture->layer_count;
136 if (!desc->u.texture.level_count
137 || (mip_slice && desc->u.texture.level_count != 1)
138 || desc->u.texture.level_idx >= texture->level_count
139 || desc->u.texture.level_count > texture->level_count - desc->u.texture.level_idx
140 || !desc->u.texture.layer_count
141 || desc->u.texture.layer_idx >= depth_or_layer_count
142 || desc->u.texture.layer_count > depth_or_layer_count - desc->u.texture.layer_idx)
143 return NULL;
146 return format;
149 static void create_texture_view(struct wined3d_gl_view *view, GLenum view_target,
150 const struct wined3d_view_desc *desc, struct wined3d_texture *texture,
151 const struct wined3d_format *view_format)
153 const struct wined3d_gl_info *gl_info;
154 unsigned int layer_idx, layer_count;
155 struct wined3d_context *context;
156 GLuint texture_name;
158 view->target = view_target;
160 context = context_acquire(texture->resource.device, NULL, 0);
161 gl_info = context->gl_info;
163 if (!gl_info->supported[ARB_TEXTURE_VIEW])
165 context_release(context);
166 FIXME("OpenGL implementation does not support texture views.\n");
167 return;
170 wined3d_texture_prepare_texture(texture, context, FALSE);
171 texture_name = wined3d_texture_get_texture_name(texture, context, FALSE);
173 layer_idx = desc->u.texture.layer_idx;
174 layer_count = desc->u.texture.layer_count;
175 if (view_target == GL_TEXTURE_3D && (layer_idx || layer_count != 1))
177 FIXME("Depth slice (%u-%u) not supported.\n", layer_idx, layer_count);
178 layer_idx = 0;
179 layer_count = 1;
182 gl_info->gl_ops.gl.p_glGenTextures(1, &view->name);
183 GL_EXTCALL(glTextureView(view->name, view->target, texture_name, view_format->glInternal,
184 desc->u.texture.level_idx, desc->u.texture.level_count,
185 layer_idx, layer_count));
186 checkGLcall("Create texture view");
188 if (is_stencil_view_format(view_format))
190 static const GLint swizzle[] = {GL_ZERO, GL_RED, GL_ZERO, GL_ZERO};
192 if (!gl_info->supported[ARB_STENCIL_TEXTURING])
194 context_release(context);
195 FIXME("OpenGL implementation does not support stencil texturing.\n");
196 return;
199 context_bind_texture(context, view->target, view->name);
200 gl_info->gl_ops.gl.p_glTexParameteriv(view->target, GL_TEXTURE_SWIZZLE_RGBA, swizzle);
201 gl_info->gl_ops.gl.p_glTexParameteri(view->target, GL_DEPTH_STENCIL_TEXTURE_MODE, GL_STENCIL_INDEX);
202 checkGLcall("Initialize stencil view");
204 context_invalidate_compute_state(context, STATE_COMPUTE_SHADER_RESOURCE_BINDING);
205 context_invalidate_state(context, STATE_GRAPHICS_SHADER_RESOURCE_BINDING);
208 context_release(context);
211 static void create_buffer_texture(struct wined3d_gl_view *view, struct wined3d_context *context,
212 struct wined3d_buffer *buffer, const struct wined3d_format *view_format,
213 unsigned int offset, unsigned int size)
215 const struct wined3d_gl_info *gl_info = context->gl_info;
217 if (!gl_info->supported[ARB_TEXTURE_BUFFER_OBJECT])
219 FIXME("OpenGL implementation does not support buffer textures.\n");
220 return;
223 if ((offset & (gl_info->limits.texture_buffer_offset_alignment - 1)))
225 FIXME("Buffer offset %u is not %u byte aligned.\n",
226 offset, gl_info->limits.texture_buffer_offset_alignment);
227 return;
230 wined3d_buffer_load_location(buffer, context, WINED3D_LOCATION_BUFFER);
232 view->target = GL_TEXTURE_BUFFER;
233 gl_info->gl_ops.gl.p_glGenTextures(1, &view->name);
235 context_bind_texture(context, GL_TEXTURE_BUFFER, view->name);
236 if (gl_info->supported[ARB_TEXTURE_BUFFER_RANGE])
238 GL_EXTCALL(glTexBufferRange(GL_TEXTURE_BUFFER, view_format->glInternal,
239 buffer->buffer_object, offset, size));
241 else
243 if (offset || size != buffer->resource.size)
244 FIXME("OpenGL implementation does not support ARB_texture_buffer_range.\n");
245 GL_EXTCALL(glTexBuffer(GL_TEXTURE_BUFFER, view_format->glInternal, buffer->buffer_object));
247 checkGLcall("Create buffer texture");
249 context_invalidate_compute_state(context, STATE_COMPUTE_SHADER_RESOURCE_BINDING);
250 context_invalidate_state(context, STATE_GRAPHICS_SHADER_RESOURCE_BINDING);
253 static void get_buffer_view_range(const struct wined3d_buffer *buffer,
254 const struct wined3d_view_desc *desc, const struct wined3d_format *view_format,
255 unsigned int *offset, unsigned int *size)
257 if (desc->format_id == WINED3DFMT_UNKNOWN)
259 *offset = desc->u.buffer.start_idx * buffer->desc.structure_byte_stride;
260 *size = desc->u.buffer.count * buffer->desc.structure_byte_stride;
262 else
264 *offset = desc->u.buffer.start_idx * view_format->byte_count;
265 *size = desc->u.buffer.count * view_format->byte_count;
269 static void create_buffer_view(struct wined3d_gl_view *view, struct wined3d_context *context,
270 const struct wined3d_view_desc *desc, struct wined3d_buffer *buffer,
271 const struct wined3d_format *view_format)
273 unsigned int offset, size;
275 get_buffer_view_range(buffer, desc, view_format, &offset, &size);
276 create_buffer_texture(view, context, buffer, view_format, offset, size);
279 static void wined3d_view_invalidate_location(struct wined3d_resource *resource,
280 const struct wined3d_view_desc *desc, DWORD location)
282 unsigned int i, sub_resource_idx, layer_count;
283 struct wined3d_texture *texture;
285 if (resource->type == WINED3D_RTYPE_BUFFER)
287 wined3d_buffer_invalidate_location(buffer_from_resource(resource), location);
288 return;
291 texture = texture_from_resource(resource);
293 sub_resource_idx = desc->u.texture.layer_idx * texture->level_count + desc->u.texture.level_idx;
294 layer_count = resource->type != WINED3D_RTYPE_TEXTURE_3D ? desc->u.texture.layer_count : 1;
295 for (i = 0; i < layer_count; ++i, sub_resource_idx += texture->level_count)
296 wined3d_texture_invalidate_location(texture, sub_resource_idx, location);
299 ULONG CDECL wined3d_rendertarget_view_incref(struct wined3d_rendertarget_view *view)
301 ULONG refcount = InterlockedIncrement(&view->refcount);
303 TRACE("%p increasing refcount to %u.\n", view, refcount);
305 return refcount;
308 static void wined3d_rendertarget_view_destroy_object(void *object)
310 struct wined3d_rendertarget_view *view = object;
311 struct wined3d_device *device = view->resource->device;
313 if (view->gl_view.name)
315 const struct wined3d_gl_info *gl_info;
316 struct wined3d_context *context;
318 context = context_acquire(device, NULL, 0);
319 gl_info = context->gl_info;
320 context_gl_resource_released(device, view->gl_view.name, FALSE);
321 gl_info->gl_ops.gl.p_glDeleteTextures(1, &view->gl_view.name);
322 checkGLcall("glDeleteTextures");
323 context_release(context);
326 HeapFree(GetProcessHeap(), 0, view);
329 ULONG CDECL wined3d_rendertarget_view_decref(struct wined3d_rendertarget_view *view)
331 ULONG refcount = InterlockedDecrement(&view->refcount);
333 TRACE("%p decreasing refcount to %u.\n", view, refcount);
335 if (!refcount)
337 struct wined3d_resource *resource = view->resource;
338 struct wined3d_device *device = resource->device;
340 /* Call wined3d_object_destroyed() before releasing the resource,
341 * since releasing the resource may end up destroying the parent. */
342 view->parent_ops->wined3d_object_destroyed(view->parent);
343 wined3d_cs_destroy_object(device->cs, wined3d_rendertarget_view_destroy_object, view);
344 wined3d_resource_decref(resource);
347 return refcount;
350 void * CDECL wined3d_rendertarget_view_get_parent(const struct wined3d_rendertarget_view *view)
352 TRACE("view %p.\n", view);
354 return view->parent;
357 void * CDECL wined3d_rendertarget_view_get_sub_resource_parent(const struct wined3d_rendertarget_view *view)
359 struct wined3d_texture *texture;
361 TRACE("view %p.\n", view);
363 if (view->resource->type == WINED3D_RTYPE_BUFFER)
364 return wined3d_buffer_get_parent(buffer_from_resource(view->resource));
366 texture = texture_from_resource(view->resource);
368 return texture->sub_resources[view->sub_resource_idx].parent;
371 void CDECL wined3d_rendertarget_view_set_parent(struct wined3d_rendertarget_view *view, void *parent)
373 TRACE("view %p, parent %p.\n", view, parent);
375 view->parent = parent;
378 struct wined3d_resource * CDECL wined3d_rendertarget_view_get_resource(const struct wined3d_rendertarget_view *view)
380 TRACE("view %p.\n", view);
382 return view->resource;
385 void wined3d_rendertarget_view_get_drawable_size(const struct wined3d_rendertarget_view *view,
386 const struct wined3d_context *context, unsigned int *width, unsigned int *height)
388 const struct wined3d_texture *texture;
390 if (view->resource->type != WINED3D_RTYPE_TEXTURE_2D)
392 *width = view->width;
393 *height = view->height;
394 return;
397 texture = texture_from_resource(view->resource);
398 if (texture->swapchain)
400 /* The drawable size of an onscreen drawable is the surface size.
401 * (Actually: The window size, but the surface is created in window
402 * size.) */
403 *width = texture->resource.width;
404 *height = texture->resource.height;
406 else if (wined3d_settings.offscreen_rendering_mode == ORM_BACKBUFFER)
408 const struct wined3d_swapchain *swapchain = context->swapchain;
410 /* The drawable size of a backbuffer / aux buffer offscreen target is
411 * the size of the current context's drawable, which is the size of
412 * the back buffer of the swapchain the active context belongs to. */
413 *width = swapchain->desc.backbuffer_width;
414 *height = swapchain->desc.backbuffer_height;
416 else
418 unsigned int level_idx = view->sub_resource_idx % texture->level_count;
420 /* The drawable size of an FBO target is the OpenGL texture size,
421 * which is the power of two size. */
422 *width = wined3d_texture_get_level_pow2_width(texture, level_idx);
423 *height = wined3d_texture_get_level_pow2_height(texture, level_idx);
427 void wined3d_rendertarget_view_prepare_location(struct wined3d_rendertarget_view *view,
428 struct wined3d_context *context, DWORD location)
430 struct wined3d_resource *resource = view->resource;
431 unsigned int i, sub_resource_idx, layer_count;
432 struct wined3d_texture *texture;
434 if (resource->type == WINED3D_RTYPE_BUFFER)
436 FIXME("Not implemented for resources %s.\n", debug_d3dresourcetype(resource->type));
437 return;
440 texture = texture_from_resource(resource);
441 sub_resource_idx = view->sub_resource_idx;
442 layer_count = resource->type != WINED3D_RTYPE_TEXTURE_3D ? view->layer_count : 1;
443 for (i = 0; i < layer_count; ++i, sub_resource_idx += texture->level_count)
444 wined3d_texture_prepare_location(texture, sub_resource_idx, context, location);
447 void wined3d_rendertarget_view_load_location(struct wined3d_rendertarget_view *view,
448 struct wined3d_context *context, DWORD location)
450 struct wined3d_resource *resource = view->resource;
451 unsigned int i, sub_resource_idx, layer_count;
452 struct wined3d_texture *texture;
454 if (resource->type == WINED3D_RTYPE_BUFFER)
456 wined3d_buffer_load_location(buffer_from_resource(resource), context, location);
457 return;
460 texture = texture_from_resource(resource);
461 sub_resource_idx = view->sub_resource_idx;
462 layer_count = resource->type != WINED3D_RTYPE_TEXTURE_3D ? view->layer_count : 1;
463 for (i = 0; i < layer_count; ++i, sub_resource_idx += texture->level_count)
464 wined3d_texture_load_location(texture, sub_resource_idx, context, location);
467 void wined3d_rendertarget_view_validate_location(struct wined3d_rendertarget_view *view, 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 FIXME("Not implemented for resources %s.\n", debug_d3dresourcetype(resource->type));
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_validate_location(texture, sub_resource_idx, location);
486 void wined3d_rendertarget_view_invalidate_location(struct wined3d_rendertarget_view *view, DWORD location)
488 wined3d_view_invalidate_location(view->resource, &view->desc, location);
491 static void wined3d_render_target_view_cs_init(void *object)
493 struct wined3d_rendertarget_view *view = object;
494 struct wined3d_resource *resource = view->resource;
495 const struct wined3d_view_desc *desc = &view->desc;
497 if (resource->type == WINED3D_RTYPE_BUFFER)
499 FIXME("Not implemented for resources %s.\n", debug_d3dresourcetype(resource->type));
501 else
503 struct wined3d_texture *texture = texture_from_resource(resource);
504 unsigned int depth_or_layer_count;
506 if (resource->type == WINED3D_RTYPE_TEXTURE_3D)
507 depth_or_layer_count = wined3d_texture_get_level_depth(texture, desc->u.texture.level_idx);
508 else
509 depth_or_layer_count = texture->layer_count;
511 if (resource->format->id != view->format->id
512 || (view->layer_count != 1 && view->layer_count != depth_or_layer_count))
514 if (resource->format->gl_view_class != view->format->gl_view_class)
516 FIXME("Render target view not supported, resource format %s, view format %s.\n",
517 debug_d3dformat(resource->format->id), debug_d3dformat(view->format->id));
518 return;
520 if (texture->swapchain && texture->swapchain->desc.backbuffer_count > 1)
522 FIXME("Swapchain views not supported.\n");
523 return;
526 create_texture_view(&view->gl_view, texture->target, desc, texture, view->format);
531 static HRESULT wined3d_rendertarget_view_init(struct wined3d_rendertarget_view *view,
532 const struct wined3d_view_desc *desc, struct wined3d_resource *resource,
533 void *parent, const struct wined3d_parent_ops *parent_ops)
535 view->refcount = 1;
536 view->parent = parent;
537 view->parent_ops = parent_ops;
539 if (!(view->format = validate_resource_view(desc, resource, TRUE)))
540 return E_INVALIDARG;
541 view->format_flags = view->format->flags[resource->gl_type];
542 view->desc = *desc;
544 if (resource->type == WINED3D_RTYPE_BUFFER)
546 view->sub_resource_idx = 0;
547 view->layer_count = 1;
548 view->width = desc->u.buffer.count;
549 view->height = 1;
551 else
553 struct wined3d_texture *texture = texture_from_resource(resource);
555 view->sub_resource_idx = desc->u.texture.level_idx;
556 if (resource->type != WINED3D_RTYPE_TEXTURE_3D)
557 view->sub_resource_idx += desc->u.texture.layer_idx * texture->level_count;
558 view->layer_count = desc->u.texture.layer_count;
559 view->width = wined3d_texture_get_level_width(texture, desc->u.texture.level_idx);
560 view->height = wined3d_texture_get_level_height(texture, desc->u.texture.level_idx);
563 wined3d_resource_incref(view->resource = resource);
565 wined3d_cs_init_object(resource->device->cs, wined3d_render_target_view_cs_init, view);
567 return WINED3D_OK;
570 HRESULT CDECL wined3d_rendertarget_view_create(const struct wined3d_view_desc *desc,
571 struct wined3d_resource *resource, void *parent, const struct wined3d_parent_ops *parent_ops,
572 struct wined3d_rendertarget_view **view)
574 struct wined3d_rendertarget_view *object;
575 HRESULT hr;
577 TRACE("desc %p, resource %p, parent %p, parent_ops %p, view %p.\n",
578 desc, resource, parent, parent_ops, view);
580 if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
581 return E_OUTOFMEMORY;
583 if (FAILED(hr = wined3d_rendertarget_view_init(object, desc, resource, parent, parent_ops)))
585 HeapFree(GetProcessHeap(), 0, object);
586 WARN("Failed to initialise view, hr %#x.\n", hr);
587 return hr;
590 TRACE("Created render target view %p.\n", object);
591 *view = object;
593 return hr;
596 HRESULT CDECL wined3d_rendertarget_view_create_from_sub_resource(struct wined3d_texture *texture,
597 unsigned int sub_resource_idx, void *parent, const struct wined3d_parent_ops *parent_ops,
598 struct wined3d_rendertarget_view **view)
600 struct wined3d_view_desc desc;
602 TRACE("texture %p, sub_resource_idx %u, parent %p, parent_ops %p, view %p.\n",
603 texture, sub_resource_idx, parent, parent_ops, view);
605 desc.format_id = texture->resource.format->id;
606 desc.flags = 0;
607 desc.u.texture.level_idx = sub_resource_idx % texture->level_count;
608 desc.u.texture.level_count = 1;
609 desc.u.texture.layer_idx = sub_resource_idx / texture->level_count;
610 desc.u.texture.layer_count = 1;
612 return wined3d_rendertarget_view_create(&desc, &texture->resource, parent, parent_ops, view);
615 ULONG CDECL wined3d_shader_resource_view_incref(struct wined3d_shader_resource_view *view)
617 ULONG refcount = InterlockedIncrement(&view->refcount);
619 TRACE("%p increasing refcount to %u.\n", view, refcount);
621 return refcount;
624 static void wined3d_shader_resource_view_destroy_object(void *object)
626 struct wined3d_shader_resource_view *view = object;
628 if (view->gl_view.name)
630 const struct wined3d_gl_info *gl_info;
631 struct wined3d_context *context;
633 context = context_acquire(view->resource->device, NULL, 0);
634 gl_info = context->gl_info;
635 gl_info->gl_ops.gl.p_glDeleteTextures(1, &view->gl_view.name);
636 checkGLcall("glDeleteTextures");
637 context_release(context);
640 HeapFree(GetProcessHeap(), 0, view);
643 ULONG CDECL wined3d_shader_resource_view_decref(struct wined3d_shader_resource_view *view)
645 ULONG refcount = InterlockedDecrement(&view->refcount);
647 TRACE("%p decreasing refcount to %u.\n", view, refcount);
649 if (!refcount)
651 struct wined3d_resource *resource = view->resource;
652 struct wined3d_device *device = resource->device;
654 /* Call wined3d_object_destroyed() before releasing the resource,
655 * since releasing the resource may end up destroying the parent. */
656 view->parent_ops->wined3d_object_destroyed(view->parent);
657 wined3d_cs_destroy_object(device->cs, wined3d_shader_resource_view_destroy_object, view);
658 wined3d_resource_decref(resource);
661 return refcount;
664 void * CDECL wined3d_shader_resource_view_get_parent(const struct wined3d_shader_resource_view *view)
666 TRACE("view %p.\n", view);
668 return view->parent;
671 static void wined3d_shader_resource_view_cs_init(void *object)
673 struct wined3d_shader_resource_view *view = object;
674 struct wined3d_resource *resource = view->resource;
675 const struct wined3d_format *view_format;
676 const struct wined3d_gl_info *gl_info;
677 const struct wined3d_view_desc *desc;
678 GLenum view_target;
680 view_format = view->format;
681 gl_info = &resource->device->adapter->gl_info;
682 desc = &view->desc;
684 if (resource->type == WINED3D_RTYPE_BUFFER)
686 struct wined3d_buffer *buffer = buffer_from_resource(resource);
687 struct wined3d_context *context;
689 context = context_acquire(resource->device, NULL, 0);
690 create_buffer_view(&view->gl_view, context, desc, buffer, view_format);
691 context_release(context);
693 else
695 struct wined3d_texture *texture = texture_from_resource(resource);
697 view_target = get_texture_view_target(gl_info, desc, texture);
699 if (resource->format->id == view_format->id && texture->target == view_target
700 && !desc->u.texture.level_idx && desc->u.texture.level_count == texture->level_count
701 && !desc->u.texture.layer_idx && desc->u.texture.layer_count == texture->layer_count
702 && !is_stencil_view_format(view_format))
704 TRACE("Creating identity shader resource view.\n");
706 else if (texture->swapchain && texture->swapchain->desc.backbuffer_count > 1)
708 FIXME("Swapchain shader resource views not supported.\n");
710 else if (resource->format->typeless_id == view_format->typeless_id
711 && resource->format->gl_view_class == view_format->gl_view_class)
713 create_texture_view(&view->gl_view, view_target, desc, texture, view_format);
715 else if (wined3d_format_is_depth_view(resource->format->id, view_format->id))
717 create_texture_view(&view->gl_view, view_target, desc, texture, resource->format);
719 else
721 FIXME("Shader resource view not supported, resource format %s, view format %s.\n",
722 debug_d3dformat(resource->format->id), debug_d3dformat(view_format->id));
727 static HRESULT wined3d_shader_resource_view_init(struct wined3d_shader_resource_view *view,
728 const struct wined3d_view_desc *desc, struct wined3d_resource *resource,
729 void *parent, const struct wined3d_parent_ops *parent_ops)
731 view->refcount = 1;
732 view->parent = parent;
733 view->parent_ops = parent_ops;
735 if (!(view->format = validate_resource_view(desc, resource, FALSE)))
736 return E_INVALIDARG;
737 view->desc = *desc;
739 wined3d_resource_incref(view->resource = resource);
741 wined3d_cs_init_object(resource->device->cs, wined3d_shader_resource_view_cs_init, view);
743 return WINED3D_OK;
746 HRESULT CDECL wined3d_shader_resource_view_create(const struct wined3d_view_desc *desc,
747 struct wined3d_resource *resource, void *parent, const struct wined3d_parent_ops *parent_ops,
748 struct wined3d_shader_resource_view **view)
750 struct wined3d_shader_resource_view *object;
751 HRESULT hr;
753 TRACE("desc %p, resource %p, parent %p, parent_ops %p, view %p.\n",
754 desc, resource, parent, parent_ops, view);
756 if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
757 return E_OUTOFMEMORY;
759 if (FAILED(hr = wined3d_shader_resource_view_init(object, desc, resource, parent, parent_ops)))
761 HeapFree(GetProcessHeap(), 0, object);
762 WARN("Failed to initialise view, hr %#x.\n", hr);
763 return hr;
766 TRACE("Created shader resource view %p.\n", object);
767 *view = object;
769 return WINED3D_OK;
772 void wined3d_shader_resource_view_bind(struct wined3d_shader_resource_view *view,
773 unsigned int unit, struct wined3d_sampler *sampler, struct wined3d_context *context)
775 const struct wined3d_gl_info *gl_info = context->gl_info;
776 struct wined3d_texture *texture;
778 context_active_texture(context, gl_info, unit);
780 if (view->gl_view.name)
782 context_bind_texture(context, view->gl_view.target, view->gl_view.name);
783 wined3d_sampler_bind(sampler, unit, NULL, context);
784 return;
787 if (view->resource->type == WINED3D_RTYPE_BUFFER)
789 FIXME("Buffer shader resources not supported.\n");
790 return;
793 texture = wined3d_texture_from_resource(view->resource);
794 wined3d_texture_bind(texture, context, FALSE);
795 wined3d_sampler_bind(sampler, unit, texture, context);
798 ULONG CDECL wined3d_unordered_access_view_incref(struct wined3d_unordered_access_view *view)
800 ULONG refcount = InterlockedIncrement(&view->refcount);
802 TRACE("%p increasing refcount to %u.\n", view, refcount);
804 return refcount;
807 static void wined3d_unordered_access_view_destroy_object(void *object)
809 struct wined3d_unordered_access_view *view = object;
811 if (view->gl_view.name || view->counter_bo)
813 const struct wined3d_gl_info *gl_info;
814 struct wined3d_context *context;
816 context = context_acquire(view->resource->device, NULL, 0);
817 gl_info = context->gl_info;
818 if (view->gl_view.name)
819 gl_info->gl_ops.gl.p_glDeleteTextures(1, &view->gl_view.name);
820 if (view->counter_bo)
821 GL_EXTCALL(glDeleteBuffers(1, &view->counter_bo));
822 checkGLcall("delete resources");
823 context_release(context);
826 HeapFree(GetProcessHeap(), 0, view);
829 ULONG CDECL wined3d_unordered_access_view_decref(struct wined3d_unordered_access_view *view)
831 ULONG refcount = InterlockedDecrement(&view->refcount);
833 TRACE("%p decreasing refcount to %u.\n", view, refcount);
835 if (!refcount)
837 struct wined3d_resource *resource = view->resource;
838 struct wined3d_device *device = resource->device;
840 /* Call wined3d_object_destroyed() before releasing the resource,
841 * since releasing the resource may end up destroying the parent. */
842 view->parent_ops->wined3d_object_destroyed(view->parent);
843 wined3d_cs_destroy_object(device->cs, wined3d_unordered_access_view_destroy_object, view);
844 wined3d_resource_decref(resource);
847 return refcount;
850 void * CDECL wined3d_unordered_access_view_get_parent(const struct wined3d_unordered_access_view *view)
852 TRACE("view %p.\n", view);
854 return view->parent;
857 void wined3d_unordered_access_view_invalidate_location(struct wined3d_unordered_access_view *view,
858 DWORD location)
860 wined3d_view_invalidate_location(view->resource, &view->desc, location);
863 void wined3d_unordered_access_view_clear_uint(struct wined3d_unordered_access_view *view,
864 const struct wined3d_uvec4 *clear_value, struct wined3d_context *context)
866 const struct wined3d_gl_info *gl_info = context->gl_info;
867 const struct wined3d_format *format;
868 struct wined3d_resource *resource;
869 struct wined3d_buffer *buffer;
870 unsigned int offset, size;
872 resource = view->resource;
873 if (resource->type != WINED3D_RTYPE_BUFFER)
875 FIXME("Not implemented for %s resources.\n", debug_d3dresourcetype(resource->type));
876 return;
879 if (!gl_info->supported[ARB_CLEAR_BUFFER_OBJECT])
881 FIXME("OpenGL implementation does not support ARB_clear_buffer_object.\n");
882 return;
885 format = view->format;
886 if (format->id != WINED3DFMT_R32_UINT && format->id != WINED3DFMT_R32_SINT
887 && format->id != WINED3DFMT_R32G32B32A32_UINT
888 && format->id != WINED3DFMT_R32G32B32A32_SINT)
890 FIXME("Not implemented for format %s.\n", debug_d3dformat(format->id));
891 return;
894 buffer = buffer_from_resource(resource);
895 wined3d_buffer_load_location(buffer, context, WINED3D_LOCATION_BUFFER);
896 wined3d_unordered_access_view_invalidate_location(view, ~WINED3D_LOCATION_BUFFER);
898 get_buffer_view_range(buffer, &view->desc, format, &offset, &size);
899 context_bind_bo(context, buffer->buffer_type_hint, buffer->buffer_object);
900 GL_EXTCALL(glClearBufferSubData(buffer->buffer_type_hint, format->glInternal,
901 offset, size, format->glFormat, format->glType, clear_value));
902 checkGLcall("clear unordered access view");
905 void wined3d_unordered_access_view_set_counter(struct wined3d_unordered_access_view *view,
906 unsigned int value)
908 const struct wined3d_gl_info *gl_info;
909 struct wined3d_context *context;
911 if (!view->counter_bo)
912 return;
914 context = context_acquire(view->resource->device, NULL, 0);
915 gl_info = context->gl_info;
916 GL_EXTCALL(glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, view->counter_bo));
917 GL_EXTCALL(glBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(value), &value));
918 checkGLcall("set atomic counter");
919 context_release(context);
922 void wined3d_unordered_access_view_copy_counter(struct wined3d_unordered_access_view *view,
923 struct wined3d_buffer *buffer, unsigned int offset, struct wined3d_context *context)
925 struct wined3d_bo_address dst, src;
926 DWORD dst_location;
928 if (!view->counter_bo)
929 return;
931 dst_location = wined3d_buffer_get_memory(buffer, &dst, buffer->locations);
932 dst.addr += offset;
934 src.buffer_object = view->counter_bo;
935 src.addr = NULL;
937 context_copy_bo_address(context, &dst, buffer->buffer_type_hint,
938 &src, GL_ATOMIC_COUNTER_BUFFER, sizeof(GLuint));
940 wined3d_buffer_invalidate_location(buffer, ~dst_location);
943 static void wined3d_unordered_access_view_cs_init(void *object)
945 struct wined3d_unordered_access_view *view = object;
946 struct wined3d_resource *resource = view->resource;
947 struct wined3d_view_desc *desc = &view->desc;
948 const struct wined3d_gl_info *gl_info;
950 gl_info = &resource->device->adapter->gl_info;
952 if (resource->type == WINED3D_RTYPE_BUFFER)
954 struct wined3d_buffer *buffer = buffer_from_resource(resource);
955 struct wined3d_context *context;
957 context = context_acquire(resource->device, NULL, 0);
958 gl_info = context->gl_info;
959 create_buffer_view(&view->gl_view, context, desc, buffer, view->format);
960 if (desc->flags & (WINED3D_VIEW_BUFFER_COUNTER | WINED3D_VIEW_BUFFER_APPEND))
962 static const GLuint initial_value = 0;
963 GL_EXTCALL(glGenBuffers(1, &view->counter_bo));
964 GL_EXTCALL(glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, view->counter_bo));
965 GL_EXTCALL(glBufferData(GL_ATOMIC_COUNTER_BUFFER,
966 sizeof(initial_value), &initial_value, GL_STATIC_DRAW));
967 checkGLcall("create atomic counter buffer");
969 context_release(context);
971 else
973 struct wined3d_texture *texture = texture_from_resource(resource);
974 unsigned int depth_or_layer_count;
976 if (resource->type == WINED3D_RTYPE_TEXTURE_3D)
977 depth_or_layer_count = wined3d_texture_get_level_depth(texture, desc->u.texture.level_idx);
978 else
979 depth_or_layer_count = texture->layer_count;
981 if (desc->u.texture.layer_idx || desc->u.texture.layer_count != depth_or_layer_count)
983 create_texture_view(&view->gl_view, get_texture_view_target(gl_info, desc, texture),
984 desc, texture, view->format);
989 static HRESULT wined3d_unordered_access_view_init(struct wined3d_unordered_access_view *view,
990 const struct wined3d_view_desc *desc, struct wined3d_resource *resource,
991 void *parent, const struct wined3d_parent_ops *parent_ops)
993 view->refcount = 1;
994 view->parent = parent;
995 view->parent_ops = parent_ops;
997 if (!(view->format = validate_resource_view(desc, resource, TRUE)))
998 return E_INVALIDARG;
999 view->desc = *desc;
1001 wined3d_resource_incref(view->resource = resource);
1003 wined3d_cs_init_object(resource->device->cs, wined3d_unordered_access_view_cs_init, view);
1005 return WINED3D_OK;
1008 HRESULT CDECL wined3d_unordered_access_view_create(const struct wined3d_view_desc *desc,
1009 struct wined3d_resource *resource, void *parent, const struct wined3d_parent_ops *parent_ops,
1010 struct wined3d_unordered_access_view **view)
1012 struct wined3d_unordered_access_view *object;
1013 HRESULT hr;
1015 TRACE("desc %p, resource %p, parent %p, parent_ops %p, view %p.\n",
1016 desc, resource, parent, parent_ops, view);
1018 if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
1019 return E_OUTOFMEMORY;
1021 if (FAILED(hr = wined3d_unordered_access_view_init(object, desc, resource, parent, parent_ops)))
1023 HeapFree(GetProcessHeap(), 0, object);
1024 WARN("Failed to initialise view, hr %#x.\n", hr);
1025 return hr;
1028 TRACE("Created unordered access view %p.\n", object);
1029 *view = object;
1031 return WINED3D_OK;