nvk: Support VkDescriptorSetVariableDescriptorCountLayoutSupport
authorGeorge Ouzounoudis <geothrock@gmail.com>
Wed, 26 Apr 2023 18:37:23 +0000 (21:37 +0300)
committerMarge Bot <emma+marge@anholt.net>
Fri, 4 Aug 2023 21:32:05 +0000 (21:32 +0000)
On cases with variable descriptor counts we need to calculate the
maximum supported variable count while taking into account the other existing
descriptors and their alignments in the set.

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/24326>

src/nouveau/vulkan/nvk_descriptor_set_layout.c

index 68ee7ae..b40be1b 100644 (file)
@@ -256,6 +256,9 @@ nvk_GetDescriptorSetLayoutSupport(VkDevice _device,
    const VkMutableDescriptorTypeCreateInfoEXT *mutable_info =
       vk_find_struct_const(pCreateInfo->pNext,
                            MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_EXT);
+   const VkDescriptorSetLayoutBindingFlagsCreateInfo *binding_flags =
+      vk_find_struct_const(pCreateInfo->pNext,
+                           DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO);
 
    /* Figure out the maximum alignment up-front.  Otherwise, we need to sort
     * the list of descriptors by binding number in order to get the size
@@ -274,11 +277,18 @@ nvk_GetDescriptorSetLayoutSupport(VkDevice _device,
       max_align = MAX2(max_align, align);
    }
 
-   uint32_t buffer_size = 0;
+   uint64_t non_variable_size = 0;
+   uint32_t variable_stride = 0;
+   uint32_t variable_count = 0;
    uint8_t dynamic_buffer_count = 0;
+
    for (uint32_t i = 0; i < pCreateInfo->bindingCount; i++) {
       const VkDescriptorSetLayoutBinding *binding = &pCreateInfo->pBindings[i];
 
+      VkDescriptorBindingFlags flags = 0;
+      if (binding_flags != NULL && binding_flags->bindingCount > 0)
+         flags = binding_flags->pBindingFlags[i];
+
       if (binding->descriptorCount == 0)
          continue;
 
@@ -303,23 +313,59 @@ nvk_GetDescriptorSetLayoutSupport(VkDevice _device,
          assert(stride <= UINT8_MAX);
          assert(util_is_power_of_two_nonzero(align));
 
-         /* Since we're aligning to the maximum and since this is just a
-          * check for whether or not the max buffer size is big enough, we
-          * keep buffer_size aligned to max_align.
-          */
-         buffer_size += stride * binding->descriptorCount;
-         buffer_size = ALIGN_POT(buffer_size, max_align);
+         if (flags & VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT) {
+            /* From the Vulkan 1.3.256 spec:
+             *
+             *    "For the purposes of this command, a variable-sized
+             *    descriptor binding with a descriptorCount of zero is treated
+             *    as if the descriptorCount is one"
+             */
+            variable_count = MAX2(1, binding->descriptorCount);
+            variable_stride = stride;
+         } else {
+            /* Since we're aligning to the maximum and since this is just a
+             * check for whether or not the max buffer size is big enough, we
+             * keep non_variable_size aligned to max_align.
+             */
+            non_variable_size += stride * binding->descriptorCount;
+            non_variable_size = ALIGN_POT(non_variable_size, max_align);
+         }
       }
    }
 
-   pSupport->supported = dynamic_buffer_count <= NVK_MAX_DYNAMIC_BUFFERS;
+   uint64_t buffer_size = non_variable_size;
+   if (variable_stride > 0) {
+      buffer_size += variable_stride * variable_count;
+      buffer_size = ALIGN_POT(buffer_size, max_align);
+   }
+
+   uint32_t max_buffer_size;
    if (pCreateInfo->flags &
-       VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR) {
-      if (buffer_size > NVK_PUSH_DESCRIPTOR_SET_SIZE)
-         pSupport->supported = false;
-   } else {
-      if (buffer_size > NVK_MAX_DESCRIPTOR_SET_SIZE)
-         pSupport->supported = false;
+       VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR)
+      max_buffer_size = NVK_PUSH_DESCRIPTOR_SET_SIZE;
+   else
+      max_buffer_size = NVK_MAX_DESCRIPTOR_SET_SIZE;
+
+   pSupport->supported = dynamic_buffer_count <= NVK_MAX_DYNAMIC_BUFFERS &&
+                         buffer_size <= max_buffer_size;
+
+   vk_foreach_struct(ext, pSupport->pNext) {
+      switch (ext->sType) {
+      case VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT: {
+         VkDescriptorSetVariableDescriptorCountLayoutSupport *vs = (void *)ext;
+         if (variable_stride > 0) {
+            vs->maxVariableDescriptorCount =
+               (max_buffer_size - non_variable_size) / variable_stride;
+         } else {
+            vs->maxVariableDescriptorCount = 0;
+         }
+         break;
+      }
+
+      default:
+         nvk_debug_ignored_stype(ext->sType);
+         break;
+      }
    }
 }