shell32/autocomplete: Reduce the strlen calls because they are redundant.
[wine.git] / dlls / wined3d / view.c
blobd1678670bfef6556106e2e1d8e3b8586b5be42ee
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_adapter *adapter = resource->device->adapter;
88 const struct wined3d_format *format;
90 format = wined3d_get_format(adapter, 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(adapter, 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(adapter, 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 unsigned int level_idx, layer_idx, layer_count;
173 const struct wined3d_gl_info *gl_info;
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 level_idx = desc->u.texture.level_idx;
193 layer_idx = desc->u.texture.layer_idx;
194 layer_count = desc->u.texture.layer_count;
195 if (view_target == GL_TEXTURE_3D)
197 if (layer_idx || layer_count != wined3d_texture_get_level_depth(texture, level_idx))
198 FIXME("Depth slice (%u-%u) not supported.\n", layer_idx, layer_count);
199 layer_idx = 0;
200 layer_count = 1;
203 gl_info->gl_ops.gl.p_glGenTextures(1, &view->name);
204 GL_EXTCALL(glTextureView(view->name, view->target, texture_name, view_format->glInternal,
205 level_idx, desc->u.texture.level_count, layer_idx, layer_count));
206 checkGLcall("create texture view");
208 if (is_stencil_view_format(view_format))
210 static const GLint swizzle[] = {GL_ZERO, GL_RED, GL_ZERO, GL_ZERO};
212 if (!gl_info->supported[ARB_STENCIL_TEXTURING])
214 context_release(context);
215 FIXME("OpenGL implementation does not support stencil texturing.\n");
216 return;
219 context_bind_texture(context, view->target, view->name);
220 gl_info->gl_ops.gl.p_glTexParameteriv(view->target, GL_TEXTURE_SWIZZLE_RGBA, swizzle);
221 gl_info->gl_ops.gl.p_glTexParameteri(view->target, GL_DEPTH_STENCIL_TEXTURE_MODE, GL_STENCIL_INDEX);
222 checkGLcall("initialize stencil view");
224 context_invalidate_compute_state(context, STATE_COMPUTE_SHADER_RESOURCE_BINDING);
225 context_invalidate_state(context, STATE_GRAPHICS_SHADER_RESOURCE_BINDING);
228 context_release(context);
231 static void create_buffer_texture(struct wined3d_gl_view *view, struct wined3d_context *context,
232 struct wined3d_buffer *buffer, const struct wined3d_format *view_format,
233 unsigned int offset, unsigned int size)
235 const struct wined3d_gl_info *gl_info = context->gl_info;
237 if (!gl_info->supported[ARB_TEXTURE_BUFFER_OBJECT])
239 FIXME("OpenGL implementation does not support buffer textures.\n");
240 return;
243 if ((offset & (gl_info->limits.texture_buffer_offset_alignment - 1)))
245 FIXME("Buffer offset %u is not %u byte aligned.\n",
246 offset, gl_info->limits.texture_buffer_offset_alignment);
247 return;
250 wined3d_buffer_load_location(buffer, context, WINED3D_LOCATION_BUFFER);
252 view->target = GL_TEXTURE_BUFFER;
253 gl_info->gl_ops.gl.p_glGenTextures(1, &view->name);
255 context_bind_texture(context, GL_TEXTURE_BUFFER, view->name);
256 if (gl_info->supported[ARB_TEXTURE_BUFFER_RANGE])
258 GL_EXTCALL(glTexBufferRange(GL_TEXTURE_BUFFER, view_format->glInternal,
259 buffer->buffer_object, offset, size));
261 else
263 if (offset || size != buffer->resource.size)
264 FIXME("OpenGL implementation does not support ARB_texture_buffer_range.\n");
265 GL_EXTCALL(glTexBuffer(GL_TEXTURE_BUFFER, view_format->glInternal, buffer->buffer_object));
267 checkGLcall("Create buffer texture");
269 context_invalidate_compute_state(context, STATE_COMPUTE_SHADER_RESOURCE_BINDING);
270 context_invalidate_state(context, STATE_GRAPHICS_SHADER_RESOURCE_BINDING);
273 static void get_buffer_view_range(const struct wined3d_buffer *buffer,
274 const struct wined3d_view_desc *desc, const struct wined3d_format *view_format,
275 unsigned int *offset, unsigned int *size)
277 if (desc->format_id == WINED3DFMT_UNKNOWN)
279 *offset = desc->u.buffer.start_idx * buffer->desc.structure_byte_stride;
280 *size = desc->u.buffer.count * buffer->desc.structure_byte_stride;
282 else
284 *offset = desc->u.buffer.start_idx * view_format->byte_count;
285 *size = desc->u.buffer.count * view_format->byte_count;
289 static void create_buffer_view(struct wined3d_gl_view *view, struct wined3d_context *context,
290 const struct wined3d_view_desc *desc, struct wined3d_buffer *buffer,
291 const struct wined3d_format *view_format)
293 unsigned int offset, size;
295 get_buffer_view_range(buffer, desc, view_format, &offset, &size);
296 create_buffer_texture(view, context, buffer, view_format, offset, size);
299 static void wined3d_view_invalidate_location(struct wined3d_resource *resource,
300 const struct wined3d_view_desc *desc, DWORD location)
302 unsigned int i, sub_resource_idx, layer_count;
303 struct wined3d_texture *texture;
305 if (resource->type == WINED3D_RTYPE_BUFFER)
307 wined3d_buffer_invalidate_location(buffer_from_resource(resource), location);
308 return;
311 texture = texture_from_resource(resource);
313 sub_resource_idx = desc->u.texture.layer_idx * texture->level_count + desc->u.texture.level_idx;
314 layer_count = resource->type != WINED3D_RTYPE_TEXTURE_3D ? desc->u.texture.layer_count : 1;
315 for (i = 0; i < layer_count; ++i, sub_resource_idx += texture->level_count)
316 wined3d_texture_invalidate_location(texture, sub_resource_idx, location);
319 ULONG CDECL wined3d_rendertarget_view_incref(struct wined3d_rendertarget_view *view)
321 ULONG refcount = InterlockedIncrement(&view->refcount);
323 TRACE("%p increasing refcount to %u.\n", view, refcount);
325 return refcount;
328 static void wined3d_rendertarget_view_destroy_object(void *object)
330 struct wined3d_rendertarget_view *view = object;
331 struct wined3d_device *device = view->resource->device;
333 if (view->gl_view.name)
335 const struct wined3d_gl_info *gl_info;
336 struct wined3d_context *context;
338 context = context_acquire(device, NULL, 0);
339 gl_info = context->gl_info;
340 context_gl_resource_released(device, view->gl_view.name, FALSE);
341 gl_info->gl_ops.gl.p_glDeleteTextures(1, &view->gl_view.name);
342 checkGLcall("glDeleteTextures");
343 context_release(context);
346 heap_free(view);
349 ULONG CDECL wined3d_rendertarget_view_decref(struct wined3d_rendertarget_view *view)
351 ULONG refcount = InterlockedDecrement(&view->refcount);
353 TRACE("%p decreasing refcount to %u.\n", view, refcount);
355 if (!refcount)
357 struct wined3d_resource *resource = view->resource;
358 struct wined3d_device *device = resource->device;
360 /* Call wined3d_object_destroyed() before releasing the resource,
361 * since releasing the resource may end up destroying the parent. */
362 view->parent_ops->wined3d_object_destroyed(view->parent);
363 wined3d_cs_destroy_object(device->cs, wined3d_rendertarget_view_destroy_object, view);
364 wined3d_resource_decref(resource);
367 return refcount;
370 void * CDECL wined3d_rendertarget_view_get_parent(const struct wined3d_rendertarget_view *view)
372 TRACE("view %p.\n", view);
374 return view->parent;
377 void * CDECL wined3d_rendertarget_view_get_sub_resource_parent(const struct wined3d_rendertarget_view *view)
379 struct wined3d_texture *texture;
381 TRACE("view %p.\n", view);
383 if (view->resource->type == WINED3D_RTYPE_BUFFER)
384 return wined3d_buffer_get_parent(buffer_from_resource(view->resource));
386 texture = texture_from_resource(view->resource);
388 return texture->sub_resources[view->sub_resource_idx].parent;
391 void CDECL wined3d_rendertarget_view_set_parent(struct wined3d_rendertarget_view *view, void *parent)
393 TRACE("view %p, parent %p.\n", view, parent);
395 view->parent = parent;
398 struct wined3d_resource * CDECL wined3d_rendertarget_view_get_resource(const struct wined3d_rendertarget_view *view)
400 TRACE("view %p.\n", view);
402 return view->resource;
405 void wined3d_rendertarget_view_get_drawable_size(const struct wined3d_rendertarget_view *view,
406 const struct wined3d_context *context, unsigned int *width, unsigned int *height)
408 const struct wined3d_texture *texture;
410 if (view->resource->type != WINED3D_RTYPE_TEXTURE_2D)
412 *width = view->width;
413 *height = view->height;
414 return;
417 texture = texture_from_resource(view->resource);
418 if (texture->swapchain)
420 /* The drawable size of an onscreen drawable is the surface size.
421 * (Actually: The window size, but the surface is created in window
422 * size.) */
423 *width = texture->resource.width;
424 *height = texture->resource.height;
426 else if (wined3d_settings.offscreen_rendering_mode == ORM_BACKBUFFER)
428 const struct wined3d_swapchain *swapchain = context->swapchain;
430 /* The drawable size of a backbuffer / aux buffer offscreen target is
431 * the size of the current context's drawable, which is the size of
432 * the back buffer of the swapchain the active context belongs to. */
433 *width = swapchain->desc.backbuffer_width;
434 *height = swapchain->desc.backbuffer_height;
436 else
438 unsigned int level_idx = view->sub_resource_idx % texture->level_count;
440 /* The drawable size of an FBO target is the OpenGL texture size,
441 * which is the power of two size. */
442 *width = wined3d_texture_get_level_pow2_width(texture, level_idx);
443 *height = wined3d_texture_get_level_pow2_height(texture, level_idx);
447 void wined3d_rendertarget_view_prepare_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 FIXME("Not implemented for resources %s.\n", debug_d3dresourcetype(resource->type));
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_prepare_location(texture, sub_resource_idx, context, location);
467 void wined3d_rendertarget_view_load_location(struct wined3d_rendertarget_view *view,
468 struct wined3d_context *context, DWORD location)
470 struct wined3d_resource *resource = view->resource;
471 unsigned int i, sub_resource_idx, layer_count;
472 struct wined3d_texture *texture;
474 if (resource->type == WINED3D_RTYPE_BUFFER)
476 wined3d_buffer_load_location(buffer_from_resource(resource), context, location);
477 return;
480 texture = texture_from_resource(resource);
481 sub_resource_idx = view->sub_resource_idx;
482 layer_count = resource->type != WINED3D_RTYPE_TEXTURE_3D ? view->layer_count : 1;
483 for (i = 0; i < layer_count; ++i, sub_resource_idx += texture->level_count)
484 wined3d_texture_load_location(texture, sub_resource_idx, context, location);
487 void wined3d_rendertarget_view_validate_location(struct wined3d_rendertarget_view *view, DWORD location)
489 struct wined3d_resource *resource = view->resource;
490 unsigned int i, sub_resource_idx, layer_count;
491 struct wined3d_texture *texture;
493 if (resource->type == WINED3D_RTYPE_BUFFER)
495 FIXME("Not implemented for resources %s.\n", debug_d3dresourcetype(resource->type));
496 return;
499 texture = texture_from_resource(resource);
500 sub_resource_idx = view->sub_resource_idx;
501 layer_count = resource->type != WINED3D_RTYPE_TEXTURE_3D ? view->layer_count : 1;
502 for (i = 0; i < layer_count; ++i, sub_resource_idx += texture->level_count)
503 wined3d_texture_validate_location(texture, sub_resource_idx, location);
506 void wined3d_rendertarget_view_invalidate_location(struct wined3d_rendertarget_view *view, DWORD location)
508 wined3d_view_invalidate_location(view->resource, &view->desc, location);
511 static void wined3d_render_target_view_cs_init(void *object)
513 struct wined3d_rendertarget_view *view = object;
514 struct wined3d_resource *resource = view->resource;
515 const struct wined3d_view_desc *desc = &view->desc;
517 if (resource->type == WINED3D_RTYPE_BUFFER)
519 FIXME("Not implemented for resources %s.\n", debug_d3dresourcetype(resource->type));
521 else
523 struct wined3d_texture *texture = texture_from_resource(resource);
524 unsigned int depth_or_layer_count;
526 if (resource->type == WINED3D_RTYPE_TEXTURE_3D)
527 depth_or_layer_count = wined3d_texture_get_level_depth(texture, desc->u.texture.level_idx);
528 else
529 depth_or_layer_count = texture->layer_count;
531 if (resource->format->id != view->format->id
532 || (view->layer_count != 1 && view->layer_count != depth_or_layer_count))
534 if (resource->format->gl_view_class != view->format->gl_view_class)
536 FIXME("Render target view not supported, resource format %s, view format %s.\n",
537 debug_d3dformat(resource->format->id), debug_d3dformat(view->format->id));
538 return;
540 if (texture->swapchain && texture->swapchain->desc.backbuffer_count > 1)
542 FIXME("Swapchain views not supported.\n");
543 return;
546 create_texture_view(&view->gl_view, texture->target, desc, texture, view->format);
551 static HRESULT wined3d_rendertarget_view_init(struct wined3d_rendertarget_view *view,
552 const struct wined3d_view_desc *desc, struct wined3d_resource *resource,
553 void *parent, const struct wined3d_parent_ops *parent_ops)
555 BOOL allow_srgb_toggle = FALSE;
557 view->refcount = 1;
558 view->parent = parent;
559 view->parent_ops = parent_ops;
561 if (resource->type != WINED3D_RTYPE_BUFFER)
563 struct wined3d_texture *texture = texture_from_resource(resource);
565 if (texture->swapchain)
566 allow_srgb_toggle = TRUE;
568 if (!(view->format = validate_resource_view(desc, resource, TRUE, allow_srgb_toggle)))
569 return E_INVALIDARG;
570 view->format_flags = view->format->flags[resource->gl_type];
571 view->desc = *desc;
573 if (resource->type == WINED3D_RTYPE_BUFFER)
575 view->sub_resource_idx = 0;
576 view->layer_count = 1;
577 view->width = desc->u.buffer.count;
578 view->height = 1;
580 else
582 struct wined3d_texture *texture = texture_from_resource(resource);
584 view->sub_resource_idx = desc->u.texture.level_idx;
585 if (resource->type != WINED3D_RTYPE_TEXTURE_3D)
586 view->sub_resource_idx += desc->u.texture.layer_idx * texture->level_count;
587 view->layer_count = desc->u.texture.layer_count;
588 view->width = wined3d_texture_get_level_width(texture, desc->u.texture.level_idx);
589 view->height = wined3d_texture_get_level_height(texture, desc->u.texture.level_idx);
592 wined3d_resource_incref(view->resource = resource);
594 wined3d_cs_init_object(resource->device->cs, wined3d_render_target_view_cs_init, view);
596 return WINED3D_OK;
599 HRESULT CDECL wined3d_rendertarget_view_create(const struct wined3d_view_desc *desc,
600 struct wined3d_resource *resource, void *parent, const struct wined3d_parent_ops *parent_ops,
601 struct wined3d_rendertarget_view **view)
603 struct wined3d_rendertarget_view *object;
604 HRESULT hr;
606 TRACE("desc %p, resource %p, parent %p, parent_ops %p, view %p.\n",
607 desc, resource, parent, parent_ops, view);
609 if (!(object = heap_alloc_zero(sizeof(*object))))
610 return E_OUTOFMEMORY;
612 if (FAILED(hr = wined3d_rendertarget_view_init(object, desc, resource, parent, parent_ops)))
614 heap_free(object);
615 WARN("Failed to initialise view, hr %#x.\n", hr);
616 return hr;
619 TRACE("Created render target view %p.\n", object);
620 *view = object;
622 return hr;
625 HRESULT CDECL wined3d_rendertarget_view_create_from_sub_resource(struct wined3d_texture *texture,
626 unsigned int sub_resource_idx, void *parent, const struct wined3d_parent_ops *parent_ops,
627 struct wined3d_rendertarget_view **view)
629 struct wined3d_view_desc desc;
631 TRACE("texture %p, sub_resource_idx %u, parent %p, parent_ops %p, view %p.\n",
632 texture, sub_resource_idx, parent, parent_ops, view);
634 desc.format_id = texture->resource.format->id;
635 desc.flags = 0;
636 desc.u.texture.level_idx = sub_resource_idx % texture->level_count;
637 desc.u.texture.level_count = 1;
638 desc.u.texture.layer_idx = sub_resource_idx / texture->level_count;
639 desc.u.texture.layer_count = 1;
641 return wined3d_rendertarget_view_create(&desc, &texture->resource, parent, parent_ops, view);
644 ULONG CDECL wined3d_shader_resource_view_incref(struct wined3d_shader_resource_view *view)
646 ULONG refcount = InterlockedIncrement(&view->refcount);
648 TRACE("%p increasing refcount to %u.\n", view, refcount);
650 return refcount;
653 static void wined3d_shader_resource_view_destroy_object(void *object)
655 struct wined3d_shader_resource_view *view = object;
657 if (view->gl_view.name)
659 const struct wined3d_gl_info *gl_info;
660 struct wined3d_context *context;
662 context = context_acquire(view->resource->device, NULL, 0);
663 gl_info = context->gl_info;
664 gl_info->gl_ops.gl.p_glDeleteTextures(1, &view->gl_view.name);
665 checkGLcall("glDeleteTextures");
666 context_release(context);
669 heap_free(view);
672 ULONG CDECL wined3d_shader_resource_view_decref(struct wined3d_shader_resource_view *view)
674 ULONG refcount = InterlockedDecrement(&view->refcount);
676 TRACE("%p decreasing refcount to %u.\n", view, refcount);
678 if (!refcount)
680 struct wined3d_resource *resource = view->resource;
681 struct wined3d_device *device = resource->device;
683 /* Call wined3d_object_destroyed() before releasing the resource,
684 * since releasing the resource may end up destroying the parent. */
685 view->parent_ops->wined3d_object_destroyed(view->parent);
686 wined3d_cs_destroy_object(device->cs, wined3d_shader_resource_view_destroy_object, view);
687 wined3d_resource_decref(resource);
690 return refcount;
693 void * CDECL wined3d_shader_resource_view_get_parent(const struct wined3d_shader_resource_view *view)
695 TRACE("view %p.\n", view);
697 return view->parent;
700 static void wined3d_shader_resource_view_cs_init(void *object)
702 struct wined3d_shader_resource_view *view = object;
703 struct wined3d_resource *resource = view->resource;
704 const struct wined3d_format *view_format;
705 const struct wined3d_gl_info *gl_info;
706 const struct wined3d_view_desc *desc;
707 GLenum view_target;
709 view_format = view->format;
710 gl_info = &resource->device->adapter->gl_info;
711 desc = &view->desc;
713 if (resource->type == WINED3D_RTYPE_BUFFER)
715 struct wined3d_buffer *buffer = buffer_from_resource(resource);
716 struct wined3d_context *context;
718 context = context_acquire(resource->device, NULL, 0);
719 create_buffer_view(&view->gl_view, context, desc, buffer, view_format);
720 context_release(context);
722 else
724 struct wined3d_texture *texture = texture_from_resource(resource);
726 view_target = get_texture_view_target(gl_info, desc, texture);
728 if (resource->format->id == view_format->id && texture->target == view_target
729 && !desc->u.texture.level_idx && desc->u.texture.level_count == texture->level_count
730 && !desc->u.texture.layer_idx && desc->u.texture.layer_count == texture->layer_count
731 && !is_stencil_view_format(view_format))
733 TRACE("Creating identity shader resource view.\n");
735 else if (texture->swapchain && texture->swapchain->desc.backbuffer_count > 1)
737 FIXME("Swapchain shader resource views not supported.\n");
739 else if (resource->format->typeless_id == view_format->typeless_id
740 && resource->format->gl_view_class == view_format->gl_view_class)
742 create_texture_view(&view->gl_view, view_target, desc, texture, view_format);
744 else if (wined3d_format_is_depth_view(resource->format->id, view_format->id))
746 create_texture_view(&view->gl_view, view_target, desc, texture, resource->format);
748 else
750 FIXME("Shader resource view not supported, resource format %s, view format %s.\n",
751 debug_d3dformat(resource->format->id), debug_d3dformat(view_format->id));
756 static HRESULT wined3d_shader_resource_view_init(struct wined3d_shader_resource_view *view,
757 const struct wined3d_view_desc *desc, struct wined3d_resource *resource,
758 void *parent, const struct wined3d_parent_ops *parent_ops)
760 view->refcount = 1;
761 view->parent = parent;
762 view->parent_ops = parent_ops;
764 if (!(view->format = validate_resource_view(desc, resource, FALSE, FALSE)))
765 return E_INVALIDARG;
766 view->desc = *desc;
768 wined3d_resource_incref(view->resource = resource);
770 wined3d_cs_init_object(resource->device->cs, wined3d_shader_resource_view_cs_init, view);
772 return WINED3D_OK;
775 HRESULT CDECL wined3d_shader_resource_view_create(const struct wined3d_view_desc *desc,
776 struct wined3d_resource *resource, void *parent, const struct wined3d_parent_ops *parent_ops,
777 struct wined3d_shader_resource_view **view)
779 struct wined3d_shader_resource_view *object;
780 HRESULT hr;
782 TRACE("desc %p, resource %p, parent %p, parent_ops %p, view %p.\n",
783 desc, resource, parent, parent_ops, view);
785 if (!(object = heap_alloc_zero(sizeof(*object))))
786 return E_OUTOFMEMORY;
788 if (FAILED(hr = wined3d_shader_resource_view_init(object, desc, resource, parent, parent_ops)))
790 heap_free(object);
791 WARN("Failed to initialise view, hr %#x.\n", hr);
792 return hr;
795 TRACE("Created shader resource view %p.\n", object);
796 *view = object;
798 return WINED3D_OK;
801 void wined3d_shader_resource_view_bind(struct wined3d_shader_resource_view *view,
802 unsigned int unit, struct wined3d_sampler *sampler, struct wined3d_context *context)
804 const struct wined3d_gl_info *gl_info = context->gl_info;
805 struct wined3d_texture *texture;
807 context_active_texture(context, gl_info, unit);
809 if (view->gl_view.name)
811 context_bind_texture(context, view->gl_view.target, view->gl_view.name);
812 wined3d_sampler_bind(sampler, unit, NULL, context);
813 return;
816 if (view->resource->type == WINED3D_RTYPE_BUFFER)
818 FIXME("Buffer shader resources not supported.\n");
819 return;
822 texture = wined3d_texture_from_resource(view->resource);
823 wined3d_texture_bind(texture, context, FALSE);
824 wined3d_sampler_bind(sampler, unit, texture, context);
827 /* Context activation is done by the caller. */
828 static void shader_resource_view_bind_and_dirtify(struct wined3d_shader_resource_view *view,
829 struct wined3d_context *context)
831 if (context->active_texture < ARRAY_SIZE(context->rev_tex_unit_map))
833 DWORD active_sampler = context->rev_tex_unit_map[context->active_texture];
834 if (active_sampler != WINED3D_UNMAPPED_STAGE)
835 context_invalidate_state(context, STATE_SAMPLER(active_sampler));
837 /* FIXME: Ideally we'd only do this when touching a binding that's used by
838 * a shader. */
839 context_invalidate_compute_state(context, STATE_COMPUTE_SHADER_RESOURCE_BINDING);
840 context_invalidate_state(context, STATE_GRAPHICS_SHADER_RESOURCE_BINDING);
842 context_bind_texture(context, view->gl_view.target, view->gl_view.name);
845 void shader_resource_view_generate_mipmaps(struct wined3d_shader_resource_view *view)
847 struct wined3d_texture *texture = texture_from_resource(view->resource);
848 unsigned int i, j, layer_count, level_count, base_level, max_level;
849 const struct wined3d_gl_info *gl_info;
850 struct wined3d_context *context;
851 struct gl_texture *gl_tex;
852 DWORD location;
853 BOOL srgb;
855 TRACE("view %p.\n", view);
857 context = context_acquire(view->resource->device, NULL, 0);
858 gl_info = context->gl_info;
859 layer_count = view->desc.u.texture.layer_count;
860 level_count = view->desc.u.texture.level_count;
861 base_level = view->desc.u.texture.level_idx;
862 max_level = base_level + level_count - 1;
864 srgb = !!(texture->flags & WINED3D_TEXTURE_IS_SRGB);
865 location = srgb ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB;
866 for (i = 0; i < layer_count; ++i)
867 wined3d_texture_load_location(texture, i * level_count + base_level, context, location);
869 if (view->gl_view.name)
871 shader_resource_view_bind_and_dirtify(view, context);
873 else
875 wined3d_texture_bind_and_dirtify(texture, context, srgb);
876 gl_info->gl_ops.gl.p_glTexParameteri(texture->target, GL_TEXTURE_BASE_LEVEL, base_level);
877 gl_info->gl_ops.gl.p_glTexParameteri(texture->target, GL_TEXTURE_MAX_LEVEL, max_level);
880 if (gl_info->supported[ARB_SAMPLER_OBJECTS])
881 GL_EXTCALL(glBindSampler(context->active_texture, 0));
882 gl_tex = wined3d_texture_get_gl_texture(texture, srgb);
883 if (context->d3d_info->wined3d_creation_flags & WINED3D_SRGB_READ_WRITE_CONTROL)
885 gl_info->gl_ops.gl.p_glTexParameteri(texture->target, GL_TEXTURE_SRGB_DECODE_EXT,
886 GL_SKIP_DECODE_EXT);
887 gl_tex->sampler_desc.srgb_decode = FALSE;
890 gl_info->fbo_ops.glGenerateMipmap(texture->target);
891 checkGLcall("glGenerateMipMap()");
893 for (i = 0; i < layer_count; ++i)
895 for (j = base_level + 1; j <= max_level; ++j)
897 wined3d_texture_validate_location(texture, i * level_count + j, location);
898 wined3d_texture_invalidate_location(texture, i * level_count + j, ~location);
902 if (!view->gl_view.name)
904 gl_tex->base_level = base_level;
905 gl_info->gl_ops.gl.p_glTexParameteri(texture->target, GL_TEXTURE_MAX_LEVEL, texture->level_count - 1);
908 context_release(context);
911 void CDECL wined3d_shader_resource_view_generate_mipmaps(struct wined3d_shader_resource_view *view)
913 struct wined3d_texture *texture;
915 TRACE("view %p.\n", view);
917 if (view->resource->type == WINED3D_RTYPE_BUFFER)
919 WARN("Called on buffer resource %p.\n", view->resource);
920 return;
923 texture = texture_from_resource(view->resource);
924 if (!(texture->flags & WINED3D_TEXTURE_GENERATE_MIPMAPS))
926 WARN("Texture without the WINED3D_TEXTURE_GENERATE_MIPMAPS flag, ignoring.\n");
927 return;
930 wined3d_cs_emit_generate_mipmaps(view->resource->device->cs, view);
933 ULONG CDECL wined3d_unordered_access_view_incref(struct wined3d_unordered_access_view *view)
935 ULONG refcount = InterlockedIncrement(&view->refcount);
937 TRACE("%p increasing refcount to %u.\n", view, refcount);
939 return refcount;
942 static void wined3d_unordered_access_view_destroy_object(void *object)
944 struct wined3d_unordered_access_view *view = object;
946 if (view->gl_view.name || view->counter_bo)
948 const struct wined3d_gl_info *gl_info;
949 struct wined3d_context *context;
951 context = context_acquire(view->resource->device, NULL, 0);
952 gl_info = context->gl_info;
953 if (view->gl_view.name)
954 gl_info->gl_ops.gl.p_glDeleteTextures(1, &view->gl_view.name);
955 if (view->counter_bo)
956 GL_EXTCALL(glDeleteBuffers(1, &view->counter_bo));
957 checkGLcall("delete resources");
958 context_release(context);
961 heap_free(view);
964 ULONG CDECL wined3d_unordered_access_view_decref(struct wined3d_unordered_access_view *view)
966 ULONG refcount = InterlockedDecrement(&view->refcount);
968 TRACE("%p decreasing refcount to %u.\n", view, refcount);
970 if (!refcount)
972 struct wined3d_resource *resource = view->resource;
973 struct wined3d_device *device = resource->device;
975 /* Call wined3d_object_destroyed() before releasing the resource,
976 * since releasing the resource may end up destroying the parent. */
977 view->parent_ops->wined3d_object_destroyed(view->parent);
978 wined3d_cs_destroy_object(device->cs, wined3d_unordered_access_view_destroy_object, view);
979 wined3d_resource_decref(resource);
982 return refcount;
985 void * CDECL wined3d_unordered_access_view_get_parent(const struct wined3d_unordered_access_view *view)
987 TRACE("view %p.\n", view);
989 return view->parent;
992 void wined3d_unordered_access_view_invalidate_location(struct wined3d_unordered_access_view *view,
993 DWORD location)
995 wined3d_view_invalidate_location(view->resource, &view->desc, location);
998 void wined3d_unordered_access_view_clear_uint(struct wined3d_unordered_access_view *view,
999 const struct wined3d_uvec4 *clear_value, struct wined3d_context *context)
1001 const struct wined3d_gl_info *gl_info = context->gl_info;
1002 const struct wined3d_format *format;
1003 struct wined3d_resource *resource;
1004 struct wined3d_buffer *buffer;
1005 unsigned int offset, size;
1007 resource = view->resource;
1008 if (resource->type != WINED3D_RTYPE_BUFFER)
1010 FIXME("Not implemented for %s resources.\n", debug_d3dresourcetype(resource->type));
1011 return;
1014 if (!gl_info->supported[ARB_CLEAR_BUFFER_OBJECT])
1016 FIXME("OpenGL implementation does not support ARB_clear_buffer_object.\n");
1017 return;
1020 format = view->format;
1021 if (format->id != WINED3DFMT_R32_UINT && format->id != WINED3DFMT_R32_SINT
1022 && format->id != WINED3DFMT_R32G32B32A32_UINT
1023 && format->id != WINED3DFMT_R32G32B32A32_SINT)
1025 FIXME("Not implemented for format %s.\n", debug_d3dformat(format->id));
1026 return;
1029 buffer = buffer_from_resource(resource);
1030 wined3d_buffer_load_location(buffer, context, WINED3D_LOCATION_BUFFER);
1031 wined3d_unordered_access_view_invalidate_location(view, ~WINED3D_LOCATION_BUFFER);
1033 get_buffer_view_range(buffer, &view->desc, format, &offset, &size);
1034 context_bind_bo(context, buffer->buffer_type_hint, buffer->buffer_object);
1035 GL_EXTCALL(glClearBufferSubData(buffer->buffer_type_hint, format->glInternal,
1036 offset, size, format->glFormat, format->glType, clear_value));
1037 checkGLcall("clear unordered access view");
1040 void wined3d_unordered_access_view_set_counter(struct wined3d_unordered_access_view *view,
1041 unsigned int value)
1043 const struct wined3d_gl_info *gl_info;
1044 struct wined3d_context *context;
1046 if (!view->counter_bo)
1047 return;
1049 context = context_acquire(view->resource->device, NULL, 0);
1050 gl_info = context->gl_info;
1051 GL_EXTCALL(glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, view->counter_bo));
1052 GL_EXTCALL(glBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(value), &value));
1053 checkGLcall("set atomic counter");
1054 context_release(context);
1057 void wined3d_unordered_access_view_copy_counter(struct wined3d_unordered_access_view *view,
1058 struct wined3d_buffer *buffer, unsigned int offset, struct wined3d_context *context)
1060 struct wined3d_bo_address dst, src;
1061 DWORD dst_location;
1063 if (!view->counter_bo)
1064 return;
1066 dst_location = wined3d_buffer_get_memory(buffer, &dst, buffer->locations);
1067 dst.addr += offset;
1069 src.buffer_object = view->counter_bo;
1070 src.addr = NULL;
1072 context_copy_bo_address(context, &dst, buffer->buffer_type_hint,
1073 &src, GL_ATOMIC_COUNTER_BUFFER, sizeof(GLuint));
1075 wined3d_buffer_invalidate_location(buffer, ~dst_location);
1078 static void wined3d_unordered_access_view_cs_init(void *object)
1080 struct wined3d_unordered_access_view *view = object;
1081 struct wined3d_resource *resource = view->resource;
1082 struct wined3d_view_desc *desc = &view->desc;
1083 const struct wined3d_gl_info *gl_info;
1085 gl_info = &resource->device->adapter->gl_info;
1087 if (resource->type == WINED3D_RTYPE_BUFFER)
1089 struct wined3d_buffer *buffer = buffer_from_resource(resource);
1090 struct wined3d_context *context;
1092 context = context_acquire(resource->device, NULL, 0);
1093 gl_info = context->gl_info;
1094 create_buffer_view(&view->gl_view, context, desc, buffer, view->format);
1095 if (desc->flags & (WINED3D_VIEW_BUFFER_COUNTER | WINED3D_VIEW_BUFFER_APPEND))
1097 static const GLuint initial_value = 0;
1098 GL_EXTCALL(glGenBuffers(1, &view->counter_bo));
1099 GL_EXTCALL(glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, view->counter_bo));
1100 GL_EXTCALL(glBufferData(GL_ATOMIC_COUNTER_BUFFER,
1101 sizeof(initial_value), &initial_value, GL_STATIC_DRAW));
1102 checkGLcall("create atomic counter buffer");
1104 context_release(context);
1106 else
1108 struct wined3d_texture *texture = texture_from_resource(resource);
1109 unsigned int depth_or_layer_count;
1111 if (resource->type == WINED3D_RTYPE_TEXTURE_3D)
1112 depth_or_layer_count = wined3d_texture_get_level_depth(texture, desc->u.texture.level_idx);
1113 else
1114 depth_or_layer_count = texture->layer_count;
1116 if (desc->u.texture.layer_idx || desc->u.texture.layer_count != depth_or_layer_count)
1118 create_texture_view(&view->gl_view, get_texture_view_target(gl_info, desc, texture),
1119 desc, texture, view->format);
1124 static HRESULT wined3d_unordered_access_view_init(struct wined3d_unordered_access_view *view,
1125 const struct wined3d_view_desc *desc, struct wined3d_resource *resource,
1126 void *parent, const struct wined3d_parent_ops *parent_ops)
1128 view->refcount = 1;
1129 view->parent = parent;
1130 view->parent_ops = parent_ops;
1132 if (!(view->format = validate_resource_view(desc, resource, TRUE, FALSE)))
1133 return E_INVALIDARG;
1134 view->desc = *desc;
1136 wined3d_resource_incref(view->resource = resource);
1138 wined3d_cs_init_object(resource->device->cs, wined3d_unordered_access_view_cs_init, view);
1140 return WINED3D_OK;
1143 HRESULT CDECL wined3d_unordered_access_view_create(const struct wined3d_view_desc *desc,
1144 struct wined3d_resource *resource, void *parent, const struct wined3d_parent_ops *parent_ops,
1145 struct wined3d_unordered_access_view **view)
1147 struct wined3d_unordered_access_view *object;
1148 HRESULT hr;
1150 TRACE("desc %p, resource %p, parent %p, parent_ops %p, view %p.\n",
1151 desc, resource, parent, parent_ops, view);
1153 if (!(object = heap_alloc_zero(sizeof(*object))))
1154 return E_OUTOFMEMORY;
1156 if (FAILED(hr = wined3d_unordered_access_view_init(object, desc, resource, parent, parent_ops)))
1158 heap_free(object);
1159 WARN("Failed to initialise view, hr %#x.\n", hr);
1160 return hr;
1163 TRACE("Created unordered access view %p.\n", object);
1164 *view = object;
1166 return WINED3D_OK;