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