zink: implement ARB_draw_indirect

other than the vaguely gross case of primitive restart with incompatible
draw modes and/or restart index, this is no trouble since the buffer formats
are compatible

Reviewed-by: Erik Faye-Lund <erik.faye-lund@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/7191>
diff --git a/docs/features.txt b/docs/features.txt
index 1cd2f27..1386d16 100644
--- a/docs/features.txt
+++ b/docs/features.txt
@@ -114,7 +114,7 @@
 GL 4.0, GLSL 4.00 --- all DONE: i965/gen7+, nvc0, r600, radeonsi, llvmpipe, virgl
 
   GL_ARB_draw_buffers_blend                             DONE (freedreno, i965/gen6+, nv50, softpipe, swr, zink, panfrost)
-  GL_ARB_draw_indirect                                  DONE (freedreno, i965/gen7+, softpipe, swr, v3d)
+  GL_ARB_draw_indirect                                  DONE (freedreno, i965/gen7+, softpipe, swr, v3d, zink)
   GL_ARB_gpu_shader5                                    DONE (i965/gen7+)
   - 'precise' qualifier                                 DONE (softpipe)
   - Dynamically uniform sampler array indices           DONE (softpipe)
diff --git a/src/gallium/drivers/zink/zink_draw.c b/src/gallium/drivers/zink/zink_draw.c
index 0dd24d0..b8a1fad 100644
--- a/src/gallium/drivers/zink/zink_draw.c
+++ b/src/gallium/drivers/zink/zink_draw.c
@@ -509,17 +509,25 @@
       struct zink_resource *res = zink_resource(index_buffer);
       vkCmdBindIndexBuffer(batch->cmdbuf, res->buffer, index_offset, index_type);
       zink_batch_reference_resource_rw(batch, res, false);
-      vkCmdDrawIndexed(batch->cmdbuf,
-         dinfo->count, dinfo->instance_count,
-         need_index_buffer_unref ? 0 : dinfo->start, dinfo->index_bias, dinfo->start_instance);
+      if (dinfo->indirect) {
+         struct zink_resource *indirect = zink_resource(dinfo->indirect->buffer);
+         zink_batch_reference_resource_rw(batch, indirect, false);
+         vkCmdDrawIndexedIndirect(batch->cmdbuf, indirect->buffer, dinfo->indirect->offset, dinfo->indirect->draw_count, dinfo->indirect->stride);
+      } else
+         vkCmdDrawIndexed(batch->cmdbuf,
+            dinfo->count, dinfo->instance_count,
+            need_index_buffer_unref ? 0 : dinfo->start, dinfo->index_bias, dinfo->start_instance);
    } else {
       if (so_target && screen->info.tf_props.transformFeedbackDraw) {
          zink_batch_reference_resource_rw(batch, zink_resource(so_target->counter_buffer), true);
          screen->vk_CmdDrawIndirectByteCountEXT(batch->cmdbuf, dinfo->instance_count, dinfo->start_instance,
                                        zink_resource(so_target->counter_buffer)->buffer, so_target->counter_buffer_offset, 0,
                                        MIN2(so_target->stride, screen->info.tf_props.maxTransformFeedbackBufferDataStride));
-      }
-      else
+      } else if (dinfo->indirect) {
+         struct zink_resource *indirect = zink_resource(dinfo->indirect->buffer);
+         zink_batch_reference_resource_rw(batch, indirect, false);
+         vkCmdDrawIndirect(batch->cmdbuf, indirect->buffer, dinfo->indirect->offset, dinfo->indirect->draw_count, dinfo->indirect->stride);
+      } else
          vkCmdDraw(batch->cmdbuf, dinfo->count, dinfo->instance_count, dinfo->start, dinfo->start_instance);
    }
 
diff --git a/src/gallium/drivers/zink/zink_screen.c b/src/gallium/drivers/zink/zink_screen.c
index 1d7b424..d7118ac 100644
--- a/src/gallium/drivers/zink/zink_screen.c
+++ b/src/gallium/drivers/zink/zink_screen.c
@@ -97,6 +97,7 @@
    switch (param) {
    case PIPE_CAP_NPOT_TEXTURES:
    case PIPE_CAP_TGSI_TEXCOORD:
+   case PIPE_CAP_DRAW_INDIRECT:
       return 1;
 
    case PIPE_CAP_VERTEX_ELEMENT_INSTANCE_DIVISOR: