diff --git a/src/gallium/drivers/zink/zink_context.c b/src/gallium/drivers/zink/zink_context.c index 77db0b28f6d..5aa6331e33b 100644 --- a/src/gallium/drivers/zink/zink_context.c +++ b/src/gallium/drivers/zink/zink_context.c @@ -4205,6 +4205,8 @@ zink_context_create(struct pipe_screen *pscreen, void *priv, unsigned flags) ctx->pipeline_changed[0] = ctx->pipeline_changed[1] = true; ctx->gfx_pipeline_state.dirty = true; + ctx->gfx_pipeline_state.uses_dynamic_stride = screen->info.have_EXT_extended_dynamic_state || + screen->info.have_EXT_vertex_input_dynamic_state; ctx->compute_pipeline_state.dirty = true; ctx->fb_changed = ctx->rp_changed = true; ctx->gfx_pipeline_state.gfx_prim_mode = PIPE_PRIM_MAX; diff --git a/src/gallium/drivers/zink/zink_draw.cpp b/src/gallium/drivers/zink/zink_draw.cpp index c1c0625ccaf..b091c6cab1b 100644 --- a/src/gallium/drivers/zink/zink_draw.cpp +++ b/src/gallium/drivers/zink/zink_draw.cpp @@ -749,8 +749,12 @@ zink_draw(struct pipe_context *pctx, if (DRAW_STATE) zink_bind_vertex_state(batch, ctx, vstate, partial_velem_mask); - else if (BATCH_CHANGED || ctx->vertex_buffers_dirty) - zink_bind_vertex_buffers(batch, ctx); + else if (BATCH_CHANGED || ctx->vertex_buffers_dirty) { + if (DYNAMIC_STATE == ZINK_DYNAMIC_VERTEX_INPUT || ctx->gfx_pipeline_state.uses_dynamic_stride) + zink_bind_vertex_buffers(batch, ctx); + else + zink_bind_vertex_buffers(batch, ctx); + } if (BATCH_CHANGED) { ctx->pipeline_changed[0] = false; diff --git a/src/gallium/drivers/zink/zink_pipeline.c b/src/gallium/drivers/zink/zink_pipeline.c index 768f20b95f7..1823dbba296 100644 --- a/src/gallium/drivers/zink/zink_pipeline.c +++ b/src/gallium/drivers/zink/zink_pipeline.c @@ -61,7 +61,7 @@ zink_create_gfx_pipeline(struct zink_screen *screen, vertex_input_state.vertexBindingDescriptionCount = state->element_state->num_bindings; vertex_input_state.pVertexAttributeDescriptions = state->element_state->attribs; vertex_input_state.vertexAttributeDescriptionCount = state->element_state->num_attribs; - if (!screen->info.have_EXT_extended_dynamic_state) { + if (!screen->info.have_EXT_extended_dynamic_state || !state->uses_dynamic_stride) { for (int i = 0; i < state->element_state->num_bindings; ++i) { const unsigned buffer_id = binding_map[i]; VkVertexInputBindingDescription *binding = &state->element_state->b.bindings[i]; @@ -232,7 +232,7 @@ zink_create_gfx_pipeline(struct zink_screen *screen, if (state->element_state->num_attribs) { if (screen->info.have_EXT_vertex_input_dynamic_state) dynamicStateEnables[state_count++] = VK_DYNAMIC_STATE_VERTEX_INPUT_EXT; - else if (screen->info.have_EXT_extended_dynamic_state) + else if (screen->info.have_EXT_extended_dynamic_state && state->uses_dynamic_stride) dynamicStateEnables[state_count++] = VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT; } if (screen->info.have_EXT_extended_dynamic_state2) { diff --git a/src/gallium/drivers/zink/zink_pipeline.h b/src/gallium/drivers/zink/zink_pipeline.h index ea220f1bc27..72807d943a4 100644 --- a/src/gallium/drivers/zink/zink_pipeline.h +++ b/src/gallium/drivers/zink/zink_pipeline.h @@ -76,6 +76,7 @@ struct zink_gfx_pipeline_state { uint32_t vertex_buffers_enabled_mask; uint32_t vertex_strides[PIPE_MAX_ATTRIBS]; bool sample_locations_enabled; + bool uses_dynamic_stride; bool have_EXT_extended_dynamic_state; bool have_EXT_extended_dynamic_state2; uint8_t has_points; //either gs outputs points or prim type is points diff --git a/src/gallium/drivers/zink/zink_program.c b/src/gallium/drivers/zink/zink_program.c index 85ed5e3e0cc..b0b41692caa 100644 --- a/src/gallium/drivers/zink/zink_program.c +++ b/src/gallium/drivers/zink/zink_program.c @@ -240,7 +240,9 @@ equals_gfx_pipeline_state(const void *a, const void *b) { const struct zink_gfx_pipeline_state *sa = a; const struct zink_gfx_pipeline_state *sb = b; - if (!sa->have_EXT_extended_dynamic_state) { + if (sa->uses_dynamic_stride != sb->uses_dynamic_stride) + return false; + if (!sa->have_EXT_extended_dynamic_state || !sa->uses_dynamic_stride) { if (sa->vertex_buffers_enabled_mask != sb->vertex_buffers_enabled_mask) return false; /* if we don't have dynamic states, we have to hash the enabled vertex buffer bindings */ @@ -252,6 +254,8 @@ equals_gfx_pipeline_state(const void *a, const void *b) if (sa->vertex_strides[idx_a] != sb->vertex_strides[idx_b]) return false; } + } + if (!sa->have_EXT_extended_dynamic_state) { if (sa->dyn_state1.front_face != sb->dyn_state1.front_face) return false; if (!!sa->dyn_state1.depth_stencil_alpha_state != !!sb->dyn_state1.depth_stencil_alpha_state || @@ -765,7 +769,29 @@ get_pipeline_idx(bool have_EXT_extended_dynamic_state, enum pipe_prim_type mode, } return vkmode; } - + +/* + VUID-vkCmdBindVertexBuffers2-pStrides-06209 + If pStrides is not NULL each element of pStrides must be either 0 or greater than or equal + to the maximum extent of all vertex input attributes fetched from the corresponding + binding, where the extent is calculated as the VkVertexInputAttributeDescription::offset + plus VkVertexInputAttributeDescription::format size + + * thus, if the stride doesn't meet the minimum requirement for a binding, + * disable the dynamic state here and use a fully-baked pipeline + */ +static bool +check_vertex_strides(struct zink_context *ctx) +{ + const struct zink_vertex_elements_state *ves = ctx->element_state; + for (unsigned i = 0; i < ves->hw_state.num_bindings; i++) { + const struct pipe_vertex_buffer *vb = ctx->vertex_buffers + ves->binding_map[i]; + unsigned stride = vb->buffer.resource ? vb->stride : 0; + if (stride < ves->min_stride[i]) + return false; + } + return true; +} VkPipeline zink_get_gfx_pipeline(struct zink_context *ctx, @@ -776,6 +802,7 @@ zink_get_gfx_pipeline(struct zink_context *ctx, struct zink_screen *screen = zink_screen(ctx->base.screen); const bool have_EXT_vertex_input_dynamic_state = screen->info.have_EXT_vertex_input_dynamic_state; const bool have_EXT_extended_dynamic_state = screen->info.have_EXT_extended_dynamic_state; + bool uses_dynamic_stride = state->uses_dynamic_stride; VkPrimitiveTopology vkmode = zink_primitive_topology(mode); const unsigned idx = get_pipeline_idx(screen->info.have_EXT_extended_dynamic_state, mode, vkmode); @@ -797,7 +824,9 @@ zink_get_gfx_pipeline(struct zink_context *ctx, if (!have_EXT_vertex_input_dynamic_state && ctx->vertex_state_changed) { if (state->pipeline) state->final_hash ^= state->vertex_hash; - if (!have_EXT_extended_dynamic_state) { + if (have_EXT_extended_dynamic_state) + uses_dynamic_stride = check_vertex_strides(ctx); + if (!uses_dynamic_stride) { uint32_t hash = 0; /* if we don't have dynamic states, we have to hash the enabled vertex buffer bindings */ uint32_t vertex_buffers_enabled_mask = state->vertex_buffers_enabled_mask; @@ -815,6 +844,7 @@ zink_get_gfx_pipeline(struct zink_context *ctx, state->final_hash ^= state->vertex_hash; } state->modules_changed = false; + state->uses_dynamic_stride = uses_dynamic_stride; ctx->vertex_state_changed = false; entry = _mesa_hash_table_search_pre_hashed(&prog->pipelines[idx], state->final_hash, state);