v3dv/descriptor: support for dynamic ubo/ssbo

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6766>
diff --git a/src/broadcom/vulkan/v3dv_cmd_buffer.c b/src/broadcom/vulkan/v3dv_cmd_buffer.c
index b455b78..59eab90 100644
--- a/src/broadcom/vulkan/v3dv_cmd_buffer.c
+++ b/src/broadcom/vulkan/v3dv_cmd_buffer.c
@@ -2346,16 +2346,28 @@
                            const uint32_t *pDynamicOffsets)
 {
    V3DV_FROM_HANDLE(v3dv_cmd_buffer, cmd_buffer, commandBuffer);
+   V3DV_FROM_HANDLE(v3dv_pipeline_layout, layout, _layout);
+
+   uint32_t dyn_index = 0;
 
    assert(pipelineBindPoint == VK_PIPELINE_BIND_POINT_GRAPHICS);
    assert(firstSet + descriptorSetCount <= MAX_SETS);
 
+   struct v3dv_descriptor_state *descriptor_state =
+      &cmd_buffer->state.descriptor_state;
+
    for (uint32_t i = 0; i < descriptorSetCount; i++) {
       V3DV_FROM_HANDLE(v3dv_descriptor_set, set, pDescriptorSets[i]);
       uint32_t index = firstSet + i;
 
-      cmd_buffer->state.descriptor_state.descriptor_sets[index] = set;
-      cmd_buffer->state.descriptor_state.valid |= (1u << index);
+      descriptor_state->descriptor_sets[index] = set;
+      descriptor_state->valid |= (1u << index);
+
+      for (uint32_t j = 0; j < set->layout->dynamic_offset_count; j++, dyn_index++) {
+         uint32_t idx = j + layout->set[i + firstSet].dynamic_offset_start;
+
+         descriptor_state->dynamic_offsets[idx] = pDynamicOffsets[dyn_index];
+      }
    }
 
    cmd_buffer->state.dirty |= V3DV_CMD_DIRTY_DESCRIPTOR_SETS;
diff --git a/src/broadcom/vulkan/v3dv_descriptor_set.c b/src/broadcom/vulkan/v3dv_descriptor_set.c
index 42eb505..625a80f 100644
--- a/src/broadcom/vulkan/v3dv_descriptor_set.c
+++ b/src/broadcom/vulkan/v3dv_descriptor_set.c
@@ -51,12 +51,21 @@
 
    layout->num_sets = pCreateInfo->setLayoutCount;
 
+   uint32_t dynamic_offset_count = 0;
    for (uint32_t set = 0; set < pCreateInfo->setLayoutCount; set++) {
       V3DV_FROM_HANDLE(v3dv_descriptor_set_layout, set_layout,
                      pCreateInfo->pSetLayouts[set]);
       layout->set[set].layout = set_layout;
+
+      layout->set[set].dynamic_offset_start = dynamic_offset_count;
+      for (uint32_t b = 0; b < set_layout->binding_count; b++) {
+         dynamic_offset_count += set_layout->binding[b].array_size *
+            set_layout->binding[b].dynamic_offset_count;
+      }
    }
 
+   layout->dynamic_offset_count = dynamic_offset_count;
+
    *pPipelineLayout = v3dv_pipeline_layout_to_handle(layout);
 
    return VK_SUCCESS;
@@ -94,6 +103,9 @@
       case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
       case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
          break;
+      case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
+      case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
+         break;
       default:
          unreachable("Unimplemented descriptor type");
          break;
@@ -264,6 +276,7 @@
    set_layout->shader_stages = 0;
 
    uint32_t descriptor_count = 0;
+   uint32_t dynamic_offset_count = 0;
 
    for (uint32_t i = 0; i < pCreateInfo->bindingCount; i++) {
       const VkDescriptorSetLayoutBinding *binding = bindings + i;
@@ -273,6 +286,10 @@
       case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
       case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
          break;
+      case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
+      case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
+         set_layout->binding[binding_number].dynamic_offset_count = 1;
+         break;
       default:
          unreachable("Unknown descriptor type\n");
          break;
@@ -281,8 +298,11 @@
       set_layout->binding[binding_number].type = binding->descriptorType;
       set_layout->binding[binding_number].array_size = binding->descriptorCount;
       set_layout->binding[binding_number].descriptor_index = descriptor_count;
+      set_layout->binding[binding_number].dynamic_offset_index = dynamic_offset_count;
 
       descriptor_count += binding->descriptorCount;
+      dynamic_offset_count += binding->descriptorCount *
+         set_layout->binding[binding_number].dynamic_offset_count;
 
       /* FIXME: right now we don't use shader_stages. We could explore if we
        * could use it to add another filter to upload or allocate the
@@ -294,6 +314,7 @@
    vk_free2(&device->alloc, pAllocator, bindings);
 
    set_layout->descriptor_count = descriptor_count;
+   set_layout->dynamic_offset_count = dynamic_offset_count;
 
    *pSetLayout = v3dv_descriptor_set_layout_to_handle(set_layout);
 
@@ -435,6 +456,8 @@
 
          switch(writeset->descriptorType) {
 
+         case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
+         case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
          case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
          case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: {
             const VkDescriptorBufferInfo *buffer_info = writeset->pBufferInfo + j;
diff --git a/src/broadcom/vulkan/v3dv_pipeline.c b/src/broadcom/vulkan/v3dv_pipeline.c
index 69d6155..689cdef 100644
--- a/src/broadcom/vulkan/v3dv_pipeline.c
+++ b/src/broadcom/vulkan/v3dv_pipeline.c
@@ -975,8 +975,6 @@
       next_stage = stages[stage];
    }
 
-   V3DV_FROM_HANDLE(v3dv_pipeline_layout, layout, pCreateInfo->layout);
-
    /* Compiling to vir */
    for (int stage = MESA_SHADER_STAGES - 1; stage >= 0; stage--) {
       if (stages[stage] == NULL || stages[stage]->entrypoint == NULL)
@@ -984,7 +982,7 @@
 
       struct v3dv_pipeline_stage *p_stage = stages[stage];
 
-      pipeline_lower_nir(pipeline, p_stage, layout);
+      pipeline_lower_nir(pipeline, p_stage, pipeline->layout);
 
       switch(stage) {
       case MESA_SHADER_VERTEX:
@@ -1608,6 +1606,9 @@
 
    pipeline->device = device;
 
+   V3DV_FROM_HANDLE(v3dv_pipeline_layout, layout, pCreateInfo->layout);
+   pipeline->layout = layout;
+
    V3DV_FROM_HANDLE(v3dv_render_pass, render_pass, pCreateInfo->renderPass);
    assert(pCreateInfo->subpass < render_pass->subpass_count);
    pipeline->subpass = &render_pass->subpasses[pCreateInfo->subpass];
diff --git a/src/broadcom/vulkan/v3dv_private.h b/src/broadcom/vulkan/v3dv_private.h
index 943c4e0..1c45d99 100644
--- a/src/broadcom/vulkan/v3dv_private.h
+++ b/src/broadcom/vulkan/v3dv_private.h
@@ -123,6 +123,11 @@
 
 #define MAX_PUSH_CONSTANTS_SIZE 128
 
+#define MAX_DYNAMIC_UNIFORM_BUFFERS 16
+#define MAX_DYNAMIC_STORAGE_BUFFERS 8
+#define MAX_DYNAMIC_BUFFERS                                                  \
+   (MAX_DYNAMIC_UNIFORM_BUFFERS + MAX_DYNAMIC_STORAGE_BUFFERS)
+
 struct v3dv_instance;
 
 #ifdef USE_V3D_SIMULATOR
@@ -574,6 +579,7 @@
 struct v3dv_descriptor_state {
    struct v3dv_descriptor_set *descriptor_sets[MAX_SETS];
    uint32_t valid;
+   uint32_t dynamic_offsets[MAX_DYNAMIC_BUFFERS];
 };
 
 struct v3dv_cmd_buffer_state {
@@ -772,6 +778,9 @@
    uint32_t array_size;
 
    uint32_t descriptor_index;
+
+   uint32_t dynamic_offset_count;
+   uint32_t dynamic_offset_index;
 };
 
 struct v3dv_descriptor_set_layout {
@@ -786,6 +795,9 @@
    /* Number of descriptors in this descriptor set */
    uint32_t descriptor_count;
 
+   /* Number of dynamic offsets used by this descriptor set */
+   uint16_t dynamic_offset_count;
+
    /* Bindings in this descriptor set */
    struct v3dv_descriptor_set_binding_layout binding[0];
 };
@@ -797,6 +809,7 @@
    } set[MAX_SETS];
 
    uint32_t num_sets;
+   uint32_t dynamic_offset_count;
 };
 
 struct v3dv_descriptor_map {
@@ -824,6 +837,8 @@
 
    struct v3dv_dynamic_state dynamic_state;
 
+   struct v3dv_pipeline_layout *layout;
+
    enum v3dv_ez_state ez_state;
 
    bool primitive_restart;
diff --git a/src/broadcom/vulkan/v3dv_uniforms.c b/src/broadcom/vulkan/v3dv_uniforms.c
index 20e3188..70151cf 100644
--- a/src/broadcom/vulkan/v3dv_uniforms.c
+++ b/src/broadcom/vulkan/v3dv_uniforms.c
@@ -27,10 +27,31 @@
 
 #include "v3dv_private.h"
 
+static bool
+descriptor_type_is_dynamic(VkDescriptorType type)
+{
+   switch (type) {
+   case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
+   case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
+      return false;
+      break;
+   case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
+   case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
+      return true;
+      break;
+   default:
+      assert(!"descriptor type not supported.\n");
+      break;
+   }
+   return false;
+}
+
 static struct v3dv_descriptor *
 get_descriptor(struct v3dv_descriptor_state *descriptor_state,
                struct v3dv_descriptor_map *map,
-               uint32_t index)
+               struct v3dv_pipeline_layout *pipeline_layout,
+               uint32_t index,
+               uint32_t *dynamic_offset)
 {
    assert(index >= 0 && index < map->num_desc);
 
@@ -50,6 +71,14 @@
    uint32_t array_index = map->array_index[index];
    assert(array_index < binding_layout->array_size);
 
+   if (descriptor_type_is_dynamic(binding_layout->type)) {
+      uint32_t dynamic_offset_index =
+         pipeline_layout->set[set_number].dynamic_offset_start +
+         binding_layout->dynamic_offset_index + array_index;
+
+      *dynamic_offset = descriptor_state->dynamic_offsets[dynamic_offset_index];
+   }
+
    return &set->descriptors[binding_layout->descriptor_index + array_index];
 }
 
@@ -172,6 +201,8 @@
             v3d_unit_data_get_offset(data) :
             0; /* FIXME */
 
+         uint32_t dynamic_offset = 0;
+
          /* For ubos, index is shifted, as 0 is reserved for push constants.
           */
          struct v3dv_descriptor *descriptor = NULL;
@@ -191,13 +222,15 @@
                data;
 
             descriptor =
-               get_descriptor(descriptor_state, map, index);
+               get_descriptor(descriptor_state, map,
+                              pipeline->layout,
+                              index, &dynamic_offset);
             assert(descriptor);
          }
 
          cl_aligned_reloc(&job->indirect, &uniforms,
                           descriptor->bo,
-                          descriptor->offset + offset);
+                          descriptor->offset + offset + dynamic_offset);
          break;
       }