po: Update Lithuanian translation.
[wine.git] / dlls / wined3d / view.c
blobff28468408927da1f921957afb4ebe819673e738
1 /*
2 * Copyright 2009, 2011 Henri Verbeet for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include "config.h"
21 #include "wine/port.h"
23 #include "wined3d_private.h"
25 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
27 #define WINED3D_VIEW_CUBE_ARRAY (WINED3D_VIEW_TEXTURE_CUBE | WINED3D_VIEW_TEXTURE_ARRAY)
29 static BOOL is_stencil_view_format(const struct wined3d_format *format)
31 return format->id == WINED3DFMT_X24_TYPELESS_G8_UINT
32 || format->id == WINED3DFMT_X32_TYPELESS_G8X24_UINT;
35 static GLenum get_texture_view_target(const struct wined3d_gl_info *gl_info,
36 const struct wined3d_view_desc *desc, const struct wined3d_texture *texture)
38 static const struct
40 GLenum texture_target;
41 unsigned int view_flags;
42 GLenum view_target;
43 enum wined3d_gl_extension extension;
45 view_types[] =
47 {GL_TEXTURE_CUBE_MAP, 0, GL_TEXTURE_CUBE_MAP},
48 {GL_TEXTURE_RECTANGLE, 0, GL_TEXTURE_RECTANGLE},
49 {GL_TEXTURE_3D, 0, GL_TEXTURE_3D},
51 {GL_TEXTURE_2D, 0, GL_TEXTURE_2D},
52 {GL_TEXTURE_2D, WINED3D_VIEW_TEXTURE_ARRAY, GL_TEXTURE_2D_ARRAY},
53 {GL_TEXTURE_2D_ARRAY, 0, GL_TEXTURE_2D},
54 {GL_TEXTURE_2D_ARRAY, WINED3D_VIEW_TEXTURE_ARRAY, GL_TEXTURE_2D_ARRAY},
55 {GL_TEXTURE_2D_ARRAY, WINED3D_VIEW_TEXTURE_CUBE, GL_TEXTURE_CUBE_MAP},
56 {GL_TEXTURE_2D_ARRAY, WINED3D_VIEW_CUBE_ARRAY, GL_TEXTURE_CUBE_MAP_ARRAY, ARB_TEXTURE_CUBE_MAP_ARRAY},
58 {GL_TEXTURE_2D_MULTISAMPLE, 0, GL_TEXTURE_2D_MULTISAMPLE},
59 {GL_TEXTURE_2D_MULTISAMPLE, WINED3D_VIEW_TEXTURE_ARRAY, GL_TEXTURE_2D_MULTISAMPLE_ARRAY},
60 {GL_TEXTURE_2D_MULTISAMPLE_ARRAY, 0, GL_TEXTURE_2D_MULTISAMPLE},
61 {GL_TEXTURE_2D_MULTISAMPLE_ARRAY, WINED3D_VIEW_TEXTURE_ARRAY, GL_TEXTURE_2D_MULTISAMPLE_ARRAY},
63 {GL_TEXTURE_1D, 0, GL_TEXTURE_1D},
64 {GL_TEXTURE_1D, WINED3D_VIEW_TEXTURE_ARRAY, GL_TEXTURE_1D_ARRAY},
65 {GL_TEXTURE_1D_ARRAY, 0, GL_TEXTURE_1D},
66 {GL_TEXTURE_1D_ARRAY, WINED3D_VIEW_TEXTURE_ARRAY, GL_TEXTURE_1D_ARRAY},
68 unsigned int i;
70 for (i = 0; i < ARRAY_SIZE(view_types); ++i)
72 if (view_types[i].texture_target != texture->target || view_types[i].view_flags != desc->flags)
73 continue;
74 if (gl_info->supported[view_types[i].extension])
75 return view_types[i].view_target;
77 FIXME("Extension %#x not supported.\n", view_types[i].extension);
80 FIXME("Unhandled view flags %#x for texture target %#x.\n", desc->flags, texture->target);
81 return texture->target;
84 static const struct wined3d_format *validate_resource_view(const struct wined3d_view_desc *desc,
85 struct wined3d_resource *resource, BOOL mip_slice, BOOL allow_srgb_toggle)
87 const struct wined3d_adapter *adapter = resource->device->adapter;
88 const struct wined3d_format *format;
90 format = wined3d_get_format(adapter, desc->format_id, resource->usage);
91 if (resource->type == WINED3D_RTYPE_BUFFER && (desc->flags & WINED3D_VIEW_BUFFER_RAW))
93 if (format->id != WINED3DFMT_R32_TYPELESS)
95 WARN("Invalid format %s for raw buffer view.\n", debug_d3dformat(format->id));
96 return NULL;
99 format = wined3d_get_format(adapter, WINED3DFMT_R32_UINT, resource->usage);
102 if (wined3d_format_is_typeless(format))
104 WARN("Trying to create view for typeless format %s.\n", debug_d3dformat(format->id));
105 return NULL;
108 if (resource->type == WINED3D_RTYPE_BUFFER)
110 struct wined3d_buffer *buffer = buffer_from_resource(resource);
111 unsigned int buffer_size, element_size;
113 if (buffer->desc.structure_byte_stride)
115 if (desc->format_id != WINED3DFMT_UNKNOWN)
117 WARN("Invalid format %s for structured buffer view.\n", debug_d3dformat(desc->format_id));
118 return NULL;
121 format = wined3d_get_format(adapter, WINED3DFMT_R32_UINT, resource->usage);
122 element_size = buffer->desc.structure_byte_stride;
124 else
126 element_size = format->byte_count;
129 if (!element_size)
130 return NULL;
132 buffer_size = buffer->resource.size / element_size;
133 if (desc->u.buffer.start_idx >= buffer_size
134 || desc->u.buffer.count > buffer_size - desc->u.buffer.start_idx)
135 return NULL;
137 else
139 struct wined3d_texture *texture = texture_from_resource(resource);
140 unsigned int depth_or_layer_count;
142 if (resource->format->id != format->id && !wined3d_format_is_typeless(resource->format)
143 && (!allow_srgb_toggle || !wined3d_formats_are_srgb_variants(resource->format->id, format->id)))
145 WARN("Trying to create incompatible view for non typeless format %s.\n",
146 debug_d3dformat(format->id));
147 return NULL;
150 if (mip_slice && resource->type == WINED3D_RTYPE_TEXTURE_3D)
151 depth_or_layer_count = wined3d_texture_get_level_depth(texture, desc->u.texture.level_idx);
152 else
153 depth_or_layer_count = texture->layer_count;
155 if (!desc->u.texture.level_count
156 || (mip_slice && desc->u.texture.level_count != 1)
157 || desc->u.texture.level_idx >= texture->level_count
158 || desc->u.texture.level_count > texture->level_count - desc->u.texture.level_idx
159 || !desc->u.texture.layer_count
160 || desc->u.texture.layer_idx >= depth_or_layer_count
161 || desc->u.texture.layer_count > depth_or_layer_count - desc->u.texture.layer_idx)
162 return NULL;
165 return format;
168 static void create_texture_view(struct wined3d_gl_view *view, GLenum view_target,
169 const struct wined3d_view_desc *desc, struct wined3d_texture *texture,
170 const struct wined3d_format *view_format)
172 const struct wined3d_format_gl *view_format_gl;
173 unsigned int level_idx, layer_idx, layer_count;
174 const struct wined3d_gl_info *gl_info;
175 struct wined3d_context *context;
176 GLuint texture_name;
178 view_format_gl = wined3d_format_gl(view_format);
179 view->target = view_target;
181 context = context_acquire(texture->resource.device, NULL, 0);
182 gl_info = context->gl_info;
184 if (!gl_info->supported[ARB_TEXTURE_VIEW])
186 context_release(context);
187 FIXME("OpenGL implementation does not support texture views.\n");
188 return;
191 wined3d_texture_prepare_texture(texture, context, FALSE);
192 texture_name = wined3d_texture_get_texture_name(texture, context, FALSE);
194 level_idx = desc->u.texture.level_idx;
195 layer_idx = desc->u.texture.layer_idx;
196 layer_count = desc->u.texture.layer_count;
197 if (view_target == GL_TEXTURE_3D)
199 if (layer_idx || layer_count != wined3d_texture_get_level_depth(texture, level_idx))
200 FIXME("Depth slice (%u-%u) not supported.\n", layer_idx, layer_count);
201 layer_idx = 0;
202 layer_count = 1;
205 gl_info->gl_ops.gl.p_glGenTextures(1, &view->name);
206 GL_EXTCALL(glTextureView(view->name, view->target, texture_name, view_format_gl->internal,
207 level_idx, desc->u.texture.level_count, layer_idx, layer_count));
208 checkGLcall("create texture view");
210 if (is_stencil_view_format(&view_format_gl->f))
212 static const GLint swizzle[] = {GL_ZERO, GL_RED, GL_ZERO, GL_ZERO};
214 if (!gl_info->supported[ARB_STENCIL_TEXTURING])
216 context_release(context);
217 FIXME("OpenGL implementation does not support stencil texturing.\n");
218 return;
221 context_bind_texture(context, view->target, view->name);
222 gl_info->gl_ops.gl.p_glTexParameteriv(view->target, GL_TEXTURE_SWIZZLE_RGBA, swizzle);
223 gl_info->gl_ops.gl.p_glTexParameteri(view->target, GL_DEPTH_STENCIL_TEXTURE_MODE, GL_STENCIL_INDEX);
224 checkGLcall("initialize stencil view");
226 context_invalidate_compute_state(context, STATE_COMPUTE_SHADER_RESOURCE_BINDING);
227 context_invalidate_state(context, STATE_GRAPHICS_SHADER_RESOURCE_BINDING);
230 context_release(context);
233 static void create_buffer_texture(struct wined3d_gl_view *view, struct wined3d_context *context,
234 struct wined3d_buffer *buffer, const struct wined3d_format *view_format,
235 unsigned int offset, unsigned int size)
237 const struct wined3d_gl_info *gl_info = context->gl_info;
238 const struct wined3d_format_gl *view_format_gl;
240 if (!gl_info->supported[ARB_TEXTURE_BUFFER_OBJECT])
242 FIXME("OpenGL implementation does not support buffer textures.\n");
243 return;
246 if ((offset & (gl_info->limits.texture_buffer_offset_alignment - 1)))
248 FIXME("Buffer offset %u is not %u byte aligned.\n",
249 offset, gl_info->limits.texture_buffer_offset_alignment);
250 return;
253 view_format_gl = wined3d_format_gl(view_format);
254 wined3d_buffer_load_location(buffer, context, WINED3D_LOCATION_BUFFER);
256 view->target = GL_TEXTURE_BUFFER;
257 gl_info->gl_ops.gl.p_glGenTextures(1, &view->name);
259 context_bind_texture(context, GL_TEXTURE_BUFFER, view->name);
260 if (gl_info->supported[ARB_TEXTURE_BUFFER_RANGE])
262 GL_EXTCALL(glTexBufferRange(GL_TEXTURE_BUFFER, view_format_gl->internal,
263 buffer->buffer_object, offset, size));
265 else
267 if (offset || size != buffer->resource.size)
268 FIXME("OpenGL implementation does not support ARB_texture_buffer_range.\n");
269 GL_EXTCALL(glTexBuffer(GL_TEXTURE_BUFFER, view_format_gl->internal, buffer->buffer_object));
271 checkGLcall("Create buffer texture");
273 context_invalidate_compute_state(context, STATE_COMPUTE_SHADER_RESOURCE_BINDING);
274 context_invalidate_state(context, STATE_GRAPHICS_SHADER_RESOURCE_BINDING);
277 static void get_buffer_view_range(const struct wined3d_buffer *buffer,
278 const struct wined3d_view_desc *desc, const struct wined3d_format *view_format,
279 unsigned int *offset, unsigned int *size)
281 if (desc->format_id == WINED3DFMT_UNKNOWN)
283 *offset = desc->u.buffer.start_idx * buffer->desc.structure_byte_stride;
284 *size = desc->u.buffer.count * buffer->desc.structure_byte_stride;
286 else
288 *offset = desc->u.buffer.start_idx * view_format->byte_count;
289 *size = desc->u.buffer.count * view_format->byte_count;
293 static void create_buffer_view(struct wined3d_gl_view *view, struct wined3d_context *context,
294 const struct wined3d_view_desc *desc, struct wined3d_buffer *buffer,
295 const struct wined3d_format *view_format)
297 unsigned int offset, size;
299 get_buffer_view_range(buffer, desc, view_format, &offset, &size);
300 create_buffer_texture(view, context, buffer, view_format, offset, size);
303 static void wined3d_view_invalidate_location(struct wined3d_resource *resource,
304 const struct wined3d_view_desc *desc, DWORD location)
306 unsigned int i, sub_resource_idx, layer_count;
307 struct wined3d_texture *texture;
309 if (resource->type == WINED3D_RTYPE_BUFFER)
311 wined3d_buffer_invalidate_location(buffer_from_resource(resource), location);
312 return;
315 texture = texture_from_resource(resource);
317 sub_resource_idx = desc->u.texture.layer_idx * texture->level_count + desc->u.texture.level_idx;
318 layer_count = resource->type != WINED3D_RTYPE_TEXTURE_3D ? desc->u.texture.layer_count : 1;
319 for (i = 0; i < layer_count; ++i, sub_resource_idx += texture->level_count)
320 wined3d_texture_invalidate_location(texture, sub_resource_idx, location);
323 ULONG CDECL wined3d_rendertarget_view_incref(struct wined3d_rendertarget_view *view)
325 ULONG refcount = InterlockedIncrement(&view->refcount);
327 TRACE("%p increasing refcount to %u.\n", view, refcount);
329 return refcount;
332 static void wined3d_rendertarget_view_destroy_object(void *object)
334 struct wined3d_rendertarget_view *view = object;
335 struct wined3d_device *device = view->resource->device;
337 if (view->gl_view.name)
339 const struct wined3d_gl_info *gl_info;
340 struct wined3d_context *context;
342 context = context_acquire(device, NULL, 0);
343 gl_info = context->gl_info;
344 context_gl_resource_released(device, view->gl_view.name, FALSE);
345 gl_info->gl_ops.gl.p_glDeleteTextures(1, &view->gl_view.name);
346 checkGLcall("glDeleteTextures");
347 context_release(context);
350 heap_free(view);
353 ULONG CDECL wined3d_rendertarget_view_decref(struct wined3d_rendertarget_view *view)
355 ULONG refcount = InterlockedDecrement(&view->refcount);
357 TRACE("%p decreasing refcount to %u.\n", view, refcount);
359 if (!refcount)
361 struct wined3d_resource *resource = view->resource;
362 struct wined3d_device *device = resource->device;
364 /* Call wined3d_object_destroyed() before releasing the resource,
365 * since releasing the resource may end up destroying the parent. */
366 view->parent_ops->wined3d_object_destroyed(view->parent);
367 wined3d_cs_destroy_object(device->cs, wined3d_rendertarget_view_destroy_object, view);
368 wined3d_resource_decref(resource);
371 return refcount;
374 void * CDECL wined3d_rendertarget_view_get_parent(const struct wined3d_rendertarget_view *view)
376 TRACE("view %p.\n", view);
378 return view->parent;
381 void * CDECL wined3d_rendertarget_view_get_sub_resource_parent(const struct wined3d_rendertarget_view *view)
383 struct wined3d_texture *texture;
385 TRACE("view %p.\n", view);
387 if (view->resource->type == WINED3D_RTYPE_BUFFER)
388 return wined3d_buffer_get_parent(buffer_from_resource(view->resource));
390 texture = texture_from_resource(view->resource);
392 return texture->sub_resources[view->sub_resource_idx].parent;
395 void CDECL wined3d_rendertarget_view_set_parent(struct wined3d_rendertarget_view *view, void *parent)
397 TRACE("view %p, parent %p.\n", view, parent);
399 view->parent = parent;
402 struct wined3d_resource * CDECL wined3d_rendertarget_view_get_resource(const struct wined3d_rendertarget_view *view)
404 TRACE("view %p.\n", view);
406 return view->resource;
409 void wined3d_rendertarget_view_get_drawable_size(const struct wined3d_rendertarget_view *view,
410 const struct wined3d_context *context, unsigned int *width, unsigned int *height)
412 const struct wined3d_texture *texture;
414 if (view->resource->type != WINED3D_RTYPE_TEXTURE_2D)
416 *width = view->width;
417 *height = view->height;
418 return;
421 texture = texture_from_resource(view->resource);
422 if (texture->swapchain)
424 /* The drawable size of an onscreen drawable is the surface size.
425 * (Actually: The window size, but the surface is created in window
426 * size.) */
427 *width = texture->resource.width;
428 *height = texture->resource.height;
430 else if (wined3d_settings.offscreen_rendering_mode == ORM_BACKBUFFER)
432 const struct wined3d_swapchain *swapchain = context->swapchain;
434 /* The drawable size of a backbuffer / aux buffer offscreen target is
435 * the size of the current context's drawable, which is the size of
436 * the back buffer of the swapchain the active context belongs to. */
437 *width = swapchain->desc.backbuffer_width;
438 *height = swapchain->desc.backbuffer_height;
440 else
442 unsigned int level_idx = view->sub_resource_idx % texture->level_count;
444 /* The drawable size of an FBO target is the OpenGL texture size,
445 * which is the power of two size. */
446 *width = wined3d_texture_get_level_pow2_width(texture, level_idx);
447 *height = wined3d_texture_get_level_pow2_height(texture, level_idx);
451 void wined3d_rendertarget_view_prepare_location(struct wined3d_rendertarget_view *view,
452 struct wined3d_context *context, DWORD location)
454 struct wined3d_resource *resource = view->resource;
455 unsigned int i, sub_resource_idx, layer_count;
456 struct wined3d_texture *texture;
458 if (resource->type == WINED3D_RTYPE_BUFFER)
460 FIXME("Not implemented for resources %s.\n", debug_d3dresourcetype(resource->type));
461 return;
464 texture = texture_from_resource(resource);
465 sub_resource_idx = view->sub_resource_idx;
466 layer_count = resource->type != WINED3D_RTYPE_TEXTURE_3D ? view->layer_count : 1;
467 for (i = 0; i < layer_count; ++i, sub_resource_idx += texture->level_count)
468 wined3d_texture_prepare_location(texture, sub_resource_idx, context, location);
471 void wined3d_rendertarget_view_load_location(struct wined3d_rendertarget_view *view,
472 struct wined3d_context *context, DWORD location)
474 struct wined3d_resource *resource = view->resource;
475 unsigned int i, sub_resource_idx, layer_count;
476 struct wined3d_texture *texture;
478 if (resource->type == WINED3D_RTYPE_BUFFER)
480 wined3d_buffer_load_location(buffer_from_resource(resource), context, location);
481 return;
484 texture = texture_from_resource(resource);
485 sub_resource_idx = view->sub_resource_idx;
486 layer_count = resource->type != WINED3D_RTYPE_TEXTURE_3D ? view->layer_count : 1;
487 for (i = 0; i < layer_count; ++i, sub_resource_idx += texture->level_count)
488 wined3d_texture_load_location(texture, sub_resource_idx, context, location);
491 void wined3d_rendertarget_view_validate_location(struct wined3d_rendertarget_view *view, DWORD location)
493 struct wined3d_resource *resource = view->resource;
494 unsigned int i, sub_resource_idx, layer_count;
495 struct wined3d_texture *texture;
497 if (resource->type == WINED3D_RTYPE_BUFFER)
499 FIXME("Not implemented for resources %s.\n", debug_d3dresourcetype(resource->type));
500 return;
503 texture = texture_from_resource(resource);
504 sub_resource_idx = view->sub_resource_idx;
505 layer_count = resource->type != WINED3D_RTYPE_TEXTURE_3D ? view->layer_count : 1;
506 for (i = 0; i < layer_count; ++i, sub_resource_idx += texture->level_count)
507 wined3d_texture_validate_location(texture, sub_resource_idx, location);
510 void wined3d_rendertarget_view_invalidate_location(struct wined3d_rendertarget_view *view, DWORD location)
512 wined3d_view_invalidate_location(view->resource, &view->desc, location);
515 static void wined3d_render_target_view_cs_init(void *object)
517 struct wined3d_rendertarget_view *view = object;
518 struct wined3d_resource *resource = view->resource;
519 const struct wined3d_view_desc *desc = &view->desc;
521 if (resource->type == WINED3D_RTYPE_BUFFER)
523 FIXME("Not implemented for resources %s.\n", debug_d3dresourcetype(resource->type));
525 else
527 struct wined3d_texture *texture = texture_from_resource(resource);
528 unsigned int depth_or_layer_count;
530 if (resource->type == WINED3D_RTYPE_TEXTURE_3D)
531 depth_or_layer_count = wined3d_texture_get_level_depth(texture, desc->u.texture.level_idx);
532 else
533 depth_or_layer_count = texture->layer_count;
535 if (resource->format->id != view->format->id
536 || (view->layer_count != 1 && view->layer_count != depth_or_layer_count))
538 GLenum resource_class, view_class;
540 resource_class = wined3d_format_gl(resource->format)->view_class;
541 view_class = wined3d_format_gl(view->format)->view_class;
542 if (resource_class != view_class)
544 FIXME("Render target view not supported, resource format %s, view format %s.\n",
545 debug_d3dformat(resource->format->id), debug_d3dformat(view->format->id));
546 return;
548 if (texture->swapchain && texture->swapchain->desc.backbuffer_count > 1)
550 FIXME("Swapchain views not supported.\n");
551 return;
554 create_texture_view(&view->gl_view, texture->target, desc, texture, view->format);
559 static HRESULT wined3d_rendertarget_view_init(struct wined3d_rendertarget_view *view,
560 const struct wined3d_view_desc *desc, struct wined3d_resource *resource,
561 void *parent, const struct wined3d_parent_ops *parent_ops)
563 BOOL allow_srgb_toggle = FALSE;
565 view->refcount = 1;
566 view->parent = parent;
567 view->parent_ops = parent_ops;
569 if (resource->type != WINED3D_RTYPE_BUFFER)
571 struct wined3d_texture *texture = texture_from_resource(resource);
573 if (texture->swapchain)
574 allow_srgb_toggle = TRUE;
576 if (!(view->format = validate_resource_view(desc, resource, TRUE, allow_srgb_toggle)))
577 return E_INVALIDARG;
578 view->format_flags = view->format->flags[resource->gl_type];
579 view->desc = *desc;
581 if (resource->type == WINED3D_RTYPE_BUFFER)
583 view->sub_resource_idx = 0;
584 view->layer_count = 1;
585 view->width = desc->u.buffer.count;
586 view->height = 1;
588 else
590 struct wined3d_texture *texture = texture_from_resource(resource);
592 view->sub_resource_idx = desc->u.texture.level_idx;
593 if (resource->type != WINED3D_RTYPE_TEXTURE_3D)
594 view->sub_resource_idx += desc->u.texture.layer_idx * texture->level_count;
595 view->layer_count = desc->u.texture.layer_count;
596 view->width = wined3d_texture_get_level_width(texture, desc->u.texture.level_idx);
597 view->height = wined3d_texture_get_level_height(texture, desc->u.texture.level_idx);
600 wined3d_resource_incref(view->resource = resource);
602 wined3d_cs_init_object(resource->device->cs, wined3d_render_target_view_cs_init, view);
604 return WINED3D_OK;
607 HRESULT CDECL wined3d_rendertarget_view_create(const struct wined3d_view_desc *desc,
608 struct wined3d_resource *resource, void *parent, const struct wined3d_parent_ops *parent_ops,
609 struct wined3d_rendertarget_view **view)
611 struct wined3d_rendertarget_view *object;
612 HRESULT hr;
614 TRACE("desc %p, resource %p, parent %p, parent_ops %p, view %p.\n",
615 desc, resource, parent, parent_ops, view);
617 if (!(object = heap_alloc_zero(sizeof(*object))))
618 return E_OUTOFMEMORY;
620 if (FAILED(hr = wined3d_rendertarget_view_init(object, desc, resource, parent, parent_ops)))
622 heap_free(object);
623 WARN("Failed to initialise view, hr %#x.\n", hr);
624 return hr;
627 TRACE("Created render target view %p.\n", object);
628 *view = object;
630 return hr;
633 HRESULT CDECL wined3d_rendertarget_view_create_from_sub_resource(struct wined3d_texture *texture,
634 unsigned int sub_resource_idx, void *parent, const struct wined3d_parent_ops *parent_ops,
635 struct wined3d_rendertarget_view **view)
637 struct wined3d_view_desc desc;
639 TRACE("texture %p, sub_resource_idx %u, parent %p, parent_ops %p, view %p.\n",
640 texture, sub_resource_idx, parent, parent_ops, view);
642 desc.format_id = texture->resource.format->id;
643 desc.flags = 0;
644 desc.u.texture.level_idx = sub_resource_idx % texture->level_count;
645 desc.u.texture.level_count = 1;
646 desc.u.texture.layer_idx = sub_resource_idx / texture->level_count;
647 desc.u.texture.layer_count = 1;
649 return wined3d_rendertarget_view_create(&desc, &texture->resource, parent, parent_ops, view);
652 ULONG CDECL wined3d_shader_resource_view_incref(struct wined3d_shader_resource_view *view)
654 ULONG refcount = InterlockedIncrement(&view->refcount);
656 TRACE("%p increasing refcount to %u.\n", view, refcount);
658 return refcount;
661 static void wined3d_shader_resource_view_destroy_object(void *object)
663 struct wined3d_shader_resource_view *view = object;
665 if (view->gl_view.name)
667 const struct wined3d_gl_info *gl_info;
668 struct wined3d_context *context;
670 context = context_acquire(view->resource->device, NULL, 0);
671 gl_info = context->gl_info;
672 gl_info->gl_ops.gl.p_glDeleteTextures(1, &view->gl_view.name);
673 checkGLcall("glDeleteTextures");
674 context_release(context);
677 heap_free(view);
680 ULONG CDECL wined3d_shader_resource_view_decref(struct wined3d_shader_resource_view *view)
682 ULONG refcount = InterlockedDecrement(&view->refcount);
684 TRACE("%p decreasing refcount to %u.\n", view, refcount);
686 if (!refcount)
688 struct wined3d_resource *resource = view->resource;
689 struct wined3d_device *device = resource->device;
691 /* Call wined3d_object_destroyed() before releasing the resource,
692 * since releasing the resource may end up destroying the parent. */
693 view->parent_ops->wined3d_object_destroyed(view->parent);
694 wined3d_cs_destroy_object(device->cs, wined3d_shader_resource_view_destroy_object, view);
695 wined3d_resource_decref(resource);
698 return refcount;
701 void * CDECL wined3d_shader_resource_view_get_parent(const struct wined3d_shader_resource_view *view)
703 TRACE("view %p.\n", view);
705 return view->parent;
708 static void wined3d_shader_resource_view_cs_init(void *object)
710 struct wined3d_shader_resource_view *view = object;
711 struct wined3d_resource *resource = view->resource;
712 const struct wined3d_format *view_format;
713 const struct wined3d_gl_info *gl_info;
714 const struct wined3d_view_desc *desc;
715 GLenum view_target;
717 view_format = view->format;
718 gl_info = &resource->device->adapter->gl_info;
719 desc = &view->desc;
721 if (resource->type == WINED3D_RTYPE_BUFFER)
723 struct wined3d_buffer *buffer = buffer_from_resource(resource);
724 struct wined3d_context *context;
726 context = context_acquire(resource->device, NULL, 0);
727 create_buffer_view(&view->gl_view, context, desc, buffer, view_format);
728 context_release(context);
730 else
732 struct wined3d_texture *texture = texture_from_resource(resource);
733 GLenum resource_class, view_class;
735 resource_class = wined3d_format_gl(resource->format)->view_class;
736 view_class = wined3d_format_gl(view_format)->view_class;
737 view_target = get_texture_view_target(gl_info, desc, texture);
739 if (resource->format->id == view_format->id && texture->target == view_target
740 && !desc->u.texture.level_idx && desc->u.texture.level_count == texture->level_count
741 && !desc->u.texture.layer_idx && desc->u.texture.layer_count == texture->layer_count
742 && !is_stencil_view_format(view_format))
744 TRACE("Creating identity shader resource view.\n");
746 else if (texture->swapchain && texture->swapchain->desc.backbuffer_count > 1)
748 FIXME("Swapchain shader resource views not supported.\n");
750 else if (resource->format->typeless_id == view_format->typeless_id
751 && resource_class == view_class)
753 create_texture_view(&view->gl_view, view_target, desc, texture, view_format);
755 else if (wined3d_format_is_depth_view(resource->format->id, view_format->id))
757 create_texture_view(&view->gl_view, view_target, desc, texture, resource->format);
759 else
761 FIXME("Shader resource view not supported, resource format %s, view format %s.\n",
762 debug_d3dformat(resource->format->id), debug_d3dformat(view_format->id));
767 static HRESULT wined3d_shader_resource_view_init(struct wined3d_shader_resource_view *view,
768 const struct wined3d_view_desc *desc, struct wined3d_resource *resource,
769 void *parent, const struct wined3d_parent_ops *parent_ops)
771 view->refcount = 1;
772 view->parent = parent;
773 view->parent_ops = parent_ops;
775 if (!(view->format = validate_resource_view(desc, resource, FALSE, FALSE)))
776 return E_INVALIDARG;
777 view->desc = *desc;
779 wined3d_resource_incref(view->resource = resource);
781 wined3d_cs_init_object(resource->device->cs, wined3d_shader_resource_view_cs_init, view);
783 return WINED3D_OK;
786 HRESULT CDECL wined3d_shader_resource_view_create(const struct wined3d_view_desc *desc,
787 struct wined3d_resource *resource, void *parent, const struct wined3d_parent_ops *parent_ops,
788 struct wined3d_shader_resource_view **view)
790 struct wined3d_shader_resource_view *object;
791 HRESULT hr;
793 TRACE("desc %p, resource %p, parent %p, parent_ops %p, view %p.\n",
794 desc, resource, parent, parent_ops, view);
796 if (!(object = heap_alloc_zero(sizeof(*object))))
797 return E_OUTOFMEMORY;
799 if (FAILED(hr = wined3d_shader_resource_view_init(object, desc, resource, parent, parent_ops)))
801 heap_free(object);
802 WARN("Failed to initialise view, hr %#x.\n", hr);
803 return hr;
806 TRACE("Created shader resource view %p.\n", object);
807 *view = object;
809 return WINED3D_OK;
812 void wined3d_shader_resource_view_bind(struct wined3d_shader_resource_view *view,
813 unsigned int unit, struct wined3d_sampler *sampler, struct wined3d_context *context)
815 const struct wined3d_gl_info *gl_info = context->gl_info;
816 struct wined3d_texture *texture;
818 context_active_texture(context, gl_info, unit);
820 if (view->gl_view.name)
822 context_bind_texture(context, view->gl_view.target, view->gl_view.name);
823 wined3d_sampler_bind(sampler, unit, NULL, context);
824 return;
827 if (view->resource->type == WINED3D_RTYPE_BUFFER)
829 FIXME("Buffer shader resources not supported.\n");
830 return;
833 texture = wined3d_texture_from_resource(view->resource);
834 wined3d_texture_bind(texture, context, FALSE);
835 wined3d_sampler_bind(sampler, unit, texture, context);
838 /* Context activation is done by the caller. */
839 static void shader_resource_view_bind_and_dirtify(struct wined3d_shader_resource_view *view,
840 struct wined3d_context *context)
842 if (context->active_texture < ARRAY_SIZE(context->rev_tex_unit_map))
844 DWORD active_sampler = context->rev_tex_unit_map[context->active_texture];
845 if (active_sampler != WINED3D_UNMAPPED_STAGE)
846 context_invalidate_state(context, STATE_SAMPLER(active_sampler));
848 /* FIXME: Ideally we'd only do this when touching a binding that's used by
849 * a shader. */
850 context_invalidate_compute_state(context, STATE_COMPUTE_SHADER_RESOURCE_BINDING);
851 context_invalidate_state(context, STATE_GRAPHICS_SHADER_RESOURCE_BINDING);
853 context_bind_texture(context, view->gl_view.target, view->gl_view.name);
856 void shader_resource_view_generate_mipmaps(struct wined3d_shader_resource_view *view)
858 struct wined3d_texture *texture = texture_from_resource(view->resource);
859 unsigned int i, j, layer_count, level_count, base_level, max_level;
860 const struct wined3d_gl_info *gl_info;
861 struct wined3d_context *context;
862 struct gl_texture *gl_tex;
863 DWORD location;
864 BOOL srgb;
866 TRACE("view %p.\n", view);
868 context = context_acquire(view->resource->device, NULL, 0);
869 gl_info = context->gl_info;
870 layer_count = view->desc.u.texture.layer_count;
871 level_count = view->desc.u.texture.level_count;
872 base_level = view->desc.u.texture.level_idx;
873 max_level = base_level + level_count - 1;
875 srgb = !!(texture->flags & WINED3D_TEXTURE_IS_SRGB);
876 location = srgb ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB;
877 for (i = 0; i < layer_count; ++i)
878 wined3d_texture_load_location(texture, i * level_count + base_level, context, location);
880 if (view->gl_view.name)
882 shader_resource_view_bind_and_dirtify(view, context);
884 else
886 wined3d_texture_bind_and_dirtify(texture, context, srgb);
887 gl_info->gl_ops.gl.p_glTexParameteri(texture->target, GL_TEXTURE_BASE_LEVEL, base_level);
888 gl_info->gl_ops.gl.p_glTexParameteri(texture->target, GL_TEXTURE_MAX_LEVEL, max_level);
891 if (gl_info->supported[ARB_SAMPLER_OBJECTS])
892 GL_EXTCALL(glBindSampler(context->active_texture, 0));
893 gl_tex = wined3d_texture_get_gl_texture(texture, srgb);
894 if (context->d3d_info->wined3d_creation_flags & WINED3D_SRGB_READ_WRITE_CONTROL)
896 gl_info->gl_ops.gl.p_glTexParameteri(texture->target, GL_TEXTURE_SRGB_DECODE_EXT,
897 GL_SKIP_DECODE_EXT);
898 gl_tex->sampler_desc.srgb_decode = FALSE;
901 gl_info->fbo_ops.glGenerateMipmap(texture->target);
902 checkGLcall("glGenerateMipMap()");
904 for (i = 0; i < layer_count; ++i)
906 for (j = base_level + 1; j <= max_level; ++j)
908 wined3d_texture_validate_location(texture, i * level_count + j, location);
909 wined3d_texture_invalidate_location(texture, i * level_count + j, ~location);
913 if (!view->gl_view.name)
915 gl_tex->base_level = base_level;
916 gl_info->gl_ops.gl.p_glTexParameteri(texture->target, GL_TEXTURE_MAX_LEVEL, texture->level_count - 1);
919 context_release(context);
922 void CDECL wined3d_shader_resource_view_generate_mipmaps(struct wined3d_shader_resource_view *view)
924 struct wined3d_texture *texture;
926 TRACE("view %p.\n", view);
928 if (view->resource->type == WINED3D_RTYPE_BUFFER)
930 WARN("Called on buffer resource %p.\n", view->resource);
931 return;
934 texture = texture_from_resource(view->resource);
935 if (!(texture->flags & WINED3D_TEXTURE_GENERATE_MIPMAPS))
937 WARN("Texture without the WINED3D_TEXTURE_GENERATE_MIPMAPS flag, ignoring.\n");
938 return;
941 wined3d_cs_emit_generate_mipmaps(view->resource->device->cs, view);
944 ULONG CDECL wined3d_unordered_access_view_incref(struct wined3d_unordered_access_view *view)
946 ULONG refcount = InterlockedIncrement(&view->refcount);
948 TRACE("%p increasing refcount to %u.\n", view, refcount);
950 return refcount;
953 static void wined3d_unordered_access_view_destroy_object(void *object)
955 struct wined3d_unordered_access_view *view = object;
957 if (view->gl_view.name || view->counter_bo)
959 const struct wined3d_gl_info *gl_info;
960 struct wined3d_context *context;
962 context = context_acquire(view->resource->device, NULL, 0);
963 gl_info = context->gl_info;
964 if (view->gl_view.name)
965 gl_info->gl_ops.gl.p_glDeleteTextures(1, &view->gl_view.name);
966 if (view->counter_bo)
967 GL_EXTCALL(glDeleteBuffers(1, &view->counter_bo));
968 checkGLcall("delete resources");
969 context_release(context);
972 heap_free(view);
975 ULONG CDECL wined3d_unordered_access_view_decref(struct wined3d_unordered_access_view *view)
977 ULONG refcount = InterlockedDecrement(&view->refcount);
979 TRACE("%p decreasing refcount to %u.\n", view, refcount);
981 if (!refcount)
983 struct wined3d_resource *resource = view->resource;
984 struct wined3d_device *device = resource->device;
986 /* Call wined3d_object_destroyed() before releasing the resource,
987 * since releasing the resource may end up destroying the parent. */
988 view->parent_ops->wined3d_object_destroyed(view->parent);
989 wined3d_cs_destroy_object(device->cs, wined3d_unordered_access_view_destroy_object, view);
990 wined3d_resource_decref(resource);
993 return refcount;
996 void * CDECL wined3d_unordered_access_view_get_parent(const struct wined3d_unordered_access_view *view)
998 TRACE("view %p.\n", view);
1000 return view->parent;
1003 void wined3d_unordered_access_view_invalidate_location(struct wined3d_unordered_access_view *view,
1004 DWORD location)
1006 wined3d_view_invalidate_location(view->resource, &view->desc, location);
1009 void wined3d_unordered_access_view_clear_uint(struct wined3d_unordered_access_view *view,
1010 const struct wined3d_uvec4 *clear_value, struct wined3d_context *context)
1012 const struct wined3d_gl_info *gl_info = context->gl_info;
1013 const struct wined3d_format_gl *format;
1014 struct wined3d_resource *resource;
1015 struct wined3d_buffer *buffer;
1016 unsigned int offset, size;
1018 resource = view->resource;
1019 if (resource->type != WINED3D_RTYPE_BUFFER)
1021 FIXME("Not implemented for %s resources.\n", debug_d3dresourcetype(resource->type));
1022 return;
1025 if (!gl_info->supported[ARB_CLEAR_BUFFER_OBJECT])
1027 FIXME("OpenGL implementation does not support ARB_clear_buffer_object.\n");
1028 return;
1031 format = wined3d_format_gl(view->format);
1032 if (format->f.id != WINED3DFMT_R32_UINT && format->f.id != WINED3DFMT_R32_SINT
1033 && format->f.id != WINED3DFMT_R32G32B32A32_UINT
1034 && format->f.id != WINED3DFMT_R32G32B32A32_SINT)
1036 FIXME("Not implemented for format %s.\n", debug_d3dformat(format->f.id));
1037 return;
1040 buffer = buffer_from_resource(resource);
1041 wined3d_buffer_load_location(buffer, context, WINED3D_LOCATION_BUFFER);
1042 wined3d_unordered_access_view_invalidate_location(view, ~WINED3D_LOCATION_BUFFER);
1044 get_buffer_view_range(buffer, &view->desc, &format->f, &offset, &size);
1045 context_bind_bo(context, buffer->buffer_type_hint, buffer->buffer_object);
1046 GL_EXTCALL(glClearBufferSubData(buffer->buffer_type_hint, format->internal,
1047 offset, size, format->format, format->type, clear_value));
1048 checkGLcall("clear unordered access view");
1051 void wined3d_unordered_access_view_set_counter(struct wined3d_unordered_access_view *view,
1052 unsigned int value)
1054 const struct wined3d_gl_info *gl_info;
1055 struct wined3d_context *context;
1057 if (!view->counter_bo)
1058 return;
1060 context = context_acquire(view->resource->device, NULL, 0);
1061 gl_info = context->gl_info;
1062 GL_EXTCALL(glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, view->counter_bo));
1063 GL_EXTCALL(glBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(value), &value));
1064 checkGLcall("set atomic counter");
1065 context_release(context);
1068 void wined3d_unordered_access_view_copy_counter(struct wined3d_unordered_access_view *view,
1069 struct wined3d_buffer *buffer, unsigned int offset, struct wined3d_context *context)
1071 struct wined3d_bo_address dst, src;
1072 DWORD dst_location;
1074 if (!view->counter_bo)
1075 return;
1077 dst_location = wined3d_buffer_get_memory(buffer, &dst, buffer->locations);
1078 dst.addr += offset;
1080 src.buffer_object = view->counter_bo;
1081 src.addr = NULL;
1083 context_copy_bo_address(context, &dst, buffer->buffer_type_hint,
1084 &src, GL_ATOMIC_COUNTER_BUFFER, sizeof(GLuint));
1086 wined3d_buffer_invalidate_location(buffer, ~dst_location);
1089 static void wined3d_unordered_access_view_cs_init(void *object)
1091 struct wined3d_unordered_access_view *view = object;
1092 struct wined3d_resource *resource = view->resource;
1093 struct wined3d_view_desc *desc = &view->desc;
1094 const struct wined3d_gl_info *gl_info;
1096 gl_info = &resource->device->adapter->gl_info;
1098 if (resource->type == WINED3D_RTYPE_BUFFER)
1100 struct wined3d_buffer *buffer = buffer_from_resource(resource);
1101 struct wined3d_context *context;
1103 context = context_acquire(resource->device, NULL, 0);
1104 gl_info = context->gl_info;
1105 create_buffer_view(&view->gl_view, context, desc, buffer, view->format);
1106 if (desc->flags & (WINED3D_VIEW_BUFFER_COUNTER | WINED3D_VIEW_BUFFER_APPEND))
1108 static const GLuint initial_value = 0;
1109 GL_EXTCALL(glGenBuffers(1, &view->counter_bo));
1110 GL_EXTCALL(glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, view->counter_bo));
1111 GL_EXTCALL(glBufferData(GL_ATOMIC_COUNTER_BUFFER,
1112 sizeof(initial_value), &initial_value, GL_STATIC_DRAW));
1113 checkGLcall("create atomic counter buffer");
1115 context_release(context);
1117 else
1119 struct wined3d_texture *texture = texture_from_resource(resource);
1120 unsigned int depth_or_layer_count;
1122 if (resource->type == WINED3D_RTYPE_TEXTURE_3D)
1123 depth_or_layer_count = wined3d_texture_get_level_depth(texture, desc->u.texture.level_idx);
1124 else
1125 depth_or_layer_count = texture->layer_count;
1127 if (desc->u.texture.layer_idx || desc->u.texture.layer_count != depth_or_layer_count)
1129 create_texture_view(&view->gl_view, get_texture_view_target(gl_info, desc, texture),
1130 desc, texture, view->format);
1135 static HRESULT wined3d_unordered_access_view_init(struct wined3d_unordered_access_view *view,
1136 const struct wined3d_view_desc *desc, struct wined3d_resource *resource,
1137 void *parent, const struct wined3d_parent_ops *parent_ops)
1139 view->refcount = 1;
1140 view->parent = parent;
1141 view->parent_ops = parent_ops;
1143 if (!(view->format = validate_resource_view(desc, resource, TRUE, FALSE)))
1144 return E_INVALIDARG;
1145 view->desc = *desc;
1147 wined3d_resource_incref(view->resource = resource);
1149 wined3d_cs_init_object(resource->device->cs, wined3d_unordered_access_view_cs_init, view);
1151 return WINED3D_OK;
1154 HRESULT CDECL wined3d_unordered_access_view_create(const struct wined3d_view_desc *desc,
1155 struct wined3d_resource *resource, void *parent, const struct wined3d_parent_ops *parent_ops,
1156 struct wined3d_unordered_access_view **view)
1158 struct wined3d_unordered_access_view *object;
1159 HRESULT hr;
1161 TRACE("desc %p, resource %p, parent %p, parent_ops %p, view %p.\n",
1162 desc, resource, parent, parent_ops, view);
1164 if (!(object = heap_alloc_zero(sizeof(*object))))
1165 return E_OUTOFMEMORY;
1167 if (FAILED(hr = wined3d_unordered_access_view_init(object, desc, resource, parent, parent_ops)))
1169 heap_free(object);
1170 WARN("Failed to initialise view, hr %#x.\n", hr);
1171 return hr;
1174 TRACE("Created unordered access view %p.\n", object);
1175 *view = object;
1177 return WINED3D_OK;