1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright © Microsoft Corporation
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next
12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
13bf215546Sopenharmony_ci * Software.
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21bf215546Sopenharmony_ci * IN THE SOFTWARE.
22bf215546Sopenharmony_ci */
23bf215546Sopenharmony_ci
24bf215546Sopenharmony_ci#include "d3d12_compiler.h"
25bf215546Sopenharmony_ci#include "d3d12_context.h"
26bf215546Sopenharmony_ci#include "d3d12_debug.h"
27bf215546Sopenharmony_ci#include "d3d12_screen.h"
28bf215546Sopenharmony_ci
29bf215546Sopenharmony_ci#include "nir.h"
30bf215546Sopenharmony_ci#include "compiler/nir/nir_builder.h"
31bf215546Sopenharmony_ci#include "compiler/nir/nir_builtin_builder.h"
32bf215546Sopenharmony_ci
33bf215546Sopenharmony_ci#include "util/u_memory.h"
34bf215546Sopenharmony_ci#include "util/u_simple_shaders.h"
35bf215546Sopenharmony_ci
36bf215546Sopenharmony_cistatic nir_ssa_def *
37bf215546Sopenharmony_cinir_cull_face(nir_builder *b, nir_variable *vertices, bool ccw)
38bf215546Sopenharmony_ci{
39bf215546Sopenharmony_ci   nir_ssa_def *v0 =
40bf215546Sopenharmony_ci       nir_load_deref(b, nir_build_deref_array(b, nir_build_deref_var(b, vertices), nir_imm_int(b, 0)));
41bf215546Sopenharmony_ci   nir_ssa_def *v1 =
42bf215546Sopenharmony_ci       nir_load_deref(b, nir_build_deref_array(b, nir_build_deref_var(b, vertices), nir_imm_int(b, 1)));
43bf215546Sopenharmony_ci   nir_ssa_def *v2 =
44bf215546Sopenharmony_ci       nir_load_deref(b, nir_build_deref_array(b, nir_build_deref_var(b, vertices), nir_imm_int(b, 2)));
45bf215546Sopenharmony_ci
46bf215546Sopenharmony_ci   nir_ssa_def *dir = nir_fdot(b, nir_cross4(b, nir_fsub(b, v1, v0),
47bf215546Sopenharmony_ci                                               nir_fsub(b, v2, v0)),
48bf215546Sopenharmony_ci                                   nir_imm_vec4(b, 0.0, 0.0, -1.0, 0.0));
49bf215546Sopenharmony_ci   if (ccw)
50bf215546Sopenharmony_ci       return nir_fge(b, nir_imm_int(b, 0), dir);
51bf215546Sopenharmony_ci   else
52bf215546Sopenharmony_ci       return nir_flt(b, nir_imm_int(b, 0), dir);
53bf215546Sopenharmony_ci}
54bf215546Sopenharmony_ci
55bf215546Sopenharmony_cistatic void
56bf215546Sopenharmony_cicopy_vars(nir_builder *b, nir_deref_instr *dst, nir_deref_instr *src)
57bf215546Sopenharmony_ci{
58bf215546Sopenharmony_ci   assert(glsl_get_bare_type(dst->type) == glsl_get_bare_type(src->type));
59bf215546Sopenharmony_ci   if (glsl_type_is_struct(dst->type)) {
60bf215546Sopenharmony_ci      for (unsigned i = 0; i < glsl_get_length(dst->type); ++i) {
61bf215546Sopenharmony_ci         copy_vars(b, nir_build_deref_struct(b, dst, i), nir_build_deref_struct(b, src, i));
62bf215546Sopenharmony_ci      }
63bf215546Sopenharmony_ci   } else if (glsl_type_is_array_or_matrix(dst->type)) {
64bf215546Sopenharmony_ci      copy_vars(b, nir_build_deref_array_wildcard(b, dst), nir_build_deref_array_wildcard(b, src));
65bf215546Sopenharmony_ci   } else {
66bf215546Sopenharmony_ci      nir_copy_deref(b, dst, src);
67bf215546Sopenharmony_ci   }
68bf215546Sopenharmony_ci}
69bf215546Sopenharmony_ci
70bf215546Sopenharmony_cistatic d3d12_shader_selector*
71bf215546Sopenharmony_cid3d12_make_passthrough_gs(struct d3d12_context *ctx, struct d3d12_gs_variant_key *key)
72bf215546Sopenharmony_ci{
73bf215546Sopenharmony_ci   struct d3d12_shader_selector *gs;
74bf215546Sopenharmony_ci   uint64_t varyings = key->varyings.mask;
75bf215546Sopenharmony_ci   nir_shader *nir;
76bf215546Sopenharmony_ci   struct pipe_shader_state templ;
77bf215546Sopenharmony_ci
78bf215546Sopenharmony_ci   nir_builder b = nir_builder_init_simple_shader(MESA_SHADER_GEOMETRY,
79bf215546Sopenharmony_ci                                                  &d3d12_screen(ctx->base.screen)->nir_options,
80bf215546Sopenharmony_ci                                                  "passthrough");
81bf215546Sopenharmony_ci
82bf215546Sopenharmony_ci   nir = b.shader;
83bf215546Sopenharmony_ci   nir->info.inputs_read = varyings;
84bf215546Sopenharmony_ci   nir->info.outputs_written = varyings;
85bf215546Sopenharmony_ci   nir->info.gs.input_primitive = GL_POINTS;
86bf215546Sopenharmony_ci   nir->info.gs.output_primitive = GL_POINTS;
87bf215546Sopenharmony_ci   nir->info.gs.vertices_in = 1;
88bf215546Sopenharmony_ci   nir->info.gs.vertices_out = 1;
89bf215546Sopenharmony_ci   nir->info.gs.invocations = 1;
90bf215546Sopenharmony_ci   nir->info.gs.active_stream_mask = 1;
91bf215546Sopenharmony_ci
92bf215546Sopenharmony_ci   /* Copy inputs to outputs. */
93bf215546Sopenharmony_ci   while (varyings) {
94bf215546Sopenharmony_ci      char tmp[100];
95bf215546Sopenharmony_ci      const int i = u_bit_scan64(&varyings);
96bf215546Sopenharmony_ci
97bf215546Sopenharmony_ci      unsigned frac_slots = key->varyings.slots[i].location_frac_mask;
98bf215546Sopenharmony_ci      while (frac_slots) {
99bf215546Sopenharmony_ci         nir_variable *in, *out;
100bf215546Sopenharmony_ci         int j = u_bit_scan(&frac_slots);
101bf215546Sopenharmony_ci
102bf215546Sopenharmony_ci         snprintf(tmp, ARRAY_SIZE(tmp), "in_%d", key->varyings.slots[i].vars[j].driver_location);
103bf215546Sopenharmony_ci         in = nir_variable_create(nir,
104bf215546Sopenharmony_ci                                  nir_var_shader_in,
105bf215546Sopenharmony_ci                                  glsl_array_type(key->varyings.slots[i].types[j], 1, false),
106bf215546Sopenharmony_ci                                  tmp);
107bf215546Sopenharmony_ci         in->data.location = i;
108bf215546Sopenharmony_ci         in->data.location_frac = j;
109bf215546Sopenharmony_ci         in->data.driver_location = key->varyings.slots[i].vars[j].driver_location;
110bf215546Sopenharmony_ci         in->data.interpolation = key->varyings.slots[i].vars[j].interpolation;
111bf215546Sopenharmony_ci         in->data.compact = key->varyings.slots[i].vars[j].compact;
112bf215546Sopenharmony_ci
113bf215546Sopenharmony_ci         snprintf(tmp, ARRAY_SIZE(tmp), "out_%d", key->varyings.slots[i].vars[j].driver_location);
114bf215546Sopenharmony_ci         out = nir_variable_create(nir,
115bf215546Sopenharmony_ci                                   nir_var_shader_out,
116bf215546Sopenharmony_ci                                   key->varyings.slots[i].types[j],
117bf215546Sopenharmony_ci                                   tmp);
118bf215546Sopenharmony_ci         out->data.location = i;
119bf215546Sopenharmony_ci         out->data.location_frac = j;
120bf215546Sopenharmony_ci         out->data.driver_location = key->varyings.slots[i].vars[j].driver_location;
121bf215546Sopenharmony_ci         out->data.interpolation = key->varyings.slots[i].vars[j].interpolation;
122bf215546Sopenharmony_ci         out->data.compact = key->varyings.slots[i].vars[j].compact;
123bf215546Sopenharmony_ci
124bf215546Sopenharmony_ci         nir_deref_instr *in_value = nir_build_deref_array(&b, nir_build_deref_var(&b, in),
125bf215546Sopenharmony_ci                                                               nir_imm_int(&b, 0));
126bf215546Sopenharmony_ci         copy_vars(&b, nir_build_deref_var(&b, out), in_value);
127bf215546Sopenharmony_ci      }
128bf215546Sopenharmony_ci   }
129bf215546Sopenharmony_ci
130bf215546Sopenharmony_ci   nir_emit_vertex(&b, 0);
131bf215546Sopenharmony_ci   nir_end_primitive(&b, 0);
132bf215546Sopenharmony_ci
133bf215546Sopenharmony_ci   NIR_PASS_V(nir, nir_lower_var_copies);
134bf215546Sopenharmony_ci   nir_validate_shader(nir, "in d3d12_create_passthrough_gs");
135bf215546Sopenharmony_ci
136bf215546Sopenharmony_ci   templ.type = PIPE_SHADER_IR_NIR;
137bf215546Sopenharmony_ci   templ.ir.nir = nir;
138bf215546Sopenharmony_ci   templ.stream_output.num_outputs = 0;
139bf215546Sopenharmony_ci
140bf215546Sopenharmony_ci   gs = d3d12_create_shader(ctx, PIPE_SHADER_GEOMETRY, &templ);
141bf215546Sopenharmony_ci
142bf215546Sopenharmony_ci   return gs;
143bf215546Sopenharmony_ci}
144bf215546Sopenharmony_ci
145bf215546Sopenharmony_cistruct emit_primitives_context
146bf215546Sopenharmony_ci{
147bf215546Sopenharmony_ci   struct d3d12_context *ctx;
148bf215546Sopenharmony_ci   nir_builder b;
149bf215546Sopenharmony_ci
150bf215546Sopenharmony_ci   unsigned num_vars;
151bf215546Sopenharmony_ci   nir_variable *in[VARYING_SLOT_MAX];
152bf215546Sopenharmony_ci   nir_variable *out[VARYING_SLOT_MAX];
153bf215546Sopenharmony_ci   nir_variable *front_facing_var;
154bf215546Sopenharmony_ci
155bf215546Sopenharmony_ci   nir_loop *loop;
156bf215546Sopenharmony_ci   nir_deref_instr *loop_index_deref;
157bf215546Sopenharmony_ci   nir_ssa_def *loop_index;
158bf215546Sopenharmony_ci   nir_ssa_def *edgeflag_cmp;
159bf215546Sopenharmony_ci   nir_ssa_def *front_facing;
160bf215546Sopenharmony_ci};
161bf215546Sopenharmony_ci
162bf215546Sopenharmony_cistatic bool
163bf215546Sopenharmony_cid3d12_begin_emit_primitives_gs(struct emit_primitives_context *emit_ctx,
164bf215546Sopenharmony_ci                               struct d3d12_context *ctx,
165bf215546Sopenharmony_ci                               struct d3d12_gs_variant_key *key,
166bf215546Sopenharmony_ci                               uint16_t output_primitive,
167bf215546Sopenharmony_ci                               unsigned vertices_out)
168bf215546Sopenharmony_ci{
169bf215546Sopenharmony_ci   nir_builder *b = &emit_ctx->b;
170bf215546Sopenharmony_ci   nir_variable *edgeflag_var = NULL;
171bf215546Sopenharmony_ci   nir_variable *pos_var = NULL;
172bf215546Sopenharmony_ci   uint64_t varyings = key->varyings.mask;
173bf215546Sopenharmony_ci
174bf215546Sopenharmony_ci   emit_ctx->ctx = ctx;
175bf215546Sopenharmony_ci
176bf215546Sopenharmony_ci   emit_ctx->b = nir_builder_init_simple_shader(MESA_SHADER_GEOMETRY,
177bf215546Sopenharmony_ci                                                &d3d12_screen(ctx->base.screen)->nir_options,
178bf215546Sopenharmony_ci                                                "edgeflags");
179bf215546Sopenharmony_ci
180bf215546Sopenharmony_ci   nir_shader *nir = b->shader;
181bf215546Sopenharmony_ci   nir->info.inputs_read = varyings;
182bf215546Sopenharmony_ci   nir->info.outputs_written = varyings;
183bf215546Sopenharmony_ci   nir->info.gs.input_primitive = GL_TRIANGLES;
184bf215546Sopenharmony_ci   nir->info.gs.output_primitive = output_primitive;
185bf215546Sopenharmony_ci   nir->info.gs.vertices_in = 3;
186bf215546Sopenharmony_ci   nir->info.gs.vertices_out = vertices_out;
187bf215546Sopenharmony_ci   nir->info.gs.invocations = 1;
188bf215546Sopenharmony_ci   nir->info.gs.active_stream_mask = 1;
189bf215546Sopenharmony_ci
190bf215546Sopenharmony_ci   while (varyings) {
191bf215546Sopenharmony_ci      char tmp[100];
192bf215546Sopenharmony_ci      const int i = u_bit_scan64(&varyings);
193bf215546Sopenharmony_ci
194bf215546Sopenharmony_ci      unsigned frac_slots = key->varyings.slots[i].location_frac_mask;
195bf215546Sopenharmony_ci      while (frac_slots) {
196bf215546Sopenharmony_ci         int j = u_bit_scan(&frac_slots);
197bf215546Sopenharmony_ci         snprintf(tmp, ARRAY_SIZE(tmp), "in_%d", emit_ctx->num_vars);
198bf215546Sopenharmony_ci         emit_ctx->in[emit_ctx->num_vars] = nir_variable_create(nir,
199bf215546Sopenharmony_ci                                                                nir_var_shader_in,
200bf215546Sopenharmony_ci                                                                glsl_array_type(key->varyings.slots[i].types[j], 3, 0),
201bf215546Sopenharmony_ci                                                                tmp);
202bf215546Sopenharmony_ci         emit_ctx->in[emit_ctx->num_vars]->data.location = i;
203bf215546Sopenharmony_ci         emit_ctx->in[emit_ctx->num_vars]->data.location_frac = j;
204bf215546Sopenharmony_ci         emit_ctx->in[emit_ctx->num_vars]->data.driver_location = key->varyings.slots[i].vars[j].driver_location;
205bf215546Sopenharmony_ci         emit_ctx->in[emit_ctx->num_vars]->data.interpolation = key->varyings.slots[i].vars[j].interpolation;
206bf215546Sopenharmony_ci         emit_ctx->in[emit_ctx->num_vars]->data.compact = key->varyings.slots[i].vars[j].compact;
207bf215546Sopenharmony_ci
208bf215546Sopenharmony_ci         /* Don't create an output for the edge flag variable */
209bf215546Sopenharmony_ci         if (i == VARYING_SLOT_EDGE) {
210bf215546Sopenharmony_ci            edgeflag_var = emit_ctx->in[emit_ctx->num_vars];
211bf215546Sopenharmony_ci            continue;
212bf215546Sopenharmony_ci         } else if (i == VARYING_SLOT_POS) {
213bf215546Sopenharmony_ci             pos_var = emit_ctx->in[emit_ctx->num_vars];
214bf215546Sopenharmony_ci         }
215bf215546Sopenharmony_ci
216bf215546Sopenharmony_ci         snprintf(tmp, ARRAY_SIZE(tmp), "out_%d", emit_ctx->num_vars);
217bf215546Sopenharmony_ci         emit_ctx->out[emit_ctx->num_vars] = nir_variable_create(nir,
218bf215546Sopenharmony_ci                                                                 nir_var_shader_out,
219bf215546Sopenharmony_ci                                                                 key->varyings.slots[i].types[j],
220bf215546Sopenharmony_ci                                                                 tmp);
221bf215546Sopenharmony_ci         emit_ctx->out[emit_ctx->num_vars]->data.location = i;
222bf215546Sopenharmony_ci         emit_ctx->out[emit_ctx->num_vars]->data.location_frac = j;
223bf215546Sopenharmony_ci         emit_ctx->out[emit_ctx->num_vars]->data.driver_location = key->varyings.slots[i].vars[j].driver_location;
224bf215546Sopenharmony_ci         emit_ctx->out[emit_ctx->num_vars]->data.interpolation = key->varyings.slots[i].vars[j].interpolation;
225bf215546Sopenharmony_ci         emit_ctx->out[emit_ctx->num_vars]->data.compact = key->varyings.slots[i].vars[j].compact;
226bf215546Sopenharmony_ci
227bf215546Sopenharmony_ci         emit_ctx->num_vars++;
228bf215546Sopenharmony_ci      }
229bf215546Sopenharmony_ci   }
230bf215546Sopenharmony_ci
231bf215546Sopenharmony_ci   if (key->has_front_face) {
232bf215546Sopenharmony_ci      emit_ctx->front_facing_var = nir_variable_create(nir,
233bf215546Sopenharmony_ci                                                       nir_var_shader_out,
234bf215546Sopenharmony_ci                                                       glsl_uint_type(),
235bf215546Sopenharmony_ci                                                       "gl_FrontFacing");
236bf215546Sopenharmony_ci      emit_ctx->front_facing_var->data.location = VARYING_SLOT_VAR12;
237bf215546Sopenharmony_ci      emit_ctx->front_facing_var->data.driver_location = emit_ctx->num_vars;
238bf215546Sopenharmony_ci      emit_ctx->front_facing_var->data.interpolation = INTERP_MODE_FLAT;
239bf215546Sopenharmony_ci   }
240bf215546Sopenharmony_ci
241bf215546Sopenharmony_ci   /* Temporary variable "loop_index" to loop over input vertices */
242bf215546Sopenharmony_ci   nir_function_impl *impl = nir_shader_get_entrypoint(nir);
243bf215546Sopenharmony_ci   nir_variable *loop_index_var =
244bf215546Sopenharmony_ci      nir_local_variable_create(impl, glsl_uint_type(), "loop_index");
245bf215546Sopenharmony_ci   emit_ctx->loop_index_deref = nir_build_deref_var(b, loop_index_var);
246bf215546Sopenharmony_ci   nir_store_deref(b, emit_ctx->loop_index_deref, nir_imm_int(b, 0), 1);
247bf215546Sopenharmony_ci
248bf215546Sopenharmony_ci   nir_ssa_def *diagonal_vertex = NULL;
249bf215546Sopenharmony_ci   if (key->edge_flag_fix) {
250bf215546Sopenharmony_ci      nir_ssa_def *prim_id = nir_load_primitive_id(b);
251bf215546Sopenharmony_ci      nir_ssa_def *odd = nir_build_alu(b, nir_op_imod,
252bf215546Sopenharmony_ci                                       prim_id,
253bf215546Sopenharmony_ci                                       nir_imm_int(b, 2),
254bf215546Sopenharmony_ci                                       NULL, NULL);
255bf215546Sopenharmony_ci      diagonal_vertex = nir_bcsel(b, nir_i2b(b, odd),
256bf215546Sopenharmony_ci                                  nir_imm_int(b, 2),
257bf215546Sopenharmony_ci                                  nir_imm_int(b, 1));
258bf215546Sopenharmony_ci   }
259bf215546Sopenharmony_ci
260bf215546Sopenharmony_ci   if (key->cull_mode != PIPE_FACE_NONE || key->has_front_face) {
261bf215546Sopenharmony_ci      if (key->cull_mode == PIPE_FACE_BACK)
262bf215546Sopenharmony_ci         emit_ctx->edgeflag_cmp = nir_cull_face(b, pos_var, key->front_ccw);
263bf215546Sopenharmony_ci      else if (key->cull_mode == PIPE_FACE_FRONT)
264bf215546Sopenharmony_ci         emit_ctx->edgeflag_cmp = nir_cull_face(b, pos_var, !key->front_ccw);
265bf215546Sopenharmony_ci
266bf215546Sopenharmony_ci      if (key->has_front_face) {
267bf215546Sopenharmony_ci         if (key->cull_mode == PIPE_FACE_BACK)
268bf215546Sopenharmony_ci            emit_ctx->front_facing = emit_ctx->edgeflag_cmp;
269bf215546Sopenharmony_ci         else
270bf215546Sopenharmony_ci            emit_ctx->front_facing = nir_cull_face(b, pos_var, key->front_ccw);
271bf215546Sopenharmony_ci         emit_ctx->front_facing = nir_i2i32(b, emit_ctx->front_facing);
272bf215546Sopenharmony_ci      }
273bf215546Sopenharmony_ci   }
274bf215546Sopenharmony_ci
275bf215546Sopenharmony_ci   /**
276bf215546Sopenharmony_ci    *  while {
277bf215546Sopenharmony_ci    *     if (loop_index >= 3)
278bf215546Sopenharmony_ci    *        break;
279bf215546Sopenharmony_ci    */
280bf215546Sopenharmony_ci   emit_ctx->loop = nir_push_loop(b);
281bf215546Sopenharmony_ci
282bf215546Sopenharmony_ci   emit_ctx->loop_index = nir_load_deref(b, emit_ctx->loop_index_deref);
283bf215546Sopenharmony_ci   nir_ssa_def *cmp = nir_ige(b, emit_ctx->loop_index,
284bf215546Sopenharmony_ci                              nir_imm_int(b, 3));
285bf215546Sopenharmony_ci   nir_if *loop_check = nir_push_if(b, cmp);
286bf215546Sopenharmony_ci   nir_jump(b, nir_jump_break);
287bf215546Sopenharmony_ci   nir_pop_if(b, loop_check);
288bf215546Sopenharmony_ci
289bf215546Sopenharmony_ci   if (edgeflag_var) {
290bf215546Sopenharmony_ci      nir_ssa_def *edge_flag =
291bf215546Sopenharmony_ci         nir_load_deref(b, nir_build_deref_array(b, nir_build_deref_var(b, edgeflag_var), emit_ctx->loop_index));
292bf215546Sopenharmony_ci      nir_ssa_def *is_edge = nir_feq(b, nir_channel(b, edge_flag, 0), nir_imm_float(b, 1.0));
293bf215546Sopenharmony_ci      if (emit_ctx->edgeflag_cmp)
294bf215546Sopenharmony_ci         emit_ctx->edgeflag_cmp = nir_iand(b, emit_ctx->edgeflag_cmp, is_edge);
295bf215546Sopenharmony_ci      else
296bf215546Sopenharmony_ci         emit_ctx->edgeflag_cmp = is_edge;
297bf215546Sopenharmony_ci   }
298bf215546Sopenharmony_ci
299bf215546Sopenharmony_ci   if (key->edge_flag_fix) {
300bf215546Sopenharmony_ci      nir_ssa_def *is_edge = nir_ine(b, emit_ctx->loop_index, diagonal_vertex);
301bf215546Sopenharmony_ci      if (emit_ctx->edgeflag_cmp)
302bf215546Sopenharmony_ci         emit_ctx->edgeflag_cmp = nir_iand(b, emit_ctx->edgeflag_cmp, is_edge);
303bf215546Sopenharmony_ci      else
304bf215546Sopenharmony_ci         emit_ctx->edgeflag_cmp = is_edge;
305bf215546Sopenharmony_ci   }
306bf215546Sopenharmony_ci
307bf215546Sopenharmony_ci   return true;
308bf215546Sopenharmony_ci}
309bf215546Sopenharmony_ci
310bf215546Sopenharmony_cistatic struct d3d12_shader_selector *
311bf215546Sopenharmony_cid3d12_finish_emit_primitives_gs(struct emit_primitives_context *emit_ctx, bool end_primitive)
312bf215546Sopenharmony_ci{
313bf215546Sopenharmony_ci   struct pipe_shader_state templ;
314bf215546Sopenharmony_ci   nir_builder *b = &emit_ctx->b;
315bf215546Sopenharmony_ci   nir_shader *nir = b->shader;
316bf215546Sopenharmony_ci
317bf215546Sopenharmony_ci   /**
318bf215546Sopenharmony_ci    *     loop_index++;
319bf215546Sopenharmony_ci    *  }
320bf215546Sopenharmony_ci    */
321bf215546Sopenharmony_ci   nir_store_deref(b, emit_ctx->loop_index_deref, nir_iadd_imm(b, emit_ctx->loop_index, 1), 1);
322bf215546Sopenharmony_ci   nir_pop_loop(b, emit_ctx->loop);
323bf215546Sopenharmony_ci
324bf215546Sopenharmony_ci   if (end_primitive)
325bf215546Sopenharmony_ci      nir_end_primitive(b, 0);
326bf215546Sopenharmony_ci
327bf215546Sopenharmony_ci   nir_validate_shader(nir, "in d3d12_lower_edge_flags");
328bf215546Sopenharmony_ci
329bf215546Sopenharmony_ci   NIR_PASS_V(nir, nir_lower_var_copies);
330bf215546Sopenharmony_ci
331bf215546Sopenharmony_ci   templ.type = PIPE_SHADER_IR_NIR;
332bf215546Sopenharmony_ci   templ.ir.nir = nir;
333bf215546Sopenharmony_ci   templ.stream_output.num_outputs = 0;
334bf215546Sopenharmony_ci
335bf215546Sopenharmony_ci   return d3d12_create_shader(emit_ctx->ctx, PIPE_SHADER_GEOMETRY, &templ);
336bf215546Sopenharmony_ci}
337bf215546Sopenharmony_ci
338bf215546Sopenharmony_cistatic d3d12_shader_selector*
339bf215546Sopenharmony_cid3d12_emit_points(struct d3d12_context *ctx, struct d3d12_gs_variant_key *key)
340bf215546Sopenharmony_ci{
341bf215546Sopenharmony_ci   struct emit_primitives_context emit_ctx = {0};
342bf215546Sopenharmony_ci   nir_builder *b = &emit_ctx.b;
343bf215546Sopenharmony_ci
344bf215546Sopenharmony_ci   d3d12_begin_emit_primitives_gs(&emit_ctx, ctx, key, GL_POINTS, 3);
345bf215546Sopenharmony_ci
346bf215546Sopenharmony_ci   /**
347bf215546Sopenharmony_ci    *  if (edge_flag)
348bf215546Sopenharmony_ci    *     out_position = in_position;
349bf215546Sopenharmony_ci    *  else
350bf215546Sopenharmony_ci    *     out_position = vec4(-2.0, -2.0, 0.0, 1.0); // Invalid position
351bf215546Sopenharmony_ci    *
352bf215546Sopenharmony_ci    *  [...] // Copy other variables
353bf215546Sopenharmony_ci    *
354bf215546Sopenharmony_ci    *  EmitVertex();
355bf215546Sopenharmony_ci    */
356bf215546Sopenharmony_ci   for (unsigned i = 0; i < emit_ctx.num_vars; ++i) {
357bf215546Sopenharmony_ci      nir_ssa_def *index = (key->flat_varyings & (1ull << emit_ctx.in[i]->data.location))  ?
358bf215546Sopenharmony_ci                              nir_imm_int(b, (key->flatshade_first ? 0 : 2)) : emit_ctx.loop_index;
359bf215546Sopenharmony_ci      nir_deref_instr *in_value = nir_build_deref_array(b, nir_build_deref_var(b, emit_ctx.in[i]), index);
360bf215546Sopenharmony_ci      if (emit_ctx.in[i]->data.location == VARYING_SLOT_POS && emit_ctx.edgeflag_cmp) {
361bf215546Sopenharmony_ci         nir_if *edge_check = nir_push_if(b, emit_ctx.edgeflag_cmp);
362bf215546Sopenharmony_ci         copy_vars(b, nir_build_deref_var(b, emit_ctx.out[i]), in_value);
363bf215546Sopenharmony_ci         nir_if *edge_else = nir_push_else(b, edge_check);
364bf215546Sopenharmony_ci         nir_store_deref(b, nir_build_deref_var(b, emit_ctx.out[i]),
365bf215546Sopenharmony_ci                         nir_imm_vec4(b, -2.0, -2.0, 0.0, 1.0), 0xf);
366bf215546Sopenharmony_ci         nir_pop_if(b, edge_else);
367bf215546Sopenharmony_ci      } else {
368bf215546Sopenharmony_ci         copy_vars(b, nir_build_deref_var(b, emit_ctx.out[i]), in_value);
369bf215546Sopenharmony_ci      }
370bf215546Sopenharmony_ci   }
371bf215546Sopenharmony_ci   if (key->has_front_face)
372bf215546Sopenharmony_ci       nir_store_var(b, emit_ctx.front_facing_var, emit_ctx.front_facing, 0x1);
373bf215546Sopenharmony_ci   nir_emit_vertex(b, 0);
374bf215546Sopenharmony_ci
375bf215546Sopenharmony_ci   return d3d12_finish_emit_primitives_gs(&emit_ctx, false);
376bf215546Sopenharmony_ci}
377bf215546Sopenharmony_ci
378bf215546Sopenharmony_cistatic d3d12_shader_selector*
379bf215546Sopenharmony_cid3d12_emit_lines(struct d3d12_context *ctx, struct d3d12_gs_variant_key *key)
380bf215546Sopenharmony_ci{
381bf215546Sopenharmony_ci   struct emit_primitives_context emit_ctx = {0};
382bf215546Sopenharmony_ci   nir_builder *b = &emit_ctx.b;
383bf215546Sopenharmony_ci
384bf215546Sopenharmony_ci   d3d12_begin_emit_primitives_gs(&emit_ctx, ctx, key, GL_LINE_STRIP, 6);
385bf215546Sopenharmony_ci
386bf215546Sopenharmony_ci   nir_ssa_def *next_index = nir_imod(b, nir_iadd_imm(b, emit_ctx.loop_index, 1), nir_imm_int(b, 3));
387bf215546Sopenharmony_ci
388bf215546Sopenharmony_ci   /* First vertex */
389bf215546Sopenharmony_ci   for (unsigned i = 0; i < emit_ctx.num_vars; ++i) {
390bf215546Sopenharmony_ci      nir_ssa_def *index = (key->flat_varyings & (1ull << emit_ctx.in[i]->data.location)) ?
391bf215546Sopenharmony_ci                              nir_imm_int(b, (key->flatshade_first ? 0 : 2)) : emit_ctx.loop_index;
392bf215546Sopenharmony_ci      nir_deref_instr *in_value = nir_build_deref_array(b, nir_build_deref_var(b, emit_ctx.in[i]), index);
393bf215546Sopenharmony_ci      copy_vars(b, nir_build_deref_var(b, emit_ctx.out[i]), in_value);
394bf215546Sopenharmony_ci   }
395bf215546Sopenharmony_ci   if (key->has_front_face)
396bf215546Sopenharmony_ci       nir_store_var(b, emit_ctx.front_facing_var, emit_ctx.front_facing, 0x1);
397bf215546Sopenharmony_ci   nir_emit_vertex(b, 0);
398bf215546Sopenharmony_ci
399bf215546Sopenharmony_ci   /* Second vertex. If not an edge, use same position as first vertex */
400bf215546Sopenharmony_ci   for (unsigned i = 0; i < emit_ctx.num_vars; ++i) {
401bf215546Sopenharmony_ci      nir_ssa_def *index = next_index;
402bf215546Sopenharmony_ci      if (emit_ctx.in[i]->data.location == VARYING_SLOT_POS)
403bf215546Sopenharmony_ci         index = nir_bcsel(b, emit_ctx.edgeflag_cmp, next_index, emit_ctx.loop_index);
404bf215546Sopenharmony_ci      else if (key->flat_varyings & (1ull << emit_ctx.in[i]->data.location))
405bf215546Sopenharmony_ci         index = nir_imm_int(b, 2);
406bf215546Sopenharmony_ci      copy_vars(b, nir_build_deref_var(b, emit_ctx.out[i]),
407bf215546Sopenharmony_ci                nir_build_deref_array(b, nir_build_deref_var(b, emit_ctx.in[i]), index));
408bf215546Sopenharmony_ci   }
409bf215546Sopenharmony_ci   if (key->has_front_face)
410bf215546Sopenharmony_ci       nir_store_var(b, emit_ctx.front_facing_var, emit_ctx.front_facing, 0x1);
411bf215546Sopenharmony_ci   nir_emit_vertex(b, 0);
412bf215546Sopenharmony_ci
413bf215546Sopenharmony_ci   nir_end_primitive(b, 0);
414bf215546Sopenharmony_ci
415bf215546Sopenharmony_ci   return d3d12_finish_emit_primitives_gs(&emit_ctx, false);
416bf215546Sopenharmony_ci}
417bf215546Sopenharmony_ci
418bf215546Sopenharmony_cistatic d3d12_shader_selector*
419bf215546Sopenharmony_cid3d12_emit_triangles(struct d3d12_context *ctx, struct d3d12_gs_variant_key *key)
420bf215546Sopenharmony_ci{
421bf215546Sopenharmony_ci   struct emit_primitives_context emit_ctx = {0};
422bf215546Sopenharmony_ci   nir_builder *b = &emit_ctx.b;
423bf215546Sopenharmony_ci
424bf215546Sopenharmony_ci   d3d12_begin_emit_primitives_gs(&emit_ctx, ctx, key, GL_TRIANGLE_STRIP, 3);
425bf215546Sopenharmony_ci
426bf215546Sopenharmony_ci   /**
427bf215546Sopenharmony_ci    *  [...] // Copy variables
428bf215546Sopenharmony_ci    *
429bf215546Sopenharmony_ci    *  EmitVertex();
430bf215546Sopenharmony_ci    */
431bf215546Sopenharmony_ci
432bf215546Sopenharmony_ci   nir_ssa_def *incr = NULL;
433bf215546Sopenharmony_ci
434bf215546Sopenharmony_ci   if (key->provoking_vertex > 0)
435bf215546Sopenharmony_ci      incr = nir_imm_int(b, key->provoking_vertex);
436bf215546Sopenharmony_ci   else
437bf215546Sopenharmony_ci      incr = nir_imm_int(b, 3);
438bf215546Sopenharmony_ci
439bf215546Sopenharmony_ci   if (key->alternate_tri) {
440bf215546Sopenharmony_ci      nir_ssa_def *odd = nir_imod(b, nir_load_primitive_id(b), nir_imm_int(b, 2));
441bf215546Sopenharmony_ci      incr = nir_isub(b, incr, odd);
442bf215546Sopenharmony_ci   }
443bf215546Sopenharmony_ci
444bf215546Sopenharmony_ci   assert(incr != NULL);
445bf215546Sopenharmony_ci   nir_ssa_def *index = nir_imod(b, nir_iadd(b, emit_ctx.loop_index, incr), nir_imm_int(b, 3));
446bf215546Sopenharmony_ci   for (unsigned i = 0; i < emit_ctx.num_vars; ++i) {
447bf215546Sopenharmony_ci      nir_deref_instr *in_value = nir_build_deref_array(b, nir_build_deref_var(b, emit_ctx.in[i]), index);
448bf215546Sopenharmony_ci      copy_vars(b, nir_build_deref_var(b, emit_ctx.out[i]), in_value);
449bf215546Sopenharmony_ci   }
450bf215546Sopenharmony_ci   nir_emit_vertex(b, 0);
451bf215546Sopenharmony_ci
452bf215546Sopenharmony_ci   return d3d12_finish_emit_primitives_gs(&emit_ctx, true);
453bf215546Sopenharmony_ci}
454bf215546Sopenharmony_ci
455bf215546Sopenharmony_cistatic uint32_t
456bf215546Sopenharmony_cihash_gs_variant_key(const void *key)
457bf215546Sopenharmony_ci{
458bf215546Sopenharmony_ci   return _mesa_hash_data(key, sizeof(struct d3d12_gs_variant_key));
459bf215546Sopenharmony_ci}
460bf215546Sopenharmony_ci
461bf215546Sopenharmony_cistatic bool
462bf215546Sopenharmony_ciequals_gs_variant_key(const void *a, const void *b)
463bf215546Sopenharmony_ci{
464bf215546Sopenharmony_ci   return memcmp(a, b, sizeof(struct d3d12_gs_variant_key)) == 0;
465bf215546Sopenharmony_ci}
466bf215546Sopenharmony_ci
467bf215546Sopenharmony_civoid
468bf215546Sopenharmony_cid3d12_gs_variant_cache_init(struct d3d12_context *ctx)
469bf215546Sopenharmony_ci{
470bf215546Sopenharmony_ci   ctx->gs_variant_cache = _mesa_hash_table_create(NULL, NULL, equals_gs_variant_key);
471bf215546Sopenharmony_ci}
472bf215546Sopenharmony_ci
473bf215546Sopenharmony_cistatic void
474bf215546Sopenharmony_cidelete_entry(struct hash_entry *entry)
475bf215546Sopenharmony_ci{
476bf215546Sopenharmony_ci   d3d12_shader_free((d3d12_shader_selector *)entry->data);
477bf215546Sopenharmony_ci}
478bf215546Sopenharmony_ci
479bf215546Sopenharmony_civoid
480bf215546Sopenharmony_cid3d12_gs_variant_cache_destroy(struct d3d12_context *ctx)
481bf215546Sopenharmony_ci{
482bf215546Sopenharmony_ci   _mesa_hash_table_destroy(ctx->gs_variant_cache, delete_entry);
483bf215546Sopenharmony_ci}
484bf215546Sopenharmony_ci
485bf215546Sopenharmony_cistatic struct d3d12_shader_selector *
486bf215546Sopenharmony_cicreate_geometry_shader_variant(struct d3d12_context *ctx, struct d3d12_gs_variant_key *key)
487bf215546Sopenharmony_ci{
488bf215546Sopenharmony_ci   d3d12_shader_selector *gs = NULL;
489bf215546Sopenharmony_ci
490bf215546Sopenharmony_ci   if (key->passthrough)
491bf215546Sopenharmony_ci      gs = d3d12_make_passthrough_gs(ctx, key);
492bf215546Sopenharmony_ci   else if (key->provoking_vertex > 0 || key->alternate_tri)
493bf215546Sopenharmony_ci      gs = d3d12_emit_triangles(ctx, key);
494bf215546Sopenharmony_ci   else if (key->fill_mode == PIPE_POLYGON_MODE_POINT)
495bf215546Sopenharmony_ci      gs = d3d12_emit_points(ctx, key);
496bf215546Sopenharmony_ci   else if (key->fill_mode == PIPE_POLYGON_MODE_LINE)
497bf215546Sopenharmony_ci      gs = d3d12_emit_lines(ctx, key);
498bf215546Sopenharmony_ci
499bf215546Sopenharmony_ci   if (gs) {
500bf215546Sopenharmony_ci      gs->is_variant = true;
501bf215546Sopenharmony_ci      gs->gs_key = *key;
502bf215546Sopenharmony_ci   }
503bf215546Sopenharmony_ci
504bf215546Sopenharmony_ci   return gs;
505bf215546Sopenharmony_ci}
506bf215546Sopenharmony_ci
507bf215546Sopenharmony_cid3d12_shader_selector *
508bf215546Sopenharmony_cid3d12_get_gs_variant(struct d3d12_context *ctx, struct d3d12_gs_variant_key *key)
509bf215546Sopenharmony_ci{
510bf215546Sopenharmony_ci   uint32_t hash = hash_gs_variant_key(key);
511bf215546Sopenharmony_ci   struct hash_entry *entry = _mesa_hash_table_search_pre_hashed(ctx->gs_variant_cache,
512bf215546Sopenharmony_ci                                                                 hash, key);
513bf215546Sopenharmony_ci   if (!entry) {
514bf215546Sopenharmony_ci      d3d12_shader_selector *gs = create_geometry_shader_variant(ctx, key);
515bf215546Sopenharmony_ci      entry = _mesa_hash_table_insert_pre_hashed(ctx->gs_variant_cache,
516bf215546Sopenharmony_ci                                                 hash, &gs->gs_key, gs);
517bf215546Sopenharmony_ci      assert(entry);
518bf215546Sopenharmony_ci   }
519bf215546Sopenharmony_ci
520bf215546Sopenharmony_ci   return (d3d12_shader_selector *)entry->data;
521bf215546Sopenharmony_ci}
522