v3dv: implement indexed draws

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 66387ac..a704088 100644
--- a/src/broadcom/vulkan/v3dv_cmd_buffer.c
+++ b/src/broadcom/vulkan/v3dv_cmd_buffer.c
@@ -1964,8 +1964,8 @@
 };
 
 static void
-cmd_buffer_emit_draw_packets(struct v3dv_cmd_buffer *cmd_buffer,
-                             struct v3dv_draw_info *info)
+cmd_buffer_emit_draw(struct v3dv_cmd_buffer *cmd_buffer,
+                     struct v3dv_draw_info *info)
 {
    struct v3dv_job *job = cmd_buffer->state.job;
    assert(job);
@@ -1989,8 +1989,7 @@
 }
 
 static void
-cmd_buffer_draw(struct v3dv_cmd_buffer *cmd_buffer,
-                struct v3dv_draw_info *info)
+cmd_buffer_emit_pre_draw(struct v3dv_cmd_buffer *cmd_buffer)
 {
    /* FIXME: likely to be filtered by really needed states */
    uint32_t *dirty = &cmd_buffer->state.dirty;
@@ -2018,12 +2017,17 @@
    if (*dirty & dynamic_stencil_dirty_flags)
       emit_stencil(cmd_buffer);
 
-   /* FIXME: any dirty flag to filter ? */
-   cmd_buffer_emit_draw_packets(cmd_buffer, info);
-
    cmd_buffer->state.dirty &= ~(*dirty);
 }
 
+static void
+cmd_buffer_draw(struct v3dv_cmd_buffer *cmd_buffer,
+                struct v3dv_draw_info *info)
+{
+   cmd_buffer_emit_pre_draw(cmd_buffer);
+   cmd_buffer_emit_draw(cmd_buffer, info);
+}
+
 void
 v3dv_CmdDraw(VkCommandBuffer commandBuffer,
              uint32_t vertexCount,
@@ -2043,6 +2047,53 @@
 }
 
 void
+v3dv_CmdDrawIndexed(VkCommandBuffer commandBuffer,
+                    uint32_t indexCount,
+                    uint32_t instanceCount,
+                    uint32_t firstIndex,
+                    int32_t vertexOffset,
+                    uint32_t firstInstance)
+{
+   V3DV_FROM_HANDLE(v3dv_cmd_buffer, cmd_buffer, commandBuffer);
+
+   struct v3dv_job *job = cmd_buffer->state.job;
+   assert(job);
+
+   cmd_buffer_emit_pre_draw(cmd_buffer);
+
+   const struct v3dv_pipeline *pipeline = cmd_buffer->state.pipeline;
+   uint32_t hw_prim_type = v3d_hw_prim_type(pipeline->vs->topology);
+   uint8_t index_type = ffs(cmd_buffer->state.index_size) - 1;
+   uint32_t index_offset = firstIndex * cmd_buffer->state.index_size;
+
+   if (vertexOffset != 0 || firstInstance != 0) {
+      cl_emit(&job->bcl, BASE_VERTEX_BASE_INSTANCE, base) {
+         base.base_instance = firstInstance;
+         base.base_vertex = vertexOffset;
+      }
+   }
+
+   if (instanceCount == 1) {
+      cl_emit(&job->bcl, INDEXED_PRIM_LIST, prim) {
+         prim.index_type = index_type;
+         prim.length = indexCount;
+         prim.index_offset = index_offset;
+         prim.mode = hw_prim_type;
+         prim.enable_primitive_restarts = false; /* FIXME */
+      }
+   } else if (instanceCount > 1) {
+      cl_emit(&job->bcl, INDEXED_INSTANCED_PRIM_LIST, prim) {
+         prim.index_type = index_type;
+         prim.index_offset = index_offset;
+         prim.mode = hw_prim_type;
+         prim.enable_primitive_restarts = false; /* FIXME */
+         prim.number_of_instances = instanceCount;
+         prim.instance_length = indexCount;
+      }
+   }
+}
+
+void
 v3dv_CmdPipelineBarrier(VkCommandBuffer commandBuffer,
                         VkPipelineStageFlags srcStageMask,
                         VkPipelineStageFlags dstStageMask,
@@ -2087,6 +2138,35 @@
 }
 
 void
+v3dv_CmdBindIndexBuffer(VkCommandBuffer commandBuffer,
+                        VkBuffer buffer,
+                        VkDeviceSize offset,
+                        VkIndexType indexType)
+{
+   V3DV_FROM_HANDLE(v3dv_cmd_buffer, cmd_buffer, commandBuffer);
+   V3DV_FROM_HANDLE(v3dv_buffer, ibuffer, buffer);
+
+   struct v3dv_job *job = cmd_buffer->state.job;
+   assert(job);
+
+   cl_emit(&job->bcl, INDEX_BUFFER_SETUP, ib) {
+      ib.address = v3dv_cl_address(ibuffer->mem->bo, offset);
+      ib.size = ibuffer->mem->bo->size;
+   }
+
+   switch (indexType) {
+   case VK_INDEX_TYPE_UINT16:
+      cmd_buffer->state.index_size = 2;
+      break;
+   case VK_INDEX_TYPE_UINT32:
+      cmd_buffer->state.index_size = 4;
+      break;
+   default:
+      unreachable("Unsupported index type");
+   }
+}
+
+void
 v3dv_CmdSetStencilCompareMask(VkCommandBuffer commandBuffer,
                               VkStencilFaceFlags faceMask,
                               uint32_t compareMask)
diff --git a/src/broadcom/vulkan/v3dv_private.h b/src/broadcom/vulkan/v3dv_private.h
index daccb13..0fb674c 100644
--- a/src/broadcom/vulkan/v3dv_private.h
+++ b/src/broadcom/vulkan/v3dv_private.h
@@ -573,6 +573,8 @@
    struct v3dv_cmd_buffer_attachment_state *attachments;
 
    struct v3dv_vertex_binding vertex_bindings[MAX_VBS];
+
+   uint8_t index_size;
 };
 
 struct v3dv_cmd_buffer {