diff --git a/src/compiler/nir/nir.h b/src/compiler/nir/nir.h index 978f5a9a834..a2e381ec917 100644 --- a/src/compiler/nir/nir.h +++ b/src/compiler/nir/nir.h @@ -5086,7 +5086,8 @@ nir_shader * nir_create_passthrough_tcs(const nir_shader_compiler_options *optio const nir_shader *vs, uint8_t patch_vertices); nir_shader * nir_create_passthrough_gs(const nir_shader_compiler_options *options, 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_fragcoord_wtrans(nir_shader *shader); diff --git a/src/compiler/nir/nir_passthrough_gs.c b/src/compiler/nir/nir_passthrough_gs.c index b9921e45ab1..c53e8f42971 100644 --- a/src/compiler/nir/nir_passthrough_gs.c +++ b/src/compiler/nir/nir_passthrough_gs.c @@ -128,18 +128,21 @@ array_size_for_prim(enum shader_prim prim) nir_shader * nir_create_passthrough_gs(const nir_shader_compiler_options *options, 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); + 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, options, "gs passthrough"); nir_shader *nir = b.shader; 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_out = vertices_out; + nir->info.gs.vertices_out = needs_closing ? vertices_out + 1 : vertices_out; nir->info.gs.invocations = 1; nir->info.gs.active_stream_mask = 1; @@ -211,19 +214,29 @@ nir_create_passthrough_gs(const nir_shader_compiler_options *options, 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. */ for (unsigned j = 0, oj = 0; j < num_inputs; ++j) { if (in_vars[j]->data.location == VARYING_SLOT_EDGE) { continue; } /* 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, (1u << value->num_components) - 1); ++oj; } 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); diff --git a/src/gallium/drivers/zink/zink_program.c b/src/gallium/drivers/zink/zink_program.c index 1037b9438b6..737b262c369 100644 --- a/src/gallium/drivers/zink/zink_program.c +++ b/src/gallium/drivers/zink/zink_program.c @@ -2219,7 +2219,8 @@ zink_set_primitive_emulation_keys(struct zink_context *ctx) nir_shader *nir = nir_create_passthrough_gs( &screen->nir_options, 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); ctx->gfx_stages[prev_vertex_stage]->non_fs.generated_gs[ctx->gfx_pipeline_state.gfx_prim_mode] = shader;