Module: Mesa Branch: master Commit: 9a062383e35f812410fe025930b016b4b67710e5 URL: http://cgit.freedesktop.org/mesa/mesa/commit/?id=9a062383e35f812410fe025930b016b4b67710e5
Author: Jason Ekstrand <ja...@jlekstrand.net> Date: Thu Oct 15 22:56:09 2020 -0500 anv: Implement VariableDescriptorCount Reviewed-by: Lionel Landwerlin <lionel.g.landwer...@intel.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/7180> --- src/intel/vulkan/anv_cmd_buffer.c | 4 +- src/intel/vulkan/anv_descriptor_set.c | 179 ++++++++++++++++++++++++++++++---- src/intel/vulkan/anv_device.c | 2 +- src/intel/vulkan/anv_private.h | 10 +- src/intel/vulkan/genX_cmd_buffer.c | 17 +++- 5 files changed, 182 insertions(+), 30 deletions(-) diff --git a/src/intel/vulkan/anv_cmd_buffer.c b/src/intel/vulkan/anv_cmd_buffer.c index 86596b66457..4734926e871 100644 --- a/src/intel/vulkan/anv_cmd_buffer.c +++ b/src/intel/vulkan/anv_cmd_buffer.c @@ -1239,9 +1239,9 @@ anv_cmd_buffer_push_descriptor_set(struct anv_cmd_buffer *cmd_buffer, 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 883c917e3d8..09d698e7ccb 100644 --- a/src/intel/vulkan/anv_descriptor_set.c +++ b/src/intel/vulkan/anv_descriptor_set.c @@ -248,17 +248,31 @@ void anv_GetDescriptorSetLayoutSupport( 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 @@ void anv_GetDescriptorSetLayoutSupport( 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 @@ VkResult anv_CreateDescriptorSetLayout( 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 @@ anv_descriptor_set_layout_destroy(struct anv_device *device, 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 @@ sha1_update_descriptor_set_layout(struct mesa_sha1 *ctx, 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 @@ anv_descriptor_pool_free_state(struct anv_descriptor_pool *pool, } 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 @@ anv_descriptor_set_create(struct anv_device *device, .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 @@ anv_descriptor_set_create(struct anv_device *device, 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 @@ anv_descriptor_set_create(struct anv_device *device, } /* 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 @@ VkResult anv_AllocateDescriptorSets( 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 2b400be65a7..ce172b41b76 100644 --- a/src/intel/vulkan/anv_device.c +++ b/src/intel/vulkan/anv_device.c @@ -1029,7 +1029,7 @@ anv_get_physical_device_features_1_2(struct anv_physical_device *pdevice, 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 f2046fb6ffe..06bc4d5f4db 100644 --- a/src/intel/vulkan/anv_private.h +++ b/src/intel/vulkan/anv_private.h @@ -1949,10 +1949,8 @@ enum anv_descriptor_data { }; 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 @@ struct anv_descriptor_set_layout { /* 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 @@ struct anv_descriptor_update_template { }; 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 @@ 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); void diff --git a/src/intel/vulkan/genX_cmd_buffer.c b/src/intel/vulkan/genX_cmd_buffer.c index 985e3b9df5f..fceb65f06cc 100644 --- a/src/intel/vulkan/genX_cmd_buffer.c +++ b/src/intel/vulkan/genX_cmd_buffer.c @@ -2602,7 +2602,22 @@ emit_binding_table(struct anv_cmd_buffer *cmd_buffer, 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) { _______________________________________________ mesa-commit mailing list mesa-commit@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-commit