Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/gallium/drivers/d3d12/d3d12_gs_variant.cpp
4570 views
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 *
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*
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
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 *
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*
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*
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*
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
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
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
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
443
delete_entry(struct hash_entry *entry)
444
{
445
d3d12_shader_free((d3d12_shader_selector *)entry->data);
446
}
447
448
void
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 *
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 *
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
492