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 "dxil_signature.h"
25#include "dxil_enums.h"
26#include "dxil_module.h"
27
28#include "glsl_types.h"
29#include "nir_to_dxil.h"
30#include "util/u_debug.h"
31
32#include <string.h>
33
34
35struct semantic_info {
36   enum dxil_semantic_kind kind;
37   char name[64];
38   int index;
39   enum dxil_prog_sig_comp_type comp_type;
40   uint8_t sig_comp_type;
41   int32_t start_row;
42   int32_t rows;
43   uint8_t start_col;
44   uint8_t cols;
45   uint8_t interpolation;
46   const char *sysvalue_name;
47};
48
49
50static bool
51is_depth_output(enum dxil_semantic_kind kind)
52{
53   return kind == DXIL_SEM_DEPTH || kind == DXIL_SEM_DEPTH_GE ||
54          kind == DXIL_SEM_DEPTH_LE || kind == DXIL_SEM_STENCIL_REF;
55}
56
57static uint8_t
58get_interpolation(nir_variable *var)
59{
60   if (unlikely(var->data.centroid)) {
61      switch (var->data.interpolation) {
62      case INTERP_MODE_NONE: return DXIL_INTERP_LINEAR_CENTROID;
63      case INTERP_MODE_FLAT: return DXIL_INTERP_CONSTANT;
64      case INTERP_MODE_NOPERSPECTIVE: return DXIL_INTERP_LINEAR_NOPERSPECTIVE_CENTROID;
65      case INTERP_MODE_SMOOTH: return DXIL_INTERP_LINEAR_CENTROID;
66
67      }
68   } else {
69      switch (var->data.interpolation) {
70      case INTERP_MODE_NONE: return DXIL_INTERP_LINEAR;
71      case INTERP_MODE_FLAT: return DXIL_INTERP_CONSTANT;
72      case INTERP_MODE_NOPERSPECTIVE: return DXIL_INTERP_LINEAR_NOPERSPECTIVE;
73      case INTERP_MODE_SMOOTH: return DXIL_INTERP_LINEAR;
74      }
75   }
76
77   return DXIL_INTERP_LINEAR;
78}
79
80static const char *
81in_sysvalue_name(nir_variable *var)
82{
83   switch (var->data.location) {
84   case VARYING_SLOT_POS:
85      return "POS";
86   case VARYING_SLOT_FACE:
87      return "FACE";
88   default:
89      return "NONE";
90   }
91}
92
93/*
94 * The signatures are written into the stream in two pieces:
95 * DxilProgramSignatureElement is a fixes size structure that gets dumped
96 * to the stream in order of the registers and each contains an offset
97 * to the semantic name string. Then these strings are dumped into the stream.
98 */
99static unsigned
100get_additional_semantic_info(nir_shader *s, nir_variable *var, struct semantic_info *info,
101                             unsigned next_row, bool is_gs_shader)
102{
103   const struct glsl_type *type = var->type;
104
105   info->comp_type =
106      dxil_get_prog_sig_comp_type(var->type);
107
108   bool is_depth = is_depth_output(info->kind);
109   info->sig_comp_type = dxil_get_comp_type(var->type);
110
111   info->rows = 1;
112   if (info->kind == DXIL_SEM_TARGET) {
113      info->start_row = info->index;
114   } else if (is_depth ||
115              (info->kind == DXIL_SEM_PRIMITIVE_ID && is_gs_shader) ||
116              info->kind == DXIL_SEM_COVERAGE ||
117              info->kind == DXIL_SEM_SAMPLE_INDEX) {
118      // This turns into a 'N/A' mask in the disassembly
119      info->start_row = -1;
120   } else if (var->data.compact) {
121      if (var->data.location_frac) {
122         info->start_row = next_row - 1;
123      } else {
124         info->start_row = next_row;
125         next_row++;
126      }
127
128      assert(glsl_type_is_array(type) && info->kind == DXIL_SEM_CLIP_DISTANCE);
129      unsigned num_floats = glsl_get_aoa_size(type);
130      unsigned start_offset = (var->data.location - VARYING_SLOT_CLIP_DIST0) * 4 +
131         var->data.location_frac;
132
133      if (start_offset >= s->info.clip_distance_array_size) {
134         info->kind = DXIL_SEM_CULL_DISTANCE;
135         snprintf(info->name, 64, "SV_CullDistance");
136      }
137      info->cols = num_floats;
138   } else {
139      info->start_row = next_row;
140      if (glsl_type_is_array(type) && is_gs_shader)
141         type = glsl_without_array(type);
142
143      if (glsl_type_is_array(type)) {
144         info->rows = glsl_get_aoa_size(type);
145         type = glsl_get_array_element(type);
146         assert(info->rows);
147      }
148      next_row += info->rows;
149   }
150   info->start_col = (uint8_t)var->data.location_frac;
151   if (!info->cols) {
152      if (glsl_type_is_array(type))
153         type = glsl_get_array_element(type);
154      info->cols = (uint8_t)glsl_get_components(type);
155   }
156
157   return next_row;
158}
159
160typedef void (*semantic_info_proc)(nir_variable *var, struct semantic_info *info, bool vulkan);
161
162static void
163get_semantic_vs_in_name(nir_variable *var, struct semantic_info *info, bool vulkan)
164{
165   strcpy(info->name, "TEXCOORD");
166   if (vulkan) {
167      info->index = var->data.location >= VERT_ATTRIB_GENERIC0 ?
168         var->data.location - VERT_ATTRIB_GENERIC0 :
169         var->data.location;
170   } else {
171      info->index = var->data.driver_location;
172   }
173   info->kind = DXIL_SEM_ARBITRARY;
174}
175
176static void
177get_semantic_sv_name(nir_variable *var, struct semantic_info *info, bool _vulkan)
178{
179   switch (var->data.location) {
180   case SYSTEM_VALUE_VERTEX_ID_ZERO_BASE:
181      info->kind = DXIL_SEM_VERTEX_ID;
182      break;
183   case SYSTEM_VALUE_FRONT_FACE:
184      info->kind = DXIL_SEM_IS_FRONT_FACE;
185      break;
186   case SYSTEM_VALUE_INSTANCE_ID:
187      info->kind = DXIL_SEM_INSTANCE_ID;
188      break;
189   case SYSTEM_VALUE_PRIMITIVE_ID:
190      info->kind = DXIL_SEM_PRIMITIVE_ID;
191      break;
192   case SYSTEM_VALUE_SAMPLE_ID:
193      info->kind = DXIL_SEM_SAMPLE_INDEX;
194      info->interpolation = get_interpolation(var);
195      break;
196   default:
197      unreachable("unsupported system value");
198   }
199   strncpy(info->name, var->name, ARRAY_SIZE(info->name) - 1);
200}
201
202static void
203get_semantic_ps_outname(nir_variable *var, struct semantic_info *info)
204{
205   info->kind = DXIL_SEM_INVALID;
206   switch (var->data.location) {
207   case FRAG_RESULT_COLOR:
208      snprintf(info->name, 64, "%s", "SV_Target");
209      info->index = var->data.index;
210      info->kind = DXIL_SEM_TARGET;
211      break;
212   case FRAG_RESULT_DATA0:
213   case FRAG_RESULT_DATA1:
214   case FRAG_RESULT_DATA2:
215   case FRAG_RESULT_DATA3:
216   case FRAG_RESULT_DATA4:
217   case FRAG_RESULT_DATA5:
218   case FRAG_RESULT_DATA6:
219   case FRAG_RESULT_DATA7:
220      snprintf(info->name, 64, "%s", "SV_Target");
221      info->index = var->data.location - FRAG_RESULT_DATA0;
222      if (var->data.location == FRAG_RESULT_DATA0 &&
223          var->data.index > 0)
224         info->index = var->data.index;
225      info->kind = DXIL_SEM_TARGET;
226      break;
227   case FRAG_RESULT_DEPTH:
228      snprintf(info->name, 64, "%s", "SV_Depth");
229      info->kind = DXIL_SEM_DEPTH;
230      break;
231   case FRAG_RESULT_STENCIL:
232      snprintf(info->name, 64, "%s", "SV_StencilRef");
233      info->kind = DXIL_SEM_STENCIL_REF; //??
234      break;
235   case FRAG_RESULT_SAMPLE_MASK:
236      snprintf(info->name, 64, "%s", "SV_Coverage");
237      info->kind = DXIL_SEM_COVERAGE; //??
238      break;
239   default:
240      snprintf(info->name, 64, "%s", "UNDEFINED");
241      break;
242   }
243}
244
245static void
246get_semantic_name(nir_variable *var, struct semantic_info *info,
247                  const struct glsl_type *type, bool vulkan)
248{
249   info->kind = DXIL_SEM_INVALID;
250   info->interpolation = get_interpolation(var);
251   switch (var->data.location) {
252
253   case VARYING_SLOT_POS:
254      assert(glsl_get_components(type) == 4);
255      snprintf(info->name, 64, "%s", "SV_Position");
256      info->kind = DXIL_SEM_POSITION;
257      break;
258
259    case VARYING_SLOT_FACE:
260      assert(glsl_get_components(var->type) == 1);
261      snprintf(info->name, 64, "%s", "SV_IsFrontFace");
262      info->kind = DXIL_SEM_IS_FRONT_FACE;
263      break;
264
265   case VARYING_SLOT_PRIMITIVE_ID:
266     assert(glsl_get_components(var->type) == 1);
267     snprintf(info->name, 64, "%s", "SV_PrimitiveID");
268     info->kind = DXIL_SEM_PRIMITIVE_ID;
269     break;
270
271   case VARYING_SLOT_CLIP_DIST1:
272      info->index = 1;
273      FALLTHROUGH;
274   case VARYING_SLOT_CLIP_DIST0:
275      assert(var->data.location == VARYING_SLOT_CLIP_DIST1 || info->index == 0);
276      snprintf(info->name, 64, "%s", "SV_ClipDistance");
277      info->kind = DXIL_SEM_CLIP_DISTANCE;
278      break;
279
280   default: {
281         info->index = var->data.location -
282            (vulkan ? VARYING_SLOT_VAR0 : VARYING_SLOT_POS);
283         strcpy(info->name, "TEXCOORD");
284         info->kind = DXIL_SEM_ARBITRARY;
285      }
286   }
287}
288
289static void
290get_semantic_in_name(nir_variable *var, struct semantic_info *info, bool vulkan)
291{
292   get_semantic_name(var, info, var->type, vulkan);
293   info->sysvalue_name = in_sysvalue_name(var);
294}
295
296static void
297get_semantic_gs_in_name(nir_variable *var, struct semantic_info *info, bool vulkan)
298{
299   /* geometry shader input varyings come as arrays, but we want to use
300    * the element type */
301   const struct glsl_type *type =
302         glsl_type_is_array(var->type) ? glsl_without_array(var->type) : var->type;
303
304   get_semantic_name(var, info, type, vulkan);
305   info->sysvalue_name = in_sysvalue_name(var);
306}
307
308
309static enum dxil_prog_sig_semantic
310prog_semantic_from_kind(enum dxil_semantic_kind kind)
311{
312   switch (kind) {
313   case DXIL_SEM_ARBITRARY: return DXIL_PROG_SEM_UNDEFINED;
314   case DXIL_SEM_VERTEX_ID: return DXIL_PROG_SEM_VERTEX_ID;
315   case DXIL_SEM_INSTANCE_ID: return DXIL_PROG_SEM_INSTANCE_ID;
316   case DXIL_SEM_POSITION: return DXIL_PROG_SEM_POSITION;
317   case DXIL_SEM_COVERAGE: return DXIL_PROG_SEM_COVERAGE;
318   case DXIL_SEM_INNER_COVERAGE: return DXIL_PROG_SEM_INNER_COVERAGE;
319   case DXIL_SEM_PRIMITIVE_ID: return DXIL_PROG_SEM_PRIMITIVE_ID;
320   case DXIL_SEM_SAMPLE_INDEX: return DXIL_PROG_SEM_SAMPLE_INDEX;
321   case DXIL_SEM_IS_FRONT_FACE: return DXIL_PROG_SEM_IS_FRONTFACE;
322   case DXIL_SEM_RENDERTARGET_ARRAY_INDEX: return DXIL_PROG_SEM_RENDERTARGET_ARRAY_INDEX;
323   case DXIL_SEM_VIEWPORT_ARRAY_INDEX: return DXIL_PROG_SEM_VIEWPORT_ARRAY_INDEX;
324   case DXIL_SEM_CLIP_DISTANCE: return DXIL_PROG_SEM_CLIP_DISTANCE;
325   case DXIL_SEM_CULL_DISTANCE: return DXIL_PROG_SEM_CULL_DISTANCE;
326   case DXIL_SEM_BARYCENTRICS: return DXIL_PROG_SEM_BARYCENTRICS;
327   case DXIL_SEM_SHADING_RATE: return DXIL_PROG_SEM_SHADING_RATE;
328   case DXIL_SEM_CULL_PRIMITIVE: return DXIL_PROG_SEM_CULL_PRIMITIVE;
329   case DXIL_SEM_TARGET: return DXIL_PROG_SEM_TARGET;
330   case DXIL_SEM_DEPTH: return DXIL_PROG_SEM_DEPTH;
331   case DXIL_SEM_DEPTH_LE: return DXIL_PROG_SEM_DEPTH_LE;
332   case DXIL_SEM_DEPTH_GE: return DXIL_PROG_SEM_DEPTH_GE;
333   case DXIL_SEM_STENCIL_REF: return DXIL_PROG_SEM_STENCIL_REF;
334   default:
335       return DXIL_PROG_SEM_UNDEFINED;
336   }
337}
338
339static
340uint32_t
341copy_semantic_name_to_string(struct _mesa_string_buffer *string_out, const char *name)
342{
343   /*  copy the semantic name */
344   uint32_t retval = string_out->length;
345   size_t name_len = strlen(name) + 1;
346   _mesa_string_buffer_append_len(string_out, name, name_len);
347   return retval;
348}
349
350static
351uint32_t
352append_semantic_index_to_table(struct dxil_psv_sem_index_table *table, uint32_t index,
353                               uint32_t num_rows)
354{
355   if (num_rows == 1) {
356      for (unsigned i = 0; i < table->size; ++i) {
357         if (table->data[i] == index)
358            return i;
359      }
360   }
361   uint32_t retval = table->size;
362   assert(table->size + num_rows <= 80);
363   for (unsigned i = 0; i < num_rows; ++i)
364      table->data[table->size++] = index + i;
365   return retval;
366}
367
368static const struct dxil_mdnode *
369fill_SV_param_nodes(struct dxil_module *mod, unsigned record_id,
370                    struct semantic_info *semantic) {
371
372   const struct dxil_mdnode *SV_params_nodes[11];
373   /* For this to always work we should use vectorize_io, but for FS out and VS in
374    * this is not implemented globally */
375   const struct dxil_mdnode *flattened_semantics[256];
376
377   for (unsigned i = 0; i < semantic->rows; ++i)
378      flattened_semantics[i] = dxil_get_metadata_int32(mod, semantic->index + i);
379
380   SV_params_nodes[0] = dxil_get_metadata_int32(mod, (int)record_id); // Unique element ID
381   SV_params_nodes[1] = dxil_get_metadata_string(mod, semantic->name); // Element name
382   SV_params_nodes[2] = dxil_get_metadata_int8(mod, semantic->sig_comp_type); // Element type
383   SV_params_nodes[3] = dxil_get_metadata_int8(mod, (int8_t)semantic->kind); // Effective system value
384   SV_params_nodes[4] = dxil_get_metadata_node(mod, flattened_semantics,
385                                               semantic->rows); // Semantic index vector
386   SV_params_nodes[5] = dxil_get_metadata_int8(mod, semantic->interpolation); // Interpolation mode
387   SV_params_nodes[6] = dxil_get_metadata_int32(mod, semantic->rows); // Number of rows
388   SV_params_nodes[7] = dxil_get_metadata_int8(mod, semantic->cols); // Number of columns
389   SV_params_nodes[8] = dxil_get_metadata_int32(mod, semantic->start_row); // Element packing start row
390   SV_params_nodes[9] = dxil_get_metadata_int8(mod, semantic->start_col); // Element packing start column
391   SV_params_nodes[10] = 0; // optional Metadata
392
393   return dxil_get_metadata_node(mod, SV_params_nodes, ARRAY_SIZE(SV_params_nodes));
394}
395
396static void
397fill_signature_element(struct dxil_signature_element *elm,
398                       struct semantic_info *semantic,
399                       unsigned row)
400{
401   memset(elm, 0, sizeof(struct dxil_signature_element));
402   // elm->stream = 0;
403   // elm->semantic_name_offset = 0;  // Offset needs to be filled out when writing
404   elm->semantic_index = semantic->index + row;
405   elm->system_value = (uint32_t) prog_semantic_from_kind(semantic->kind);
406   elm->comp_type = (uint32_t) semantic->comp_type;
407   elm->reg = semantic->start_row + row;
408
409   assert(semantic->cols + semantic->start_col <= 4);
410   elm->mask = (uint8_t) (((1 << semantic->cols) - 1) << semantic->start_col);
411   // elm->never_writes_mask = 0;
412   elm->min_precision = DXIL_MIN_PREC_DEFAULT;
413}
414
415static bool
416fill_psv_signature_element(struct dxil_psv_signature_element *psv_elm,
417                           struct semantic_info *semantic, struct dxil_module *mod)
418{
419   memset(psv_elm, 0, sizeof(struct dxil_psv_signature_element));
420   psv_elm->rows = semantic->rows;
421   if (semantic->start_row >= 0) {
422      assert(semantic->start_row < 256);
423      psv_elm->start_row = semantic->start_row;
424      psv_elm->cols_and_start = (1u << 6) | (semantic->start_col << 4) | semantic->cols;
425   } else {
426      /* The validation expects that the the start row is not egative
427       * and apparently the extra bit in the cols_and_start indicates that the
428       * row is meant literally, so don't set it in this case.
429       * (Source of information: Comparing with the validation structures
430       * created by dxcompiler)
431       */
432      psv_elm->start_row = 0;
433      psv_elm->cols_and_start = (semantic->start_col << 4) | semantic->cols;
434   }
435   psv_elm->semantic_kind = (uint8_t)semantic->kind;
436   psv_elm->component_type = semantic->comp_type; //`??
437   psv_elm->interpolation_mode = semantic->interpolation;
438   /* to be filled later
439     psv_elm->dynamic_mask_and_stream = 0;
440   */
441   if (semantic->kind == DXIL_SEM_ARBITRARY && strlen(semantic->name)) {
442      psv_elm->semantic_name_offset =
443            copy_semantic_name_to_string(mod->sem_string_table, semantic->name);
444
445      /* TODO: clean up memory */
446      if (psv_elm->semantic_name_offset == (uint32_t)-1)
447         return false;
448   }
449
450   psv_elm->semantic_indexes_offset =
451         append_semantic_index_to_table(&mod->sem_index_table, semantic->index, semantic->rows);
452
453   return true;
454}
455
456static bool
457fill_io_signature(struct dxil_module *mod, int id,
458                  struct semantic_info *semantic,
459                  const struct dxil_mdnode **io,
460                  struct dxil_signature_element *elm,
461                  struct dxil_psv_signature_element *psv_elm)
462{
463
464   *io = fill_SV_param_nodes(mod, id, semantic);
465   for (unsigned i = 0; i < semantic->rows; ++i)
466      fill_signature_element(&elm[i], semantic, i);
467   return fill_psv_signature_element(psv_elm, semantic, mod);
468}
469
470static unsigned
471get_input_signature_group(struct dxil_module *mod, const struct dxil_mdnode **inputs,
472                          unsigned num_inputs,
473                          nir_shader *s, nir_variable_mode modes,
474                          semantic_info_proc get_semantics, unsigned *row_iter,
475                          bool is_gs_shader, bool vulkan)
476{
477   nir_foreach_variable_with_modes(var, s, modes) {
478      struct semantic_info semantic = {0};
479      get_semantics(var, &semantic, vulkan);
480      mod->inputs[num_inputs].sysvalue = semantic.sysvalue_name;
481      *row_iter = get_additional_semantic_info(s, var, &semantic, *row_iter, is_gs_shader);
482
483      mod->inputs[num_inputs].name = ralloc_strdup(mod->ralloc_ctx,
484                                                   semantic.name);
485      mod->inputs[num_inputs].num_elements = semantic.rows;
486      struct dxil_signature_element *elm = mod->inputs[num_inputs].elements;
487      struct dxil_psv_signature_element *psv_elm = &mod->psv_inputs[num_inputs];
488
489      if (!fill_io_signature(mod, num_inputs, &semantic,
490                             &inputs[num_inputs], elm, psv_elm))
491         return 0;
492
493      mod->num_psv_inputs = MAX2(mod->num_psv_inputs,
494                                 semantic.start_row + semantic.rows);
495
496      mod->info.has_per_sample_input |=
497         semantic.kind == DXIL_SEM_SAMPLE_INDEX ||
498         semantic.interpolation == DXIL_INTERP_LINEAR_SAMPLE ||
499         semantic.interpolation == DXIL_INTERP_LINEAR_NOPERSPECTIVE_SAMPLE;
500
501      ++num_inputs;
502      assert(num_inputs < VARYING_SLOT_MAX);
503   }
504   return num_inputs;
505}
506
507static const struct dxil_mdnode *
508get_input_signature(struct dxil_module *mod, nir_shader *s, bool vulkan)
509{
510   if (s->info.stage == MESA_SHADER_KERNEL)
511      return NULL;
512
513   const struct dxil_mdnode *inputs[VARYING_SLOT_MAX];
514   unsigned next_row = 0;
515   bool is_gs_shader = s->info.stage == MESA_SHADER_GEOMETRY;
516
517   mod->num_sig_inputs = get_input_signature_group(mod, inputs, 0,
518                                                   s, nir_var_shader_in,
519                                                   s->info.stage == MESA_SHADER_VERTEX ?
520                                                      get_semantic_vs_in_name :
521                                                      (s->info.stage == MESA_SHADER_GEOMETRY ?
522                                                         get_semantic_gs_in_name : get_semantic_in_name),
523                                                   &next_row, is_gs_shader,
524                                                   vulkan);
525
526   mod->num_sig_inputs = get_input_signature_group(mod, inputs, mod->num_sig_inputs,
527                                                   s, nir_var_system_value,
528                                                   get_semantic_sv_name,
529                                                   &next_row, is_gs_shader,
530                                                   vulkan);
531
532   if (!mod->num_sig_inputs && !mod->num_sig_inputs)
533      return NULL;
534
535   const struct dxil_mdnode *retval = mod->num_sig_inputs ?
536         dxil_get_metadata_node(mod, inputs, mod->num_sig_inputs) : NULL;
537
538   return retval;
539}
540
541static const char *out_sysvalue_name(nir_variable *var)
542{
543   switch (var->data.location) {
544   case VARYING_SLOT_FACE:
545      return "FACE";
546   case VARYING_SLOT_POS:
547      return "POS";
548   case VARYING_SLOT_CLIP_DIST0:
549   case VARYING_SLOT_CLIP_DIST1:
550      return "CLIPDST";
551   case VARYING_SLOT_PRIMITIVE_ID:
552      return "PRIMID";
553   default:
554      return "NO";
555   }
556}
557
558static const struct dxil_mdnode *
559get_output_signature(struct dxil_module *mod, nir_shader *s, bool vulkan)
560{
561   const struct dxil_mdnode *outputs[VARYING_SLOT_MAX];
562   unsigned num_outputs = 0;
563   unsigned next_row = 0;
564   nir_foreach_variable_with_modes(var, s, nir_var_shader_out) {
565      struct semantic_info semantic = {0};
566
567      if (s->info.stage == MESA_SHADER_FRAGMENT) {
568         get_semantic_ps_outname(var, &semantic);
569         mod->outputs[num_outputs].sysvalue = "TARGET";
570      } else {
571         get_semantic_name(var, &semantic, var->type, vulkan);
572         mod->outputs[num_outputs].sysvalue = out_sysvalue_name(var);
573      }
574      next_row = get_additional_semantic_info(s, var, &semantic, next_row, false);
575
576      mod->info.has_out_position |= semantic.kind== DXIL_SEM_POSITION;
577      mod->info.has_out_depth |= semantic.kind == DXIL_SEM_DEPTH;
578
579      mod->outputs[num_outputs].name = ralloc_strdup(mod->ralloc_ctx,
580                                                     semantic.name);
581      mod->outputs[num_outputs].num_elements = semantic.rows;
582      struct dxil_signature_element *elm = mod->outputs[num_outputs].elements;
583
584      struct dxil_psv_signature_element *psv_elm = &mod->psv_outputs[num_outputs];
585
586      if (!fill_io_signature(mod, num_outputs, &semantic,
587                             &outputs[num_outputs], elm, psv_elm))
588         return NULL;
589
590      /* This is fishy, logic suggests that the LHS should be 0xf, but from the
591       * validation it needs to be 0xff */
592      elm->never_writes_mask = 0xff & ~elm->mask;
593
594      ++num_outputs;
595
596      mod->num_psv_outputs = MAX2(mod->num_psv_outputs,
597                                  semantic.start_row + semantic.rows);
598
599      assert(num_outputs < ARRAY_SIZE(outputs));
600   }
601
602   if (!num_outputs)
603      return NULL;
604
605   const struct dxil_mdnode *retval = dxil_get_metadata_node(mod, outputs, num_outputs);
606   mod->num_sig_outputs = num_outputs;
607   return retval;
608}
609
610const struct dxil_mdnode *
611get_signatures(struct dxil_module *mod, nir_shader *s, bool vulkan)
612{
613   /* DXC does the same: Add an empty string before everything else */
614   mod->sem_string_table = _mesa_string_buffer_create(mod->ralloc_ctx, 1024);
615   copy_semantic_name_to_string(mod->sem_string_table, "");
616
617   const struct dxil_mdnode *input_signature = get_input_signature(mod, s, vulkan);
618   const struct dxil_mdnode *output_signature = get_output_signature(mod, s, vulkan);
619
620   const struct dxil_mdnode *SV_nodes[3] = {
621      input_signature,
622      output_signature,
623      NULL
624   };
625   if (output_signature || input_signature)
626      return dxil_get_metadata_node(mod, SV_nodes, ARRAY_SIZE(SV_nodes));
627   else
628      return NULL;
629}
630