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