• 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  * on the rights to use, copy, modify, merge, publish, distribute, sub
8  * license, and/or sell copies of the Software, and to permit persons to whom
9  * the 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 NON-INFRINGEMENT. IN NO EVENT SHALL
18  * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21  * USE OR OTHER DEALINGS IN THE SOFTWARE.
22  */
23 
24 #include "d3d12_nir_passes.h"
25 #include "d3d12_compiler.h"
26 #include "nir_builder.h"
27 #include "nir_builtin_builder.h"
28 #include "nir_format_convert.h"
29 #include "program/prog_instruction.h"
30 #include "dxil_nir.h"
31 
32 /**
33  * Lower Y Flip:
34  *
35  * We can't do a Y flip simply by negating the viewport height,
36  * so we need to lower the flip into the NIR shader.
37  */
38 
39 static nir_ssa_def *
get_state_var(nir_builder * b,enum d3d12_state_var var_enum,const char * var_name,const struct glsl_type * var_type,nir_variable ** out_var)40 get_state_var(nir_builder *b,
41               enum d3d12_state_var var_enum,
42               const char *var_name,
43               const struct glsl_type *var_type,
44               nir_variable **out_var)
45 {
46    const gl_state_index16 tokens[STATE_LENGTH] = { STATE_INTERNAL_DRIVER, var_enum };
47    if (*out_var == NULL) {
48       nir_variable *var = nir_variable_create(b->shader,
49                                               nir_var_uniform,
50                                               var_type,
51                                               var_name);
52 
53       var->num_state_slots = 1;
54       var->state_slots = ralloc_array(var, nir_state_slot, 1);
55       memcpy(var->state_slots[0].tokens, tokens,
56              sizeof(var->state_slots[0].tokens));
57       var->data.how_declared = nir_var_hidden;
58       b->shader->num_uniforms++;
59       *out_var = var;
60    }
61    return nir_load_var(b, *out_var);
62 }
63 
64 static void
lower_pos_write(nir_builder * b,struct nir_instr * instr,nir_variable ** flip)65 lower_pos_write(nir_builder *b, struct nir_instr *instr, nir_variable **flip)
66 {
67    if (instr->type != nir_instr_type_intrinsic)
68       return;
69 
70    nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
71    if (intr->intrinsic != nir_intrinsic_store_deref)
72       return;
73 
74    nir_variable *var = nir_intrinsic_get_var(intr, 0);
75    if (var->data.mode != nir_var_shader_out ||
76        var->data.location != VARYING_SLOT_POS)
77       return;
78 
79    b->cursor = nir_before_instr(&intr->instr);
80 
81    nir_ssa_def *pos = nir_ssa_for_src(b, intr->src[1], 4);
82    nir_ssa_def *flip_y = get_state_var(b, D3D12_STATE_VAR_Y_FLIP, "d3d12_FlipY",
83                                        glsl_float_type(), flip);
84    nir_ssa_def *def = nir_vec4(b,
85                                nir_channel(b, pos, 0),
86                                nir_fmul(b, nir_channel(b, pos, 1), flip_y),
87                                nir_channel(b, pos, 2),
88                                nir_channel(b, pos, 3));
89    nir_instr_rewrite_src(&intr->instr, intr->src + 1, nir_src_for_ssa(def));
90 }
91 
92 void
d3d12_lower_yflip(nir_shader * nir)93 d3d12_lower_yflip(nir_shader *nir)
94 {
95    nir_variable *flip = NULL;
96 
97    if (nir->info.stage != MESA_SHADER_VERTEX &&
98        nir->info.stage != MESA_SHADER_GEOMETRY)
99       return;
100 
101    nir_foreach_function(function, nir) {
102       if (function->impl) {
103          nir_builder b;
104          nir_builder_init(&b, function->impl);
105 
106          nir_foreach_block(block, function->impl) {
107             nir_foreach_instr_safe(instr, block) {
108                lower_pos_write(&b, instr, &flip);
109             }
110          }
111 
112          nir_metadata_preserve(function->impl, nir_metadata_block_index |
113                                                nir_metadata_dominance);
114       }
115    }
116 }
117 
118 static void
lower_load_face(nir_builder * b,struct nir_instr * instr,nir_variable * var)119 lower_load_face(nir_builder *b, struct nir_instr *instr, nir_variable *var)
120 {
121    if (instr->type != nir_instr_type_intrinsic)
122       return;
123 
124    nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
125    if (intr->intrinsic != nir_intrinsic_load_front_face)
126       return;
127 
128    b->cursor = nir_before_instr(&intr->instr);
129 
130    nir_ssa_def *load = nir_load_var(b, var);
131 
132    nir_ssa_def_rewrite_uses(&intr->dest.ssa, load);
133    nir_instr_remove(instr);
134 }
135 
136 void
d3d12_forward_front_face(nir_shader * nir)137 d3d12_forward_front_face(nir_shader *nir)
138 {
139    assert(nir->info.stage == MESA_SHADER_FRAGMENT);
140 
141    nir_variable *var = nir_variable_create(nir, nir_var_shader_in,
142                                            glsl_bool_type(),
143                                            "gl_FrontFacing");
144    var->data.location = VARYING_SLOT_VAR12;
145    var->data.interpolation = INTERP_MODE_FLAT;
146 
147 
148    nir_foreach_function(function, nir) {
149       if (function->impl) {
150          nir_builder b;
151          nir_builder_init(&b, function->impl);
152 
153          nir_foreach_block(block, function->impl) {
154             nir_foreach_instr_safe(instr, block) {
155                lower_load_face(&b, instr, var);
156             }
157          }
158 
159          nir_metadata_preserve(function->impl, nir_metadata_block_index |
160                                                nir_metadata_dominance);
161       }
162    }
163 }
164 
165 static void
lower_pos_read(nir_builder * b,struct nir_instr * instr,nir_variable ** depth_transform_var)166 lower_pos_read(nir_builder *b, struct nir_instr *instr,
167                nir_variable **depth_transform_var)
168 {
169    if (instr->type != nir_instr_type_intrinsic)
170       return;
171 
172    nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
173    if (intr->intrinsic != nir_intrinsic_load_deref)
174       return;
175 
176    nir_variable *var = nir_intrinsic_get_var(intr, 0);
177    if (var->data.mode != nir_var_shader_in ||
178        var->data.location != VARYING_SLOT_POS)
179       return;
180 
181    b->cursor = nir_after_instr(instr);
182 
183    nir_ssa_def *pos = nir_instr_ssa_def(instr);
184    nir_ssa_def *depth = nir_channel(b, pos, 2);
185 
186    assert(depth_transform_var);
187    nir_ssa_def *depth_transform = get_state_var(b, D3D12_STATE_VAR_DEPTH_TRANSFORM,
188                                                 "d3d12_DepthTransform",
189                                                 glsl_vec_type(2),
190                                                 depth_transform_var);
191    depth = nir_fmad(b, depth, nir_channel(b, depth_transform, 0),
192                               nir_channel(b, depth_transform, 1));
193 
194    pos = nir_vector_insert_imm(b, pos, depth, 2);
195 
196    assert(intr->dest.is_ssa);
197    nir_ssa_def_rewrite_uses_after(&intr->dest.ssa, pos,
198                                   pos->parent_instr);
199 }
200 
201 void
d3d12_lower_depth_range(nir_shader * nir)202 d3d12_lower_depth_range(nir_shader *nir)
203 {
204    assert(nir->info.stage == MESA_SHADER_FRAGMENT);
205    nir_variable *depth_transform = NULL;
206    nir_foreach_function(function, nir) {
207       if (function->impl) {
208          nir_builder b;
209          nir_builder_init(&b, function->impl);
210 
211          nir_foreach_block(block, function->impl) {
212             nir_foreach_instr_safe(instr, block) {
213                lower_pos_read(&b, instr, &depth_transform);
214             }
215          }
216 
217          nir_metadata_preserve(function->impl, nir_metadata_block_index |
218                                                nir_metadata_dominance);
219       }
220    }
221 }
222 
223 static bool
is_color_output(nir_variable * var)224 is_color_output(nir_variable *var)
225 {
226    return (var->data.mode == nir_var_shader_out &&
227            (var->data.location == FRAG_RESULT_COLOR ||
228             var->data.location >= FRAG_RESULT_DATA0));
229 }
230 
231 static void
lower_uint_color_write(nir_builder * b,struct nir_instr * instr,bool is_signed)232 lower_uint_color_write(nir_builder *b, struct nir_instr *instr, bool is_signed)
233 {
234    const unsigned NUM_BITS = 8;
235    const unsigned bits[4] = { NUM_BITS, NUM_BITS, NUM_BITS, NUM_BITS };
236 
237    if (instr->type != nir_instr_type_intrinsic)
238       return;
239 
240    nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
241    if (intr->intrinsic != nir_intrinsic_store_deref)
242       return;
243 
244    nir_variable *var = nir_intrinsic_get_var(intr, 0);
245    if (!is_color_output(var))
246       return;
247 
248    b->cursor = nir_before_instr(&intr->instr);
249 
250    nir_ssa_def *col = nir_ssa_for_src(b, intr->src[1], intr->num_components);
251    nir_ssa_def *def = is_signed ? nir_format_float_to_snorm(b, col, bits) :
252                                   nir_format_float_to_unorm(b, col, bits);
253    if (is_signed)
254       def = nir_bcsel(b, nir_ilt(b, def, nir_imm_int(b, 0)),
255                       nir_iadd(b, def, nir_imm_int(b, 1 << NUM_BITS)),
256                       def);
257    nir_instr_rewrite_src(&intr->instr, intr->src + 1, nir_src_for_ssa(def));
258 }
259 
260 void
d3d12_lower_uint_cast(nir_shader * nir,bool is_signed)261 d3d12_lower_uint_cast(nir_shader *nir, bool is_signed)
262 {
263    if (nir->info.stage != MESA_SHADER_FRAGMENT)
264       return;
265 
266    nir_foreach_function(function, nir) {
267       if (function->impl) {
268          nir_builder b;
269          nir_builder_init(&b, function->impl);
270 
271          nir_foreach_block(block, function->impl) {
272             nir_foreach_instr_safe(instr, block) {
273                lower_uint_color_write(&b, instr, is_signed);
274             }
275          }
276 
277          nir_metadata_preserve(function->impl, nir_metadata_block_index |
278                                                nir_metadata_dominance);
279       }
280    }
281 }
282 
283 static bool
lower_load_first_vertex(nir_builder * b,nir_instr * instr,nir_variable ** first_vertex)284 lower_load_first_vertex(nir_builder *b, nir_instr *instr, nir_variable **first_vertex)
285 {
286    if (instr->type != nir_instr_type_intrinsic)
287       return false;
288 
289    nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
290 
291    if (intr->intrinsic != nir_intrinsic_load_first_vertex)
292       return false;
293 
294    b->cursor = nir_before_instr(&intr->instr);
295 
296    nir_ssa_def *load = get_state_var(b, D3D12_STATE_VAR_FIRST_VERTEX, "d3d12_FirstVertex",
297                                      glsl_uint_type(), first_vertex);
298    nir_ssa_def_rewrite_uses(&intr->dest.ssa, load);
299    nir_instr_remove(instr);
300 
301    return true;
302 }
303 
304 bool
d3d12_lower_load_first_vertex(struct nir_shader * nir)305 d3d12_lower_load_first_vertex(struct nir_shader *nir)
306 {
307    nir_variable *first_vertex = NULL;
308    bool progress = false;
309 
310    if (nir->info.stage != MESA_SHADER_VERTEX)
311       return false;
312 
313    nir_foreach_function(function, nir) {
314       if (function->impl) {
315          nir_builder b;
316          nir_builder_init(&b, function->impl);
317 
318          nir_foreach_block(block, function->impl) {
319             nir_foreach_instr_safe(instr, block) {
320                progress |= lower_load_first_vertex(&b, instr, &first_vertex);
321             }
322          }
323 
324          nir_metadata_preserve(function->impl, nir_metadata_block_index |
325                                                nir_metadata_dominance);
326       }
327    }
328    return progress;
329 }
330 
331 static void
invert_depth(nir_builder * b,struct nir_instr * instr)332 invert_depth(nir_builder *b, struct nir_instr *instr)
333 {
334    if (instr->type != nir_instr_type_intrinsic)
335       return;
336 
337    nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
338    if (intr->intrinsic != nir_intrinsic_store_deref)
339       return;
340 
341    nir_variable *var = nir_intrinsic_get_var(intr, 0);
342    if (var->data.mode != nir_var_shader_out ||
343        var->data.location != VARYING_SLOT_POS)
344       return;
345 
346    b->cursor = nir_before_instr(&intr->instr);
347 
348    nir_ssa_def *pos = nir_ssa_for_src(b, intr->src[1], 4);
349    nir_ssa_def *def = nir_vec4(b,
350                                nir_channel(b, pos, 0),
351                                nir_channel(b, pos, 1),
352                                nir_fneg(b, nir_channel(b, pos, 2)),
353                                nir_channel(b, pos, 3));
354    nir_instr_rewrite_src(&intr->instr, intr->src + 1, nir_src_for_ssa(def));
355 }
356 
357 /* In OpenGL the windows space depth value z_w is evaluated according to "s * z_d + b"
358  * with  "s + (far - near) / 2" (depth clip:minus_one_to_one) [OpenGL 3.3, 2.13.1].
359  * When we switch the far and near value to satisfy DirectX requirements we have
360  * to compensate by inverting "z_d' = -z_d" with this lowering pass.
361  */
362 void
d3d12_nir_invert_depth(nir_shader * shader)363 d3d12_nir_invert_depth(nir_shader *shader)
364 {
365    if (shader->info.stage != MESA_SHADER_VERTEX &&
366        shader->info.stage != MESA_SHADER_GEOMETRY)
367       return;
368 
369    nir_foreach_function(function, shader) {
370       if (function->impl) {
371          nir_builder b;
372          nir_builder_init(&b, function->impl);
373 
374          nir_foreach_block(block, function->impl) {
375             nir_foreach_instr_safe(instr, block) {
376                invert_depth(&b, instr);
377             }
378          }
379 
380          nir_metadata_preserve(function->impl, nir_metadata_block_index |
381                                                nir_metadata_dominance);
382       }
383    }
384 }
385 
386 
387 /**
388  * Lower State Vars:
389  *
390  * All uniforms related to internal D3D12 variables are
391  * condensed into a UBO that is appended at the end of the
392  * current ones.
393  */
394 
395 static unsigned
get_state_var_offset(struct d3d12_shader * shader,enum d3d12_state_var var)396 get_state_var_offset(struct d3d12_shader *shader, enum d3d12_state_var var)
397 {
398    for (unsigned i = 0; i < shader->num_state_vars; ++i) {
399       if (shader->state_vars[i].var == var)
400          return shader->state_vars[i].offset;
401    }
402 
403    unsigned offset = shader->state_vars_size;
404    shader->state_vars[shader->num_state_vars].offset = offset;
405    shader->state_vars[shader->num_state_vars].var = var;
406    shader->state_vars_size += 4; /* Use 4-words slots no matter the variable size */
407    shader->num_state_vars++;
408 
409    return offset;
410 }
411 
412 static bool
lower_instr(nir_intrinsic_instr * instr,nir_builder * b,struct d3d12_shader * shader,unsigned binding)413 lower_instr(nir_intrinsic_instr *instr, nir_builder *b,
414             struct d3d12_shader *shader, unsigned binding)
415 {
416    nir_variable *variable = NULL;
417    nir_deref_instr *deref = NULL;
418 
419    b->cursor = nir_before_instr(&instr->instr);
420 
421    if (instr->intrinsic == nir_intrinsic_load_uniform) {
422       nir_foreach_variable_with_modes(var, b->shader, nir_var_uniform) {
423          if (var->data.driver_location == nir_intrinsic_base(instr)) {
424             variable = var;
425             break;
426          }
427       }
428    } else if (instr->intrinsic == nir_intrinsic_load_deref) {
429       deref = nir_src_as_deref(instr->src[0]);
430       variable = nir_intrinsic_get_var(instr, 0);
431    }
432 
433    if (variable == NULL ||
434        variable->num_state_slots != 1 ||
435        variable->state_slots[0].tokens[0] != STATE_INTERNAL_DRIVER)
436       return false;
437 
438    enum d3d12_state_var var = variable->state_slots[0].tokens[1];
439    nir_ssa_def *ubo_idx = nir_imm_int(b, binding);
440    nir_ssa_def *ubo_offset =  nir_imm_int(b, get_state_var_offset(shader, var) * 4);
441    nir_ssa_def *load =
442       nir_load_ubo(b, instr->num_components, instr->dest.ssa.bit_size,
443                    ubo_idx, ubo_offset,
444                    .align_mul = instr->dest.ssa.bit_size / 8,
445                    .align_offset = 0,
446                    .range_base = 0,
447                    .range = ~0,
448                    );
449 
450    nir_ssa_def_rewrite_uses(&instr->dest.ssa, load);
451 
452    /* Remove the old load_* instruction and any parent derefs */
453    nir_instr_remove(&instr->instr);
454    for (nir_deref_instr *d = deref; d; d = nir_deref_instr_parent(d)) {
455       /* If anyone is using this deref, leave it alone */
456       assert(d->dest.is_ssa);
457       if (!list_is_empty(&d->dest.ssa.uses))
458          break;
459 
460       nir_instr_remove(&d->instr);
461    }
462 
463    return true;
464 }
465 
466 bool
d3d12_lower_state_vars(nir_shader * nir,struct d3d12_shader * shader)467 d3d12_lower_state_vars(nir_shader *nir, struct d3d12_shader *shader)
468 {
469    bool progress = false;
470 
471    /* The state var UBO is added after all the other UBOs if it already
472     * exists it will be replaced by using the same binding.
473     * In the event there are no other UBO's, use binding slot 1 to
474     * be consistent with other non-default UBO's */
475    unsigned binding = MAX2(nir->info.num_ubos, 1);
476 
477    nir_foreach_variable_with_modes_safe(var, nir, nir_var_uniform) {
478       if (var->num_state_slots == 1 &&
479           var->state_slots[0].tokens[0] == STATE_INTERNAL_DRIVER) {
480          if (var->data.mode == nir_var_mem_ubo) {
481             binding = var->data.binding;
482          }
483       }
484    }
485 
486    nir_foreach_function(function, nir) {
487       if (function->impl) {
488          nir_builder builder;
489          nir_builder_init(&builder, function->impl);
490          nir_foreach_block(block, function->impl) {
491             nir_foreach_instr_safe(instr, block) {
492                if (instr->type == nir_instr_type_intrinsic)
493                   progress |= lower_instr(nir_instr_as_intrinsic(instr),
494                                           &builder,
495                                           shader,
496                                           binding);
497             }
498          }
499 
500          nir_metadata_preserve(function->impl, nir_metadata_block_index |
501                                                nir_metadata_dominance);
502       }
503    }
504 
505    if (progress) {
506       assert(shader->num_state_vars > 0);
507 
508       shader->state_vars_used = true;
509 
510       /* Remove state variables */
511       nir_foreach_variable_with_modes_safe(var, nir, nir_var_uniform) {
512          if (var->num_state_slots == 1 &&
513              var->state_slots[0].tokens[0] == STATE_INTERNAL_DRIVER) {
514             exec_node_remove(&var->node);
515             nir->num_uniforms--;
516          }
517       }
518 
519       const gl_state_index16 tokens[STATE_LENGTH] = { STATE_INTERNAL_DRIVER };
520       const struct glsl_type *type = glsl_array_type(glsl_vec4_type(),
521                                                      shader->state_vars_size / 4, 0);
522       nir_variable *ubo = nir_variable_create(nir, nir_var_mem_ubo, type,
523                                                   "d3d12_state_vars");
524       if (binding >= nir->info.num_ubos)
525          nir->info.num_ubos = binding + 1;
526       ubo->data.binding = binding;
527       ubo->num_state_slots = 1;
528       ubo->state_slots = ralloc_array(ubo, nir_state_slot, 1);
529       memcpy(ubo->state_slots[0].tokens, tokens,
530               sizeof(ubo->state_slots[0].tokens));
531 
532       struct glsl_struct_field field = {
533           .type = type,
534           .name = "data",
535           .location = -1,
536       };
537       ubo->interface_type =
538               glsl_interface_type(&field, 1, GLSL_INTERFACE_PACKING_STD430,
539                                   false, "__d3d12_state_vars_interface");
540    }
541 
542    return progress;
543 }
544 
545 void
d3d12_add_missing_dual_src_target(struct nir_shader * s,unsigned missing_mask)546 d3d12_add_missing_dual_src_target(struct nir_shader *s,
547                                   unsigned missing_mask)
548 {
549    assert(missing_mask != 0);
550    nir_builder b;
551    nir_function_impl *impl = nir_shader_get_entrypoint(s);
552    nir_builder_init(&b, impl);
553    b.cursor = nir_before_cf_list(&impl->body);
554 
555    nir_ssa_def *zero = nir_imm_zero(&b, 4, 32);
556    for (unsigned i = 0; i < 2; ++i) {
557 
558       if (!(missing_mask & (1u << i)))
559          continue;
560 
561       const char *name = i == 0 ? "gl_FragData[0]" :
562                                   "gl_SecondaryFragDataEXT[0]";
563       nir_variable *out = nir_variable_create(s, nir_var_shader_out,
564                                               glsl_vec4_type(), name);
565       out->data.location = FRAG_RESULT_DATA0;
566       out->data.driver_location = i;
567       out->data.index = i;
568 
569       nir_store_var(&b, out, zero, 0xf);
570    }
571    nir_metadata_preserve(impl, nir_metadata_block_index |
572                                nir_metadata_dominance);
573 }
574 
575 static bool
fix_io_uint_type(struct nir_shader * s,nir_variable_mode modes,int slot)576 fix_io_uint_type(struct nir_shader *s, nir_variable_mode modes, int slot)
577 {
578    nir_variable *fixed_var = NULL;
579    nir_foreach_variable_with_modes(var, s, modes) {
580       if (var->data.location == slot) {
581          var->type = glsl_uint_type();
582          fixed_var = var;
583          break;
584       }
585    }
586 
587    assert(fixed_var);
588 
589    nir_foreach_function(function, s) {
590       if (function->impl) {
591          nir_foreach_block(block, function->impl) {
592             nir_foreach_instr_safe(instr, block) {
593                if (instr->type == nir_instr_type_deref) {
594                   nir_deref_instr *deref = nir_instr_as_deref(instr);
595                   if (deref->var == fixed_var)
596                      deref->type = fixed_var->type;
597                }
598             }
599          }
600       }
601    }
602    return true;
603 }
604 
605 bool
d3d12_fix_io_uint_type(struct nir_shader * s,uint64_t in_mask,uint64_t out_mask)606 d3d12_fix_io_uint_type(struct nir_shader *s, uint64_t in_mask, uint64_t out_mask)
607 {
608    if (!(s->info.outputs_written & out_mask) &&
609        !(s->info.inputs_read & in_mask))
610       return false;
611 
612    bool progress = false;
613 
614    while (in_mask) {
615       int slot = u_bit_scan64(&in_mask);
616       progress |= (s->info.inputs_read & (1ull << slot)) &&
617                   fix_io_uint_type(s, nir_var_shader_in, slot);
618    }
619 
620    while (out_mask) {
621       int slot = u_bit_scan64(&out_mask);
622       progress |= (s->info.outputs_written & (1ull << slot)) &&
623                   fix_io_uint_type(s, nir_var_shader_out, slot);
624    }
625 
626    return progress;
627 }
628 
629 static bool
lower_load_ubo_packed_filter(const nir_instr * instr,UNUSED const void * _options)630 lower_load_ubo_packed_filter(const nir_instr *instr,
631                              UNUSED const void *_options) {
632    if (instr->type != nir_instr_type_intrinsic)
633       return false;
634 
635    nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
636 
637    return intr->intrinsic == nir_intrinsic_load_ubo;
638 }
639 
640 static nir_ssa_def *
lower_load_ubo_packed_impl(nir_builder * b,nir_instr * instr,UNUSED void * _options)641 lower_load_ubo_packed_impl(nir_builder *b, nir_instr *instr,
642                               UNUSED void *_options) {
643    nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
644 
645    nir_ssa_def *buffer = intr->src[0].ssa;
646    nir_ssa_def *offset = intr->src[1].ssa;
647 
648    nir_ssa_def *result =
649       build_load_ubo_dxil(b, buffer,
650                           offset,
651                           nir_dest_num_components(intr->dest),
652                           nir_dest_bit_size(intr->dest));
653    return result;
654 }
655 
656 bool
nir_lower_packed_ubo_loads(nir_shader * nir)657 nir_lower_packed_ubo_loads(nir_shader *nir) {
658    return nir_shader_lower_instructions(nir,
659                                         lower_load_ubo_packed_filter,
660                                         lower_load_ubo_packed_impl,
661                                         NULL);
662 }
663 
664 void
d3d12_lower_primitive_id(nir_shader * shader)665 d3d12_lower_primitive_id(nir_shader *shader)
666 {
667    nir_builder b;
668    nir_function_impl *impl = nir_shader_get_entrypoint(shader);
669    nir_ssa_def *primitive_id;
670    nir_builder_init(&b, impl);
671 
672    nir_variable *primitive_id_var = nir_variable_create(shader, nir_var_shader_out,
673                                                         glsl_uint_type(), "primitive_id");
674    primitive_id_var->data.location = VARYING_SLOT_PRIMITIVE_ID;
675    primitive_id_var->data.interpolation = INTERP_MODE_FLAT;
676 
677    nir_foreach_block(block, impl) {
678       b.cursor = nir_before_block(block);
679       primitive_id = nir_load_primitive_id(&b);
680 
681       nir_foreach_instr_safe(instr, block) {
682          if (instr->type != nir_instr_type_intrinsic ||
683              nir_instr_as_intrinsic(instr)->intrinsic != nir_intrinsic_emit_vertex)
684             continue;
685 
686          b.cursor = nir_before_instr(instr);
687          nir_store_var(&b, primitive_id_var, primitive_id, 0x1);
688       }
689    }
690 
691    nir_metadata_preserve(impl, nir_metadata_none);
692 }
693 
694 static void
lower_triangle_strip_store(nir_builder * b,nir_intrinsic_instr * intr,nir_variable * vertex_count_var,nir_variable ** varyings)695 lower_triangle_strip_store(nir_builder *b, nir_intrinsic_instr *intr,
696                            nir_variable *vertex_count_var,
697                            nir_variable **varyings)
698 {
699    /**
700     * tmp_varying[slot][min(vertex_count, 2)] = src
701     */
702    nir_ssa_def *vertex_count = nir_load_var(b, vertex_count_var);
703    nir_ssa_def *index = nir_imin(b, vertex_count, nir_imm_int(b, 2));
704    nir_variable *var = nir_intrinsic_get_var(intr, 0);
705 
706    if (var->data.mode != nir_var_shader_out)
707       return;
708 
709    nir_deref_instr *deref = nir_build_deref_array(b, nir_build_deref_var(b, varyings[var->data.location]), index);
710    nir_ssa_def *value = nir_ssa_for_src(b, intr->src[1], intr->num_components);
711    nir_store_deref(b, deref, value, 0xf);
712    nir_instr_remove(&intr->instr);
713 }
714 
715 static void
lower_triangle_strip_emit_vertex(nir_builder * b,nir_intrinsic_instr * intr,nir_variable * vertex_count_var,nir_variable ** varyings,nir_variable ** out_varyings)716 lower_triangle_strip_emit_vertex(nir_builder *b, nir_intrinsic_instr *intr,
717                                  nir_variable *vertex_count_var,
718                                  nir_variable **varyings,
719                                  nir_variable **out_varyings)
720 {
721    // TODO xfb + flat shading + last_pv
722    /**
723     * if (vertex_count >= 2) {
724     *    for (i = 0; i < 3; i++) {
725     *       foreach(slot)
726     *          out[slot] = tmp_varying[slot][i];
727     *       EmitVertex();
728     *    }
729     *    EndPrimitive();
730     *    foreach(slot)
731     *       tmp_varying[slot][vertex_count % 2] = tmp_varying[slot][2];
732     * }
733     * vertex_count++;
734     */
735 
736    nir_ssa_def *two = nir_imm_int(b, 2);
737    nir_ssa_def *vertex_count = nir_load_var(b, vertex_count_var);
738    nir_ssa_def *count_cmp = nir_uge(b, vertex_count, two);
739    nir_if *count_check = nir_push_if(b, count_cmp);
740 
741    for (int j = 0; j < 3; ++j) {
742       for (int i = 0; i < VARYING_SLOT_MAX; ++i) {
743          if (!varyings[i])
744             continue;
745          nir_copy_deref(b, nir_build_deref_var(b, out_varyings[i]),
746                         nir_build_deref_array_imm(b, nir_build_deref_var(b, varyings[i]), j));
747       }
748       nir_emit_vertex(b, 0);
749    }
750 
751    for (int i = 0; i < VARYING_SLOT_MAX; ++i) {
752       if (!varyings[i])
753          continue;
754       nir_copy_deref(b, nir_build_deref_array(b, nir_build_deref_var(b, varyings[i]), nir_umod(b, vertex_count, two)),
755                         nir_build_deref_array(b, nir_build_deref_var(b, varyings[i]), two));
756    }
757 
758    nir_end_primitive(b, .stream_id = 0);
759 
760    nir_pop_if(b, count_check);
761 
762    vertex_count = nir_iadd(b, vertex_count, nir_imm_int(b, 1));
763    nir_store_var(b, vertex_count_var, vertex_count, 0x1);
764 
765    nir_instr_remove(&intr->instr);
766 }
767 
768 static void
lower_triangle_strip_end_primitive(nir_builder * b,nir_intrinsic_instr * intr,nir_variable * vertex_count_var)769 lower_triangle_strip_end_primitive(nir_builder *b, nir_intrinsic_instr *intr,
770                                    nir_variable *vertex_count_var)
771 {
772    /**
773     * vertex_count = 0;
774     */
775    nir_store_var(b, vertex_count_var, nir_imm_int(b, 0), 0x1);
776    nir_instr_remove(&intr->instr);
777 }
778 
779 void
d3d12_lower_triangle_strip(nir_shader * shader)780 d3d12_lower_triangle_strip(nir_shader *shader)
781 {
782    nir_builder b;
783    nir_function_impl *impl = nir_shader_get_entrypoint(shader);
784    nir_variable *tmp_vars[VARYING_SLOT_MAX] = {0};
785    nir_variable *out_vars[VARYING_SLOT_MAX] = {0};
786    nir_builder_init(&b, impl);
787 
788    shader->info.gs.vertices_out = (shader->info.gs.vertices_out - 2) * 3;
789 
790    nir_variable *vertex_count_var =
791       nir_local_variable_create(impl, glsl_uint_type(), "vertex_count");
792 
793    nir_block *first = nir_start_block(impl);
794    b.cursor = nir_before_block(first);
795    nir_foreach_variable_with_modes(var, shader, nir_var_shader_out) {
796       const struct glsl_type *type = glsl_array_type(var->type, 3, 0);
797       tmp_vars[var->data.location] =  nir_local_variable_create(impl, type, "tmp_var");
798       out_vars[var->data.location] = var;
799    }
800    nir_store_var(&b, vertex_count_var, nir_imm_int(&b, 0), 1);
801 
802    nir_foreach_block(block, impl) {
803       nir_foreach_instr_safe(instr, block) {
804          if (instr->type != nir_instr_type_intrinsic)
805             continue;
806 
807          nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
808          switch (intrin->intrinsic) {
809          case nir_intrinsic_store_deref:
810             b.cursor = nir_before_instr(instr);
811             lower_triangle_strip_store(&b, intrin, vertex_count_var, tmp_vars);
812             break;
813          case nir_intrinsic_emit_vertex_with_counter:
814          case nir_intrinsic_emit_vertex:
815             b.cursor = nir_before_instr(instr);
816             lower_triangle_strip_emit_vertex(&b, intrin, vertex_count_var,
817                                              tmp_vars, out_vars);
818             break;
819          case nir_intrinsic_end_primitive:
820          case nir_intrinsic_end_primitive_with_counter:
821             b.cursor = nir_before_instr(instr);
822             lower_triangle_strip_end_primitive(&b, intrin, vertex_count_var);
823             break;
824          default:
825             break;
826          }
827       }
828    }
829 
830    nir_metadata_preserve(impl, nir_metadata_none);
831    NIR_PASS_V(shader, nir_lower_var_copies);
832 }
833