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