nir: handle edge flags in nir_create_passthrough_gs

`nir_create_passthrough_gs` will now take a boolean argument to decide
whether it needs to handle edgeflags.

When true is passed it will output a line strip where edges that
shouldn't be visible are not emitted.

This is usefull because geometry shaders will generally throw away
edgeflags so for a passthrough GS to act transparently it needs to emulate them.

Acked-by: Mike Blumenkrantz <michael.blumenkrantz@gmail.com>
Reviewed-by: Erik Faye-Lund <erik.faye-lund@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/21238>
This commit is contained in:
antonino
2023-02-02 17:30:05 +01:00
committed by Marge Bot
parent a0751e8088
commit 24535ffb3d
3 changed files with 22 additions and 7 deletions

View File

@@ -5086,7 +5086,8 @@ nir_shader * nir_create_passthrough_tcs(const nir_shader_compiler_options *optio
const nir_shader *vs, uint8_t patch_vertices); const nir_shader *vs, uint8_t patch_vertices);
nir_shader * nir_create_passthrough_gs(const nir_shader_compiler_options *options, nir_shader * nir_create_passthrough_gs(const nir_shader_compiler_options *options,
const nir_shader *prev_stage, const nir_shader *prev_stage,
enum shader_prim primitive_type); enum shader_prim primitive_type,
bool emulate_edgeflags);
bool nir_lower_fragcolor(nir_shader *shader, unsigned max_cbufs); bool nir_lower_fragcolor(nir_shader *shader, unsigned max_cbufs);
bool nir_lower_fragcoord_wtrans(nir_shader *shader); bool nir_lower_fragcoord_wtrans(nir_shader *shader);

View File

@@ -128,18 +128,21 @@ array_size_for_prim(enum shader_prim prim)
nir_shader * nir_shader *
nir_create_passthrough_gs(const nir_shader_compiler_options *options, nir_create_passthrough_gs(const nir_shader_compiler_options *options,
const nir_shader *prev_stage, const nir_shader *prev_stage,
enum shader_prim primitive_type) enum shader_prim primitive_type,
bool emulate_edgeflags)
{ {
unsigned int vertices_out = vertices_for_prim(primitive_type); unsigned int vertices_out = vertices_for_prim(primitive_type);
emulate_edgeflags = emulate_edgeflags && (prev_stage->info.outputs_written & VARYING_BIT_EDGE);
bool needs_closing = emulate_edgeflags && vertices_out >= 3;
nir_builder b = nir_builder_init_simple_shader(MESA_SHADER_GEOMETRY, nir_builder b = nir_builder_init_simple_shader(MESA_SHADER_GEOMETRY,
options, options,
"gs passthrough"); "gs passthrough");
nir_shader *nir = b.shader; nir_shader *nir = b.shader;
nir->info.gs.input_primitive = gs_in_prim_for_topology(primitive_type); nir->info.gs.input_primitive = gs_in_prim_for_topology(primitive_type);
nir->info.gs.output_primitive = gs_out_prim_for_topology(primitive_type); nir->info.gs.output_primitive = emulate_edgeflags ? SHADER_PRIM_LINE_STRIP : gs_out_prim_for_topology(primitive_type);
nir->info.gs.vertices_in = vertices_out; nir->info.gs.vertices_in = vertices_out;
nir->info.gs.vertices_out = vertices_out; nir->info.gs.vertices_out = needs_closing ? vertices_out + 1 : vertices_out;
nir->info.gs.invocations = 1; nir->info.gs.invocations = 1;
nir->info.gs.active_stream_mask = 1; nir->info.gs.active_stream_mask = 1;
@@ -211,19 +214,29 @@ nir_create_passthrough_gs(const nir_shader_compiler_options *options,
break; break;
} }
for (unsigned i = start_vert; i < end_vert; i += vert_step) { nir_variable *edge_var = nir_find_variable_with_location(nir, nir_var_shader_in, VARYING_SLOT_EDGE);
for (unsigned i = start_vert; i < end_vert || needs_closing; i += vert_step) {
int idx = i < end_vert ? i : start_vert;
/* Copy inputs to outputs. */ /* Copy inputs to outputs. */
for (unsigned j = 0, oj = 0; j < num_inputs; ++j) { for (unsigned j = 0, oj = 0; j < num_inputs; ++j) {
if (in_vars[j]->data.location == VARYING_SLOT_EDGE) { if (in_vars[j]->data.location == VARYING_SLOT_EDGE) {
continue; continue;
} }
/* no need to use copy_var to save a lower pass */ /* no need to use copy_var to save a lower pass */
nir_ssa_def *value = nir_load_array_var_imm(&b, in_vars[j], i); nir_ssa_def *value = nir_load_array_var_imm(&b, in_vars[j], idx);
nir_store_var(&b, out_vars[oj], value, nir_store_var(&b, out_vars[oj], value,
(1u << value->num_components) - 1); (1u << value->num_components) - 1);
++oj; ++oj;
} }
nir_emit_vertex(&b, 0); nir_emit_vertex(&b, 0);
if (emulate_edgeflags) {
nir_ssa_def *edge_value = nir_channel(&b, nir_load_array_var_imm(&b, edge_var, idx), 0);
nir_if *edge_if = nir_push_if(&b, nir_fneu(&b, edge_value, nir_imm_float(&b, 1.0)));
nir_end_primitive(&b, 0);
nir_pop_if(&b, edge_if);
}
if (i >= end_vert)
break;
} }
nir_end_primitive(&b, 0); nir_end_primitive(&b, 0);

View File

@@ -2219,7 +2219,8 @@ zink_set_primitive_emulation_keys(struct zink_context *ctx)
nir_shader *nir = nir_create_passthrough_gs( nir_shader *nir = nir_create_passthrough_gs(
&screen->nir_options, &screen->nir_options,
ctx->gfx_stages[prev_vertex_stage]->nir, ctx->gfx_stages[prev_vertex_stage]->nir,
(lower_line_stipple || lower_line_smooth) ? SHADER_PRIM_LINE_STRIP : SHADER_PRIM_POINTS); (lower_line_stipple || lower_line_smooth) ? SHADER_PRIM_LINE_STRIP : SHADER_PRIM_POINTS,
false);
struct zink_shader *shader = zink_shader_create(screen, nir, NULL); struct zink_shader *shader = zink_shader_create(screen, nir, NULL);
ctx->gfx_stages[prev_vertex_stage]->non_fs.generated_gs[ctx->gfx_pipeline_state.gfx_prim_mode] = shader; ctx->gfx_stages[prev_vertex_stage]->non_fs.generated_gs[ctx->gfx_pipeline_state.gfx_prim_mode] = shader;