anv: Implement VariableDescriptorCount
Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/7180>
diff --git a/src/intel/vulkan/anv_cmd_buffer.c b/src/intel/vulkan/anv_cmd_buffer.c
index 86596b6..4734926 100644
--- a/src/intel/vulkan/anv_cmd_buffer.c
+++ b/src/intel/vulkan/anv_cmd_buffer.c
@@ -1239,9 +1239,9 @@
anv_descriptor_set_layout_ref(layout);
set->layout = layout;
}
- set->size = anv_descriptor_set_layout_size(layout);
+ set->size = anv_descriptor_set_layout_size(layout, 0);
set->buffer_view_count = layout->buffer_view_count;
- set->descriptor_count = layout->size;
+ set->descriptor_count = layout->descriptor_count;
set->buffer_views = (*push_set)->buffer_views;
if (layout->descriptor_buffer_size &&
diff --git a/src/intel/vulkan/anv_descriptor_set.c b/src/intel/vulkan/anv_descriptor_set.c
index 883c917..09d698e 100644
--- a/src/intel/vulkan/anv_descriptor_set.c
+++ b/src/intel/vulkan/anv_descriptor_set.c
@@ -248,17 +248,31 @@
const struct anv_physical_device *pdevice = device->physical;
uint32_t surface_count[MESA_SHADER_STAGES] = { 0, };
+ VkDescriptorType varying_desc_type = VK_DESCRIPTOR_TYPE_MAX_ENUM;
bool needs_descriptor_buffer = false;
+ const VkDescriptorSetLayoutBindingFlagsCreateInfo *binding_flags_info =
+ vk_find_struct_const(pCreateInfo->pNext,
+ DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO);
+
for (uint32_t b = 0; b < pCreateInfo->bindingCount; b++) {
const VkDescriptorSetLayoutBinding *binding = &pCreateInfo->pBindings[b];
+ VkDescriptorBindingFlags flags = 0;
+ if (binding_flags_info && binding_flags_info->bindingCount > 0) {
+ assert(binding_flags_info->bindingCount == pCreateInfo->bindingCount);
+ flags = binding_flags_info->pBindingFlags[b];
+ }
+
enum anv_descriptor_data desc_data =
anv_descriptor_data_for_type(pdevice, binding->descriptorType);
if (anv_needs_descriptor_buffer(binding->descriptorType, desc_data))
needs_descriptor_buffer = true;
+ if (flags & VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT)
+ varying_desc_type = binding->descriptorType;
+
switch (binding->descriptorType) {
case VK_DESCRIPTOR_TYPE_SAMPLER:
/* There is no real limit on samplers */
@@ -300,6 +314,19 @@
surface_count[s] += 1;
}
+ VkDescriptorSetVariableDescriptorCountLayoutSupport *vdcls =
+ vk_find_struct(pSupport->pNext,
+ DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT);
+ if (vdcls != NULL) {
+ if (varying_desc_type == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) {
+ vdcls->maxVariableDescriptorCount = MAX_INLINE_UNIFORM_BLOCK_SIZE;
+ } else if (varying_desc_type != VK_DESCRIPTOR_TYPE_MAX_ENUM) {
+ vdcls->maxVariableDescriptorCount = UINT16_MAX;
+ } else {
+ vdcls->maxVariableDescriptorCount = 0;
+ }
+ }
+
bool supported = true;
for (unsigned s = 0; s < MESA_SHADER_STAGES; s++) {
/* Our maximum binding table size is 240 and we need to reserve 8 for
@@ -417,22 +444,37 @@
if (binding->descriptorCount == 0)
continue;
-#ifndef NDEBUG
set_layout->binding[b].type = binding->descriptorType;
-#endif
if (binding_flags_info && binding_flags_info->bindingCount > 0) {
assert(binding_flags_info->bindingCount == pCreateInfo->bindingCount);
set_layout->binding[b].flags =
binding_flags_info->pBindingFlags[info_idx];
+
+ /* From the Vulkan spec:
+ *
+ * "If VkDescriptorSetLayoutCreateInfo::flags includes
+ * VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR, then
+ * all elements of pBindingFlags must not include
+ * VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT,
+ * VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT, or
+ * VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT"
+ */
+ if (pCreateInfo->flags &
+ VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR) {
+ assert(!(set_layout->binding[b].flags &
+ (VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT |
+ VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT |
+ VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT)));
+ }
}
set_layout->binding[b].data =
anv_descriptor_data_for_type(device->physical,
binding->descriptorType);
set_layout->binding[b].array_size = binding->descriptorCount;
- set_layout->binding[b].descriptor_index = set_layout->size;
- set_layout->size += binding->descriptorCount;
+ set_layout->binding[b].descriptor_index = set_layout->descriptor_count;
+ set_layout->descriptor_count += binding->descriptorCount;
if (set_layout->binding[b].data & ANV_DESCRIPTOR_BUFFER_VIEW) {
set_layout->binding[b].buffer_view_index = buffer_view_count;
@@ -514,6 +556,79 @@
vk_free(&device->vk.alloc, layout);
}
+static const struct anv_descriptor_set_binding_layout *
+set_layout_dynamic_binding(const struct anv_descriptor_set_layout *set_layout)
+{
+ if (set_layout->binding_count == 0)
+ return NULL;
+
+ const struct anv_descriptor_set_binding_layout *last_binding =
+ &set_layout->binding[set_layout->binding_count - 1];
+ if (!(last_binding->flags & VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT))
+ return NULL;
+
+ return last_binding;
+}
+
+static uint32_t
+set_layout_descriptor_count(const struct anv_descriptor_set_layout *set_layout,
+ uint32_t var_desc_count)
+{
+ const struct anv_descriptor_set_binding_layout *dynamic_binding =
+ set_layout_dynamic_binding(set_layout);
+ if (dynamic_binding == NULL)
+ return set_layout->descriptor_count;
+
+ assert(var_desc_count <= dynamic_binding->array_size);
+ uint32_t shrink = dynamic_binding->array_size - var_desc_count;
+
+ if (dynamic_binding->type == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT)
+ return set_layout->descriptor_count;
+
+ return set_layout->descriptor_count - shrink;
+}
+
+static uint32_t
+set_layout_buffer_view_count(const struct anv_descriptor_set_layout *set_layout,
+ uint32_t var_desc_count)
+{
+ const struct anv_descriptor_set_binding_layout *dynamic_binding =
+ set_layout_dynamic_binding(set_layout);
+ if (dynamic_binding == NULL)
+ return set_layout->buffer_view_count;
+
+ assert(var_desc_count <= dynamic_binding->array_size);
+ uint32_t shrink = dynamic_binding->array_size - var_desc_count;
+
+ if (!(dynamic_binding->data & ANV_DESCRIPTOR_BUFFER_VIEW))
+ return set_layout->buffer_view_count;
+
+ return set_layout->buffer_view_count - shrink;
+}
+
+static uint32_t
+set_layout_descriptor_buffer_size(const struct anv_descriptor_set_layout *set_layout,
+ uint32_t var_desc_count)
+{
+ const struct anv_descriptor_set_binding_layout *dynamic_binding =
+ set_layout_dynamic_binding(set_layout);
+ if (dynamic_binding == NULL)
+ return set_layout->descriptor_buffer_size;
+
+ assert(var_desc_count <= dynamic_binding->array_size);
+ uint32_t shrink = dynamic_binding->array_size - var_desc_count;
+
+ if (dynamic_binding->type == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) {
+ /* Inline uniform blocks are specified to use the descriptor array
+ * size as the size in bytes of the block.
+ */
+ return set_layout->descriptor_buffer_size - shrink;
+ } else {
+ return set_layout->descriptor_buffer_size -
+ shrink * anv_descriptor_size(dynamic_binding);
+ }
+}
+
void anv_DestroyDescriptorSetLayout(
VkDevice _device,
VkDescriptorSetLayout _set_layout,
@@ -566,7 +681,7 @@
const struct anv_descriptor_set_layout *layout)
{
SHA1_UPDATE_VALUE(ctx, layout->binding_count);
- SHA1_UPDATE_VALUE(ctx, layout->size);
+ SHA1_UPDATE_VALUE(ctx, layout->descriptor_count);
SHA1_UPDATE_VALUE(ctx, layout->shader_stages);
SHA1_UPDATE_VALUE(ctx, layout->buffer_view_count);
SHA1_UPDATE_VALUE(ctx, layout->dynamic_offset_count);
@@ -918,32 +1033,40 @@
}
size_t
-anv_descriptor_set_layout_size(const struct anv_descriptor_set_layout *layout)
+anv_descriptor_set_layout_size(const struct anv_descriptor_set_layout *layout,
+ uint32_t var_desc_count)
{
- return
- sizeof(struct anv_descriptor_set) +
- layout->size * sizeof(struct anv_descriptor) +
- layout->buffer_view_count * sizeof(struct anv_buffer_view);
+ const uint32_t descriptor_count =
+ set_layout_descriptor_count(layout, var_desc_count);
+ const uint32_t buffer_view_count =
+ set_layout_buffer_view_count(layout, var_desc_count);
+
+ return sizeof(struct anv_descriptor_set) +
+ descriptor_count * sizeof(struct anv_descriptor) +
+ buffer_view_count * sizeof(struct anv_buffer_view);
}
VkResult
anv_descriptor_set_create(struct anv_device *device,
struct anv_descriptor_pool *pool,
struct anv_descriptor_set_layout *layout,
+ uint32_t var_desc_count,
struct anv_descriptor_set **out_set)
{
struct anv_descriptor_set *set;
- const size_t size = anv_descriptor_set_layout_size(layout);
+ const size_t size = anv_descriptor_set_layout_size(layout, var_desc_count);
VkResult result = anv_descriptor_pool_alloc_set(pool, size, &set);
if (result != VK_SUCCESS)
return result;
- if (layout->descriptor_buffer_size) {
+ uint32_t descriptor_buffer_size =
+ set_layout_descriptor_buffer_size(layout, var_desc_count);
+ if (descriptor_buffer_size) {
/* Align the size to 32 so that alignment gaps don't cause extra holes
* in the heap which can lead to bad performance.
*/
- uint32_t set_buffer_size = ALIGN(layout->descriptor_buffer_size, 32);
+ uint32_t set_buffer_size = ALIGN(descriptor_buffer_size, 32);
uint64_t pool_vma_offset =
util_vma_heap_alloc(&pool->bo_heap, set_buffer_size, 32);
if (pool_vma_offset == 0) {
@@ -966,7 +1089,7 @@
.bo = pool->bo,
.offset = set->desc_mem.offset,
},
- layout->descriptor_buffer_size, 1);
+ descriptor_buffer_size, 1);
} else {
set->desc_mem = ANV_STATE_NULL;
set->desc_surface_state = ANV_STATE_NULL;
@@ -978,16 +1101,19 @@
set->layout = layout;
anv_descriptor_set_layout_ref(layout);
- set->buffer_views =
- (struct anv_buffer_view *) &set->descriptors[layout->size];
- set->buffer_view_count = layout->buffer_view_count;
+ set->buffer_view_count =
+ set_layout_buffer_view_count(layout, var_desc_count);
+ set->descriptor_count =
+ set_layout_descriptor_count(layout, var_desc_count);
- set->descriptor_count = layout->size;
+ set->buffer_views =
+ (struct anv_buffer_view *) &set->descriptors[set->descriptor_count];
/* By defining the descriptors to be zero now, we can later verify that
* a descriptor has not been populated with user data.
*/
- memset(set->descriptors, 0, sizeof(struct anv_descriptor) * layout->size);
+ memset(set->descriptors, 0,
+ sizeof(struct anv_descriptor) * set->descriptor_count);
/* Go through and fill out immutable samplers if we have any */
struct anv_descriptor *desc = set->descriptors;
@@ -1013,7 +1139,7 @@
}
/* Allocate surface state for the buffer views. */
- for (uint32_t b = 0; b < layout->buffer_view_count; b++) {
+ for (uint32_t b = 0; b < set->buffer_view_count; b++) {
set->buffer_views[b].surface_state =
anv_descriptor_pool_alloc_state(pool);
}
@@ -1060,11 +1186,22 @@
struct anv_descriptor_set *set;
uint32_t i;
+ const VkDescriptorSetVariableDescriptorCountAllocateInfo *vdcai =
+ vk_find_struct_const(pAllocateInfo->pNext,
+ DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO);
+
for (i = 0; i < pAllocateInfo->descriptorSetCount; i++) {
ANV_FROM_HANDLE(anv_descriptor_set_layout, layout,
pAllocateInfo->pSetLayouts[i]);
- result = anv_descriptor_set_create(device, pool, layout, &set);
+ uint32_t var_desc_count = 0;
+ if (vdcai != NULL && vdcai->descriptorSetCount > 0) {
+ assert(vdcai->descriptorSetCount == pAllocateInfo->descriptorSetCount);
+ var_desc_count = vdcai->pDescriptorCounts[i];
+ }
+
+ result = anv_descriptor_set_create(device, pool, layout,
+ var_desc_count, &set);
if (result != VK_SUCCESS)
break;
diff --git a/src/intel/vulkan/anv_device.c b/src/intel/vulkan/anv_device.c
index 2b400be..ce172b4 100644
--- a/src/intel/vulkan/anv_device.c
+++ b/src/intel/vulkan/anv_device.c
@@ -1029,7 +1029,7 @@
f->descriptorBindingStorageTexelBufferUpdateAfterBind = descIndexing;
f->descriptorBindingUpdateUnusedWhilePending = descIndexing;
f->descriptorBindingPartiallyBound = descIndexing;
- f->descriptorBindingVariableDescriptorCount = false;
+ f->descriptorBindingVariableDescriptorCount = descIndexing;
f->runtimeDescriptorArray = descIndexing;
f->samplerFilterMinmax = pdevice->info.gen >= 9;
diff --git a/src/intel/vulkan/anv_private.h b/src/intel/vulkan/anv_private.h
index f2046fb..06bc4d5 100644
--- a/src/intel/vulkan/anv_private.h
+++ b/src/intel/vulkan/anv_private.h
@@ -1949,10 +1949,8 @@
};
struct anv_descriptor_set_binding_layout {
-#ifndef NDEBUG
/* The type of the descriptors in this binding */
VkDescriptorType type;
-#endif
/* Flags provided when this binding was created */
VkDescriptorBindingFlagsEXT flags;
@@ -2006,8 +2004,8 @@
/* Number of bindings in this descriptor set */
uint16_t binding_count;
- /* Total size of the descriptor set with room for all array entries */
- uint16_t size;
+ /* Total number of descriptors */
+ uint16_t descriptor_count;
/* Shader stages affected by this descriptor set */
uint16_t shader_stages;
@@ -2188,7 +2186,8 @@
};
size_t
-anv_descriptor_set_layout_size(const struct anv_descriptor_set_layout *layout);
+anv_descriptor_set_layout_size(const struct anv_descriptor_set_layout *layout,
+ uint32_t var_desc_count);
void
anv_descriptor_set_write_image_view(struct anv_device *device,
@@ -2235,6 +2234,7 @@
anv_descriptor_set_create(struct anv_device *device,
struct anv_descriptor_pool *pool,
struct anv_descriptor_set_layout *layout,
+ uint32_t var_desc_count,
struct anv_descriptor_set **out_set);
void
diff --git a/src/intel/vulkan/genX_cmd_buffer.c b/src/intel/vulkan/genX_cmd_buffer.c
index 985e3b9..fceb65f 100644
--- a/src/intel/vulkan/genX_cmd_buffer.c
+++ b/src/intel/vulkan/genX_cmd_buffer.c
@@ -2602,7 +2602,22 @@
assert(binding->set < MAX_SETS);
const struct anv_descriptor_set *set =
pipe_state->descriptors[binding->set];
- assert(binding->index < set->descriptor_count);
+ if (binding->index >= set->descriptor_count) {
+ /* From the Vulkan spec section entitled "DescriptorSet and
+ * Binding Assignment":
+ *
+ * "If the array is runtime-sized, then array elements greater
+ * than or equal to the size of that binding in the bound
+ * descriptor set must not be used."
+ *
+ * Unfortunately, the compiler isn't smart enough to figure out
+ * when a dynamic binding isn't used so it may grab the whole
+ * array and stick it in the binding table. In this case, it's
+ * safe to just skip those bindings that are OOB.
+ */
+ assert(binding->index < set->layout->descriptor_count);
+ continue;
+ }
const struct anv_descriptor *desc = &set->descriptors[binding->index];
switch (desc->type) {