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;