2 * Copyright © 2022 Collabora Ltc.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 #include "nir_builder.h"
28 gs_in_prim_for_topology(enum shader_prim prim)
31 case SHADER_PRIM_QUADS:
32 return SHADER_PRIM_LINES_ADJACENCY;
38 static enum shader_prim
39 gs_out_prim_for_topology(enum shader_prim prim)
42 case SHADER_PRIM_POINTS:
43 return SHADER_PRIM_POINTS;
44 case SHADER_PRIM_LINES:
45 case SHADER_PRIM_LINE_LOOP:
46 case SHADER_PRIM_LINES_ADJACENCY:
47 case SHADER_PRIM_LINE_STRIP_ADJACENCY:
48 case SHADER_PRIM_LINE_STRIP:
49 return SHADER_PRIM_LINE_STRIP;
50 case SHADER_PRIM_TRIANGLES:
51 case SHADER_PRIM_TRIANGLE_STRIP:
52 case SHADER_PRIM_TRIANGLE_FAN:
53 case SHADER_PRIM_TRIANGLES_ADJACENCY:
54 case SHADER_PRIM_TRIANGLE_STRIP_ADJACENCY:
55 case SHADER_PRIM_POLYGON:
56 return SHADER_PRIM_TRIANGLE_STRIP;
57 case SHADER_PRIM_QUADS:
58 case SHADER_PRIM_QUAD_STRIP:
59 case SHADER_PRIM_PATCHES:
61 return SHADER_PRIM_QUADS;
66 vertices_for_prim(enum shader_prim prim)
69 case SHADER_PRIM_POINTS:
71 case SHADER_PRIM_LINES:
72 case SHADER_PRIM_LINE_LOOP:
73 case SHADER_PRIM_LINES_ADJACENCY:
74 case SHADER_PRIM_LINE_STRIP_ADJACENCY:
75 case SHADER_PRIM_LINE_STRIP:
77 case SHADER_PRIM_TRIANGLES:
78 case SHADER_PRIM_TRIANGLE_STRIP:
79 case SHADER_PRIM_TRIANGLE_FAN:
80 case SHADER_PRIM_TRIANGLES_ADJACENCY:
81 case SHADER_PRIM_TRIANGLE_STRIP_ADJACENCY:
82 case SHADER_PRIM_POLYGON:
84 case SHADER_PRIM_QUADS:
85 case SHADER_PRIM_QUAD_STRIP:
87 case SHADER_PRIM_PATCHES:
89 unreachable("unsupported primitive for gs input");
94 array_size_for_prim(enum shader_prim prim)
97 case SHADER_PRIM_POINTS:
99 case SHADER_PRIM_LINES:
100 case SHADER_PRIM_LINE_LOOP:
101 case SHADER_PRIM_LINE_STRIP:
103 case SHADER_PRIM_LINES_ADJACENCY:
104 case SHADER_PRIM_LINE_STRIP_ADJACENCY:
106 case SHADER_PRIM_TRIANGLES:
107 case SHADER_PRIM_TRIANGLE_STRIP:
108 case SHADER_PRIM_TRIANGLE_FAN:
109 case SHADER_PRIM_POLYGON:
111 case SHADER_PRIM_TRIANGLES_ADJACENCY:
112 case SHADER_PRIM_TRIANGLE_STRIP_ADJACENCY:
114 case SHADER_PRIM_QUADS:
115 case SHADER_PRIM_QUAD_STRIP:
117 case SHADER_PRIM_PATCHES:
119 unreachable("unsupported primitive for gs input");
124 * A helper to create a passthrough GS shader for drivers that needs to lower
125 * some rendering tasks to the GS.
129 nir_create_passthrough_gs(const nir_shader_compiler_options *options,
130 const nir_shader *prev_stage,
131 enum shader_prim primitive_type,
132 bool emulate_edgeflags,
133 bool force_line_strip_out)
135 unsigned int vertices_out = vertices_for_prim(primitive_type);
136 emulate_edgeflags = emulate_edgeflags && (prev_stage->info.outputs_written & VARYING_BIT_EDGE);
137 bool needs_closing = (force_line_strip_out || emulate_edgeflags) && vertices_out >= 3;
138 nir_builder b = nir_builder_init_simple_shader(MESA_SHADER_GEOMETRY,
142 nir_shader *nir = b.shader;
143 nir->info.gs.input_primitive = gs_in_prim_for_topology(primitive_type);
144 nir->info.gs.output_primitive = (force_line_strip_out || emulate_edgeflags) ?
145 SHADER_PRIM_LINE_STRIP : gs_out_prim_for_topology(primitive_type);
146 nir->info.gs.vertices_in = vertices_out;
147 nir->info.gs.vertices_out = needs_closing ? vertices_out + 1 : vertices_out;
148 nir->info.gs.invocations = 1;
149 nir->info.gs.active_stream_mask = 1;
151 nir_variable *in_vars[VARYING_SLOT_MAX];
152 nir_variable *out_vars[VARYING_SLOT_MAX];
153 unsigned num_inputs = 0, num_outputs = 0;
155 /* Create input/output variables. */
156 nir_foreach_shader_out_variable(var, prev_stage) {
157 assert(!var->data.patch);
161 snprintf(name, sizeof(name), "in_%s", var->name);
163 snprintf(name, sizeof(name), "in_%d", var->data.driver_location);
165 nir_variable *in = nir_variable_create(nir, nir_var_shader_in,
166 glsl_array_type(var->type,
167 array_size_for_prim(primitive_type),
170 in->data.location = var->data.location;
171 in->data.location_frac = var->data.location_frac;
172 in->data.driver_location = var->data.driver_location;
173 in->data.interpolation = var->data.interpolation;
174 in->data.compact = var->data.compact;
176 in_vars[num_inputs++] = in;
179 if (in->data.location == VARYING_SLOT_EDGE)
182 if (var->data.location != VARYING_SLOT_POS)
186 snprintf(name, sizeof(name), "out_%s", var->name);
188 snprintf(name, sizeof(name), "out_%d", var->data.driver_location);
190 nir_variable *out = nir_variable_create(nir, nir_var_shader_out,
192 out->data.location = var->data.location;
193 out->data.location_frac = var->data.location_frac;
194 out->data.driver_location = var->data.driver_location;
195 out->data.interpolation = var->data.interpolation;
196 out->data.compact = var->data.compact;
198 out_vars[num_outputs++] = out;
201 unsigned int start_vert = 0;
202 unsigned int end_vert = vertices_out;
203 unsigned int vert_step = 1;
204 switch (primitive_type) {
205 case PIPE_PRIM_LINES_ADJACENCY:
206 case PIPE_PRIM_LINE_STRIP_ADJACENCY:
210 case PIPE_PRIM_TRIANGLES_ADJACENCY:
211 case PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY:
219 nir_variable *edge_var = nir_find_variable_with_location(nir, nir_var_shader_in, VARYING_SLOT_EDGE);
220 for (unsigned i = start_vert; i < end_vert || needs_closing; i += vert_step) {
221 int idx = i < end_vert ? i : start_vert;
222 /* Copy inputs to outputs. */
223 for (unsigned j = 0, oj = 0; j < num_inputs; ++j) {
224 if (in_vars[j]->data.location == VARYING_SLOT_EDGE) {
227 /* no need to use copy_var to save a lower pass */
228 nir_ssa_def *value = nir_load_array_var_imm(&b, in_vars[j], idx);
229 nir_store_var(&b, out_vars[oj], value,
230 (1u << value->num_components) - 1);
233 nir_emit_vertex(&b, 0);
234 if (emulate_edgeflags) {
235 nir_ssa_def *edge_value = nir_channel(&b, nir_load_array_var_imm(&b, edge_var, idx), 0);
236 nir_if *edge_if = nir_push_if(&b, nir_fneu(&b, edge_value, nir_imm_float(&b, 1.0)));
237 nir_end_primitive(&b, 0);
238 nir_pop_if(&b, edge_if);
244 nir_end_primitive(&b, 0);
245 nir_shader_gather_info(nir, nir_shader_get_entrypoint(nir));
246 nir_validate_shader(nir, "in nir_create_passthrough_gs");