From 55abc1202c67ebbc406ad7c64af64bbbf875895c Mon Sep 17 00:00:00 2001 From: Mike Blumenkrantz Date: Wed, 19 Aug 2020 17:59:13 -0400 Subject: [PATCH] zink: wrap shader gl_BaseVertex access with a bcsel based on push constant state vulkan has different mechanics than gl for this variable based on whether the current draw is indexed, so we need to rewrite the access here for that case this also requires that we add some padding to the tcs shader injection to account for new members being added to the push constant Reviewed-by: Dave Airlie Part-of: --- src/gallium/drivers/zink/zink_compiler.c | 75 ++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/src/gallium/drivers/zink/zink_compiler.c b/src/gallium/drivers/zink/zink_compiler.c index caff88a2c67..1bff75bdbfb 100644 --- a/src/gallium/drivers/zink/zink_compiler.c +++ b/src/gallium/drivers/zink/zink_compiler.c @@ -201,6 +201,80 @@ lower_64bit_vertex_attribs(nir_shader *shader) return nir_shader_instructions_pass(shader, lower_64bit_vertex_attribs_instr, nir_metadata_dominance, NULL); } +static bool +lower_basevertex_instr(nir_intrinsic_instr *instr, nir_builder *b) +{ + nir_variable *vs_pushconst = NULL; + + if (instr->intrinsic != nir_intrinsic_load_base_vertex) + return false; + + nir_foreach_shader_in_variable(var, b->shader) { + if (var->data.location == INT_MAX) { + vs_pushconst = var; + break; + } + } + b->cursor = nir_after_instr(&instr->instr); + + if (!vs_pushconst) { + /* create compatible layout for the ntv push constant loader */ + struct glsl_struct_field *fields = rzalloc_array(b->shader, struct glsl_struct_field, 1); + fields[0].type = glsl_array_type(glsl_uint_type(), 1, 0); + fields[0].name = ralloc_asprintf(b->shader, "draw_mode_is_indexed"); + fields[0].offset = offsetof(struct zink_push_constant, draw_mode_is_indexed); + vs_pushconst = nir_variable_create(b->shader, nir_var_mem_push_const, + glsl_struct_type(fields, 1, "struct", false), "vs_pushconst"); + vs_pushconst->data.location = INT_MAX; //doesn't really matter + } + + nir_intrinsic_instr *load = nir_intrinsic_instr_create(b->shader, nir_intrinsic_load_push_constant); + load->src[0] = nir_src_for_ssa(nir_imm_int(b, 0)); + nir_intrinsic_set_range(load, 4); + load->num_components = 1; + nir_ssa_dest_init(&load->instr, &load->dest, 1, 32, "draw_mode_is_indexed"); + nir_builder_instr_insert(b, &load->instr); + + nir_ssa_def *composite = nir_build_alu(b, nir_op_bcsel, + nir_build_alu(b, nir_op_ieq, &load->dest.ssa, nir_imm_int(b, 1), NULL, NULL), + &instr->dest.ssa, + nir_imm_int(b, 0), + NULL); + + nir_ssa_def_rewrite_uses_after(&instr->dest.ssa, nir_src_for_ssa(composite), composite->parent_instr); + return true; +} + +static bool +lower_basevertex(nir_shader *shader) +{ + bool progress = false; + + if (shader->info.stage != MESA_SHADER_VERTEX) + return false; + + if (!BITSET_TEST(shader->info.system_values_read, SYSTEM_VALUE_BASE_VERTEX)) + return false; + + nir_foreach_function(function, shader) { + if (function->impl) { + nir_builder builder; + nir_builder_init(&builder, function->impl); + nir_foreach_block(block, function->impl) { + nir_foreach_instr_safe(instr, block) { + if (instr->type == nir_instr_type_intrinsic) + progress |= lower_basevertex_instr(nir_instr_as_intrinsic(instr), + &builder); + } + } + + nir_metadata_preserve(function->impl, nir_metadata_dominance); + } + } + + return progress; +} + void zink_screen_init_compiler(struct zink_screen *screen) { @@ -431,6 +505,7 @@ zink_shader_create(struct zink_screen *screen, struct nir_shader *nir, have_psiz = check_psiz(nir); if (nir->info.stage == MESA_SHADER_GEOMETRY) NIR_PASS_V(nir, nir_lower_gs_intrinsics, nir_lower_gs_intrinsics_per_stream); + NIR_PASS_V(nir, lower_basevertex); NIR_PASS_V(nir, nir_lower_regs_to_ssa); NIR_PASS_V(nir, lower_baseinstance); optimize_nir(nir);