mesa/src/imagination/vulkan/pvr_descriptor_set.c

1904 lines
71 KiB
C
Raw Normal View History

/*
* Copyright © 2022 Imagination Technologies Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <assert.h>
#include <limits.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <vulkan/vulkan.h>
#include "hwdef/rogue_hw_utils.h"
#include "pvr_bo.h"
#include "pvr_private.h"
#include "pvr_types.h"
#include "util/compiler.h"
#include "util/list.h"
#include "util/log.h"
#include "util/macros.h"
#include "vk_alloc.h"
#include "vk_format.h"
#include "vk_log.h"
#include "vk_object.h"
#include "vk_util.h"
#if defined(DEBUG)
static const struct {
const char *raw;
const char *primary;
const char *secondary;
const char *primary_dynamic;
const char *secondary_dynamic;
} stage_names[] = {
{ "Vertex",
"Vertex Primary",
"Vertex Secondary",
"Vertex Dynamic Primary",
"Vertex Dynamic Secondary" },
{ "Fragment",
"Fragment Primary",
"Fragment Secondary",
"Fragment Dynamic Primary",
"Fragment Dynamic Secondary" },
{ "Compute",
"Compute Primary",
"Compute Secondary",
"Compute Dynamic Primary",
"Compute Dynamic Secondary" },
};
static const char *descriptor_names[] = { "VK SAMPLER",
"VK COMBINED_IMAGE_SAMPLER",
"VK SAMPLED_IMAGE",
"VK STORAGE_IMAGE",
"VK UNIFORM_TEXEL_BUFFER",
"VK STORAGE_TEXEL_BUFFER",
"VK UNIFORM_BUFFER",
"VK STORAGE_BUFFER",
"VK UNIFORM_BUFFER_DYNAMIC",
"VK STORAGE_BUFFER_DYNAMIC",
"VK INPUT_ATTACHMENT" };
#endif
#define PVR_DESC_IMAGE_SECONDARY_OFFSET_ARRAYBASE 0U
#define PVR_DESC_IMAGE_SECONDARY_SIZE_ARRAYBASE 2U
#define PVR_DESC_IMAGE_SECONDARY_OFFSET_ARRAYSTRIDE \
(PVR_DESC_IMAGE_SECONDARY_OFFSET_ARRAYBASE + \
PVR_DESC_IMAGE_SECONDARY_SIZE_ARRAYBASE)
#define PVR_DESC_IMAGE_SECONDARY_SIZE_ARRAYSTRIDE 1U
#define PVR_DESC_IMAGE_SECONDARY_OFFSET_ARRAYMAXINDEX(dev_info) \
(PVR_HAS_FEATURE(dev_info, tpu_array_textures) \
? (0) \
: PVR_DESC_IMAGE_SECONDARY_OFFSET_ARRAYSTRIDE + \
PVR_DESC_IMAGE_SECONDARY_SIZE_ARRAYSTRIDE)
#define PVR_DESC_IMAGE_SECONDARY_SIZE_ARRAYMAXINDEX 1U
#define PVR_DESC_IMAGE_SECONDARY_OFFSET_WIDTH(dev_info) \
(PVR_DESC_IMAGE_SECONDARY_OFFSET_ARRAYMAXINDEX(dev_info) + \
PVR_DESC_IMAGE_SECONDARY_SIZE_ARRAYMAXINDEX)
#define PVR_DESC_IMAGE_SECONDARY_SIZE_WIDTH 1U
#define PVR_DESC_IMAGE_SECONDARY_OFFSET_HEIGHT(dev_info) \
(PVR_DESC_IMAGE_SECONDARY_OFFSET_WIDTH(dev_info) + \
PVR_DESC_IMAGE_SECONDARY_SIZE_WIDTH)
#define PVR_DESC_IMAGE_SECONDARY_SIZE_HEIGHT 1U
#define PVR_DESC_IMAGE_SECONDARY_OFFSET_DEPTH(dev_info) \
(PVR_DESC_IMAGE_SECONDARY_OFFSET_HEIGHT(dev_info) + \
PVR_DESC_IMAGE_SECONDARY_SIZE_HEIGHT)
#define PVR_DESC_IMAGE_SECONDARY_SIZE_DEPTH 1U
#define PVR_DESC_IMAGE_SECONDARY_TOTAL_SIZE(dev_info) \
(PVR_DESC_IMAGE_SECONDARY_OFFSET_DEPTH(dev_info) + \
PVR_DESC_IMAGE_SECONDARY_SIZE_DEPTH)
static void pvr_descriptor_size_info_init(
const struct pvr_device *device,
VkDescriptorType type,
struct pvr_descriptor_size_info *const size_info_out)
{
/* UINT_MAX is a place holder. These values will be filled by calling the
* init function, and set appropriately based on device features.
*/
static const struct pvr_descriptor_size_info template_size_infos[] = {
/* VK_DESCRIPTOR_TYPE_SAMPLER */
{ PVR_SAMPLER_DESCRIPTOR_SIZE, 0, 4 },
/* VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER */
{ PVR_IMAGE_DESCRIPTOR_SIZE + PVR_SAMPLER_DESCRIPTOR_SIZE, UINT_MAX, 4 },
/* VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE */
{ 4, UINT_MAX, 4 },
/* VK_DESCRIPTOR_TYPE_STORAGE_IMAGE */
{ 4, UINT_MAX, 4 },
/* VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER */
{ 4, UINT_MAX, 4 },
/* VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER */
{ 4, UINT_MAX, 4 },
/* VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER */
{ 2, UINT_MAX, 2 },
/* VK_DESCRIPTOR_TYPE_STORAGE_BUFFER */
{ 2, 1, 2 },
/* VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC */
{ 2, UINT_MAX, 2 },
/* VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC */
{ 2, 1, 2 },
/* VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT */
{ 8, UINT_MAX, 4 }
};
*size_info_out = template_size_infos[type];
switch (type) {
case VK_DESCRIPTOR_TYPE_SAMPLER:
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
break;
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
size_info_out->secondary =
PVR_DESC_IMAGE_SECONDARY_TOTAL_SIZE(&device->pdevice->dev_info);
break;
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
size_info_out->secondary = (uint32_t)device->features.robustBufferAccess;
break;
default:
unreachable("Unknown descriptor type");
}
}
static bool pvr_stage_matches_vk_flags(enum pvr_stage_allocation pvr_stage,
VkShaderStageFlags flags)
{
VkShaderStageFlags flags_per_stage;
switch (pvr_stage) {
case PVR_STAGE_ALLOCATION_VERTEX_GEOMETRY:
flags_per_stage = VK_SHADER_STAGE_VERTEX_BIT |
VK_SHADER_STAGE_GEOMETRY_BIT;
break;
case PVR_STAGE_ALLOCATION_FRAGMENT:
flags_per_stage = VK_SHADER_STAGE_FRAGMENT_BIT;
break;
case PVR_STAGE_ALLOCATION_COMPUTE:
flags_per_stage = VK_SHADER_STAGE_COMPUTE_BIT;
break;
default:
unreachable("Unrecognized allocation stage.");
}
return !!(flags_per_stage & flags);
}
/* If allocator == NULL, the internal one will be used. */
static struct pvr_descriptor_set_layout *
pvr_descriptor_set_layout_allocate(struct pvr_device *device,
const VkAllocationCallbacks *allocator,
uint32_t binding_count,
uint32_t immutable_sampler_count,
uint32_t supported_descriptors_count)
{
struct pvr_descriptor_set_layout_binding *bindings;
struct pvr_descriptor_set_layout *layout;
__typeof__(layout->per_stage_descriptor_count) counts;
pvr: Fix seg fault in vkAllocateDescriptorSets(). In cases when no immutable samplers were present but sampler descriptor set layout bindings were, a seg fault was being caused by an attempt to get the immutable sampler from within the immutable sampler array while the array was not allocated. This commit also remove the binding type check since only those specific types can have immutable samplers. The check is covered by the descriptor set layout creation and assignment of has_immutable_samplers. This commit also makes the immutable samplers const, since they're meant to be immutable. This commit also adds has_immutable_samplers field to descriptor set layout. Previously to check whether immutable samplers were present or not you'd check for the layout binding's descriptor count to be 0 and the immutable sampler offset to be 0. This doesn't tell you everything. If you have a descriptor of the appropriate type (VK_DESCRIPTOR_TYPE_{COMBINED_,}IMAGE_SAMPLER). So descriptor count of >1. The offset can be 0 if you don't have immutable sampler, or have them at the beginning of the immutable samplers array. So you can't determine if you really have immutable samplers or not. One could attempt to perform a NULL check on the array but this would not work in cases where you have following set layout bindings with immutable samplers as the array stores the whole layout's immutable samplers. Signed-off-by: Karmjit Mahil <Karmjit.Mahil@imgtec.com> Reviewed-by: Rajnesh Kanwal <rajnesh.kanwal@imgtec.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/15688>
2022-02-25 09:29:57 +00:00
const struct pvr_sampler **immutable_samplers;
VK_MULTIALLOC(ma);
vk_multialloc_add(&ma, &layout, __typeof__(*layout), 1);
vk_multialloc_add(&ma, &bindings, __typeof__(*bindings), binding_count);
vk_multialloc_add(&ma,
&immutable_samplers,
__typeof__(*immutable_samplers),
immutable_sampler_count);
for (uint32_t stage = 0; stage < ARRAY_SIZE(counts); stage++) {
vk_multialloc_add(&ma,
&counts[stage],
__typeof__(*counts[0]),
supported_descriptors_count);
}
/* pvr_CreateDescriptorSetLayout() relies on this being zero allocated. */
if (!vk_multialloc_zalloc2(&ma,
&device->vk.alloc,
allocator,
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT)) {
return NULL;
}
layout->bindings = bindings;
layout->immutable_samplers = immutable_samplers;
memcpy(&layout->per_stage_descriptor_count, &counts, sizeof(counts));
vk_object_base_init(&device->vk,
&layout->base,
VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT);
return layout;
}
/* If allocator == NULL, the internal one will be used. */
static void
pvr_descriptor_set_layout_free(struct pvr_device *device,
const VkAllocationCallbacks *allocator,
struct pvr_descriptor_set_layout *layout)
{
vk_object_base_finish(&layout->base);
vk_free2(&device->vk.alloc, allocator, layout);
}
static int pvr_binding_compare(const void *a, const void *b)
{
uint32_t binding_a = ((VkDescriptorSetLayoutBinding *)a)->binding;
uint32_t binding_b = ((VkDescriptorSetLayoutBinding *)b)->binding;
if (binding_a < binding_b)
return -1;
if (binding_a > binding_b)
return 1;
return 0;
}
/* If allocator == NULL, the internal one will be used. */
static VkDescriptorSetLayoutBinding *
pvr_create_sorted_bindings(struct pvr_device *device,
const VkAllocationCallbacks *allocator,
const VkDescriptorSetLayoutBinding *bindings,
uint32_t binding_count)
{
VkDescriptorSetLayoutBinding *sorted_bindings =
vk_alloc2(&device->vk.alloc,
allocator,
binding_count * sizeof(*sorted_bindings),
8,
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
if (!sorted_bindings)
return NULL;
memcpy(sorted_bindings, bindings, binding_count * sizeof(*sorted_bindings));
qsort(sorted_bindings,
binding_count,
sizeof(*sorted_bindings),
pvr_binding_compare);
return sorted_bindings;
}
struct pvr_register_usage {
uint32_t primary;
uint32_t primary_dynamic;
uint32_t secondary;
uint32_t secondary_dynamic;
};
static void pvr_setup_in_memory_layout_sizes(
struct pvr_descriptor_set_layout *layout,
const struct pvr_register_usage reg_usage[PVR_STAGE_ALLOCATION_COUNT])
{
for (uint32_t stage = 0;
stage < ARRAY_SIZE(layout->memory_layout_in_dwords_per_stage);
stage++) {
layout->total_size_in_dwords = ALIGN_POT(layout->total_size_in_dwords, 4);
layout->memory_layout_in_dwords_per_stage[stage].primary_offset =
layout->total_size_in_dwords;
layout->memory_layout_in_dwords_per_stage[stage].primary_size =
reg_usage[stage].primary;
layout->total_size_in_dwords += reg_usage[stage].primary;
layout->total_size_in_dwords = ALIGN_POT(layout->total_size_in_dwords, 4);
layout->memory_layout_in_dwords_per_stage[stage].secondary_offset =
layout->total_size_in_dwords;
layout->memory_layout_in_dwords_per_stage[stage].secondary_size =
reg_usage[stage].secondary;
layout->total_size_in_dwords += reg_usage[stage].secondary;
layout->memory_layout_in_dwords_per_stage[stage].primary_dynamic_size =
reg_usage[stage].primary_dynamic;
layout->memory_layout_in_dwords_per_stage[stage].secondary_dynamic_size =
reg_usage[stage].secondary_dynamic;
}
}
#if defined(DEBUG)
static void
pvr_dump_in_memory_layout_sizes(const struct pvr_descriptor_set_layout *layout)
{
mesa_logd("=== SET LAYOUT ===");
mesa_logd("----------------------------------------------");
mesa_logd(" in memory:");
mesa_logd("----------------------------------------------");
for (uint32_t stage = 0;
stage < ARRAY_SIZE(layout->memory_layout_in_dwords_per_stage);
stage++) {
mesa_logd(
"| %-18s @ %04u |",
stage_names[stage].primary,
layout->memory_layout_in_dwords_per_stage[stage].primary_offset);
mesa_logd("----------------------------------------------");
/* Print primaries. */
for (uint32_t i = 0; i < layout->binding_count; i++) {
const struct pvr_descriptor_set_layout_binding *const binding =
&layout->bindings[i];
if (binding->type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ||
binding->type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)
continue;
mesa_logd("| %s %04u | %-26s[%3u] |",
(binding->shader_stage_mask & (1U << stage)) ? " " : "X",
binding->per_stage_offset_in_dwords[stage].primary,
descriptor_names[binding->type],
binding->descriptor_count);
}
/* Print dynamic primaries. */
for (uint32_t i = 0; i < layout->binding_count; i++) {
const struct pvr_descriptor_set_layout_binding *const binding =
&layout->bindings[i];
if (binding->type != VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC &&
binding->type != VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)
continue;
mesa_logd("| * %s %04u | %-26s[%3u] |",
(binding->shader_stage_mask & (1U << stage)) ? " " : "X",
binding->per_stage_offset_in_dwords[stage].primary,
descriptor_names[binding->type],
binding->descriptor_count);
}
mesa_logd("----------------------------------------------");
mesa_logd(
"| %-18s @ %04u |",
stage_names[stage].secondary,
layout->memory_layout_in_dwords_per_stage[stage].secondary_offset);
mesa_logd("----------------------------------------------");
/* Print secondaries. */
for (uint32_t i = 0; i < layout->binding_count; i++) {
const struct pvr_descriptor_set_layout_binding *const binding =
&layout->bindings[i];
if (binding->type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ||
binding->type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)
continue;
mesa_logd("| %s %04u | %-26s[%3u] |",
(binding->shader_stage_mask & (1U << stage)) ? " " : "X",
binding->per_stage_offset_in_dwords[stage].secondary,
descriptor_names[binding->type],
binding->descriptor_count);
}
/* Print dynamic secondaries. */
for (uint32_t i = 0; i < layout->binding_count; i++) {
const struct pvr_descriptor_set_layout_binding *const binding =
&layout->bindings[i];
if (binding->type != VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC &&
binding->type != VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)
continue;
mesa_logd("| * %s %04u | %-26s[%3u] |",
(binding->shader_stage_mask & (1U << stage)) ? " " : "X",
binding->per_stage_offset_in_dwords[stage].secondary,
descriptor_names[binding->type],
binding->descriptor_count);
}
mesa_logd("==============================================");
}
}
#endif
VkResult pvr_CreateDescriptorSetLayout(
VkDevice _device,
const VkDescriptorSetLayoutCreateInfo *pCreateInfo,
const VkAllocationCallbacks *pAllocator,
VkDescriptorSetLayout *pSetLayout)
{
/* Used to accumulate sizes and set each descriptor's offsets per stage. */
struct pvr_register_usage reg_usage[PVR_STAGE_ALLOCATION_COUNT] = { 0 };
PVR_FROM_HANDLE(pvr_device, device, _device);
struct pvr_descriptor_set_layout *layout;
VkDescriptorSetLayoutBinding *bindings;
uint32_t immutable_sampler_count;
assert(pCreateInfo->sType ==
VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO);
vk_foreach_struct_const (ext, pCreateInfo->pNext) {
pvr_debug_ignored_stype(ext->sType);
}
/* TODO: Add support for push descriptors. */
if (pCreateInfo->bindingCount == 0) {
layout = pvr_descriptor_set_layout_allocate(device, pAllocator, 0, 0, 0);
if (!layout)
return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
*pSetLayout = pvr_descriptor_set_layout_to_handle(layout);
return VK_SUCCESS;
}
/* TODO: Instead of sorting, maybe do what anvil does? */
bindings = pvr_create_sorted_bindings(device,
pAllocator,
pCreateInfo->pBindings,
pCreateInfo->bindingCount);
if (!bindings)
return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
immutable_sampler_count = 0;
for (uint32_t i = 0; i < pCreateInfo->bindingCount; i++) {
/* From the Vulkan 1.1.97 spec for VkDescriptorSetLayoutBinding:
*
* "If descriptorType specifies a VK_DESCRIPTOR_TYPE_SAMPLER or
* VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER type descriptor, then
* pImmutableSamplers can be used to initialize a set of immutable
* samplers. [...] If descriptorType is not one of these descriptor
* types, then pImmutableSamplers is ignored.
*
* We need to be careful here and only parse pImmutableSamplers if we
* have one of the right descriptor types.
*/
const VkDescriptorType descriptor_type = bindings[i].descriptorType;
if ((descriptor_type == VK_DESCRIPTOR_TYPE_SAMPLER ||
descriptor_type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) &&
bindings[i].pImmutableSamplers)
immutable_sampler_count += bindings[i].descriptorCount;
}
/* From the Vulkan 1.2.190 spec for VkDescriptorSetLayoutCreateInfo:
*
* "The VkDescriptorSetLayoutBinding::binding members of the elements
* of the pBindings array must each have different values."
*
* So we don't worry about duplicates and just allocate for bindingCount
* amount of bindings.
*/
layout = pvr_descriptor_set_layout_allocate(
device,
pAllocator,
pCreateInfo->bindingCount,
immutable_sampler_count,
PVR_PIPELINE_LAYOUT_SUPPORTED_DESCRIPTOR_TYPE_COUNT);
if (!layout) {
vk_free2(&device->vk.alloc, pAllocator, bindings);
return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
}
layout->binding_count = pCreateInfo->bindingCount;
for (uint32_t bind_num = 0; bind_num < layout->binding_count; bind_num++) {
const VkDescriptorSetLayoutBinding *const binding = &bindings[bind_num];
struct pvr_descriptor_set_layout_binding *const internal_binding =
&layout->bindings[bind_num];
VkShaderStageFlags shader_stages = 0;
internal_binding->type = binding->descriptorType;
/* The binding_numbers can be non-contiguous so we ignore the user
* specified binding numbers and make them contiguous ourselves.
*/
internal_binding->binding_number = bind_num;
/* From Vulkan spec 1.2.189:
*
* "If descriptorCount is zero this binding entry is reserved and the
* resource must not be accessed from any stage via this binding"
*
* So do not use bindings->stageFlags, use shader_stages instead.
*/
if (binding->descriptorCount) {
shader_stages = binding->stageFlags;
internal_binding->descriptor_count = binding->descriptorCount;
internal_binding->descriptor_index = layout->descriptor_count;
layout->descriptor_count += binding->descriptorCount;
}
switch (binding->descriptorType) {
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
case VK_DESCRIPTOR_TYPE_SAMPLER:
if (binding->pImmutableSamplers && binding->descriptorCount > 0) {
pvr: Fix seg fault in vkAllocateDescriptorSets(). In cases when no immutable samplers were present but sampler descriptor set layout bindings were, a seg fault was being caused by an attempt to get the immutable sampler from within the immutable sampler array while the array was not allocated. This commit also remove the binding type check since only those specific types can have immutable samplers. The check is covered by the descriptor set layout creation and assignment of has_immutable_samplers. This commit also makes the immutable samplers const, since they're meant to be immutable. This commit also adds has_immutable_samplers field to descriptor set layout. Previously to check whether immutable samplers were present or not you'd check for the layout binding's descriptor count to be 0 and the immutable sampler offset to be 0. This doesn't tell you everything. If you have a descriptor of the appropriate type (VK_DESCRIPTOR_TYPE_{COMBINED_,}IMAGE_SAMPLER). So descriptor count of >1. The offset can be 0 if you don't have immutable sampler, or have them at the beginning of the immutable samplers array. So you can't determine if you really have immutable samplers or not. One could attempt to perform a NULL check on the array but this would not work in cases where you have following set layout bindings with immutable samplers as the array stores the whole layout's immutable samplers. Signed-off-by: Karmjit Mahil <Karmjit.Mahil@imgtec.com> Reviewed-by: Rajnesh Kanwal <rajnesh.kanwal@imgtec.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/15688>
2022-02-25 09:29:57 +00:00
internal_binding->has_immutable_samplers = true;
internal_binding->immutable_samplers_index =
layout->immutable_sampler_count;
for (uint32_t j = 0; j < binding->descriptorCount; j++) {
PVR_FROM_HANDLE(pvr_sampler,
sampler,
bindings->pImmutableSamplers[j]);
const uint32_t next = j + layout->immutable_sampler_count;
layout->immutable_samplers[next] = sampler;
}
layout->immutable_sampler_count += binding->descriptorCount;
}
break;
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
layout->dynamic_buffer_count += binding->descriptorCount;
break;
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
break;
default:
unreachable("Unknown descriptor type");
break;
}
if (!shader_stages)
continue;
internal_binding->shader_stages = shader_stages;
layout->shader_stages |= shader_stages;
for (uint32_t stage = 0;
stage < ARRAY_SIZE(layout->bindings[0].per_stage_offset_in_dwords);
stage++) {
const VkDescriptorType descriptor_type = binding->descriptorType;
if (!pvr_stage_matches_vk_flags(stage, shader_stages))
continue;
internal_binding->shader_stage_mask |= (1U << stage);
/* TODO: Do we have to allocate them at the end? We could speed it
* by allocating them here if not. */
/* We allocate dynamics primary and secondaries at the end. */
if (descriptor_type != VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC &&
descriptor_type != VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) {
struct pvr_descriptor_size_info size_info;
pvr_descriptor_size_info_init(device, descriptor_type, &size_info);
STATIC_ASSERT(
ARRAY_SIZE(reg_usage) ==
ARRAY_SIZE(layout->bindings[0].per_stage_offset_in_dwords));
reg_usage[stage].primary =
ALIGN_POT(reg_usage[stage].primary, size_info.alignment);
internal_binding->per_stage_offset_in_dwords[stage].primary =
reg_usage[stage].primary;
reg_usage[stage].primary +=
size_info.primary * internal_binding->descriptor_count;
internal_binding->per_stage_offset_in_dwords[stage].secondary =
reg_usage[stage].secondary;
reg_usage[stage].secondary +=
size_info.secondary * internal_binding->descriptor_count;
}
STATIC_ASSERT(
ARRAY_SIZE(layout->per_stage_descriptor_count) ==
ARRAY_SIZE(layout->bindings[0].per_stage_offset_in_dwords));
layout->per_stage_descriptor_count[stage][descriptor_type] +=
internal_binding->descriptor_count;
}
}
for (uint32_t bind_num = 0; bind_num < layout->binding_count; bind_num++) {
struct pvr_descriptor_set_layout_binding *const internal_binding =
&layout->bindings[bind_num];
const VkDescriptorType descriptor_type = internal_binding->type;
if (descriptor_type != VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC &&
descriptor_type != VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)
continue;
for (uint32_t stage = 0;
stage < ARRAY_SIZE(layout->bindings[0].per_stage_offset_in_dwords);
stage++) {
struct pvr_descriptor_size_info size_info;
const VkShaderStageFlags shader_stages =
internal_binding->shader_stages;
if (!pvr_stage_matches_vk_flags(stage, shader_stages))
continue;
pvr_descriptor_size_info_init(device, descriptor_type, &size_info);
/* TODO: align primary like we did with other descriptors? */
internal_binding->per_stage_offset_in_dwords[stage].primary =
reg_usage[stage].primary_dynamic;
reg_usage[stage].primary_dynamic +=
size_info.primary * internal_binding->descriptor_count;
internal_binding->per_stage_offset_in_dwords[stage].secondary =
reg_usage[stage].secondary_dynamic;
reg_usage[stage].secondary_dynamic +=
size_info.secondary * internal_binding->descriptor_count;
}
}
pvr_setup_in_memory_layout_sizes(layout, reg_usage);
#if defined(DEBUG)
pvr_dump_in_memory_layout_sizes(layout);
#endif
vk_free2(&device->vk.alloc, pAllocator, bindings);
*pSetLayout = pvr_descriptor_set_layout_to_handle(layout);
return VK_SUCCESS;
}
void pvr_DestroyDescriptorSetLayout(VkDevice _device,
VkDescriptorSetLayout _set_layout,
const VkAllocationCallbacks *pAllocator)
{
PVR_FROM_HANDLE(pvr_descriptor_set_layout, layout, _set_layout);
PVR_FROM_HANDLE(pvr_device, device, _device);
pvr_descriptor_set_layout_free(device, pAllocator, layout);
}
#if defined(DEBUG)
static void
pvr_dump_in_register_layout_sizes(const struct pvr_device *device,
const struct pvr_pipeline_layout *layout)
{
mesa_logd("=== SET LAYOUT ===");
mesa_logd("----------------------------------------------------");
mesa_logd(" in registers:");
mesa_logd("----------------------------------------------------");
for (uint32_t stage = 0;
stage < ARRAY_SIZE(layout->register_layout_in_dwords_per_stage);
stage++) {
uint32_t dynamic_offset = 0;
mesa_logd("| %-48s |", stage_names[stage].primary_dynamic);
mesa_logd("----------------------------------------------------");
/* Print dynamic primaries. */
for (uint32_t set_num = 0; set_num < layout->set_count; set_num++) {
const struct pvr_descriptor_set_layout *const set_layout =
layout->set_layout[set_num];
for (uint32_t i = 0; i < set_layout->binding_count; i++) {
const struct pvr_descriptor_set_layout_binding *const binding =
&set_layout->bindings[i];
bool valid = !!(binding->shader_stage_mask & (1U << stage));
if (binding->type != VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC &&
binding->type != VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)
continue;
mesa_logd("| %s %04u | %u:%03u | %-26s[%3u] |",
(valid) ? " " : "X",
dynamic_offset,
set_num,
i,
descriptor_names[binding->type],
binding->descriptor_count);
if (valid) {
struct pvr_descriptor_size_info size_info;
pvr_descriptor_size_info_init(device, binding->type, &size_info);
dynamic_offset += size_info.primary;
}
}
}
mesa_logd("----------------------------------------------------");
mesa_logd("| %-48s |", stage_names[stage].secondary_dynamic);
mesa_logd("----------------------------------------------------");
/* Print dynamic secondaries. */
for (uint32_t set_num = 0; set_num < layout->set_count; set_num++) {
const struct pvr_descriptor_set_layout *const set_layout =
layout->set_layout[set_num];
for (uint32_t i = 0; i < set_layout->binding_count; i++) {
const struct pvr_descriptor_set_layout_binding *const binding =
&set_layout->bindings[i];
bool valid = !!(binding->shader_stage_mask & (1U << stage));
if (binding->type != VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC &&
binding->type != VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)
continue;
mesa_logd("| %s %04u | %u:%03u | %-26s[%3u] |",
(valid) ? " " : "X",
dynamic_offset,
set_num,
i,
descriptor_names[binding->type],
binding->descriptor_count);
if (valid) {
struct pvr_descriptor_size_info size_info;
pvr_descriptor_size_info_init(device, binding->type, &size_info);
dynamic_offset += size_info.secondary;
}
}
}
mesa_logd("----------------------------------------------------");
mesa_logd("| %-48s |", stage_names[stage].primary);
mesa_logd("----------------------------------------------------");
/* Print primaries. */
for (uint32_t set_num = 0; set_num < layout->set_count; set_num++) {
const struct pvr_descriptor_set_layout *const set_layout =
layout->set_layout[set_num];
const uint32_t base =
layout->register_layout_in_dwords_per_stage[stage][set_num]
.primary_offset;
for (uint32_t i = 0; i < set_layout->binding_count; i++) {
const struct pvr_descriptor_set_layout_binding *const binding =
&set_layout->bindings[i];
if (binding->type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ||
binding->type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)
continue;
mesa_logd("| %s %04u | %u:%03u | %-26s[%3u] |",
(binding->shader_stage_mask & (1U << stage)) ? " " : "X",
base + binding->per_stage_offset_in_dwords[stage].primary,
set_num,
i,
descriptor_names[binding->type],
binding->descriptor_count);
}
}
mesa_logd("----------------------------------------------------");
mesa_logd("| %-48s |", stage_names[stage].secondary);
mesa_logd("----------------------------------------------------");
/* Print secondaries. */
for (uint32_t set_num = 0; set_num < layout->set_count; set_num++) {
const struct pvr_descriptor_set_layout *const set_layout =
layout->set_layout[set_num];
const uint32_t base =
layout->register_layout_in_dwords_per_stage[stage][set_num]
.secondary_offset;
for (uint32_t i = 0; i < set_layout->binding_count; i++) {
const struct pvr_descriptor_set_layout_binding *const binding =
&set_layout->bindings[i];
if (binding->type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ||
binding->type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)
continue;
mesa_logd("| %s %04u | %u:%03u | %-26s[%3u] |",
(binding->shader_stage_mask & (1U << stage)) ? " " : "X",
base +
binding->per_stage_offset_in_dwords[stage].secondary,
set_num,
i,
descriptor_names[binding->type],
binding->descriptor_count);
}
}
mesa_logd("====================================================");
}
}
#endif
/* Pipeline layouts. These have nothing to do with the pipeline. They are
* just multiple descriptor set layouts pasted together.
*/
VkResult pvr_CreatePipelineLayout(VkDevice _device,
const VkPipelineLayoutCreateInfo *pCreateInfo,
const VkAllocationCallbacks *pAllocator,
VkPipelineLayout *pPipelineLayout)
{
uint32_t next_free_reg[PVR_STAGE_ALLOCATION_COUNT];
PVR_FROM_HANDLE(pvr_device, device, _device);
struct pvr_pipeline_layout *layout;
assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO);
assert(pCreateInfo->setLayoutCount <= PVR_MAX_DESCRIPTOR_SETS);
layout = vk_object_alloc(&device->vk,
pAllocator,
sizeof(*layout),
VK_OBJECT_TYPE_PIPELINE_LAYOUT);
if (!layout)
return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
layout->set_count = pCreateInfo->setLayoutCount;
layout->shader_stages = 0;
for (uint32_t stage = 0; stage < PVR_STAGE_ALLOCATION_COUNT; stage++) {
uint32_t descriptor_counts
[PVR_PIPELINE_LAYOUT_SUPPORTED_DESCRIPTOR_TYPE_COUNT] = { 0 };
struct pvr_pipeline_layout_reg_info *const reg_info =
&layout->per_stage_reg_info[stage];
*reg_info = (struct pvr_pipeline_layout_reg_info){ 0 };
layout->per_stage_descriptor_masks[stage] = 0;
for (uint32_t set_num = 0; set_num < layout->set_count; set_num++) {
/* So we don't write these again and again. Just do it once. */
if (stage == 0) {
PVR_FROM_HANDLE(pvr_descriptor_set_layout,
set_layout,
pCreateInfo->pSetLayouts[set_num]);
layout->set_layout[set_num] = set_layout;
layout->shader_stages |= set_layout->shader_stages;
}
const struct pvr_descriptor_set_layout_mem_layout *const mem_layout =
&layout->set_layout[set_num]
->memory_layout_in_dwords_per_stage[stage];
/* Allocate registers counts for dynamic descriptors. */
reg_info->primary_dynamic_size_in_dwords +=
mem_layout->primary_dynamic_size;
reg_info->secondary_dynamic_size_in_dwords +=
mem_layout->secondary_dynamic_size;
for (VkDescriptorType type = 0;
type < PVR_PIPELINE_LAYOUT_SUPPORTED_DESCRIPTOR_TYPE_COUNT;
type++) {
uint32_t descriptor_count;
layout->descriptor_offsets[set_num][stage][type] =
descriptor_counts[type];
descriptor_count = layout->set_layout[set_num]
->per_stage_descriptor_count[stage][type];
if (!descriptor_count)
continue;
switch (type) {
case VK_DESCRIPTOR_TYPE_SAMPLER:
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
layout->per_stage_descriptor_masks[stage] |= 1U << set_num;
descriptor_counts[type] += descriptor_count;
break;
/* We don't need to keep track of the counts or masks for other
* descriptor types so there is no assert() here since other
* types are not invalid or unsupported.
*/
/* TODO: Improve the comment above to specify why, when we find
* out.
*/
default:
break;
}
}
}
next_free_reg[stage] = reg_info->primary_dynamic_size_in_dwords +
reg_info->secondary_dynamic_size_in_dwords;
}
/* Allocate registers counts for primary and secondary descriptors. */
for (uint32_t stage = 0; stage < PVR_STAGE_ALLOCATION_COUNT; stage++) {
for (uint32_t set_num = 0; set_num < layout->set_count; set_num++) {
const struct pvr_descriptor_set_layout_mem_layout *const mem_layout =
&layout->set_layout[set_num]
->memory_layout_in_dwords_per_stage[stage];
struct pvr_descriptor_set_layout_mem_layout *const reg_layout =
&layout->register_layout_in_dwords_per_stage[stage][set_num];
next_free_reg[stage] = ALIGN_POT(next_free_reg[stage], 4);
reg_layout->primary_offset = next_free_reg[stage];
reg_layout->primary_size = mem_layout->primary_size;
next_free_reg[stage] += reg_layout->primary_size;
}
/* To optimize the total shared layout allocation used by the shader,
* secondary descriptors come last since they're less likely to be used.
*/
for (uint32_t set_num = 0; set_num < layout->set_count; set_num++) {
const struct pvr_descriptor_set_layout_mem_layout *const mem_layout =
&layout->set_layout[set_num]
->memory_layout_in_dwords_per_stage[stage];
struct pvr_descriptor_set_layout_mem_layout *const reg_layout =
&layout->register_layout_in_dwords_per_stage[stage][set_num];
/* Should we be aligning next_free_reg like it's done with the
* primary descriptors?
*/
reg_layout->secondary_offset = next_free_reg[stage];
reg_layout->secondary_size = mem_layout->secondary_size;
next_free_reg[stage] += reg_layout->secondary_size;
}
}
layout->push_constants_shader_stages = 0;
for (uint32_t i = 0; i < pCreateInfo->pushConstantRangeCount; ++i) {
const VkPushConstantRange *range = &pCreateInfo->pPushConstantRanges[i];
layout->push_constants_shader_stages |= range->stageFlags;
}
#if defined(DEBUG)
pvr_dump_in_register_layout_sizes(device, layout);
#endif
*pPipelineLayout = pvr_pipeline_layout_to_handle(layout);
return VK_SUCCESS;
}
void pvr_DestroyPipelineLayout(VkDevice _device,
VkPipelineLayout _pipelineLayout,
const VkAllocationCallbacks *pAllocator)
{
PVR_FROM_HANDLE(pvr_device, device, _device);
PVR_FROM_HANDLE(pvr_pipeline_layout, layout, _pipelineLayout);
vk_object_free(&device->vk, pAllocator, layout);
}
VkResult pvr_CreateDescriptorPool(VkDevice _device,
const VkDescriptorPoolCreateInfo *pCreateInfo,
const VkAllocationCallbacks *pAllocator,
VkDescriptorPool *pDescriptorPool)
{
PVR_FROM_HANDLE(pvr_device, device, _device);
struct pvr_descriptor_pool *pool;
assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO);
pool = vk_object_alloc(&device->vk,
pAllocator,
sizeof(*pool),
VK_OBJECT_TYPE_DESCRIPTOR_POOL);
if (!pool)
return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
if (pAllocator)
pool->alloc = *pAllocator;
else
pool->alloc = device->vk.alloc;
pool->max_sets = pCreateInfo->maxSets;
list_inithead(&pool->descriptor_sets);
pool->total_size_in_dwords = 0;
for (uint32_t i = 0; i < pCreateInfo->poolSizeCount; i++) {
struct pvr_descriptor_size_info size_info;
const uint32_t descriptor_count =
pCreateInfo->pPoolSizes[i].descriptorCount;
pvr_descriptor_size_info_init(device,
pCreateInfo->pPoolSizes[i].type,
&size_info);
const uint32_t secondary = ALIGN_POT(size_info.secondary, 4);
const uint32_t primary = ALIGN_POT(size_info.primary, 4);
pool->total_size_in_dwords += descriptor_count * (primary + secondary);
}
pool->total_size_in_dwords *= PVR_STAGE_ALLOCATION_COUNT;
pool->current_size_in_dwords = 0;
pvr_finishme("Entry tracker for allocations?");
*pDescriptorPool = pvr_descriptor_pool_to_handle(pool);
return VK_SUCCESS;
}
static void pvr_free_descriptor_set(struct pvr_device *device,
struct pvr_descriptor_pool *pool,
struct pvr_descriptor_set *set)
{
list_del(&set->link);
pvr_bo_free(device, set->pvr_bo);
vk_object_free(&device->vk, &pool->alloc, set);
}
void pvr_DestroyDescriptorPool(VkDevice _device,
VkDescriptorPool _pool,
const VkAllocationCallbacks *pAllocator)
{
PVR_FROM_HANDLE(pvr_device, device, _device);
PVR_FROM_HANDLE(pvr_descriptor_pool, pool, _pool);
if (!pool)
return;
list_for_each_entry_safe (struct pvr_descriptor_set,
set,
&pool->descriptor_sets,
link) {
pvr_free_descriptor_set(device, pool, set);
}
vk_object_free(&device->vk, pAllocator, pool);
}
VkResult pvr_ResetDescriptorPool(VkDevice _device,
VkDescriptorPool descriptorPool,
VkDescriptorPoolResetFlags flags)
{
assert(!"Unimplemented");
return VK_SUCCESS;
}
static uint16_t pvr_get_descriptor_primary_offset(
const struct pvr_device *device,
const struct pvr_descriptor_set_layout *layout,
const struct pvr_descriptor_set_layout_binding *binding,
const uint32_t stage,
const uint32_t desc_idx)
{
struct pvr_descriptor_size_info size_info;
uint32_t offset;
assert(stage < ARRAY_SIZE(layout->memory_layout_in_dwords_per_stage));
assert(desc_idx < binding->descriptor_count);
pvr_descriptor_size_info_init(device, binding->type, &size_info);
offset = layout->memory_layout_in_dwords_per_stage[stage].primary_offset;
offset += binding->per_stage_offset_in_dwords[stage].primary;
offset += (desc_idx * size_info.primary);
/* Offset must be less than 16bits. */
assert(offset < UINT16_MAX);
return (uint16_t)offset;
}
static uint16_t pvr_get_descriptor_secondary_offset(
const struct pvr_device *device,
const struct pvr_descriptor_set_layout *layout,
const struct pvr_descriptor_set_layout_binding *binding,
const uint32_t stage,
const uint32_t desc_idx)
{
struct pvr_descriptor_size_info size_info;
uint32_t offset;
assert(stage < ARRAY_SIZE(layout->memory_layout_in_dwords_per_stage));
assert(desc_idx < binding->descriptor_count);
pvr_descriptor_size_info_init(device, binding->type, &size_info);
offset = layout->memory_layout_in_dwords_per_stage[stage].secondary_offset;
offset += binding->per_stage_offset_in_dwords[stage].secondary;
offset += (desc_idx * size_info.secondary);
/* Offset must be less than 16bits. */
assert(offset < UINT16_MAX);
return (uint16_t)offset;
}
#define PVR_MAX_DESCRIPTOR_MEM_SIZE_IN_DWORDS (4 * 1024)
static VkResult
pvr_descriptor_set_create(struct pvr_device *device,
struct pvr_descriptor_pool *pool,
const struct pvr_descriptor_set_layout *layout,
struct pvr_descriptor_set **const descriptor_set_out)
{
struct pvr_descriptor_set *set;
VkResult result;
size_t size;
void *map;
size = sizeof(*set) + sizeof(set->descriptors[0]) * layout->descriptor_count;
/* TODO: Add support to allocate descriptors from descriptor pool, also
* check the required descriptors must not exceed max allowed descriptors.
*/
set = vk_object_zalloc(&device->vk,
&pool->alloc,
size,
VK_OBJECT_TYPE_DESCRIPTOR_SET);
if (!set)
return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
/* TODO: Add support to allocate device memory from a common pool. Look at
* something like anv. Also we can allocate a whole chunk of device memory
* for max descriptors supported by pool as done by v3dv. Also check the
* possibility if this can be removed from here and done on need basis.
*/
if (layout->binding_count > 0) {
const uint32_t cache_line_size =
rogue_get_slc_cache_line_size(&device->pdevice->dev_info);
uint64_t bo_size = MIN2(pool->total_size_in_dwords,
PVR_MAX_DESCRIPTOR_MEM_SIZE_IN_DWORDS) *
sizeof(uint32_t);
result = pvr_bo_alloc(device,
device->heaps.general_heap,
bo_size,
cache_line_size,
PVR_BO_ALLOC_FLAG_CPU_MAPPED,
&set->pvr_bo);
if (result != VK_SUCCESS)
goto err_free_descriptor_set;
}
set->layout = layout;
set->pool = pool;
map = set->pvr_bo->bo->map;
for (uint32_t i = 0; i < layout->binding_count; i++) {
const struct pvr_descriptor_set_layout_binding *binding =
&layout->bindings[i];
pvr: Fix seg fault in vkAllocateDescriptorSets(). In cases when no immutable samplers were present but sampler descriptor set layout bindings were, a seg fault was being caused by an attempt to get the immutable sampler from within the immutable sampler array while the array was not allocated. This commit also remove the binding type check since only those specific types can have immutable samplers. The check is covered by the descriptor set layout creation and assignment of has_immutable_samplers. This commit also makes the immutable samplers const, since they're meant to be immutable. This commit also adds has_immutable_samplers field to descriptor set layout. Previously to check whether immutable samplers were present or not you'd check for the layout binding's descriptor count to be 0 and the immutable sampler offset to be 0. This doesn't tell you everything. If you have a descriptor of the appropriate type (VK_DESCRIPTOR_TYPE_{COMBINED_,}IMAGE_SAMPLER). So descriptor count of >1. The offset can be 0 if you don't have immutable sampler, or have them at the beginning of the immutable samplers array. So you can't determine if you really have immutable samplers or not. One could attempt to perform a NULL check on the array but this would not work in cases where you have following set layout bindings with immutable samplers as the array stores the whole layout's immutable samplers. Signed-off-by: Karmjit Mahil <Karmjit.Mahil@imgtec.com> Reviewed-by: Rajnesh Kanwal <rajnesh.kanwal@imgtec.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/15688>
2022-02-25 09:29:57 +00:00
if (binding->descriptor_count == 0 || !binding->has_immutable_samplers)
continue;
for (uint32_t stage = 0;
stage < ARRAY_SIZE(binding->per_stage_offset_in_dwords);
stage++) {
if (!(binding->shader_stage_mask & (1U << stage)))
continue;
for (uint32_t j = 0; j < binding->descriptor_count; j++) {
uint32_t idx = binding->immutable_samplers_index + j;
pvr: Fix seg fault in vkAllocateDescriptorSets(). In cases when no immutable samplers were present but sampler descriptor set layout bindings were, a seg fault was being caused by an attempt to get the immutable sampler from within the immutable sampler array while the array was not allocated. This commit also remove the binding type check since only those specific types can have immutable samplers. The check is covered by the descriptor set layout creation and assignment of has_immutable_samplers. This commit also makes the immutable samplers const, since they're meant to be immutable. This commit also adds has_immutable_samplers field to descriptor set layout. Previously to check whether immutable samplers were present or not you'd check for the layout binding's descriptor count to be 0 and the immutable sampler offset to be 0. This doesn't tell you everything. If you have a descriptor of the appropriate type (VK_DESCRIPTOR_TYPE_{COMBINED_,}IMAGE_SAMPLER). So descriptor count of >1. The offset can be 0 if you don't have immutable sampler, or have them at the beginning of the immutable samplers array. So you can't determine if you really have immutable samplers or not. One could attempt to perform a NULL check on the array but this would not work in cases where you have following set layout bindings with immutable samplers as the array stores the whole layout's immutable samplers. Signed-off-by: Karmjit Mahil <Karmjit.Mahil@imgtec.com> Reviewed-by: Rajnesh Kanwal <rajnesh.kanwal@imgtec.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/15688>
2022-02-25 09:29:57 +00:00
const struct pvr_sampler *sampler = layout->immutable_samplers[idx];
unsigned int offset_in_dwords =
pvr_get_descriptor_primary_offset(device,
layout,
binding,
stage,
j);
if (binding->type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
offset_in_dwords += 4;
memcpy((uint8_t *)map + offset_in_dwords * sizeof(uint32_t),
sampler->descriptor.words,
sizeof(sampler->descriptor.words));
}
}
}
list_addtail(&set->link, &pool->descriptor_sets);
*descriptor_set_out = set;
return VK_SUCCESS;
err_free_descriptor_set:
vk_object_free(&device->vk, &pool->alloc, set);
return result;
}
VkResult
pvr_AllocateDescriptorSets(VkDevice _device,
const VkDescriptorSetAllocateInfo *pAllocateInfo,
VkDescriptorSet *pDescriptorSets)
{
PVR_FROM_HANDLE(pvr_descriptor_pool, pool, pAllocateInfo->descriptorPool);
PVR_FROM_HANDLE(pvr_device, device, _device);
VkResult result;
uint32_t i;
vk_foreach_struct_const (ext, pAllocateInfo->pNext) {
pvr_debug_ignored_stype(ext->sType);
}
for (i = 0; i < pAllocateInfo->descriptorSetCount; i++) {
PVR_FROM_HANDLE(pvr_descriptor_set_layout,
layout,
pAllocateInfo->pSetLayouts[i]);
struct pvr_descriptor_set *set = NULL;
result = pvr_descriptor_set_create(device, pool, layout, &set);
if (result != VK_SUCCESS)
goto err_free_descriptor_sets;
pDescriptorSets[i] = pvr_descriptor_set_to_handle(set);
}
return VK_SUCCESS;
err_free_descriptor_sets:
pvr_FreeDescriptorSets(_device,
pAllocateInfo->descriptorPool,
i,
pDescriptorSets);
for (i = 0; i < pAllocateInfo->descriptorSetCount; i++)
pDescriptorSets[i] = VK_NULL_HANDLE;
return result;
}
VkResult pvr_FreeDescriptorSets(VkDevice _device,
VkDescriptorPool descriptorPool,
uint32_t count,
const VkDescriptorSet *pDescriptorSets)
{
PVR_FROM_HANDLE(pvr_descriptor_pool, pool, descriptorPool);
PVR_FROM_HANDLE(pvr_device, device, _device);
for (uint32_t i = 0; i < count; i++) {
struct pvr_descriptor_set *set;
if (!pDescriptorSets[i])
continue;
set = pvr_descriptor_set_from_handle(pDescriptorSets[i]);
pvr_free_descriptor_set(device, pool, set);
}
return VK_SUCCESS;
}
static int pvr_compare_layout_binding(const void *a, const void *b)
{
uint32_t binding_a;
uint32_t binding_b;
binding_a = ((struct pvr_descriptor_set_layout_binding *)a)->binding_number;
binding_b = ((struct pvr_descriptor_set_layout_binding *)b)->binding_number;
if (binding_a < binding_b)
return -1;
if (binding_a > binding_b)
return 1;
return 0;
}
/* This function does not assume that the binding will always exist for a
* particular binding_num. Caller should check before using the return pointer.
*/
static struct pvr_descriptor_set_layout_binding *
pvr_get_descriptor_binding(const struct pvr_descriptor_set_layout *layout,
const uint32_t binding_num)
{
struct pvr_descriptor_set_layout_binding binding;
binding.binding_number = binding_num;
return bsearch(&binding,
layout->bindings,
layout->binding_count,
sizeof(binding),
pvr_compare_layout_binding);
}
static void pvr_descriptor_update_buffer_info(
const struct pvr_device *device,
const VkWriteDescriptorSet *write_set,
struct pvr_descriptor_set *set,
const struct pvr_descriptor_set_layout_binding *binding,
uint32_t *mem_ptr,
uint32_t start_stage,
uint32_t end_stage)
{
struct pvr_descriptor_size_info size_info;
bool is_dynamic;
is_dynamic = (binding->type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) ||
(binding->type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC);
pvr_descriptor_size_info_init(device, binding->type, &size_info);
for (uint32_t i = 0; i < write_set->descriptorCount; i++) {
const VkDescriptorBufferInfo *buffer_info = &write_set->pBufferInfo[i];
PVR_FROM_HANDLE(pvr_buffer, buffer, buffer_info->buffer);
const uint32_t desc_idx =
binding->descriptor_index + write_set->dstArrayElement + i;
const pvr_dev_addr_t addr =
PVR_DEV_ADDR_OFFSET(buffer->dev_addr, buffer_info->offset);
uint32_t range = (buffer_info->range == VK_WHOLE_SIZE)
? (buffer->vk.size - buffer_info->offset)
: (buffer_info->range);
set->descriptors[desc_idx].type = write_set->descriptorType;
set->descriptors[desc_idx].buffer_dev_addr = addr;
set->descriptors[desc_idx].buffer_create_info_size = buffer->vk.size;
set->descriptors[desc_idx].buffer_desc_range = range;
if (is_dynamic)
continue;
/* Update the entries in the descriptor memory for static buffer. */
for (uint32_t j = start_stage; j < end_stage; j++) {
uint32_t primary_offset;
uint32_t secondary_offset;
if (!(binding->shader_stage_mask & BITFIELD_BIT(j)))
continue;
/* Offset calculation functions expect descriptor_index to be
* binding relative not layout relative, so we have used
* write_set->dstArrayElement + i rather than desc_idx.
*/
primary_offset =
pvr_get_descriptor_primary_offset(device,
set->layout,
binding,
j,
write_set->dstArrayElement + i);
secondary_offset =
pvr_get_descriptor_secondary_offset(device,
set->layout,
binding,
j,
write_set->dstArrayElement + i);
memcpy(mem_ptr + primary_offset, &addr, size_info.primary << 2);
memcpy(mem_ptr + secondary_offset, &range, size_info.secondary << 2);
}
}
}
static void pvr_descriptor_update_sampler(
const struct pvr_device *device,
const VkWriteDescriptorSet *write_set,
struct pvr_descriptor_set *set,
const struct pvr_descriptor_set_layout_binding *binding,
uint32_t *mem_ptr,
uint32_t start_stage,
uint32_t end_stage)
{
struct pvr_descriptor_size_info size_info;
pvr_descriptor_size_info_init(device, binding->type, &size_info);
for (uint32_t i = 0; i < write_set->descriptorCount; i++) {
PVR_FROM_HANDLE(pvr_sampler, sampler, write_set->pImageInfo[i].sampler);
const uint32_t desc_idx =
binding->descriptor_index + write_set->dstArrayElement + i;
set->descriptors[desc_idx].type = write_set->descriptorType;
set->descriptors[desc_idx].sampler = sampler;
for (uint32_t j = start_stage; j < end_stage; j++) {
uint32_t primary_offset;
if (!(binding->shader_stage_mask & BITFIELD_BIT(j)))
continue;
/* Offset calculation functions expect descriptor_index to be binding
* relative not layout relative, so we have used
* write_set->dstArrayElement + i rather than desc_idx.
*/
primary_offset =
pvr_get_descriptor_primary_offset(device,
set->layout,
binding,
j,
write_set->dstArrayElement + i);
memcpy(mem_ptr + primary_offset,
sampler->descriptor.words,
sizeof(sampler->descriptor.words));
}
}
}
static void
pvr_write_image_descriptor_primaries(const struct pvr_device_info *dev_info,
const struct pvr_image_view *iview,
VkDescriptorType descriptorType,
uint32_t *primary)
{
uint64_t *qword_ptr = (uint64_t *)primary;
if (descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE &&
(iview->vk.view_type == VK_IMAGE_VIEW_TYPE_CUBE ||
iview->vk.view_type == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY)) {
qword_ptr[0] = iview->texture_state[PVR_TEXTURE_STATE_STORAGE][0];
qword_ptr[1] = iview->texture_state[PVR_TEXTURE_STATE_STORAGE][1];
} else if (descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT) {
qword_ptr[0] = iview->texture_state[PVR_TEXTURE_STATE_ATTACHMENT][0];
qword_ptr[1] = iview->texture_state[PVR_TEXTURE_STATE_ATTACHMENT][1];
} else {
qword_ptr[0] = iview->texture_state[PVR_TEXTURE_STATE_SAMPLE][0];
qword_ptr[1] = iview->texture_state[PVR_TEXTURE_STATE_SAMPLE][1];
}
if (descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE &&
!PVR_HAS_FEATURE(dev_info, tpu_extended_integer_lookup)) {
uint64_t tmp;
pvr_csb_pack (&tmp, TEXSTATE_STRIDE_IMAGE_WORD1, word1) {
word1.index_lookup = true;
}
qword_ptr[1] |= tmp;
}
}
static void
pvr_write_image_descriptor_secondaries(const struct pvr_device_info *dev_info,
const struct pvr_image_view *iview,
VkDescriptorType descriptorType,
uint32_t *secondary)
{
const bool cube_array_adjust =
descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE &&
iview->vk.view_type == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
if (!PVR_HAS_FEATURE(dev_info, tpu_array_textures)) {
uint64_t addr = iview->image->dev_addr.addr +
iview->vk.base_array_layer * iview->image->layer_size;
secondary[PVR_DESC_IMAGE_SECONDARY_OFFSET_ARRAYBASE] = (uint32_t)addr;
secondary[PVR_DESC_IMAGE_SECONDARY_OFFSET_ARRAYBASE + 1U] =
(uint32_t)(addr >> 32U);
secondary[PVR_DESC_IMAGE_SECONDARY_OFFSET_ARRAYSTRIDE] =
cube_array_adjust ? iview->image->layer_size * 6
: iview->image->layer_size;
}
if (cube_array_adjust) {
secondary[PVR_DESC_IMAGE_SECONDARY_OFFSET_ARRAYMAXINDEX(dev_info)] =
iview->vk.layer_count / 6 - 1;
} else {
secondary[PVR_DESC_IMAGE_SECONDARY_OFFSET_ARRAYMAXINDEX(dev_info)] =
iview->vk.layer_count - 1;
}
secondary[PVR_DESC_IMAGE_SECONDARY_OFFSET_WIDTH(dev_info)] =
iview->vk.extent.width;
secondary[PVR_DESC_IMAGE_SECONDARY_OFFSET_HEIGHT(dev_info)] =
iview->vk.extent.height;
secondary[PVR_DESC_IMAGE_SECONDARY_OFFSET_DEPTH(dev_info)] =
iview->vk.extent.depth;
}
static void pvr_descriptor_update_sampler_texture(
const struct pvr_device *device,
const VkWriteDescriptorSet *write_set,
struct pvr_descriptor_set *set,
const struct pvr_descriptor_set_layout_binding *binding,
uint32_t *mem_ptr,
uint32_t start_stage,
uint32_t end_stage)
{
const struct pvr_device_info *dev_info = &device->pdevice->dev_info;
for (uint32_t i = 0; i < write_set->descriptorCount; i++) {
PVR_FROM_HANDLE(pvr_image_view,
iview,
write_set->pImageInfo[i].imageView);
const uint32_t desc_idx =
binding->descriptor_index + write_set->dstArrayElement + i;
set->descriptors[desc_idx].type = write_set->descriptorType;
set->descriptors[desc_idx].iview = iview;
set->descriptors[desc_idx].layout = write_set->pImageInfo[i].imageLayout;
for (uint32_t j = start_stage; j < end_stage; j++) {
uint32_t secondary_offset;
uint32_t primary_offset;
if (!(binding->shader_stage_mask & BITFIELD_BIT(j)))
continue;
/* Offset calculation functions expect descriptor_index to be
* binding relative not layout relative, so we have used
* write_set->dstArrayElement + i rather than desc_idx.
*/
primary_offset =
pvr_get_descriptor_primary_offset(device,
set->layout,
binding,
j,
write_set->dstArrayElement + i);
secondary_offset =
pvr_get_descriptor_secondary_offset(device,
set->layout,
binding,
j,
write_set->dstArrayElement + i);
pvr_write_image_descriptor_primaries(dev_info,
iview,
write_set->descriptorType,
mem_ptr + primary_offset);
/* We don't need to update the sampler words if they belong to an
* immutable sampler.
*/
if (!binding->has_immutable_samplers) {
PVR_FROM_HANDLE(pvr_sampler,
sampler,
write_set->pImageInfo[i].sampler);
set->descriptors[desc_idx].sampler = sampler;
/* Sampler words are located at the end of the primary image words.
*/
memcpy(mem_ptr + primary_offset + PVR_IMAGE_DESCRIPTOR_SIZE,
sampler->descriptor.words,
sizeof(sampler->descriptor.words));
}
pvr_write_image_descriptor_secondaries(dev_info,
iview,
write_set->descriptorType,
mem_ptr + secondary_offset);
}
}
}
static void pvr_descriptor_update_texture(
const struct pvr_device *device,
const VkWriteDescriptorSet *write_set,
struct pvr_descriptor_set *set,
const struct pvr_descriptor_set_layout_binding *binding,
uint32_t *mem_ptr,
uint32_t start_stage,
uint32_t end_stage)
{
const struct pvr_device_info *dev_info = &device->pdevice->dev_info;
for (uint32_t i = 0; i < write_set->descriptorCount; i++) {
PVR_FROM_HANDLE(pvr_image_view,
iview,
write_set->pImageInfo[i].imageView);
const uint32_t desc_idx =
binding->descriptor_index + write_set->dstArrayElement + i;
set->descriptors[desc_idx].type = write_set->descriptorType;
set->descriptors[desc_idx].iview = iview;
set->descriptors[desc_idx].layout = write_set->pImageInfo[i].imageLayout;
for (uint32_t j = start_stage; j < end_stage; j++) {
uint32_t secondary_offset;
uint32_t primary_offset;
if (!(binding->shader_stage_mask & BITFIELD_BIT(j)))
continue;
/* Offset calculation functions expect descriptor_index to be
* binding relative not layout relative, so we have used
* write_set->dstArrayElement + i rather than desc_idx.
*/
primary_offset =
pvr_get_descriptor_primary_offset(device,
set->layout,
binding,
j,
write_set->dstArrayElement + i);
secondary_offset =
pvr_get_descriptor_secondary_offset(device,
set->layout,
binding,
j,
write_set->dstArrayElement + i);
pvr_write_image_descriptor_primaries(dev_info,
iview,
write_set->descriptorType,
mem_ptr + primary_offset);
pvr_write_image_descriptor_secondaries(dev_info,
iview,
write_set->descriptorType,
mem_ptr + secondary_offset);
}
}
}
static void pvr_write_buffer_descriptor(const struct pvr_device_info *dev_info,
const struct pvr_buffer_view *bview,
VkDescriptorType descriptorType,
uint32_t *primary,
uint32_t *secondary)
{
uint64_t *qword_ptr = (uint64_t *)primary;
qword_ptr[0] = bview->texture_state[0];
qword_ptr[1] = bview->texture_state[1];
if (descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER &&
!PVR_HAS_FEATURE(dev_info, tpu_extended_integer_lookup)) {
uint64_t tmp;
pvr_csb_pack (&tmp, TEXSTATE_STRIDE_IMAGE_WORD1, word1) {
word1.index_lookup = true;
}
qword_ptr[1] |= tmp;
}
if (secondary) {
/* NOTE: Range check for texture buffer writes is not strictly required as
* we have already validated that the index is in range. We'd need a
* compiler change to allow us to skip the range check.
*/
secondary[PVR_DESC_IMAGE_SECONDARY_OFFSET_WIDTH(dev_info)] =
(uint32_t)(bview->range / vk_format_get_blocksize(bview->format));
secondary[PVR_DESC_IMAGE_SECONDARY_OFFSET_HEIGHT(dev_info)] = 1;
}
}
static void pvr_descriptor_update_buffer_view(
const struct pvr_device *device,
const VkWriteDescriptorSet *write_set,
struct pvr_descriptor_set *set,
const struct pvr_descriptor_set_layout_binding *binding,
uint32_t *mem_ptr,
uint32_t start_stage,
uint32_t end_stage)
{
const struct pvr_device_info *dev_info = &device->pdevice->dev_info;
struct pvr_descriptor_size_info size_info;
pvr_descriptor_size_info_init(device, binding->type, &size_info);
for (uint32_t i = 0; i < write_set->descriptorCount; i++) {
PVR_FROM_HANDLE(pvr_buffer_view, bview, write_set->pTexelBufferView[i]);
const uint32_t desc_idx =
binding->descriptor_index + write_set->dstArrayElement + i;
set->descriptors[desc_idx].type = write_set->descriptorType;
set->descriptors[desc_idx].bview = bview;
for (uint32_t j = start_stage; j < end_stage; j++) {
uint32_t secondary_offset;
uint32_t primary_offset;
if (!(binding->shader_stage_mask & BITFIELD_BIT(j)))
continue;
/* Offset calculation functions expect descriptor_index to be
* binding relative not layout relative, so we have used
* write_set->dstArrayElement + i rather than desc_idx.
*/
primary_offset =
pvr_get_descriptor_primary_offset(device,
set->layout,
binding,
j,
write_set->dstArrayElement + i);
secondary_offset =
pvr_get_descriptor_secondary_offset(device,
set->layout,
binding,
j,
write_set->dstArrayElement + i);
pvr_write_buffer_descriptor(
dev_info,
bview,
write_set->descriptorType,
mem_ptr + primary_offset,
size_info.secondary ? mem_ptr + secondary_offset : NULL);
}
}
}
static void pvr_descriptor_update_input_attachment(
const struct pvr_device *device,
const VkWriteDescriptorSet *write_set,
struct pvr_descriptor_set *set,
const struct pvr_descriptor_set_layout_binding *binding,
uint32_t *mem_ptr,
uint32_t start_stage,
uint32_t end_stage)
{
const struct pvr_device_info *dev_info = &device->pdevice->dev_info;
struct pvr_descriptor_size_info size_info;
pvr_descriptor_size_info_init(device, binding->type, &size_info);
for (uint32_t i = 0; i < write_set->descriptorCount; i++) {
PVR_FROM_HANDLE(pvr_image_view,
iview,
write_set->pImageInfo[i].imageView);
const uint32_t desc_idx =
binding->descriptor_index + write_set->dstArrayElement + i;
set->descriptors[desc_idx].type = write_set->descriptorType;
set->descriptors[desc_idx].iview = iview;
set->descriptors[desc_idx].layout = write_set->pImageInfo[i].imageLayout;
for (uint32_t j = start_stage; j < end_stage; j++) {
uint32_t primary_offset;
if (!(binding->shader_stage_mask & BITFIELD_BIT(j)))
continue;
/* Offset calculation functions expect descriptor_index to be
* binding relative not layout relative, so we have used
* write_set->dstArrayElement + i rather than desc_idx.
*/
primary_offset =
pvr_get_descriptor_primary_offset(device,
set->layout,
binding,
j,
write_set->dstArrayElement + i);
pvr_write_image_descriptor_primaries(dev_info,
iview,
write_set->descriptorType,
mem_ptr + primary_offset);
*(uint64_t *)(mem_ptr + primary_offset + PVR_IMAGE_DESCRIPTOR_SIZE) =
device->input_attachment_sampler;
if (!PVR_HAS_FEATURE(dev_info, tpu_array_textures)) {
const uint32_t secondary_offset =
pvr_get_descriptor_secondary_offset(device,
set->layout,
binding,
j,
write_set->dstArrayElement +
i);
pvr_write_image_descriptor_secondaries(dev_info,
iview,
write_set->descriptorType,
mem_ptr + secondary_offset);
}
}
}
}
void pvr_UpdateDescriptorSets(VkDevice _device,
uint32_t descriptorWriteCount,
const VkWriteDescriptorSet *pDescriptorWrites,
uint32_t descriptorCopyCount,
const VkCopyDescriptorSet *pDescriptorCopies)
{
PVR_FROM_HANDLE(pvr_device, device, _device);
for (uint32_t i = 0; i < descriptorWriteCount; i++) {
const VkWriteDescriptorSet *write_set = &pDescriptorWrites[i];
PVR_FROM_HANDLE(pvr_descriptor_set, set, write_set->dstSet);
uint32_t *map = set->pvr_bo->bo->map;
const struct pvr_descriptor_set_layout_binding *binding =
pvr_get_descriptor_binding(set->layout, write_set->dstBinding);
/* Binding should not be NULL. */
assert(binding);
/* Only need to update the descriptor if it is actually being used. If it
* was not used in any stage, then the shader_stage_mask would be 0 and we
* can skip this update.
*/
if (binding->shader_stage_mask == 0)
continue;
vk_foreach_struct_const (ext, write_set->pNext) {
pvr_debug_ignored_stype(ext->sType);
}
switch (write_set->descriptorType) {
case VK_DESCRIPTOR_TYPE_SAMPLER:
pvr_descriptor_update_sampler(device,
write_set,
set,
binding,
map,
0,
PVR_STAGE_ALLOCATION_COUNT);
break;
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
pvr_descriptor_update_sampler_texture(device,
write_set,
set,
binding,
map,
0,
PVR_STAGE_ALLOCATION_COUNT);
break;
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
pvr_descriptor_update_texture(device,
write_set,
set,
binding,
map,
0,
PVR_STAGE_ALLOCATION_COUNT);
break;
case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
pvr_descriptor_update_buffer_view(device,
write_set,
set,
binding,
map,
0,
PVR_STAGE_ALLOCATION_COUNT);
break;
case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
pvr_descriptor_update_input_attachment(device,
write_set,
set,
binding,
map,
0,
PVR_STAGE_ALLOCATION_COUNT);
break;
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
pvr_descriptor_update_buffer_info(device,
write_set,
set,
binding,
map,
0,
PVR_STAGE_ALLOCATION_COUNT);
break;
default:
unreachable("Unknown descriptor type");
break;
}
}
if (descriptorCopyCount > 0)
pvr_finishme("Descriptor copying support missing\n");
}