Merge PR #283 "[USBPORT] Transaction Translator (TT) support bringup"
[reactos.git] / dll / directx / wine / wined3d / view.c
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 }