From 89077b866cabfe736dcd2d27994930c468138161 Mon Sep 17 00:00:00 2001 From: antonino Date: Tue, 4 Apr 2023 16:49:57 +0200 Subject: [PATCH] zink: use ring buffer to preserve last element Previously, whenever a vertex was emitted immediately after emitting a primitive, that vertex would not use the attributes that where assigned last because the position variable got set. Now the temporary attributes array is treated as a ring buffer and whenever the position is set to 0 it's previous value is used as an offset when accessing it. This way when a new primitive is created the attributes at index 0 correspond to the last attributes written. Fixes: 5a4083349f3 ("zink: add provoking vertex mode lowering") Reviewed-by: Erik Faye-Lund Part-of: --- src/gallium/drivers/zink/zink_compiler.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/src/gallium/drivers/zink/zink_compiler.c b/src/gallium/drivers/zink/zink_compiler.c index 18c5a07..aed61db 100644 --- a/src/gallium/drivers/zink/zink_compiler.c +++ b/src/gallium/drivers/zink/zink_compiler.c @@ -390,10 +390,22 @@ struct lower_pv_mode_state { nir_variable *varyings[VARYING_SLOT_MAX]; nir_variable *pos_counter; nir_variable *out_pos_counter; + nir_variable *ring_offset; + unsigned ring_size; unsigned primitive_vert_count; unsigned prim; }; +static nir_ssa_def* +lower_pv_mode_gs_ring_index(nir_builder *b, + struct lower_pv_mode_state *state, + nir_ssa_def *index) +{ + nir_ssa_def *ring_offset = nir_load_var(b, state->ring_offset); + return nir_imod(b, nir_iadd(b, index, ring_offset), + nir_imm_int(b, state->ring_size)); +} + static bool lower_pv_mode_gs_store(nir_builder *b, nir_intrinsic_instr *intrin, @@ -408,8 +420,9 @@ lower_pv_mode_gs_store(nir_builder *b, assert(state->varyings[location]); assert(intrin->src[1].is_ssa); nir_ssa_def *pos_counter = nir_load_var(b, state->pos_counter); + nir_ssa_def *index = lower_pv_mode_gs_ring_index(b, state, pos_counter); nir_store_array_var(b, state->varyings[location], - pos_counter, intrin->src[1].ssa, + index, intrin->src[1].ssa, nir_intrinsic_write_mask(intrin)); nir_instr_remove(&intrin->instr); return true; @@ -474,7 +487,8 @@ lower_pv_mode_emit_rotated_prim(nir_builder *b, nir_foreach_variable_with_modes(var, b->shader, nir_var_shader_out) { gl_varying_slot location = var->data.location; if (state->varyings[location]) { - nir_ssa_def *value = nir_load_array_var(b, state->varyings[location], rotated_i); + nir_ssa_def *index = lower_pv_mode_gs_ring_index(b, state, rotated_i); + nir_ssa_def *value = nir_load_array_var(b, state->varyings[location], index); nir_store_var(b, var, value, (1u << value->num_components) - 1); } } @@ -519,6 +533,10 @@ lower_pv_mode_gs_end_primitive(nir_builder *b, nir_store_var(b, state->out_pos_counter, nir_iadd_imm(b, out_pos_counter, 1), 1); } nir_pop_loop(b, NULL); + /* Set the ring offset such that when position 0 is + * read we get the last value written + */ + nir_store_var(b, state->ring_offset, pos_counter, 1); nir_store_var(b, state->pos_counter, nir_imm_int(b, 0), 1); nir_store_var(b, state->out_pos_counter, nir_imm_int(b, 0), 1); @@ -579,6 +597,7 @@ lower_pv_mode_gs(nir_shader *shader, unsigned prim) state.primitive_vert_count = lower_pv_mode_vertices_for_prim(shader->info.gs.output_primitive); + state.ring_size = shader->info.gs.vertices_out; nir_foreach_variable_with_modes(var, shader, nir_var_shader_out) { gl_varying_slot location = var->data.location; @@ -588,7 +607,7 @@ lower_pv_mode_gs(nir_shader *shader, unsigned prim) state.varyings[location] = nir_local_variable_create(entry, glsl_array_type(var->type, - shader->info.gs.vertices_out, + state.ring_size, false), name); } @@ -601,11 +620,16 @@ lower_pv_mode_gs(nir_shader *shader, unsigned prim) glsl_uint_type(), "__out_pos_counter"); + state.ring_offset = nir_local_variable_create(entry, + glsl_uint_type(), + "__ring_offset"); + state.prim = prim; // initialize pos_counter and out_pos_counter nir_store_var(&b, state.pos_counter, nir_imm_int(&b, 0), 1); nir_store_var(&b, state.out_pos_counter, nir_imm_int(&b, 0), 1); + nir_store_var(&b, state.ring_offset, nir_imm_int(&b, 0), 1); shader->info.gs.vertices_out = (shader->info.gs.vertices_out - (state.primitive_vert_count - 1)) * -- 2.7.4