view.c 76.7 KB
Newer Older
1
/*
2
 * Copyright 2009, 2011 Henri Verbeet for CodeWeavers
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 *
 */

#include "config.h"
#include "wine/port.h"

#include "wined3d_private.h"

WINE_DEFAULT_DEBUG_CHANNEL(d3d);

27 28
#define WINED3D_VIEW_CUBE_ARRAY (WINED3D_VIEW_TEXTURE_CUBE | WINED3D_VIEW_TEXTURE_ARRAY)

29 30 31 32 33 34
static BOOL is_stencil_view_format(const struct wined3d_format *format)
{
    return format->id == WINED3DFMT_X24_TYPELESS_G8_UINT
            || 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_gl *texture_gl)
37 38 39 40 41 42
{
    static const struct
    {
        GLenum texture_target;
        unsigned int view_flags;
        GLenum view_target;
43
        enum wined3d_gl_extension extension;
44 45 46
    }
    view_types[] =
    {
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
        {GL_TEXTURE_CUBE_MAP,  0, GL_TEXTURE_CUBE_MAP},
        {GL_TEXTURE_RECTANGLE, 0, GL_TEXTURE_RECTANGLE},
        {GL_TEXTURE_3D,        0, GL_TEXTURE_3D},

        {GL_TEXTURE_2D,       0,                          GL_TEXTURE_2D},
        {GL_TEXTURE_2D,       WINED3D_VIEW_TEXTURE_ARRAY, GL_TEXTURE_2D_ARRAY},
        {GL_TEXTURE_2D_ARRAY, 0,                          GL_TEXTURE_2D},
        {GL_TEXTURE_2D_ARRAY, WINED3D_VIEW_TEXTURE_ARRAY, GL_TEXTURE_2D_ARRAY},
        {GL_TEXTURE_2D_ARRAY, WINED3D_VIEW_TEXTURE_CUBE,  GL_TEXTURE_CUBE_MAP},
        {GL_TEXTURE_2D_ARRAY, WINED3D_VIEW_CUBE_ARRAY,    GL_TEXTURE_CUBE_MAP_ARRAY, ARB_TEXTURE_CUBE_MAP_ARRAY},

        {GL_TEXTURE_2D_MULTISAMPLE,       0,                          GL_TEXTURE_2D_MULTISAMPLE},
        {GL_TEXTURE_2D_MULTISAMPLE,       WINED3D_VIEW_TEXTURE_ARRAY, GL_TEXTURE_2D_MULTISAMPLE_ARRAY},
        {GL_TEXTURE_2D_MULTISAMPLE_ARRAY, 0,                          GL_TEXTURE_2D_MULTISAMPLE},
        {GL_TEXTURE_2D_MULTISAMPLE_ARRAY, WINED3D_VIEW_TEXTURE_ARRAY, GL_TEXTURE_2D_MULTISAMPLE_ARRAY},
62 63 64 65 66

        {GL_TEXTURE_1D,       0,                          GL_TEXTURE_1D},
        {GL_TEXTURE_1D,       WINED3D_VIEW_TEXTURE_ARRAY, GL_TEXTURE_1D_ARRAY},
        {GL_TEXTURE_1D_ARRAY, 0,                          GL_TEXTURE_1D},
        {GL_TEXTURE_1D_ARRAY, WINED3D_VIEW_TEXTURE_ARRAY, GL_TEXTURE_1D_ARRAY},
67
    };
68 69
    unsigned int flags = desc->flags & (WINED3D_VIEW_BUFFER_RAW | WINED3D_VIEW_BUFFER_APPEND
            | WINED3D_VIEW_BUFFER_COUNTER | WINED3D_VIEW_TEXTURE_CUBE | WINED3D_VIEW_TEXTURE_ARRAY);
70 71 72 73
    unsigned int i;

    for (i = 0; i < ARRAY_SIZE(view_types); ++i)
    {
74
        if (view_types[i].texture_target != texture_gl->target || view_types[i].view_flags != flags)
75 76
            continue;
        if (gl_info->supported[view_types[i].extension])
77
            return view_types[i].view_target;
78 79

        FIXME("Extension %#x not supported.\n", view_types[i].extension);
80 81
    }

82
    FIXME("Unhandled view flags %#x for texture target %#x.\n", flags, texture_gl->target);
83
    return texture_gl->target;
84 85
}

86
static const struct wined3d_format *validate_resource_view(const struct wined3d_view_desc *desc,
87
        struct wined3d_resource *resource, BOOL mip_slice, BOOL allow_srgb_toggle)
88
{
89
    const struct wined3d_adapter *adapter = resource->device->adapter;
90 91
    const struct wined3d_format *format;

92
    format = wined3d_get_format(adapter, desc->format_id, resource->bind_flags);
93 94 95 96 97 98 99 100
    if (resource->type == WINED3D_RTYPE_BUFFER && (desc->flags & WINED3D_VIEW_BUFFER_RAW))
    {
        if (format->id != WINED3DFMT_R32_TYPELESS)
        {
            WARN("Invalid format %s for raw buffer view.\n", debug_d3dformat(format->id));
            return NULL;
        }

101
        format = wined3d_get_format(adapter, WINED3DFMT_R32_UINT, resource->bind_flags);
102 103 104 105 106 107 108 109 110 111 112 113 114
    }

    if (wined3d_format_is_typeless(format))
    {
        WARN("Trying to create view for typeless format %s.\n", debug_d3dformat(format->id));
        return NULL;
    }

    if (resource->type == WINED3D_RTYPE_BUFFER)
    {
        struct wined3d_buffer *buffer = buffer_from_resource(resource);
        unsigned int buffer_size, element_size;

115
        if (buffer->structure_byte_stride)
116 117 118 119 120 121 122
        {
            if (desc->format_id != WINED3DFMT_UNKNOWN)
            {
                WARN("Invalid format %s for structured buffer view.\n", debug_d3dformat(desc->format_id));
                return NULL;
            }

123
            format = wined3d_get_format(adapter, WINED3DFMT_R32_UINT, resource->bind_flags);
124
            element_size = buffer->structure_byte_stride;
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
        }
        else
        {
            element_size = format->byte_count;
        }

        if (!element_size)
            return NULL;

        buffer_size = buffer->resource.size / element_size;
        if (desc->u.buffer.start_idx >= buffer_size
                || desc->u.buffer.count > buffer_size - desc->u.buffer.start_idx)
            return NULL;
    }
    else
    {
        struct wined3d_texture *texture = texture_from_resource(resource);
        unsigned int depth_or_layer_count;

144
        if (resource->format->id != format->id && !wined3d_format_is_typeless(resource->format)
145
                && (!allow_srgb_toggle || !wined3d_formats_are_srgb_variants(resource->format->id, format->id)))
146 147 148 149 150 151
        {
            WARN("Trying to create incompatible view for non typeless format %s.\n",
                    debug_d3dformat(format->id));
            return NULL;
        }

152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
        if (mip_slice && resource->type == WINED3D_RTYPE_TEXTURE_3D)
            depth_or_layer_count = wined3d_texture_get_level_depth(texture, desc->u.texture.level_idx);
        else
            depth_or_layer_count = texture->layer_count;

        if (!desc->u.texture.level_count
                || (mip_slice && desc->u.texture.level_count != 1)
                || desc->u.texture.level_idx >= texture->level_count
                || desc->u.texture.level_count > texture->level_count - desc->u.texture.level_idx
                || !desc->u.texture.layer_count
                || desc->u.texture.layer_idx >= depth_or_layer_count
                || desc->u.texture.layer_count > depth_or_layer_count - desc->u.texture.layer_idx)
            return NULL;
    }

    return format;
}

170
static void create_texture_view(struct wined3d_gl_view *view, GLenum view_target,
171
        const struct wined3d_view_desc *desc, struct wined3d_texture_gl *texture_gl,
172 173
        const struct wined3d_format *view_format)
{
174
    const struct wined3d_format_gl *view_format_gl;
175
    unsigned int level_idx, layer_idx, layer_count;
176
    const struct wined3d_gl_info *gl_info;
177
    struct wined3d_context_gl *context_gl;
178
    struct wined3d_context *context;
179
    GLuint texture_name;
180

181
    view_format_gl = wined3d_format_gl(view_format);
182 183
    view->target = view_target;

184
    context = context_acquire(texture_gl->t.resource.device, NULL, 0);
185
    context_gl = wined3d_context_gl(context);
186
    gl_info = context_gl->gl_info;
187 188 189 190 191 192 193 194

    if (!gl_info->supported[ARB_TEXTURE_VIEW])
    {
        context_release(context);
        FIXME("OpenGL implementation does not support texture views.\n");
        return;
    }

195
    wined3d_texture_gl_prepare_texture(texture_gl, context_gl, FALSE);
196
    texture_name = wined3d_texture_gl_get_texture_name(texture_gl, context, FALSE);
197

198
    level_idx = desc->u.texture.level_idx;
199 200
    layer_idx = desc->u.texture.layer_idx;
    layer_count = desc->u.texture.layer_count;
201
    if (view_target == GL_TEXTURE_3D)
202
    {
203
        if (layer_idx || layer_count != wined3d_texture_get_level_depth(&texture_gl->t, level_idx))
204
            FIXME("Depth slice (%u-%u) not supported.\n", layer_idx, layer_count);
205 206 207 208
        layer_idx = 0;
        layer_count = 1;
    }

209
    gl_info->gl_ops.gl.p_glGenTextures(1, &view->name);
210
    GL_EXTCALL(glTextureView(view->name, view->target, texture_name, view_format_gl->internal,
211 212
            level_idx, desc->u.texture.level_count, layer_idx, layer_count));
    checkGLcall("create texture view");
213

214
    if (is_stencil_view_format(view_format))
215 216 217 218 219 220 221 222 223 224
    {
        static const GLint swizzle[] = {GL_ZERO, GL_RED, GL_ZERO, GL_ZERO};

        if (!gl_info->supported[ARB_STENCIL_TEXTURING])
        {
            context_release(context);
            FIXME("OpenGL implementation does not support stencil texturing.\n");
            return;
        }

225
        wined3d_context_gl_bind_texture(context_gl, view->target, view->name);
226 227
        gl_info->gl_ops.gl.p_glTexParameteriv(view->target, GL_TEXTURE_SWIZZLE_RGBA, swizzle);
        gl_info->gl_ops.gl.p_glTexParameteri(view->target, GL_DEPTH_STENCIL_TEXTURE_MODE, GL_STENCIL_INDEX);
228
        checkGLcall("initialize stencil view");
229

230 231
        context_invalidate_compute_state(context, STATE_COMPUTE_SHADER_RESOURCE_BINDING);
        context_invalidate_state(context, STATE_GRAPHICS_SHADER_RESOURCE_BINDING);
232
    }
233
    else if (!is_identity_fixup(view_format->color_fixup) && can_use_texture_swizzle(context->d3d_info, view_format))
234 235 236
    {
        GLint swizzle[4];

237
        wined3d_context_gl_bind_texture(context_gl, view->target, view->name);
238 239 240
        wined3d_gl_texture_swizzle_from_color_fixup(swizzle, view_format->color_fixup);
        gl_info->gl_ops.gl.p_glTexParameteriv(view->target, GL_TEXTURE_SWIZZLE_RGBA, swizzle);
        checkGLcall("set format swizzle");
241 242 243

        context_invalidate_compute_state(context, STATE_COMPUTE_SHADER_RESOURCE_BINDING);
        context_invalidate_state(context, STATE_GRAPHICS_SHADER_RESOURCE_BINDING);
244
    }
245 246 247 248

    context_release(context);
}

249 250
static void create_buffer_texture(struct wined3d_gl_view *view, struct wined3d_context_gl *context_gl,
        struct wined3d_buffer_gl *buffer_gl, const struct wined3d_format_gl *view_format_gl,
251
        unsigned int offset, unsigned int size)
252
{
253
    const struct wined3d_gl_info *gl_info = context_gl->gl_info;
254 255 256 257 258 259 260

    if (!gl_info->supported[ARB_TEXTURE_BUFFER_OBJECT])
    {
        FIXME("OpenGL implementation does not support buffer textures.\n");
        return;
    }

261 262 263 264 265 266 267
    if ((offset & (gl_info->limits.texture_buffer_offset_alignment - 1)))
    {
        FIXME("Buffer offset %u is not %u byte aligned.\n",
                offset, gl_info->limits.texture_buffer_offset_alignment);
        return;
    }

268
    wined3d_buffer_load_location(&buffer_gl->b, &context_gl->c, WINED3D_LOCATION_BUFFER);
269 270

    view->target = GL_TEXTURE_BUFFER;
271 272
    if (!view->name)
        gl_info->gl_ops.gl.p_glGenTextures(1, &view->name);
273

274
    wined3d_context_gl_bind_texture(context_gl, GL_TEXTURE_BUFFER, view->name);
275 276
    if (gl_info->supported[ARB_TEXTURE_BUFFER_RANGE])
    {
277
        GL_EXTCALL(glTexBufferRange(GL_TEXTURE_BUFFER, view_format_gl->internal, buffer_gl->bo.id, offset, size));
278 279 280
    }
    else
    {
281
        if (offset || size != buffer_gl->b.resource.size)
282
            FIXME("OpenGL implementation does not support ARB_texture_buffer_range.\n");
283
        GL_EXTCALL(glTexBuffer(GL_TEXTURE_BUFFER, view_format_gl->internal, buffer_gl->bo.id));
284
    }
285 286
    checkGLcall("Create buffer texture");

287 288
    context_invalidate_compute_state(&context_gl->c, STATE_COMPUTE_SHADER_RESOURCE_BINDING);
    context_invalidate_state(&context_gl->c, STATE_GRAPHICS_SHADER_RESOURCE_BINDING);
289 290
}

291 292 293
static void get_buffer_view_range(const struct wined3d_buffer *buffer,
        const struct wined3d_view_desc *desc, const struct wined3d_format *view_format,
        unsigned int *offset, unsigned int *size)
294 295 296
{
    if (desc->format_id == WINED3DFMT_UNKNOWN)
    {
297 298
        *offset = desc->u.buffer.start_idx * buffer->structure_byte_stride;
        *size = desc->u.buffer.count * buffer->structure_byte_stride;
299 300 301
    }
    else
    {
302 303
        *offset = desc->u.buffer.start_idx * view_format->byte_count;
        *size = desc->u.buffer.count * view_format->byte_count;
304
    }
305
}
306

307 308 309 310 311 312 313
static void create_buffer_view(struct wined3d_gl_view *view, struct wined3d_context *context,
        const struct wined3d_view_desc *desc, struct wined3d_buffer *buffer,
        const struct wined3d_format *view_format)
{
    unsigned int offset, size;

    get_buffer_view_range(buffer, desc, view_format, &offset, &size);
314 315
    create_buffer_texture(view, wined3d_context_gl(context),
            wined3d_buffer_gl(buffer), wined3d_format_gl(view_format), offset, size);
316 317
}

318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337
static void wined3d_view_invalidate_location(struct wined3d_resource *resource,
        const struct wined3d_view_desc *desc, DWORD location)
{
    unsigned int i, sub_resource_idx, layer_count;
    struct wined3d_texture *texture;

    if (resource->type == WINED3D_RTYPE_BUFFER)
    {
        wined3d_buffer_invalidate_location(buffer_from_resource(resource), location);
        return;
    }

    texture = texture_from_resource(resource);

    sub_resource_idx = desc->u.texture.layer_idx * texture->level_count + desc->u.texture.level_idx;
    layer_count = resource->type != WINED3D_RTYPE_TEXTURE_3D ? desc->u.texture.layer_count : 1;
    for (i = 0; i < layer_count; ++i, sub_resource_idx += texture->level_count)
        wined3d_texture_invalidate_location(texture, sub_resource_idx, location);
}

338
ULONG CDECL wined3d_rendertarget_view_incref(struct wined3d_rendertarget_view *view)
339
{
340
    ULONG refcount = InterlockedIncrement(&view->refcount);
341

342
    TRACE("%p increasing refcount to %u.\n", view, refcount);
343 344 345 346

    return refcount;
}

347
void wined3d_rendertarget_view_cleanup(struct wined3d_rendertarget_view *view)
348
{
349 350 351 352
    /* Call wined3d_object_destroyed() before releasing the resource,
     * since releasing the resource may end up destroying the parent. */
    view->parent_ops->wined3d_object_destroyed(view->parent);
    wined3d_resource_decref(view->resource);
353 354
}

355
ULONG CDECL wined3d_rendertarget_view_decref(struct wined3d_rendertarget_view *view)
356
{
357
    ULONG refcount = InterlockedDecrement(&view->refcount);
358

359
    TRACE("%p decreasing refcount to %u.\n", view, refcount);
360 361

    if (!refcount)
362
        view->resource->device->adapter->adapter_ops->adapter_destroy_rendertarget_view(view);
363 364 365 366

    return refcount;
}

367
void * CDECL wined3d_rendertarget_view_get_parent(const struct wined3d_rendertarget_view *view)
368
{
369
    TRACE("view %p.\n", view);
370

371
    return view->parent;
372 373
}

374 375
void * CDECL wined3d_rendertarget_view_get_sub_resource_parent(const struct wined3d_rendertarget_view *view)
{
376
    struct wined3d_texture *texture;
377 378 379 380 381 382

    TRACE("view %p.\n", view);

    if (view->resource->type == WINED3D_RTYPE_BUFFER)
        return wined3d_buffer_get_parent(buffer_from_resource(view->resource));

383
    texture = texture_from_resource(view->resource);
384

385
    return texture->sub_resources[view->sub_resource_idx].parent;
386 387 388 389 390 391 392 393 394
}

void CDECL wined3d_rendertarget_view_set_parent(struct wined3d_rendertarget_view *view, void *parent)
{
    TRACE("view %p, parent %p.\n", view, parent);

    view->parent = parent;
}

395
struct wined3d_resource * CDECL wined3d_rendertarget_view_get_resource(const struct wined3d_rendertarget_view *view)
396
{
397
    TRACE("view %p.\n", view);
398

399
    return view->resource;
400 401
}

402 403
void wined3d_rendertarget_view_get_drawable_size(const struct wined3d_rendertarget_view *view,
        const struct wined3d_context *context, unsigned int *width, unsigned int *height)
404
{
405 406 407 408
    const struct wined3d_texture *texture;

    if (view->resource->type != WINED3D_RTYPE_TEXTURE_2D)
    {
409 410
        *width = view->width;
        *height = view->height;
411 412 413 414 415
        return;
    }

    texture = texture_from_resource(view->resource);
    if (texture->swapchain)
416 417 418 419
    {
        /* The drawable size of an onscreen drawable is the surface size.
         * (Actually: The window size, but the surface is created in window
         * size.) */
420 421
        *width = texture->resource.width;
        *height = texture->resource.height;
422 423 424
    }
    else if (wined3d_settings.offscreen_rendering_mode == ORM_BACKBUFFER)
    {
425
        const struct wined3d_swapchain_desc *desc = &context->swapchain->state.desc;
426 427 428 429

        /* The drawable size of a backbuffer / aux buffer offscreen target is
         * the size of the current context's drawable, which is the size of
         * the back buffer of the swapchain the active context belongs to. */
430 431
        *width = desc->backbuffer_width;
        *height = desc->backbuffer_height;
432 433 434
    }
    else
    {
435
        unsigned int level_idx = view->sub_resource_idx % texture->level_count;
436 437 438

        /* The drawable size of an FBO target is the OpenGL texture size,
         * which is the power of two size. */
439 440
        *width = wined3d_texture_get_level_pow2_width(texture, level_idx);
        *height = wined3d_texture_get_level_pow2_height(texture, level_idx);
441 442 443
    }
}

444 445 446 447
void wined3d_rendertarget_view_prepare_location(struct wined3d_rendertarget_view *view,
        struct wined3d_context *context, DWORD location)
{
    struct wined3d_resource *resource = view->resource;
448
    unsigned int i, sub_resource_idx, layer_count;
449 450 451 452 453 454 455 456 457 458
    struct wined3d_texture *texture;

    if (resource->type == WINED3D_RTYPE_BUFFER)
    {
        FIXME("Not implemented for resources %s.\n", debug_d3dresourcetype(resource->type));
        return;
    }

    texture = texture_from_resource(resource);
    sub_resource_idx = view->sub_resource_idx;
459 460
    layer_count = resource->type != WINED3D_RTYPE_TEXTURE_3D ? view->layer_count : 1;
    for (i = 0; i < layer_count; ++i, sub_resource_idx += texture->level_count)
461 462 463
        wined3d_texture_prepare_location(texture, sub_resource_idx, context, location);
}

464 465 466 467
void wined3d_rendertarget_view_load_location(struct wined3d_rendertarget_view *view,
        struct wined3d_context *context, DWORD location)
{
    struct wined3d_resource *resource = view->resource;
468
    unsigned int i, sub_resource_idx, layer_count;
469 470 471 472 473 474 475 476 477 478
    struct wined3d_texture *texture;

    if (resource->type == WINED3D_RTYPE_BUFFER)
    {
        wined3d_buffer_load_location(buffer_from_resource(resource), context, location);
        return;
    }

    texture = texture_from_resource(resource);
    sub_resource_idx = view->sub_resource_idx;
479 480
    layer_count = resource->type != WINED3D_RTYPE_TEXTURE_3D ? view->layer_count : 1;
    for (i = 0; i < layer_count; ++i, sub_resource_idx += texture->level_count)
481 482 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)
{
    struct wined3d_resource *resource = view->resource;
487
    unsigned int i, sub_resource_idx, layer_count;
488 489 490 491 492 493 494 495 496 497
    struct wined3d_texture *texture;

    if (resource->type == WINED3D_RTYPE_BUFFER)
    {
        FIXME("Not implemented for resources %s.\n", debug_d3dresourcetype(resource->type));
        return;
    }

    texture = texture_from_resource(resource);
    sub_resource_idx = view->sub_resource_idx;
498 499
    layer_count = resource->type != WINED3D_RTYPE_TEXTURE_3D ? view->layer_count : 1;
    for (i = 0; i < layer_count; ++i, sub_resource_idx += texture->level_count)
500 501 502
        wined3d_texture_validate_location(texture, sub_resource_idx, location);
}

503 504 505 506 507
void wined3d_rendertarget_view_invalidate_location(struct wined3d_rendertarget_view *view, DWORD location)
{
    wined3d_view_invalidate_location(view->resource, &view->desc, location);
}

508
static void wined3d_render_target_view_gl_cs_init(void *object)
509
{
510 511 512
    struct wined3d_rendertarget_view_gl *view_gl = object;
    struct wined3d_resource *resource = view_gl->v.resource;
    const struct wined3d_view_desc *desc = &view_gl->v.desc;
513

514 515
    TRACE("view_gl %p.\n", view_gl);

516 517 518 519 520 521
    if (resource->type == WINED3D_RTYPE_BUFFER)
    {
        FIXME("Not implemented for resources %s.\n", debug_d3dresourcetype(resource->type));
    }
    else
    {
522
        struct wined3d_texture_gl *texture_gl = wined3d_texture_gl(texture_from_resource(resource));
523 524 525
        unsigned int depth_or_layer_count;

        if (resource->type == WINED3D_RTYPE_TEXTURE_3D)
526
            depth_or_layer_count = wined3d_texture_get_level_depth(&texture_gl->t, desc->u.texture.level_idx);
527
        else
528
            depth_or_layer_count = texture_gl->t.layer_count;
529

530 531
        if (resource->format->id != view_gl->v.format->id
                || (view_gl->v.layer_count != 1 && view_gl->v.layer_count != depth_or_layer_count))
532
        {
533 534 535
            GLenum resource_class, view_class;

            resource_class = wined3d_format_gl(resource->format)->view_class;
536
            view_class = wined3d_format_gl(view_gl->v.format)->view_class;
537
            if (resource_class != view_class)
538 539
            {
                FIXME("Render target view not supported, resource format %s, view format %s.\n",
540
                        debug_d3dformat(resource->format->id), debug_d3dformat(view_gl->v.format->id));
541 542
                return;
            }
543
            if (texture_gl->t.swapchain && texture_gl->t.swapchain->state.desc.backbuffer_count > 1)
544 545 546 547 548
            {
                FIXME("Swapchain views not supported.\n");
                return;
            }

549
            create_texture_view(&view_gl->gl_view, texture_gl->target, desc, texture_gl, view_gl->v.format);
550 551 552 553
        }
    }
}

554
static HRESULT wined3d_rendertarget_view_init(struct wined3d_rendertarget_view *view,
555
        const struct wined3d_view_desc *desc, struct wined3d_resource *resource,
556
        void *parent, const struct wined3d_parent_ops *parent_ops)
557
{
558 559
    BOOL allow_srgb_toggle = FALSE;

560 561
    view->refcount = 1;
    view->parent = parent;
562
    view->parent_ops = parent_ops;
563

564 565 566 567 568 569 570 571
    if (resource->type != WINED3D_RTYPE_BUFFER)
    {
        struct wined3d_texture *texture = texture_from_resource(resource);

        if (texture->swapchain)
            allow_srgb_toggle = TRUE;
    }
    if (!(view->format = validate_resource_view(desc, resource, TRUE, allow_srgb_toggle)))
572
        return E_INVALIDARG;
573
    view->format_flags = view->format->flags[resource->gl_type];
574
    view->desc = *desc;
575

576 577 578
    if (resource->type == WINED3D_RTYPE_BUFFER)
    {
        view->sub_resource_idx = 0;
579
        view->layer_count = 1;
580 581 582 583 584
        view->width = desc->u.buffer.count;
        view->height = 1;
    }
    else
    {
585
        struct wined3d_texture *texture = texture_from_resource(resource);
586 587 588 589

        view->sub_resource_idx = desc->u.texture.level_idx;
        if (resource->type != WINED3D_RTYPE_TEXTURE_3D)
            view->sub_resource_idx += desc->u.texture.layer_idx * texture->level_count;
590
        view->layer_count = desc->u.texture.layer_count;
591 592
        view->width = wined3d_texture_get_level_width(texture, desc->u.texture.level_idx);
        view->height = wined3d_texture_get_level_height(texture, desc->u.texture.level_idx);
593
    }
594

595 596 597
    wined3d_resource_incref(view->resource = resource);

    return WINED3D_OK;
598
}
599

600 601 602
HRESULT wined3d_rendertarget_view_no3d_init(struct wined3d_rendertarget_view *view_no3d,
        const struct wined3d_view_desc *desc, struct wined3d_resource *resource,
        void *parent, const struct wined3d_parent_ops *parent_ops)
603
{
604 605
    TRACE("view_no3d %p, desc %s, resource %p, parent %p, parent_ops %p.\n",
            view_no3d, wined3d_debug_view_desc(desc, resource), resource, parent, parent_ops);
606

607 608
    return wined3d_rendertarget_view_init(view_no3d, desc, resource, parent, parent_ops);
}
609

610 611 612 613 614
HRESULT wined3d_rendertarget_view_gl_init(struct wined3d_rendertarget_view_gl *view_gl,
        const struct wined3d_view_desc *desc, struct wined3d_resource *resource,
        void *parent, const struct wined3d_parent_ops *parent_ops)
{
    HRESULT hr;
615

616 617
    TRACE("view_gl %p, desc %s, resource %p, parent %p, parent_ops %p.\n",
            view_gl, wined3d_debug_view_desc(desc, resource), resource, parent, parent_ops);
618

619 620
    if (FAILED(hr = wined3d_rendertarget_view_init(&view_gl->v, desc, resource, parent, parent_ops)))
        return hr;
621

622
    wined3d_cs_init_object(resource->device->cs, wined3d_render_target_view_gl_cs_init, view_gl);
623

624
    return hr;
625
}
626

627
VkImageViewType vk_image_view_type_from_wined3d(enum wined3d_resource_type type, uint32_t flags)
628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658
{
    switch (type)
    {
        case WINED3D_RTYPE_TEXTURE_1D:
            if (flags & WINED3D_VIEW_TEXTURE_ARRAY)
                return VK_IMAGE_VIEW_TYPE_1D_ARRAY;
            else
                return VK_IMAGE_VIEW_TYPE_1D;

        case WINED3D_RTYPE_TEXTURE_2D:
            if (flags & WINED3D_VIEW_TEXTURE_CUBE)
            {
                if (flags & WINED3D_VIEW_TEXTURE_ARRAY)
                    return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
                else
                    return VK_IMAGE_VIEW_TYPE_CUBE;
            }
            if (flags & WINED3D_VIEW_TEXTURE_ARRAY)
                return VK_IMAGE_VIEW_TYPE_2D_ARRAY;
            else
                return VK_IMAGE_VIEW_TYPE_2D;

        case WINED3D_RTYPE_TEXTURE_3D:
            return VK_IMAGE_VIEW_TYPE_3D;

        default:
            ERR("Unhandled resource type %s.\n", debug_d3dresourcetype(type));
            return ~0u;
    }
}

659
static VkBufferView wined3d_view_vk_create_vk_buffer_view(struct wined3d_context_vk *context_vk,
660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690
        const struct wined3d_view_desc *desc, struct wined3d_buffer_vk *buffer_vk,
        const struct wined3d_format_vk *view_format_vk)
{
    const struct wined3d_vk_info *vk_info = context_vk->vk_info;
    VkBufferViewCreateInfo create_info;
    struct wined3d_device_vk *device_vk;
    VkBufferView vk_buffer_view;
    unsigned int offset, size;
    VkResult vr;

    get_buffer_view_range(&buffer_vk->b, desc, &view_format_vk->f, &offset, &size);
    wined3d_buffer_prepare_location(&buffer_vk->b, &context_vk->c, WINED3D_LOCATION_BUFFER);

    create_info.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO;
    create_info.pNext = NULL;
    create_info.flags = 0;
    create_info.buffer = buffer_vk->bo.vk_buffer;
    create_info.format = view_format_vk->vk_format;
    create_info.offset = buffer_vk->bo.buffer_offset + offset;
    create_info.range = size;

    device_vk = wined3d_device_vk(buffer_vk->b.resource.device);
    if ((vr = VK_CALL(vkCreateBufferView(device_vk->vk_device, &create_info, NULL, &vk_buffer_view))) < 0)
    {
        ERR("Failed to create buffer view, vr %s.\n", wined3d_debug_vkresult(vr));
        return VK_NULL_HANDLE;
    }

    return vk_buffer_view;
}

691
static VkImageView wined3d_view_vk_create_vk_image_view(struct wined3d_context_vk *context_vk,
692
        const struct wined3d_view_desc *desc, struct wined3d_texture_vk *texture_vk,
693
        const struct wined3d_format_vk *view_format_vk, struct color_fixup_desc fixup, bool rtv)
694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732
{
    const struct wined3d_resource *resource = &texture_vk->t.resource;
    const struct wined3d_vk_info *vk_info = context_vk->vk_info;
    const struct wined3d_format_vk *format_vk;
    struct wined3d_device_vk *device_vk;
    VkImageViewCreateInfo create_info;
    VkImageView vk_image_view;
    VkResult vr;

    device_vk = wined3d_device_vk(resource->device);

    if (!wined3d_texture_vk_prepare_texture(texture_vk, context_vk))
    {
        ERR("Failed to prepare texture.\n");
        return VK_NULL_HANDLE;
    }

    /* Depth formats are a little complicated. For example, the typeless
     * format corresponding to depth/stencil view format WINED3DFMT_D32_FLOAT
     * is WINED3DFMT_R32_TYPELESS, and the corresponding shader resource view
     * format would be WINED3DFMT_R32_FLOAT. Vulkan depth/stencil formats are
     * only compatible with themselves, so it's not possible to create e.g. a
     * VK_FORMAT_R32_SFLOAT view on a VK_FORMAT_D32_SFLOAT image. In order to
     * make it work, we create Vulkan images for WINED3DFMT_R32_TYPELESS
     * resources with either a depth format (VK_FORMAT_D32_SFLOAT) or a colour
     * format, depending on whether the bind flags include
     * WINED3D_BIND_DEPTH_STENCIL or not. In order to then create a Vulkan
     * view on the image, we then replace the view format here with the
     * underlying resource format. However, that means it's still not possible
     * to create e.g. a WINED3DFMT_R32_UINT view on a WINED3DFMT_R32_TYPELESS
     * depth/stencil resource. */
    if (resource->bind_flags & WINED3D_BIND_DEPTH_STENCIL)
        format_vk = wined3d_format_vk(resource->format);
    else
        format_vk = view_format_vk;

    create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
    create_info.pNext = NULL;
    create_info.flags = 0;
733
    create_info.image = texture_vk->image.vk_image;
734
    create_info.viewType = vk_image_view_type_from_wined3d(resource->type, desc->flags);
735
    if (rtv && create_info.viewType == VK_IMAGE_VIEW_TYPE_3D)
736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775
    {
        if (desc->u.texture.layer_count > 1)
            create_info.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
        else
            create_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
    }
    create_info.format = format_vk->vk_format;
    if (is_stencil_view_format(&view_format_vk->f))
    {
        create_info.components.r = VK_COMPONENT_SWIZZLE_ZERO;
        create_info.components.g = VK_COMPONENT_SWIZZLE_R;
        create_info.components.b = VK_COMPONENT_SWIZZLE_ZERO;
        create_info.components.a = VK_COMPONENT_SWIZZLE_ZERO;
    }
    else if (is_identity_fixup(fixup) || !can_use_texture_swizzle(context_vk->c.d3d_info, &format_vk->f))
    {
        create_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
        create_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
        create_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
        create_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
    }
    else
    {
        wined3d_vk_swizzle_from_color_fixup(&create_info.components, fixup);
    }
    if ((resource->bind_flags & WINED3D_BIND_DEPTH_STENCIL)
            && (view_format_vk->f.red_size || view_format_vk->f.green_size))
    {
        create_info.subresourceRange.aspectMask = 0;
        if (view_format_vk->f.red_size)
            create_info.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
        if (view_format_vk->f.green_size)
            create_info.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
    }
    else
    {
        create_info.subresourceRange.aspectMask = vk_aspect_mask_from_format(&format_vk->f);
    }
    create_info.subresourceRange.baseMipLevel = desc->u.texture.level_idx;
    create_info.subresourceRange.levelCount = desc->u.texture.level_count;
776 777 778 779 780 781 782 783 784 785 786 787 788
    if (create_info.viewType == VK_IMAGE_VIEW_TYPE_3D)
    {
        if (desc->u.texture.layer_idx || (desc->u.texture.layer_count != texture_vk->t.resource.depth
                && desc->u.texture.layer_count != ~0u))
            WARN("Partial 3D texture views are not supported.\n");
        create_info.subresourceRange.baseArrayLayer = 0;
        create_info.subresourceRange.layerCount = 1;
    }
    else
    {
        create_info.subresourceRange.baseArrayLayer = desc->u.texture.layer_idx;
        create_info.subresourceRange.layerCount = desc->u.texture.layer_count;
    }
789 790 791 792 793 794 795 796 797
    if ((vr = VK_CALL(vkCreateImageView(device_vk->vk_device, &create_info, NULL, &vk_image_view))) < 0)
    {
        ERR("Failed to create Vulkan image view, vr %s.\n", wined3d_debug_vkresult(vr));
        return VK_NULL_HANDLE;
    }

    return vk_image_view;
}

798 799 800 801 802 803 804 805 806 807
static void wined3d_render_target_view_vk_cs_init(void *object)
{
    struct wined3d_rendertarget_view_vk *view_vk = object;
    struct wined3d_view_desc *desc = &view_vk->v.desc;
    const struct wined3d_format_vk *format_vk;
    struct wined3d_texture_vk *texture_vk;
    struct wined3d_resource *resource;
    struct wined3d_context *context;
    uint32_t default_flags = 0;

808 809
    TRACE("view_vk %p.\n", view_vk);

810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838
    resource = view_vk->v.resource;
    if (resource->type == WINED3D_RTYPE_BUFFER)
    {
        FIXME("Buffer views not implemented.\n");
        return;
    }

    texture_vk = wined3d_texture_vk(texture_from_resource(resource));
    format_vk = wined3d_format_vk(view_vk->v.format);

    if (texture_vk->t.layer_count > 1)
        default_flags |= WINED3D_VIEW_TEXTURE_ARRAY;

    if (resource->format->id == format_vk->f.id && desc->flags == default_flags
            && !desc->u.texture.level_idx && desc->u.texture.level_count == texture_vk->t.level_count
            && !desc->u.texture.layer_idx && desc->u.texture.layer_count == texture_vk->t.layer_count
            && !is_stencil_view_format(&format_vk->f) && resource->type != WINED3D_RTYPE_TEXTURE_3D
            && is_identity_fixup(format_vk->f.color_fixup))
    {
        TRACE("Creating identity render target view.\n");
        return;
    }

    if (texture_vk->t.swapchain && texture_vk->t.swapchain->state.desc.backbuffer_count > 1)
    {
        FIXME("Swapchain views not supported.\n");
        return;
    }

839
    context = context_acquire(resource->device, NULL, 0);
840
    view_vk->vk_image_view = wined3d_view_vk_create_vk_image_view(wined3d_context_vk(context),
841
            desc, texture_vk, format_vk, COLOR_FIXUP_IDENTITY, true);
842
    context_release(context);
843

844
    if (!view_vk->vk_image_view)
845 846 847 848 849
        return;

    TRACE("Created image view 0x%s.\n", wine_dbgstr_longlong(view_vk->vk_image_view));
}

850 851 852 853
HRESULT wined3d_rendertarget_view_vk_init(struct wined3d_rendertarget_view_vk *view_vk,
        const struct wined3d_view_desc *desc, struct wined3d_resource *resource,
        void *parent, const struct wined3d_parent_ops *parent_ops)
{
854 855
    HRESULT hr;

856 857 858
    TRACE("view_vk %p, desc %s, resource %p, parent %p, parent_ops %p.\n",
            view_vk, wined3d_debug_view_desc(desc, resource), resource, parent, parent_ops);

859 860 861 862 863 864
    if (FAILED(hr = wined3d_rendertarget_view_init(&view_vk->v, desc, resource, parent, parent_ops)))
        return hr;

    wined3d_cs_init_object(resource->device->cs, wined3d_render_target_view_vk_cs_init, view_vk);

    return hr;
865 866 867 868 869 870 871 872 873 874 875 876 877 878 879
}

HRESULT CDECL wined3d_rendertarget_view_create(const struct wined3d_view_desc *desc,
        struct wined3d_resource *resource, void *parent, const struct wined3d_parent_ops *parent_ops,
        struct wined3d_rendertarget_view **view)
{
    const struct wined3d_adapter_ops *adapter_ops;

    TRACE("desc %s, resource %p, parent %p, parent_ops %p, view %p.\n",
            wined3d_debug_view_desc(desc, resource), resource, parent, parent_ops, view);

    adapter_ops = resource->device->adapter->adapter_ops;
    return adapter_ops->adapter_create_rendertarget_view(desc, resource, parent, parent_ops, view);
}

880 881 882 883
HRESULT CDECL wined3d_rendertarget_view_create_from_sub_resource(struct wined3d_texture *texture,
        unsigned int sub_resource_idx, void *parent, const struct wined3d_parent_ops *parent_ops,
        struct wined3d_rendertarget_view **view)
{
884
    struct wined3d_view_desc desc;
885 886 887 888

    TRACE("texture %p, sub_resource_idx %u, parent %p, parent_ops %p, view %p.\n",
            texture, sub_resource_idx, parent, parent_ops, view);

889
    desc.format_id = texture->resource.format->id;
890
    desc.flags = 0;
891
    desc.u.texture.level_idx = sub_resource_idx % texture->level_count;
892
    desc.u.texture.level_count = 1;
893 894
    desc.u.texture.layer_idx = sub_resource_idx / texture->level_count;
    desc.u.texture.layer_count = 1;
895

896
    return wined3d_rendertarget_view_create(&desc, &texture->resource, parent, parent_ops, view);
897 898
}

899 900 901 902 903 904 905 906 907
ULONG CDECL wined3d_shader_resource_view_incref(struct wined3d_shader_resource_view *view)
{
    ULONG refcount = InterlockedIncrement(&view->refcount);

    TRACE("%p increasing refcount to %u.\n", view, refcount);

    return refcount;
}

908
void wined3d_shader_resource_view_cleanup(struct wined3d_shader_resource_view *view)
909
{
910 911 912 913
    /* Call wined3d_object_destroyed() before releasing the resource,
     * since releasing the resource may end up destroying the parent. */
    view->parent_ops->wined3d_object_destroyed(view->parent);
    wined3d_resource_decref(view->resource);
914 915
}

916 917 918 919 920 921 922
ULONG CDECL wined3d_shader_resource_view_decref(struct wined3d_shader_resource_view *view)
{
    ULONG refcount = InterlockedDecrement(&view->refcount);

    TRACE("%p decreasing refcount to %u.\n", view, refcount);

    if (!refcount)
923
        view->resource->device->adapter->adapter_ops->adapter_destroy_shader_resource_view(view);
924 925 926 927

    return refcount;
}

928 929 930 931 932 933 934
void * CDECL wined3d_shader_resource_view_get_parent(const struct wined3d_shader_resource_view *view)
{
    TRACE("view %p.\n", view);

    return view->parent;
}

935 936 937 938 939 940 941 942
void wined3d_shader_resource_view_gl_update(struct wined3d_shader_resource_view_gl *srv_gl,
        struct wined3d_context_gl *context_gl)
{
    create_buffer_view(&srv_gl->gl_view, &context_gl->c, &srv_gl->v.desc,
            buffer_from_resource(srv_gl->v.resource), srv_gl->v.format);
    srv_gl->bo_user.valid = true;
}

943
static void wined3d_shader_resource_view_gl_cs_init(void *object)
944
{
945 946
    struct wined3d_shader_resource_view_gl *view_gl = object;
    struct wined3d_resource *resource = view_gl->v.resource;
947 948 949 950 951
    const struct wined3d_format *view_format;
    const struct wined3d_gl_info *gl_info;
    const struct wined3d_view_desc *desc;
    GLenum view_target;

952 953
    TRACE("view_gl %p.\n", view_gl);

954
    view_format = view_gl->v.format;
955
    gl_info = &resource->device->adapter->gl_info;
956
    desc = &view_gl->v.desc;
957 958 959 960

    if (resource->type == WINED3D_RTYPE_BUFFER)
    {
        struct wined3d_buffer *buffer = buffer_from_resource(resource);
961
        struct wined3d_context *context;
962

963
        context = context_acquire(resource->device, NULL, 0);
964
        create_buffer_view(&view_gl->gl_view, context, desc, buffer, view_format);
965 966
        view_gl->bo_user.valid = true;
        list_add_head(&wined3d_buffer_gl(buffer)->bo.users, &view_gl->bo_user.entry);
967
        context_release(context);
968 969 970
    }
    else
    {
971
        struct wined3d_texture_gl *texture_gl = wined3d_texture_gl(texture_from_resource(resource));
972
        GLenum resource_class, view_class;
973

974 975
        resource_class = wined3d_format_gl(resource->format)->view_class;
        view_class = wined3d_format_gl(view_format)->view_class;
976
        view_target = get_texture_view_target(gl_info, desc, texture_gl);
977

978
        if (resource->format->id == view_format->id && texture_gl->target == view_target
979 980
                && !desc->u.texture.level_idx && desc->u.texture.level_count == texture_gl->t.level_count
                && !desc->u.texture.layer_idx && desc->u.texture.layer_count == texture_gl->t.layer_count
981 982 983 984
                && !is_stencil_view_format(view_format))
        {
            TRACE("Creating identity shader resource view.\n");
        }
985
        else if (texture_gl->t.swapchain && texture_gl->t.swapchain->state.desc.backbuffer_count > 1)
986 987 988 989
        {
            FIXME("Swapchain shader resource views not supported.\n");
        }
        else if (resource->format->typeless_id == view_format->typeless_id
990
                && resource_class == view_class)
991
        {
992
            create_texture_view(&view_gl->gl_view, view_target, desc, texture_gl, view_format);
993
        }
994 995
        else if (wined3d_format_is_depth_view(resource->format->id, view_format->id))
        {
996
            create_texture_view(&view_gl->gl_view, view_target, desc, texture_gl, resource->format);
997
        }
998 999 1000 1001 1002 1003 1004 1005
        else
        {
            FIXME("Shader resource view not supported, resource format %s, view format %s.\n",
                    debug_d3dformat(resource->format->id), debug_d3dformat(view_format->id));
        }
    }
}

1006
static HRESULT wined3d_shader_resource_view_init(struct wined3d_shader_resource_view *view,
1007
        const struct wined3d_view_desc *desc, struct wined3d_resource *resource,
1008 1009
        void *parent, const struct wined3d_parent_ops *parent_ops)
{
1010 1011 1012
    view->refcount = 1;
    view->parent = parent;
    view->parent_ops = parent_ops;
1013

1014 1015
    if (!(resource->bind_flags & WINED3D_BIND_SHADER_RESOURCE))
        return E_INVALIDARG;
1016
    if (!(view->format = validate_resource_view(desc, resource, FALSE, FALSE)))
1017
        return E_INVALIDARG;
1018 1019
    view->desc = *desc;

1020 1021
    wined3d_resource_incref(view->resource = resource);

1022 1023 1024
    return WINED3D_OK;
}

1025 1026 1027
HRESULT wined3d_shader_resource_view_gl_init(struct wined3d_shader_resource_view_gl *view_gl,
        const struct wined3d_view_desc *desc, struct wined3d_resource *resource,
        void *parent, const struct wined3d_parent_ops *parent_ops)
1028
{
1029
    HRESULT hr;
1030

1031 1032
    TRACE("view_gl %p, desc %s, resource %p, parent %p, parent_ops %p.\n",
            view_gl, wined3d_debug_view_desc(desc, resource), resource, parent, parent_ops);
1033

1034
    if (FAILED(hr = wined3d_shader_resource_view_init(&view_gl->v, desc, resource, parent, parent_ops)))
1035
        return hr;
1036

1037
    list_init(&view_gl->bo_user.entry);
1038
    wined3d_cs_init_object(resource->device->cs, wined3d_shader_resource_view_gl_cs_init, view_gl);
1039

1040 1041
    return hr;
}
1042

1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053
void wined3d_shader_resource_view_vk_update(struct wined3d_shader_resource_view_vk *srv_vk,
        struct wined3d_context_vk *context_vk)
{
    const struct wined3d_format_vk *view_format_vk = wined3d_format_vk(srv_vk->v.format);
    const struct wined3d_view_desc *desc = &srv_vk->v.desc;
    struct wined3d_resource *resource = srv_vk->v.resource;
    struct wined3d_view_vk *view_vk = &srv_vk->view_vk;
    struct wined3d_buffer_vk *buffer_vk;
    VkBufferView vk_buffer_view;

    buffer_vk = wined3d_buffer_vk(buffer_from_resource(resource));
1054 1055
    wined3d_context_vk_destroy_vk_buffer_view(context_vk, view_vk->u.vk_buffer_view, view_vk->command_buffer_id);
    if ((vk_buffer_view = wined3d_view_vk_create_vk_buffer_view(context_vk, desc, buffer_vk, view_format_vk)))
1056 1057 1058 1059 1060 1061
    {
        view_vk->u.vk_buffer_view = vk_buffer_view;
        view_vk->bo_user.valid = true;
    }
}

1062 1063 1064 1065 1066 1067
static void wined3d_shader_resource_view_vk_cs_init(void *object)
{
    struct wined3d_shader_resource_view_vk *srv_vk = object;
    struct wined3d_view_desc *desc = &srv_vk->v.desc;
    struct wined3d_texture_vk *texture_vk;
    const struct wined3d_format *format;
1068
    struct wined3d_buffer_vk *buffer_vk;
1069 1070
    struct wined3d_resource *resource;
    struct wined3d_context *context;
1071
    VkBufferView vk_buffer_view;
1072 1073 1074
    uint32_t default_flags = 0;
    VkImageView vk_image_view;

1075 1076
    TRACE("srv_vk %p.\n", srv_vk);

1077 1078 1079 1080 1081
    resource = srv_vk->v.resource;
    format = srv_vk->v.format;

    if (resource->type == WINED3D_RTYPE_BUFFER)
    {
1082 1083
        buffer_vk = wined3d_buffer_vk(buffer_from_resource(resource));

1084
        context = context_acquire(resource->device, NULL, 0);
1085
        vk_buffer_view = wined3d_view_vk_create_vk_buffer_view(wined3d_context_vk(context),
1086
                desc, buffer_vk, wined3d_format_vk(format));
1087 1088 1089 1090 1091 1092 1093 1094
        context_release(context);

        if (!vk_buffer_view)
            return;

        TRACE("Created buffer view 0x%s.\n", wine_dbgstr_longlong(vk_buffer_view));

        srv_vk->view_vk.u.vk_buffer_view = vk_buffer_view;
1095 1096
        srv_vk->view_vk.bo_user.valid = true;
        list_add_head(&buffer_vk->bo.users, &srv_vk->view_vk.bo_user.entry);
1097

1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118
        return;
    }

    texture_vk = wined3d_texture_vk(texture_from_resource(resource));

    if (texture_vk->t.layer_count > 1)
        default_flags |= WINED3D_VIEW_TEXTURE_ARRAY;

    if (resource->format->id == format->id && desc->flags == default_flags
            && !desc->u.texture.level_idx && desc->u.texture.level_count == texture_vk->t.level_count
            && !desc->u.texture.layer_idx && desc->u.texture.layer_count == texture_vk->t.layer_count
            && !(resource->bind_flags & WINED3D_BIND_DEPTH_STENCIL))
    {
        TRACE("Creating identity shader resource view.\n");
        return;
    }

    if (texture_vk->t.swapchain && texture_vk->t.swapchain->state.desc.backbuffer_count > 1)
        FIXME("Swapchain shader resource views not supported.\n");

    context = context_acquire(resource->device, NULL, 0);
1119
    vk_image_view = wined3d_view_vk_create_vk_image_view(wined3d_context_vk(context),
1120
            desc, texture_vk, wined3d_format_vk(format), format->color_fixup, false);
1121 1122 1123 1124 1125 1126 1127
    context_release(context);

    if (!vk_image_view)
        return;

    TRACE("Created image view 0x%s.\n", wine_dbgstr_longlong(vk_image_view));

1128 1129 1130
    srv_vk->view_vk.u.vk_image_info.imageView = vk_image_view;
    srv_vk->view_vk.u.vk_image_info.sampler = VK_NULL_HANDLE;
    srv_vk->view_vk.u.vk_image_info.imageLayout = texture_vk->layout;
1131 1132
}

1133 1134 1135 1136
HRESULT wined3d_shader_resource_view_vk_init(struct wined3d_shader_resource_view_vk *view_vk,
        const struct wined3d_view_desc *desc, struct wined3d_resource *resource,
        void *parent, const struct wined3d_parent_ops *parent_ops)
{
1137 1138
    HRESULT hr;

1139 1140 1141
    TRACE("view_vk %p, desc %s, resource %p, parent %p, parent_ops %p.\n",
            view_vk, wined3d_debug_view_desc(desc, resource), resource, parent, parent_ops);

1142 1143 1144
    if (FAILED(hr = wined3d_shader_resource_view_init(&view_vk->v, desc, resource, parent, parent_ops)))
        return hr;

1145
    list_init(&view_vk->view_vk.bo_user.entry);
1146 1147 1148
    wined3d_cs_init_object(resource->device->cs, wined3d_shader_resource_view_vk_cs_init, view_vk);

    return hr;
1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161
}

HRESULT CDECL wined3d_shader_resource_view_create(const struct wined3d_view_desc *desc,
        struct wined3d_resource *resource, void *parent, const struct wined3d_parent_ops *parent_ops,
        struct wined3d_shader_resource_view **view)
{
    const struct wined3d_adapter_ops *adapter_ops;

    TRACE("desc %s, resource %p, parent %p, parent_ops %p, view %p.\n",
            wined3d_debug_view_desc(desc, resource), resource, parent, parent_ops, view);

    adapter_ops = resource->device->adapter->adapter_ops;
    return adapter_ops->adapter_create_shader_resource_view(desc, resource, parent, parent_ops, view);
1162
}
1163

1164
void wined3d_shader_resource_view_gl_bind(struct wined3d_shader_resource_view_gl *view_gl,
1165
        unsigned int unit, struct wined3d_sampler_gl *sampler_gl, struct wined3d_context_gl *context_gl)
1166
{
1167
    const struct wined3d_gl_info *gl_info = context_gl->gl_info;
1168
    struct wined3d_texture_gl *texture_gl;
1169

1170
    wined3d_context_gl_active_texture(context_gl, gl_info, unit);
1171

1172
    if (view_gl->gl_view.name)
1173
    {
1174
        wined3d_context_gl_bind_texture(context_gl, view_gl->gl_view.target, view_gl->gl_view.name);
1175
        wined3d_sampler_gl_bind(sampler_gl, unit, NULL, context_gl);
1176 1177 1178
        return;
    }

1179
    if (view_gl->v.resource->type == WINED3D_RTYPE_BUFFER)
1180 1181 1182 1183 1184
    {
        FIXME("Buffer shader resources not supported.\n");
        return;
    }

1185
    texture_gl = wined3d_texture_gl(wined3d_texture_from_resource(view_gl->v.resource));
1186
    wined3d_texture_gl_bind(texture_gl, context_gl, FALSE);
1187
    wined3d_sampler_gl_bind(sampler_gl, unit, texture_gl, context_gl);
1188
}
1189

1190
/* Context activation is done by the caller. */
1191
static void shader_resource_view_gl_bind_and_dirtify(struct wined3d_shader_resource_view_gl *view_gl,
1192
        struct wined3d_context_gl *context_gl)
1193
{
1194
    if (context_gl->active_texture < ARRAY_SIZE(context_gl->rev_tex_unit_map))
1195
    {
1196
        unsigned int active_sampler = context_gl->rev_tex_unit_map[context_gl->active_texture];
1197
        if (active_sampler != WINED3D_UNMAPPED_STAGE)
1198
            context_invalidate_state(&context_gl->c, STATE_SAMPLER(active_sampler));
1199 1200 1201
    }
    /* FIXME: Ideally we'd only do this when touching a binding that's used by
     * a shader. */
1202 1203
    context_invalidate_compute_state(&context_gl->c, STATE_COMPUTE_SHADER_RESOURCE_BINDING);
    context_invalidate_state(&context_gl->c, STATE_GRAPHICS_SHADER_RESOURCE_BINDING);
1204

1205
    wined3d_context_gl_bind_texture(context_gl, view_gl->gl_view.target, view_gl->gl_view.name);
1206 1207
}

1208 1209
void wined3d_shader_resource_view_gl_generate_mipmap(struct wined3d_shader_resource_view_gl *view_gl,
        struct wined3d_context_gl *context_gl)
1210
{
1211
    unsigned int i, j, layer_count, level_count, base_level, base_layer, sub_resource_idx;
1212
    const struct wined3d_gl_info *gl_info = context_gl->gl_info;
1213
    struct wined3d_texture_gl *texture_gl;
1214 1215 1216 1217
    struct gl_texture *gl_tex;
    DWORD location;
    BOOL srgb;

1218
    TRACE("view_gl %p.\n", view_gl);
1219

1220 1221 1222
    layer_count = view_gl->v.desc.u.texture.layer_count;
    level_count = view_gl->v.desc.u.texture.level_count;
    base_level = view_gl->v.desc.u.texture.level_idx;
1223
    base_layer = view_gl->v.desc.u.texture.layer_idx;
1224

1225
    texture_gl = wined3d_texture_gl(texture_from_resource(view_gl->v.resource));
1226
    srgb = !!(texture_gl->t.flags & WINED3D_TEXTURE_IS_SRGB);
1227 1228
    location = srgb ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB;
    for (i = 0; i < layer_count; ++i)
1229
    {
1230 1231
        sub_resource_idx = (base_layer + i) * texture_gl->t.level_count + base_level;
        if (!wined3d_texture_load_location(&texture_gl->t, sub_resource_idx, &context_gl->c, location))
1232
            ERR("Failed to load source layer %u.\n", base_layer + i);
1233
    }
1234

1235
    if (view_gl->gl_view.name)
1236
    {
1237
        shader_resource_view_gl_bind_and_dirtify(view_gl, context_gl);
1238
    }
1239
    else
1240
    {
1241
        wined3d_texture_gl_bind_and_dirtify(texture_gl, context_gl, srgb);
1242
        gl_info->gl_ops.gl.p_glTexParameteri(texture_gl->target, GL_TEXTURE_BASE_LEVEL, base_level);
1243
        gl_info->gl_ops.gl.p_glTexParameteri(texture_gl->target, GL_TEXTURE_MAX_LEVEL, base_level + level_count - 1);
1244 1245
    }

1246
    if (gl_info->supported[ARB_SAMPLER_OBJECTS])
1247
        GL_EXTCALL(glBindSampler(context_gl->active_texture, 0));
1248
    gl_tex = wined3d_texture_gl_get_gl_texture(texture_gl, srgb);
1249
    if (context_gl->c.d3d_info->wined3d_creation_flags & WINED3D_SRGB_READ_WRITE_CONTROL)
1250
    {
1251 1252
        gl_info->gl_ops.gl.p_glTexParameteri(texture_gl->target,
                GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT);
1253 1254 1255
        gl_tex->sampler_desc.srgb_decode = FALSE;
    }

1256
    gl_info->fbo_ops.glGenerateMipmap(texture_gl->target);
1257 1258 1259 1260
    checkGLcall("glGenerateMipMap()");

    for (i = 0; i < layer_count; ++i)
    {
1261
        for (j = 1; j < level_count; ++j)
1262
        {
1263 1264 1265
            sub_resource_idx = (base_layer + i) * texture_gl->t.level_count + base_level + j;
            wined3d_texture_validate_location(&texture_gl->t, sub_resource_idx, location);
            wined3d_texture_invalidate_location(&texture_gl->t, sub_resource_idx, ~location);
1266 1267 1268
        }
    }

1269
    if (!view_gl->gl_view.name)
1270 1271
    {
        gl_tex->base_level = base_level;
1272
        gl_info->gl_ops.gl.p_glTexParameteri(texture_gl->target,
1273
                GL_TEXTURE_MAX_LEVEL, texture_gl->t.level_count - 1);
1274
    }
1275
}
1276

1277 1278 1279
void wined3d_shader_resource_view_vk_generate_mipmap(struct wined3d_shader_resource_view_vk *srv_vk,
        struct wined3d_context_vk *context_vk)
{
1280
    unsigned int i, j, layer_count, level_count, base_level, base_layer, sub_resource_idx;
1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296
    const struct wined3d_vk_info *vk_info = context_vk->vk_info;
    VkImageSubresourceRange vk_src_range, vk_dst_range;
    struct wined3d_texture_vk *texture_vk;
    VkCommandBuffer vk_command_buffer;
    VkImageBlit region;

    TRACE("srv_vk %p.\n", srv_vk);

    layer_count = srv_vk->v.desc.u.texture.layer_count;
    level_count = srv_vk->v.desc.u.texture.level_count;
    base_level = srv_vk->v.desc.u.texture.level_idx;
    base_layer = srv_vk->v.desc.u.texture.layer_idx;

    texture_vk = wined3d_texture_vk(texture_from_resource(srv_vk->v.resource));
    for (i = 0; i < layer_count; ++i)
    {
1297 1298 1299
        sub_resource_idx = (base_layer + i) * texture_vk->t.level_count + base_level;
        if (!wined3d_texture_load_location(&texture_vk->t, sub_resource_idx,
                &context_vk->c, WINED3D_LOCATION_TEXTURE_RGB))
1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331
            ERR("Failed to load source layer %u.\n", base_layer + i);
    }

    if (context_vk->c.d3d_info->wined3d_creation_flags & WINED3D_SRGB_READ_WRITE_CONTROL)
        FIXME("Unhandled sRGB read/write control.\n");

    if (wined3d_format_vk(srv_vk->v.format)->vk_format != wined3d_format_vk(texture_vk->t.resource.format)->vk_format)
        FIXME("Ignoring view format %s.\n", debug_d3dformat(srv_vk->v.format->id));

    if (wined3d_resource_get_sample_count(&texture_vk->t.resource) > 1)
        FIXME("Unhandled multi-sampled resource.\n");

    if (!(vk_command_buffer = wined3d_context_vk_get_command_buffer(context_vk)))
    {
        ERR("Failed to get command buffer.\n");
        return;
    }

    vk_src_range.aspectMask = vk_aspect_mask_from_format(texture_vk->t.resource.format);
    vk_src_range.baseMipLevel = base_level;
    vk_src_range.levelCount = 1;
    vk_src_range.baseArrayLayer = base_layer;
    vk_src_range.layerCount = layer_count;

    vk_dst_range = vk_src_range;
    ++vk_dst_range.baseMipLevel;

    wined3d_context_vk_image_barrier(context_vk, vk_command_buffer,
            VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
            vk_access_mask_from_bind_flags(texture_vk->t.resource.bind_flags),
            VK_ACCESS_TRANSFER_READ_BIT,
            texture_vk->layout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1332
            texture_vk->image.vk_image, &vk_src_range);
1333 1334 1335 1336 1337
    wined3d_context_vk_image_barrier(context_vk, vk_command_buffer,
            VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
            vk_access_mask_from_bind_flags(texture_vk->t.resource.bind_flags),
            VK_ACCESS_TRANSFER_WRITE_BIT,
            texture_vk->layout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1338
            texture_vk->image.vk_image, &vk_dst_range);
1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365

    region.srcSubresource.aspectMask = vk_src_range.aspectMask;
    region.srcSubresource.mipLevel = vk_src_range.baseMipLevel;
    region.srcSubresource.baseArrayLayer = vk_src_range.baseArrayLayer;
    region.srcSubresource.layerCount = vk_src_range.layerCount;
    region.srcOffsets[0].x = 0;
    region.srcOffsets[0].y = 0;
    region.srcOffsets[0].z = 0;

    region.dstSubresource.aspectMask = vk_dst_range.aspectMask;
    region.dstSubresource.mipLevel = vk_dst_range.baseMipLevel;
    region.dstSubresource.baseArrayLayer = vk_dst_range.baseArrayLayer;
    region.dstSubresource.layerCount = vk_dst_range.layerCount;
    region.dstOffsets[0].x = 0;
    region.dstOffsets[0].y = 0;
    region.dstOffsets[0].z = 0;

    for (i = 1; i < level_count; ++i)
    {
        region.srcOffsets[1].x = wined3d_texture_get_level_width(&texture_vk->t, vk_src_range.baseMipLevel);
        region.srcOffsets[1].y = wined3d_texture_get_level_height(&texture_vk->t, vk_src_range.baseMipLevel);
        region.srcOffsets[1].z = wined3d_texture_get_level_depth(&texture_vk->t, vk_src_range.baseMipLevel);

        region.dstOffsets[1].x = wined3d_texture_get_level_width(&texture_vk->t, vk_dst_range.baseMipLevel);
        region.dstOffsets[1].y = wined3d_texture_get_level_height(&texture_vk->t, vk_dst_range.baseMipLevel);
        region.dstOffsets[1].z = wined3d_texture_get_level_depth(&texture_vk->t, vk_dst_range.baseMipLevel);

1366 1367
        VK_CALL(vkCmdBlitImage(vk_command_buffer, texture_vk->image.vk_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
                texture_vk->image.vk_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region, VK_FILTER_LINEAR));
1368 1369 1370 1371 1372 1373

        wined3d_context_vk_image_barrier(context_vk, vk_command_buffer,
                VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
                VK_ACCESS_TRANSFER_READ_BIT,
                vk_access_mask_from_bind_flags(texture_vk->t.resource.bind_flags),
                VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, texture_vk->layout,
1374
                texture_vk->image.vk_image, &vk_src_range);
1375 1376 1377 1378 1379 1380 1381 1382

        if (i == level_count - 1)
        {
            wined3d_context_vk_image_barrier(context_vk, vk_command_buffer,
                    VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
                    VK_ACCESS_TRANSFER_WRITE_BIT,
                    vk_access_mask_from_bind_flags(texture_vk->t.resource.bind_flags),
                    VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, texture_vk->layout,
1383
                    texture_vk->image.vk_image, &vk_dst_range);
1384 1385 1386
        }
        else
        {
1387 1388 1389
            region.srcSubresource.mipLevel = ++vk_src_range.baseMipLevel;
            region.dstSubresource.mipLevel = ++vk_dst_range.baseMipLevel;

1390 1391 1392 1393
            wined3d_context_vk_image_barrier(context_vk, vk_command_buffer,
                    VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
                    VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
                    VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1394
                    texture_vk->image.vk_image, &vk_src_range);
1395 1396 1397 1398 1399
            wined3d_context_vk_image_barrier(context_vk, vk_command_buffer,
                    VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
                    vk_access_mask_from_bind_flags(texture_vk->t.resource.bind_flags),
                    VK_ACCESS_TRANSFER_WRITE_BIT,
                    texture_vk->layout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1400
                    texture_vk->image.vk_image, &vk_dst_range);
1401 1402 1403 1404 1405 1406 1407
        }
    }

    for (i = 0; i < layer_count; ++i)
    {
        for (j = 1; j < level_count; ++j)
        {
1408 1409 1410
            sub_resource_idx = (base_layer + i) * texture_vk->t.level_count + base_level + j;
            wined3d_texture_validate_location(&texture_vk->t, sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB);
            wined3d_texture_invalidate_location(&texture_vk->t, sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB);
1411 1412 1413 1414
        }
    }

    wined3d_context_vk_reference_texture(context_vk, texture_vk);
1415 1416
}

1417 1418 1419 1420 1421 1422 1423 1424 1425
ULONG CDECL wined3d_unordered_access_view_incref(struct wined3d_unordered_access_view *view)
{
    ULONG refcount = InterlockedIncrement(&view->refcount);

    TRACE("%p increasing refcount to %u.\n", view, refcount);

    return refcount;
}

1426
void wined3d_unordered_access_view_cleanup(struct wined3d_unordered_access_view *view)
1427
{
1428 1429 1430 1431
    /* Call wined3d_object_destroyed() before releasing the resource,
     * since releasing the resource may end up destroying the parent. */
    view->parent_ops->wined3d_object_destroyed(view->parent);
    wined3d_resource_decref(view->resource);
1432 1433 1434 1435 1436 1437 1438 1439 1440
}

ULONG CDECL wined3d_unordered_access_view_decref(struct wined3d_unordered_access_view *view)
{
    ULONG refcount = InterlockedDecrement(&view->refcount);

    TRACE("%p decreasing refcount to %u.\n", view, refcount);

    if (!refcount)
1441
        view->resource->device->adapter->adapter_ops->adapter_destroy_unordered_access_view(view);
1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452

    return refcount;
}

void * CDECL wined3d_unordered_access_view_get_parent(const struct wined3d_unordered_access_view *view)
{
    TRACE("view %p.\n", view);

    return view->parent;
}

1453 1454 1455
void wined3d_unordered_access_view_invalidate_location(struct wined3d_unordered_access_view *view,
        DWORD location)
{
1456
    wined3d_view_invalidate_location(view->resource, &view->desc, location);
1457 1458
}

1459 1460
void wined3d_unordered_access_view_gl_clear(struct wined3d_unordered_access_view_gl *view_gl,
        const struct wined3d_uvec4 *clear_value, struct wined3d_context_gl *context_gl, bool fp)
1461
{
1462
    const struct wined3d_gl_info *gl_info = context_gl->gl_info;
1463
    const struct wined3d_format_gl *format_gl;
1464
    struct wined3d_buffer_gl *buffer_gl;
1465 1466 1467
    struct wined3d_resource *resource;
    unsigned int offset, size;

1468
    resource = view_gl->v.resource;
1469 1470
    if (resource->type != WINED3D_RTYPE_BUFFER)
    {
1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490
        unsigned int layer_count, level_count, base_level, base_layer;
        unsigned int sub_resource_idx, width, height, depth, i, j;
        struct wined3d_texture_gl *texture_gl;
        const void *data = clear_value;
        GLenum gl_format, gl_type;
        uint32_t packed;

        if (!gl_info->supported[ARB_CLEAR_TEXTURE])
        {
            FIXME("OpenGL implementation does not support ARB_clear_texture.\n");
            return;
        }

        format_gl = wined3d_format_gl(resource->format);
        texture_gl = wined3d_texture_gl(texture_from_resource(resource));
        layer_count = view_gl->v.desc.u.texture.layer_count;
        level_count = view_gl->v.desc.u.texture.level_count;
        base_layer = view_gl->v.desc.u.texture.layer_idx;
        base_level = view_gl->v.desc.u.texture.level_idx;

1491
        if (format_gl->f.byte_count <= 4 && !fp)
1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546
        {
            gl_format = format_gl->format;
            gl_type = format_gl->type;
            packed = wined3d_format_pack(&format_gl->f, clear_value);
            data = &packed;
        }
        else if (resource->format_flags & WINED3DFMT_FLAG_INTEGER)
        {
            gl_format = GL_RGBA_INTEGER;
            gl_type = GL_UNSIGNED_INT;
        }
        else
        {
            gl_format = GL_RGBA;
            gl_type = GL_FLOAT;
        }

        for (i = 0; i < layer_count; ++i)
        {
            for (j = 0; j < level_count; ++j)
            {
                sub_resource_idx = (base_layer + i) * texture_gl->t.level_count + base_level + j;
                wined3d_texture_prepare_location(&texture_gl->t, sub_resource_idx,
                        &context_gl->c, WINED3D_LOCATION_TEXTURE_RGB);

                width = wined3d_texture_get_level_width(&texture_gl->t, base_level + j);
                height = wined3d_texture_get_level_height(&texture_gl->t, base_level + j);
                depth = wined3d_texture_get_level_depth(&texture_gl->t, base_level + j);

                switch (texture_gl->target)
                {
                    case GL_TEXTURE_1D_ARRAY:
                        GL_EXTCALL(glClearTexSubImage(texture_gl->texture_rgb.name, base_level + j,
                                0, base_layer + i, 0, width, 1, 1, gl_format, gl_type, data));
                        break;

                    case GL_TEXTURE_2D_ARRAY:
                    case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
                    case GL_TEXTURE_CUBE_MAP:
                    case GL_TEXTURE_CUBE_MAP_ARRAY:
                        GL_EXTCALL(glClearTexSubImage(texture_gl->texture_rgb.name, base_level + j,
                                0, 0, base_layer + i, width, height, 1, gl_format, gl_type, data));
                        break;

                    default:
                        GL_EXTCALL(glClearTexSubImage(texture_gl->texture_rgb.name, base_level + j,
                                0, 0, 0, width, height, depth, gl_format, gl_type, data));
                        break;
                }

                wined3d_texture_validate_location(&texture_gl->t, sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB);
                wined3d_texture_invalidate_location(&texture_gl->t, sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB);
            }
        }

1547 1548 1549 1550 1551 1552 1553 1554 1555
        return;
    }

    if (!gl_info->supported[ARB_CLEAR_BUFFER_OBJECT])
    {
        FIXME("OpenGL implementation does not support ARB_clear_buffer_object.\n");
        return;
    }

1556 1557 1558 1559
    format_gl = wined3d_format_gl(view_gl->v.format);
    if (format_gl->f.id != WINED3DFMT_R32_UINT && format_gl->f.id != WINED3DFMT_R32_SINT
            && format_gl->f.id != WINED3DFMT_R32G32B32A32_UINT
            && format_gl->f.id != WINED3DFMT_R32G32B32A32_SINT)
1560
    {
1561
        FIXME("Not implemented for format %s.\n", debug_d3dformat(format_gl->f.id));
1562 1563 1564
        return;
    }

1565 1566 1567 1568 1569 1570
    if (fp)
    {
        FIXME("Floating-point buffer clears not implemented.\n");
        return;
    }

1571
    buffer_gl = wined3d_buffer_gl(buffer_from_resource(resource));
1572 1573
    wined3d_buffer_load_location(&buffer_gl->b, &context_gl->c, WINED3D_LOCATION_BUFFER);
    wined3d_unordered_access_view_invalidate_location(&view_gl->v, ~WINED3D_LOCATION_BUFFER);
1574

1575
    get_buffer_view_range(&buffer_gl->b, &view_gl->v.desc, &format_gl->f, &offset, &size);
1576
    wined3d_context_gl_bind_bo(context_gl, buffer_gl->bo.binding, buffer_gl->bo.id);
1577 1578
    GL_EXTCALL(glClearBufferSubData(buffer_gl->bo.binding, format_gl->internal,
            offset, size, format_gl->format, format_gl->type, clear_value));
1579
    wined3d_context_gl_reference_bo(context_gl, &buffer_gl->bo);
1580
    checkGLcall("clear unordered access view");
1581 1582
}

1583 1584 1585
void wined3d_unordered_access_view_set_counter(struct wined3d_unordered_access_view *view,
        unsigned int value)
{
1586
    struct wined3d_bo_address dst, src;
1587 1588
    struct wined3d_context *context;

1589
    if (!view->counter_bo)
1590 1591
        return;

1592 1593 1594 1595 1596 1597 1598 1599
    context = context_acquire(view->resource->device, NULL, 0);

    src.buffer_object = 0;
    src.addr = (void *)&value;

    dst.buffer_object = view->counter_bo;
    dst.addr = NULL;

1600
    wined3d_context_copy_bo_address(context, &dst, &src, sizeof(uint32_t));
1601

1602 1603 1604
    context_release(context);
}

1605 1606 1607
void wined3d_unordered_access_view_copy_counter(struct wined3d_unordered_access_view *view,
        struct wined3d_buffer *buffer, unsigned int offset, struct wined3d_context *context)
{
1608
    struct wined3d_const_bo_address src;
1609

1610
    if (!view->counter_bo)
1611 1612
        return;

1613
    src.buffer_object = view->counter_bo;
1614 1615
    src.addr = NULL;

1616
    wined3d_buffer_copy_bo_address(buffer, context, offset, &src, sizeof(uint32_t));
1617 1618
}

1619 1620 1621 1622 1623 1624 1625 1626
void wined3d_unordered_access_view_gl_update(struct wined3d_unordered_access_view_gl *uav_gl,
        struct wined3d_context_gl *context_gl)
{
    create_buffer_view(&uav_gl->gl_view, &context_gl->c, &uav_gl->v.desc,
            buffer_from_resource(uav_gl->v.resource), uav_gl->v.format);
    uav_gl->bo_user.valid = true;
}

1627
static void wined3d_unordered_access_view_gl_cs_init(void *object)
1628
{
1629 1630 1631
    struct wined3d_unordered_access_view_gl *view_gl = object;
    struct wined3d_resource *resource = view_gl->v.resource;
    struct wined3d_view_desc *desc = &view_gl->v.desc;
1632 1633
    const struct wined3d_gl_info *gl_info;

1634 1635
    TRACE("view_gl %p.\n", view_gl);

1636 1637 1638 1639 1640
    gl_info = &resource->device->adapter->gl_info;

    if (resource->type == WINED3D_RTYPE_BUFFER)
    {
        struct wined3d_buffer *buffer = buffer_from_resource(resource);
1641
        struct wined3d_context_gl *context_gl;
1642

1643 1644
        context_gl = wined3d_context_gl(context_acquire(resource->device, NULL, 0));
        create_buffer_view(&view_gl->gl_view, &context_gl->c, desc, buffer, view_gl->v.format);
1645 1646
        view_gl->bo_user.valid = true;
        list_add_head(&wined3d_buffer_gl(buffer)->bo.users, &view_gl->bo_user.entry);
1647
        if (desc->flags & (WINED3D_VIEW_BUFFER_COUNTER | WINED3D_VIEW_BUFFER_APPEND))
1648
        {
1649
            struct wined3d_bo_gl *bo = &view_gl->counter_bo;
1650

1651
            view_gl->v.counter_bo = (uintptr_t)bo;
1652 1653
            wined3d_context_gl_create_bo(context_gl, sizeof(uint32_t), GL_ATOMIC_COUNTER_BUFFER,
                    GL_STATIC_DRAW, true, GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_CLIENT_STORAGE_BIT, bo);
1654
            wined3d_unordered_access_view_set_counter(&view_gl->v, 0);
1655
        }
1656
        context_release(&context_gl->c);
1657 1658 1659
    }
    else
    {
1660
        struct wined3d_texture_gl *texture_gl = wined3d_texture_gl(texture_from_resource(resource));
1661 1662 1663
        unsigned int depth_or_layer_count;

        if (resource->type == WINED3D_RTYPE_TEXTURE_3D)
1664
            depth_or_layer_count = wined3d_texture_get_level_depth(&texture_gl->t, desc->u.texture.level_idx);
1665
        else
1666
            depth_or_layer_count = texture_gl->t.layer_count;
1667 1668 1669

        if (desc->u.texture.layer_idx || desc->u.texture.layer_count != depth_or_layer_count)
        {
1670 1671
            create_texture_view(&view_gl->gl_view, get_texture_view_target(gl_info, desc, texture_gl),
                    desc, texture_gl, view_gl->v.format);
1672 1673 1674 1675
        }
    }
}

1676
static HRESULT wined3d_unordered_access_view_init(struct wined3d_unordered_access_view *view,
1677
        const struct wined3d_view_desc *desc, struct wined3d_resource *resource,
1678 1679 1680 1681 1682 1683
        void *parent, const struct wined3d_parent_ops *parent_ops)
{
    view->refcount = 1;
    view->parent = parent;
    view->parent_ops = parent_ops;

1684 1685
    if (!(resource->bind_flags & WINED3D_BIND_UNORDERED_ACCESS))
        return E_INVALIDARG;
1686
    if (!(view->format = validate_resource_view(desc, resource, TRUE, FALSE)))
1687
        return E_INVALIDARG;
1688
    view->desc = *desc;
1689 1690 1691 1692 1693 1694

    wined3d_resource_incref(view->resource = resource);

    return WINED3D_OK;
}

1695 1696 1697
HRESULT wined3d_unordered_access_view_gl_init(struct wined3d_unordered_access_view_gl *view_gl,
        const struct wined3d_view_desc *desc, struct wined3d_resource *resource,
        void *parent, const struct wined3d_parent_ops *parent_ops)
1698 1699 1700
{
    HRESULT hr;

1701 1702
    TRACE("view_gl %p, desc %s, resource %p, parent %p, parent_ops %p.\n",
            view_gl, wined3d_debug_view_desc(desc, resource), resource, parent, parent_ops);
1703

1704
    if (FAILED(hr = wined3d_unordered_access_view_init(&view_gl->v, desc, resource, parent, parent_ops)))
1705 1706
        return hr;

1707
    list_init(&view_gl->bo_user.entry);
1708
    wined3d_cs_init_object(resource->device->cs, wined3d_unordered_access_view_gl_cs_init, view_gl);
1709

1710 1711
    return hr;
}
1712

1713 1714
void wined3d_unordered_access_view_vk_clear(struct wined3d_unordered_access_view_vk *view_vk,
        const struct wined3d_uvec4 *clear_value, struct wined3d_context_vk *context_vk, bool fp)
1715 1716 1717 1718 1719 1720 1721 1722 1723 1724
{
    const struct wined3d_vk_info *vk_info;
    const struct wined3d_format *format;
    struct wined3d_buffer_vk *buffer_vk;
    struct wined3d_resource *resource;
    VkCommandBuffer vk_command_buffer;
    VkBufferMemoryBarrier vk_barrier;
    VkAccessFlags access_mask;
    unsigned int offset, size;

1725
    TRACE("view_vk %p, clear_value %s, context_vk %p, fp %#x.\n", view_vk, debug_uvec4(clear_value), context_vk, fp);
1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775

    resource = view_vk->v.resource;
    if (resource->type != WINED3D_RTYPE_BUFFER)
    {
        FIXME("Not implemented for %s resources.\n", debug_d3dresourcetype(resource->type));
        return;
    }

    format = view_vk->v.format;
    if (format->id != WINED3DFMT_R32_UINT && format->id != WINED3DFMT_R32_SINT)
    {
        FIXME("Not implemented for format %s.\n", debug_d3dformat(format->id));
        return;
    }

    vk_info = context_vk->vk_info;
    buffer_vk = wined3d_buffer_vk(buffer_from_resource(resource));
    wined3d_buffer_load_location(&buffer_vk->b, &context_vk->c, WINED3D_LOCATION_BUFFER);
    wined3d_buffer_invalidate_location(&buffer_vk->b, ~WINED3D_LOCATION_BUFFER);

    get_buffer_view_range(&buffer_vk->b, &view_vk->v.desc, format, &offset, &size);

    if (!(vk_command_buffer = wined3d_context_vk_get_command_buffer(context_vk)))
        return;
    wined3d_context_vk_end_current_render_pass(context_vk);

    access_mask = vk_access_mask_from_bind_flags(buffer_vk->b.resource.bind_flags);
    vk_barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
    vk_barrier.pNext = NULL;
    vk_barrier.srcAccessMask = access_mask;
    vk_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
    vk_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
    vk_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
    vk_barrier.buffer = buffer_vk->bo.vk_buffer;
    vk_barrier.offset = buffer_vk->bo.buffer_offset + offset;
    vk_barrier.size = size;
    VK_CALL(vkCmdPipelineBarrier(vk_command_buffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
            VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 1, &vk_barrier, 0, NULL));

    VK_CALL(vkCmdFillBuffer(vk_command_buffer, buffer_vk->bo.vk_buffer,
            buffer_vk->bo.buffer_offset + offset, size, clear_value->x));

    vk_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
    vk_barrier.dstAccessMask = access_mask;
    VK_CALL(vkCmdPipelineBarrier(vk_command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT,
            VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, NULL, 1, &vk_barrier, 0, NULL));

    wined3d_context_vk_reference_bo(context_vk, &buffer_vk->bo);
}

1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786
void wined3d_unordered_access_view_vk_update(struct wined3d_unordered_access_view_vk *uav_vk,
        struct wined3d_context_vk *context_vk)
{
    const struct wined3d_format_vk *view_format_vk = wined3d_format_vk(uav_vk->v.format);
    const struct wined3d_view_desc *desc = &uav_vk->v.desc;
    struct wined3d_resource *resource = uav_vk->v.resource;
    struct wined3d_view_vk *view_vk = &uav_vk->view_vk;
    struct wined3d_buffer_vk *buffer_vk;
    VkBufferView vk_buffer_view;

    buffer_vk = wined3d_buffer_vk(buffer_from_resource(resource));
1787 1788
    wined3d_context_vk_destroy_vk_buffer_view(context_vk, view_vk->u.vk_buffer_view, view_vk->command_buffer_id);
    if ((vk_buffer_view = wined3d_view_vk_create_vk_buffer_view(context_vk, desc, buffer_vk, view_format_vk)))
1789 1790 1791 1792 1793 1794
    {
        view_vk->u.vk_buffer_view = vk_buffer_view;
        view_vk->bo_user.valid = true;
    }
}

1795 1796 1797 1798 1799 1800
static void wined3d_unordered_access_view_vk_cs_init(void *object)
{
    struct wined3d_unordered_access_view_vk *uav_vk = object;
    struct wined3d_view_vk *view_vk = &uav_vk->view_vk;
    struct wined3d_view_desc *desc = &uav_vk->v.desc;
    const struct wined3d_format_vk *format_vk;
1801
    const struct wined3d_vk_info *vk_info;
1802 1803 1804
    struct wined3d_texture_vk *texture_vk;
    struct wined3d_context_vk *context_vk;
    struct wined3d_device_vk *device_vk;
1805
    struct wined3d_buffer_vk *buffer_vk;
1806
    VkBufferViewCreateInfo create_info;
1807
    struct wined3d_resource *resource;
1808
    VkBufferView vk_buffer_view;
1809 1810
    uint32_t default_flags = 0;
    VkImageView vk_image_view;
1811
    VkResult vr;
1812

1813 1814
    TRACE("uav_vk %p.\n", uav_vk);

1815 1816 1817 1818 1819 1820
    resource = uav_vk->v.resource;
    device_vk = wined3d_device_vk(resource->device);
    format_vk = wined3d_format_vk(uav_vk->v.format);

    if (resource->type == WINED3D_RTYPE_BUFFER)
    {
1821 1822
        buffer_vk = wined3d_buffer_vk(buffer_from_resource(resource));

1823
        context_vk = wined3d_context_vk(context_acquire(&device_vk->d, NULL, 0));
1824
        vk_info = context_vk->vk_info;
1825

1826
        if ((vk_buffer_view = wined3d_view_vk_create_vk_buffer_view(context_vk, desc, buffer_vk, format_vk)))
1827 1828
        {
            TRACE("Created buffer view 0x%s.\n", wine_dbgstr_longlong(vk_buffer_view));
1829

1830
            uav_vk->view_vk.u.vk_buffer_view = vk_buffer_view;
1831 1832
            uav_vk->view_vk.bo_user.valid = true;
            list_add_head(&buffer_vk->bo.users, &view_vk->bo_user.entry);
1833 1834 1835 1836 1837 1838 1839 1840 1841 1842
        }

        if (desc->flags & (WINED3D_VIEW_BUFFER_COUNTER | WINED3D_VIEW_BUFFER_APPEND))
        {
            if (!wined3d_context_vk_create_bo(context_vk, sizeof(uint32_t), VK_BUFFER_USAGE_TRANSFER_SRC_BIT
                    | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT,
                    VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &uav_vk->counter_bo))
            {
                ERR("Failed to create counter bo.\n");
                context_release(&context_vk->c);
1843

1844 1845 1846
                return;
            }

1847
            wined3d_context_vk_end_current_render_pass(context_vk);
1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872
            VK_CALL(vkCmdFillBuffer(wined3d_context_vk_get_command_buffer(context_vk),
                    uav_vk->counter_bo.vk_buffer, uav_vk->counter_bo.buffer_offset, sizeof(uint32_t), 0));
            wined3d_context_vk_reference_bo(context_vk, &uav_vk->counter_bo);

            create_info.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO;
            create_info.pNext = NULL;
            create_info.flags = 0;
            create_info.buffer = uav_vk->counter_bo.vk_buffer;
            create_info.format = VK_FORMAT_R32_UINT;
            create_info.offset = uav_vk->counter_bo.buffer_offset;
            create_info.range = sizeof(uint32_t);
            if ((vr = VK_CALL(vkCreateBufferView(device_vk->vk_device,
                    &create_info, NULL, &uav_vk->vk_counter_view))) < 0)
            {
                ERR("Failed to create counter buffer view, vr %s.\n", wined3d_debug_vkresult(vr));
            }
            else
            {
                TRACE("Created counter buffer view 0x%s.\n", wine_dbgstr_longlong(uav_vk->vk_counter_view));

                uav_vk->v.counter_bo = (uintptr_t)&uav_vk->counter_bo;
            }
        }

        context_release(&context_vk->c);
1873

1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894
        return;
    }

    texture_vk = wined3d_texture_vk(texture_from_resource(resource));

    if (texture_vk->t.layer_count > 1)
        default_flags |= WINED3D_VIEW_TEXTURE_ARRAY;

    if (resource->format->id == format_vk->f.id && desc->flags == default_flags
            && !desc->u.texture.level_idx && desc->u.texture.level_count == texture_vk->t.level_count
            && !desc->u.texture.layer_idx && desc->u.texture.layer_count == texture_vk->t.layer_count
            && !(resource->bind_flags & WINED3D_BIND_DEPTH_STENCIL) && resource->type != WINED3D_RTYPE_TEXTURE_3D)
    {
        TRACE("Creating identity unordered access view.\n");
        return;
    }

    if (texture_vk->t.swapchain && texture_vk->t.swapchain->state.desc.backbuffer_count > 1)
        FIXME("Swapchain unordered access views not supported.\n");

    context_vk = wined3d_context_vk(context_acquire(&device_vk->d, NULL, 0));
1895
    vk_image_view = wined3d_view_vk_create_vk_image_view(context_vk, desc,
1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908
            texture_vk, format_vk, format_vk->f.color_fixup, false);
    context_release(&context_vk->c);

    if (!vk_image_view)
        return;

    TRACE("Created image view 0x%s.\n", wine_dbgstr_longlong(vk_image_view));

    view_vk->u.vk_image_info.imageView = vk_image_view;
    view_vk->u.vk_image_info.sampler = VK_NULL_HANDLE;
    view_vk->u.vk_image_info.imageLayout = texture_vk->layout;
}

1909 1910 1911 1912
HRESULT wined3d_unordered_access_view_vk_init(struct wined3d_unordered_access_view_vk *view_vk,
        const struct wined3d_view_desc *desc, struct wined3d_resource *resource,
        void *parent, const struct wined3d_parent_ops *parent_ops)
{
1913 1914
    HRESULT hr;

1915 1916 1917
    TRACE("view_vk %p, desc %s, resource %p, parent %p, parent_ops %p.\n",
            view_vk, wined3d_debug_view_desc(desc, resource), resource, parent, parent_ops);

1918 1919 1920
    if (FAILED(hr = wined3d_unordered_access_view_init(&view_vk->v, desc, resource, parent, parent_ops)))
        return hr;

1921
    list_init(&view_vk->view_vk.bo_user.entry);
1922 1923 1924
    wined3d_cs_init_object(resource->device->cs, wined3d_unordered_access_view_vk_cs_init, view_vk);

    return hr;
1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937
}

HRESULT CDECL wined3d_unordered_access_view_create(const struct wined3d_view_desc *desc,
        struct wined3d_resource *resource, void *parent, const struct wined3d_parent_ops *parent_ops,
        struct wined3d_unordered_access_view **view)
{
    const struct wined3d_adapter_ops *adapter_ops;

    TRACE("desc %s, resource %p, parent %p, parent_ops %p, view %p.\n",
            wined3d_debug_view_desc(desc, resource), resource, parent, parent_ops, view);

    adapter_ops = resource->device->adapter->adapter_ops;
    return adapter_ops->adapter_create_unordered_access_view(desc, resource, parent, parent_ops, view);
1938
}