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