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