Mesa (main): zink: handle vertex buffer offset overflows

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Thu Jul 22 00:21:05 UTC 2021


Module: Mesa
Branch: main
Commit: 9823b970fb51db21ac6ce29753eba82dc25f3072
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=9823b970fb51db21ac6ce29753eba82dc25f3072

Author: Mike Blumenkrantz <michael.blumenkrantz at gmail.com>
Date:   Thu May 13 15:54:36 2021 -0400

zink: handle vertex buffer offset overflows

there's a screen limit for vertex buffer offsets (???), so if a buffer
is going to overflow that limit, just rebind it as a new tmp buffer and
clamp the offset to 0

this also applies to buffer rebinds

Reviewed-by: Dave Airlie <airlied at redhat.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/11836>

---

 src/gallium/drivers/zink/zink_context.c | 34 ++++++++++++++++++++++++++++++---
 src/gallium/drivers/zink/zink_context.h |  2 ++
 src/gallium/drivers/zink/zink_draw.cpp  |  9 +++++----
 3 files changed, 38 insertions(+), 7 deletions(-)

diff --git a/src/gallium/drivers/zink/zink_context.c b/src/gallium/drivers/zink/zink_context.c
index 613ab845e13..4bc8c9c23a3 100644
--- a/src/gallium/drivers/zink/zink_context.c
+++ b/src/gallium/drivers/zink/zink_context.c
@@ -900,9 +900,35 @@ update_existing_vbo(struct zink_context *ctx, unsigned slot)
       return;
    struct zink_resource *res = zink_resource(ctx->vertex_buffers[slot].buffer.resource);
    res->vbo_bind_mask &= ~BITFIELD_BIT(slot);
+   ctx->vbufs[slot] = VK_NULL_HANDLE;
+   ctx->vbuf_offsets[slot] = 0;
    update_res_bind_count(ctx, res, false, true);
 }
 
+ALWAYS_INLINE static void
+set_vertex_buffer_clamped(struct zink_context *ctx, unsigned slot)
+{
+   const struct pipe_vertex_buffer *ctx_vb = &ctx->vertex_buffers[slot];
+   struct zink_resource *res = zink_resource(ctx_vb->buffer.resource);
+   struct zink_screen *screen = zink_screen(ctx->base.screen);
+   if (ctx_vb->buffer_offset > screen->info.props.limits.maxVertexInputAttributeOffset) {
+      /* buffer offset exceeds maximum: make a tmp buffer at this offset */
+      ctx->vbufs[slot] = zink_resource_tmp_buffer(screen, res, ctx_vb->buffer_offset, 0, &ctx->vbuf_offsets[slot]);
+      util_dynarray_append(&res->obj->tmp, VkBuffer, ctx->vbufs[slot]);
+      /* the driver is broken and sets a min alignment that's larger than its max offset: rebind as staging buffer */
+      if (unlikely(ctx->vbuf_offsets[slot] > screen->info.props.limits.maxVertexInputAttributeOffset)) {
+         static bool warned = false;
+         if (!warned)
+            debug_printf("zink: this vulkan driver is BROKEN! maxVertexInputAttributeOffset < VkMemoryRequirements::alignment\n");
+         warned = true;
+      }
+   } else {
+      ctx->vbufs[slot] = res->obj->buffer;
+      ctx->vbuf_offsets[slot] = ctx_vb->buffer_offset;
+   }
+   assert(ctx->vbufs[slot]);
+}
+
 static void
 zink_set_vertex_buffers(struct pipe_context *pctx,
                         unsigned start_slot,
@@ -936,9 +962,11 @@ zink_set_vertex_buffers(struct pipe_context *pctx,
             update_res_bind_count(ctx, res, false, false);
             ctx_vb->stride = vb->stride;
             ctx_vb->buffer_offset = vb->buffer_offset;
-            zink_batch_resource_usage_set(&ctx->batch, res, false);
+            /* always barrier before possible rebind */
             zink_resource_buffer_barrier(ctx, NULL, res, VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT,
                                          VK_PIPELINE_STAGE_VERTEX_INPUT_BIT);
+            set_vertex_buffer_clamped(ctx, start_slot + i);
+            zink_batch_resource_usage_set(&ctx->batch, res, false);
          }
       }
    } else {
@@ -3128,10 +3156,10 @@ rebind_buffer(struct zink_context *ctx, struct zink_resource *res)
       u_foreach_bit(slot, res->vbo_bind_mask) {
          if (ctx->vertex_buffers[slot].buffer.resource != &res->base.b) //wrong context
             return;
-         break;
+         set_vertex_buffer_clamped(ctx, slot);
+         num_rebinds++;
       }
       ctx->vertex_buffers_dirty = true;
-      num_rebinds += util_bitcount(res->vbo_bind_mask);
    }
    for (unsigned shader = 0; num_rebinds < total_rebinds && shader < PIPE_SHADER_TYPES; shader++) {
       u_foreach_bit(slot, res->ubo_bind_mask[shader]) {
diff --git a/src/gallium/drivers/zink/zink_context.h b/src/gallium/drivers/zink/zink_context.h
index db1f944a5c7..2714899beab 100644
--- a/src/gallium/drivers/zink/zink_context.h
+++ b/src/gallium/drivers/zink/zink_context.h
@@ -224,6 +224,8 @@ struct zink_context {
    uint16_t clears_enabled;
    uint16_t rp_clears_enabled;
 
+   VkBuffer vbufs[PIPE_MAX_ATTRIBS];
+   unsigned vbuf_offsets[PIPE_MAX_ATTRIBS];
    struct pipe_vertex_buffer vertex_buffers[PIPE_MAX_ATTRIBS];
    bool vertex_buffers_dirty;
 
diff --git a/src/gallium/drivers/zink/zink_draw.cpp b/src/gallium/drivers/zink/zink_draw.cpp
index 6c3d597c4ec..7ae8fee0e6f 100644
--- a/src/gallium/drivers/zink/zink_draw.cpp
+++ b/src/gallium/drivers/zink/zink_draw.cpp
@@ -137,12 +137,13 @@ zink_bind_vertex_buffers(struct zink_batch *batch, struct zink_context *ctx)
       return;
 
    for (unsigned i = 0; i < elems->hw_state.num_bindings; i++) {
-      struct pipe_vertex_buffer *vb = ctx->vertex_buffers + ctx->element_state->binding_map[i];
+      const unsigned buffer_id = ctx->element_state->binding_map[i];
+      struct pipe_vertex_buffer *vb = ctx->vertex_buffers + buffer_id;
       assert(vb);
       if (vb->buffer.resource) {
-         struct zink_resource *res = zink_resource(vb->buffer.resource);
-         buffers[i] = res->obj->buffer;
-         buffer_offsets[i] = vb->buffer_offset;
+         buffers[i] = ctx->vbufs[buffer_id];
+         assert(buffers[i]);
+         buffer_offsets[i] = ctx->vbuf_offsets[buffer_id];
          buffer_strides[i] = vb->stride;
       } else {
          buffers[i] = zink_resource(ctx->dummy_vertex_buffer)->obj->buffer;



More information about the mesa-commit mailing list