Path: blob/21.2-virgl/src/microsoft/compiler/dxil_signature.c
4564 views
/*1* Copyright © Microsoft Corporation2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice (including the next11* paragraph) shall be included in all copies or substantial portions of the12* Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER18* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING19* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS20* IN THE SOFTWARE.21*/2223#include "dxil_enums.h"24#include "dxil_module.h"25#include "dxil_signature.h"2627#include "nir_to_dxil.h"28#include "glsl_types.h"29#include "util/u_debug.h"3031#include <string.h>323334struct semantic_info {35enum dxil_semantic_kind kind;36char name[64];37int index;38enum dxil_prog_sig_comp_type comp_type;39uint8_t sig_comp_type;40int32_t start_row;41int32_t rows;42uint8_t start_col;43uint8_t cols;44uint8_t interpolation;45const char *sysvalue_name;46};474849static bool50is_depth_output(enum dxil_semantic_kind kind)51{52return kind == DXIL_SEM_DEPTH ||53kind == DXIL_SEM_STENCIL_REF;54}5556static uint8_t57get_interpolation(nir_variable *var)58{59if (unlikely(var->data.centroid)) {60switch (var->data.interpolation) {61case INTERP_MODE_NONE: return DXIL_INTERP_LINEAR_CENTROID;62case INTERP_MODE_FLAT: return DXIL_INTERP_CONSTANT;63case INTERP_MODE_NOPERSPECTIVE: return DXIL_INTERP_LINEAR_NOPERSPECTIVE_CENTROID;64case INTERP_MODE_SMOOTH: return DXIL_INTERP_LINEAR_CENTROID;6566}67} else {68switch (var->data.interpolation) {69case INTERP_MODE_NONE: return DXIL_INTERP_LINEAR;70case INTERP_MODE_FLAT: return DXIL_INTERP_CONSTANT;71case INTERP_MODE_NOPERSPECTIVE: return DXIL_INTERP_LINEAR_NOPERSPECTIVE;72case INTERP_MODE_SMOOTH: return DXIL_INTERP_LINEAR;73}74}7576return DXIL_INTERP_LINEAR;77}7879static const char *80in_sysvalue_name(nir_variable *var)81{82switch (var->data.location) {83case VARYING_SLOT_POS:84return "POS";85case VARYING_SLOT_FACE:86return "FACE";87default:88return "NONE";89}90}9192/*93* The signatures are written into the stream in two pieces:94* DxilProgramSignatureElement is a fixes size structure that gets dumped95* to the stream in order of the registers and each contains an offset96* to the semantic name string. Then these strings are dumped into the stream.97*/98static unsigned99get_additional_semantic_info(nir_shader *s, nir_variable *var, struct semantic_info *info,100unsigned next_row, bool is_gs_shader)101{102const struct glsl_type *type = var->type;103104info->comp_type =105dxil_get_prog_sig_comp_type(var->type);106107bool is_depth = is_depth_output(info->kind);108info->sig_comp_type = dxil_get_comp_type(var->type);109110info->rows = 1;111if (info->kind == DXIL_SEM_TARGET) {112info->start_row = info->index;113} else if (is_depth || (info->kind == DXIL_SEM_PRIMITIVE_ID && is_gs_shader)) {114info->start_row = -1;115} else if (var->data.compact) {116if (var->data.location_frac) {117info->start_row = next_row - 1;118} else {119info->start_row = next_row;120next_row++;121}122123assert(glsl_type_is_array(type) && info->kind == DXIL_SEM_CLIP_DISTANCE);124unsigned num_floats = glsl_get_aoa_size(type);125unsigned start_offset = (var->data.location - VARYING_SLOT_CLIP_DIST0) * 4 +126var->data.location_frac;127128if (start_offset >= s->info.clip_distance_array_size) {129info->kind = DXIL_SEM_CULL_DISTANCE;130snprintf(info->name, 64, "SV_CullDistance");131}132info->cols = num_floats;133} else {134info->start_row = next_row;135if (glsl_type_is_array(type) && is_gs_shader)136type = glsl_without_array(type);137138if (glsl_type_is_array(type)) {139info->rows = glsl_get_aoa_size(type);140type = glsl_get_array_element(type);141assert(info->rows);142}143next_row += info->rows;144}145info->start_col = (uint8_t)var->data.location_frac;146if (!info->cols) {147if (glsl_type_is_array(type))148type = glsl_get_array_element(type);149info->cols = (uint8_t)glsl_get_components(type);150}151152return next_row;153}154155typedef void (*semantic_info_proc)(nir_variable *var, struct semantic_info *info, bool vulkan);156157static void158get_semantic_vs_in_name(nir_variable *var, struct semantic_info *info, bool vulkan)159{160strcpy(info->name, "TEXCOORD");161if (vulkan) {162info->index = var->data.location >= VERT_ATTRIB_GENERIC0 ?163var->data.location - VERT_ATTRIB_GENERIC0 :164var->data.location;165} else {166info->index = var->data.driver_location;167}168info->kind = DXIL_SEM_ARBITRARY;169}170171static void172get_semantic_sv_name(nir_variable *var, struct semantic_info *info, bool _vulkan)173{174switch (var->data.location) {175case SYSTEM_VALUE_VERTEX_ID_ZERO_BASE:176info->kind = DXIL_SEM_VERTEX_ID;177break;178case SYSTEM_VALUE_FRONT_FACE:179info->kind = DXIL_SEM_IS_FRONT_FACE;180break;181case SYSTEM_VALUE_INSTANCE_ID:182info->kind = DXIL_SEM_INSTANCE_ID;183break;184case SYSTEM_VALUE_PRIMITIVE_ID:185info->kind = DXIL_SEM_PRIMITIVE_ID;186break;187default:188unreachable("unsupported system value");189}190strncpy(info->name, var->name, ARRAY_SIZE(info->name) - 1);191}192193static void194get_semantic_ps_outname(nir_variable *var, struct semantic_info *info)195{196info->kind = DXIL_SEM_INVALID;197switch (var->data.location) {198case FRAG_RESULT_COLOR:199snprintf(info->name, 64, "%s", "SV_Target");200info->index = var->data.index;201info->kind = DXIL_SEM_TARGET;202break;203case FRAG_RESULT_DATA0:204case FRAG_RESULT_DATA1:205case FRAG_RESULT_DATA2:206case FRAG_RESULT_DATA3:207case FRAG_RESULT_DATA4:208case FRAG_RESULT_DATA5:209case FRAG_RESULT_DATA6:210case FRAG_RESULT_DATA7:211snprintf(info->name, 64, "%s", "SV_Target");212info->index = var->data.location - FRAG_RESULT_DATA0;213if (var->data.location == FRAG_RESULT_DATA0 &&214var->data.index > 0)215info->index = var->data.index;216info->kind = DXIL_SEM_TARGET;217break;218case FRAG_RESULT_DEPTH:219snprintf(info->name, 64, "%s", "SV_Depth");220info->kind = DXIL_SEM_DEPTH;221break;222case FRAG_RESULT_STENCIL:223snprintf(info->name, 64, "%s", "SV_StencilRef");224info->kind = DXIL_SEM_STENCIL_REF; //??225break;226case FRAG_RESULT_SAMPLE_MASK:227snprintf(info->name, 64, "%s", "SV_Coverage");228info->kind = DXIL_SEM_COVERAGE; //??229break;230default:231snprintf(info->name, 64, "%s", "UNDEFINED");232break;233}234}235236static void237get_semantic_name(nir_variable *var, struct semantic_info *info,238const struct glsl_type *type, bool vulkan)239{240info->kind = DXIL_SEM_INVALID;241info->interpolation = get_interpolation(var);242switch (var->data.location) {243244case VARYING_SLOT_POS:245assert(glsl_get_components(type) == 4);246snprintf(info->name, 64, "%s", "SV_Position");247info->kind = DXIL_SEM_POSITION;248break;249250case VARYING_SLOT_FACE:251assert(glsl_get_components(var->type) == 1);252snprintf(info->name, 64, "%s", "SV_IsFrontFace");253info->kind = DXIL_SEM_IS_FRONT_FACE;254break;255256case VARYING_SLOT_PRIMITIVE_ID:257assert(glsl_get_components(var->type) == 1);258snprintf(info->name, 64, "%s", "SV_PrimitiveID");259info->kind = DXIL_SEM_PRIMITIVE_ID;260break;261262case VARYING_SLOT_CLIP_DIST1:263info->index = 1;264FALLTHROUGH;265case VARYING_SLOT_CLIP_DIST0:266assert(var->data.location == VARYING_SLOT_CLIP_DIST1 || info->index == 0);267snprintf(info->name, 64, "%s", "SV_ClipDistance");268info->kind = DXIL_SEM_CLIP_DISTANCE;269break;270271default: {272info->index = var->data.location -273(vulkan ? VARYING_SLOT_VAR0 : VARYING_SLOT_POS);274strcpy(info->name, "TEXCOORD");275info->kind = DXIL_SEM_ARBITRARY;276}277}278}279280static void281get_semantic_in_name(nir_variable *var, struct semantic_info *info, bool vulkan)282{283get_semantic_name(var, info, var->type, vulkan);284info->sysvalue_name = in_sysvalue_name(var);285}286287static void288get_semantic_gs_in_name(nir_variable *var, struct semantic_info *info, bool vulkan)289{290/* geometry shader input varyings come as arrays, but we want to use291* the element type */292const struct glsl_type *type =293glsl_type_is_array(var->type) ? glsl_without_array(var->type) : var->type;294295get_semantic_name(var, info, type, vulkan);296info->sysvalue_name = in_sysvalue_name(var);297}298299300static enum dxil_prog_sig_semantic301prog_semantic_from_kind(enum dxil_semantic_kind kind)302{303switch (kind) {304case DXIL_SEM_ARBITRARY: return DXIL_PROG_SEM_UNDEFINED;305case DXIL_SEM_VERTEX_ID: return DXIL_PROG_SEM_VERTEX_ID;306case DXIL_SEM_INSTANCE_ID: return DXIL_PROG_SEM_INSTANCE_ID;307case DXIL_SEM_POSITION: return DXIL_PROG_SEM_POSITION;308case DXIL_SEM_COVERAGE: return DXIL_PROG_SEM_COVERAGE;309case DXIL_SEM_INNER_COVERAGE: return DXIL_PROG_SEM_INNER_COVERAGE;310case DXIL_SEM_PRIMITIVE_ID: return DXIL_PROG_SEM_PRIMITIVE_ID;311case DXIL_SEM_SAMPLE_INDEX: return DXIL_PROG_SEM_SAMPLE_INDEX;312case DXIL_SEM_IS_FRONT_FACE: return DXIL_PROG_SEM_IS_FRONTFACE;313case DXIL_SEM_RENDERTARGET_ARRAY_INDEX: return DXIL_PROG_SEM_RENDERTARGET_ARRAY_INDEX;314case DXIL_SEM_VIEWPORT_ARRAY_INDEX: return DXIL_PROG_SEM_VIEWPORT_ARRAY_INDEX;315case DXIL_SEM_CLIP_DISTANCE: return DXIL_PROG_SEM_CLIP_DISTANCE;316case DXIL_SEM_CULL_DISTANCE: return DXIL_PROG_SEM_CULL_DISTANCE;317case DXIL_SEM_BARYCENTRICS: return DXIL_PROG_SEM_BARYCENTRICS;318case DXIL_SEM_SHADING_RATE: return DXIL_PROG_SEM_SHADING_RATE;319case DXIL_SEM_CULL_PRIMITIVE: return DXIL_PROG_SEM_CULL_PRIMITIVE;320case DXIL_SEM_TARGET: return DXIL_PROG_SEM_TARGET;321case DXIL_SEM_DEPTH: return DXIL_PROG_SEM_DEPTH;322case DXIL_SEM_DEPTH_LE: return DXIL_PROG_SEM_DEPTH_LE;323case DXIL_SEM_DEPTH_GE: return DXIL_PROG_SEM_DEPTH_GE;324case DXIL_SEM_STENCIL_REF: return DXIL_PROG_SEM_STENCIL_REF;325default:326return DXIL_PROG_SEM_UNDEFINED;327}328}329330static331uint32_t332copy_semantic_name_to_string(struct _mesa_string_buffer *string_out, const char *name)333{334/* copy the semantic name */335uint32_t retval = string_out->length;336size_t name_len = strlen(name) + 1;337_mesa_string_buffer_append_len(string_out, name, name_len);338return retval;339}340341static342uint32_t343append_semantic_index_to_table(struct dxil_psv_sem_index_table *table, uint32_t index,344uint32_t num_rows)345{346if (num_rows == 1) {347for (unsigned i = 0; i < table->size; ++i) {348if (table->data[i] == index)349return i;350}351}352uint32_t retval = table->size;353assert(table->size + num_rows <= 80);354for (unsigned i = 0; i < num_rows; ++i)355table->data[table->size++] = index + i;356return retval;357}358359static const struct dxil_mdnode *360fill_SV_param_nodes(struct dxil_module *mod, unsigned record_id,361struct semantic_info *semantic) {362363const struct dxil_mdnode *SV_params_nodes[11];364/* For this to always work we should use vectorize_io, but for FS out and VS in365* this is not implemented globally */366const struct dxil_mdnode *flattened_semantics[256];367368for (unsigned i = 0; i < semantic->rows; ++i)369flattened_semantics[i] = dxil_get_metadata_int32(mod, semantic->index + i);370371SV_params_nodes[0] = dxil_get_metadata_int32(mod, (int)record_id); // Unique element ID372SV_params_nodes[1] = dxil_get_metadata_string(mod, semantic->name); // Element name373SV_params_nodes[2] = dxil_get_metadata_int8(mod, semantic->sig_comp_type); // Element type374SV_params_nodes[3] = dxil_get_metadata_int8(mod, (int8_t)semantic->kind); // Effective system value375SV_params_nodes[4] = dxil_get_metadata_node(mod, flattened_semantics,376semantic->rows); // Semantic index vector377SV_params_nodes[5] = dxil_get_metadata_int8(mod, semantic->interpolation); // Interpolation mode378SV_params_nodes[6] = dxil_get_metadata_int32(mod, semantic->rows); // Number of rows379SV_params_nodes[7] = dxil_get_metadata_int8(mod, semantic->cols); // Number of columns380SV_params_nodes[8] = dxil_get_metadata_int32(mod, semantic->start_row); // Element packing start row381SV_params_nodes[9] = dxil_get_metadata_int8(mod, semantic->start_col); // Element packing start column382SV_params_nodes[10] = 0; // optional Metadata383384return dxil_get_metadata_node(mod, SV_params_nodes, ARRAY_SIZE(SV_params_nodes));385}386387static void388fill_signature_element(struct dxil_signature_element *elm,389struct semantic_info *semantic,390unsigned row)391{392memset(elm, 0, sizeof(struct dxil_signature_element));393// elm->stream = 0;394// elm->semantic_name_offset = 0; // Offset needs to be filled out when writing395elm->semantic_index = semantic->index + row;396elm->system_value = (uint32_t) prog_semantic_from_kind(semantic->kind);397elm->comp_type = (uint32_t) semantic->comp_type;398elm->reg = semantic->start_row + row;399400assert(semantic->cols + semantic->start_col <= 4);401elm->mask = (uint8_t) (((1 << semantic->cols) - 1) << semantic->start_col);402// elm->never_writes_mask = 0;403elm->min_precision = DXIL_MIN_PREC_DEFAULT;404}405406static bool407fill_psv_signature_element(struct dxil_psv_signature_element *psv_elm,408struct semantic_info *semantic, struct dxil_module *mod)409{410memset(psv_elm, 0, sizeof(struct dxil_psv_signature_element));411psv_elm->rows = semantic->rows;412if (semantic->start_row >= 0) {413assert(semantic->start_row < 256);414psv_elm->start_row = semantic->start_row;415psv_elm->cols_and_start = (1u << 6) | (semantic->start_col << 4) | semantic->cols;416} else {417/* The validation expects that the the start row is not egative418* and apparently the extra bit in the cols_and_start indicates that the419* row is meant literally, so don't set it in this case.420* (Source of information: Comparing with the validation structures421* created by dxcompiler)422*/423psv_elm->start_row = 0;424psv_elm->cols_and_start = (semantic->start_col << 4) | semantic->cols;425}426psv_elm->semantic_kind = (uint8_t)semantic->kind;427psv_elm->component_type = semantic->comp_type; //`??428psv_elm->interpolation_mode = semantic->interpolation;429/* to be filled later430psv_elm->dynamic_mask_and_stream = 0;431*/432if (semantic->kind == DXIL_SEM_ARBITRARY && strlen(semantic->name)) {433psv_elm->semantic_name_offset =434copy_semantic_name_to_string(mod->sem_string_table, semantic->name);435436/* TODO: clean up memory */437if (psv_elm->semantic_name_offset == (uint32_t)-1)438return false;439}440441psv_elm->semantic_indexes_offset =442append_semantic_index_to_table(&mod->sem_index_table, semantic->index, semantic->rows);443444return true;445}446447static bool448fill_io_signature(struct dxil_module *mod, int id,449struct semantic_info *semantic,450const struct dxil_mdnode **io,451struct dxil_signature_element *elm,452struct dxil_psv_signature_element *psv_elm)453{454455*io = fill_SV_param_nodes(mod, id, semantic);456for (unsigned i = 0; i < semantic->rows; ++i)457fill_signature_element(&elm[i], semantic, i);458return fill_psv_signature_element(psv_elm, semantic, mod);459}460461static unsigned462get_input_signature_group(struct dxil_module *mod, const struct dxil_mdnode **inputs,463unsigned num_inputs,464nir_shader *s, nir_variable_mode modes,465semantic_info_proc get_semantics, unsigned *row_iter,466bool is_gs_shader, bool vulkan)467{468nir_foreach_variable_with_modes(var, s, modes) {469struct semantic_info semantic = {0};470get_semantics(var, &semantic, vulkan);471mod->inputs[num_inputs].sysvalue = semantic.sysvalue_name;472*row_iter = get_additional_semantic_info(s, var, &semantic, *row_iter, is_gs_shader);473474mod->inputs[num_inputs].name = ralloc_strdup(mod->ralloc_ctx,475semantic.name);476mod->inputs[num_inputs].num_elements = semantic.rows;477struct dxil_signature_element *elm = mod->inputs[num_inputs].elements;478struct dxil_psv_signature_element *psv_elm = &mod->psv_inputs[num_inputs];479480if (!fill_io_signature(mod, num_inputs, &semantic,481&inputs[num_inputs], elm, psv_elm))482return 0;483484++num_inputs;485assert(num_inputs < VARYING_SLOT_MAX);486}487return num_inputs;488}489490static const struct dxil_mdnode *491get_input_signature(struct dxil_module *mod, nir_shader *s, bool vulkan)492{493if (s->info.stage == MESA_SHADER_KERNEL)494return NULL;495496const struct dxil_mdnode *inputs[VARYING_SLOT_MAX];497unsigned next_row = 0;498bool is_gs_shader = s->info.stage == MESA_SHADER_GEOMETRY;499500mod->num_sig_inputs = get_input_signature_group(mod, inputs, 0,501s, nir_var_shader_in,502s->info.stage == MESA_SHADER_VERTEX ?503get_semantic_vs_in_name :504(s->info.stage == MESA_SHADER_GEOMETRY ?505get_semantic_gs_in_name : get_semantic_in_name),506&next_row, is_gs_shader,507vulkan);508509mod->num_sig_inputs = get_input_signature_group(mod, inputs, mod->num_sig_inputs,510s, nir_var_system_value,511get_semantic_sv_name,512&next_row, is_gs_shader,513vulkan);514515if (!mod->num_sig_inputs && !mod->num_sig_inputs)516return NULL;517518mod->num_psv_inputs = next_row;519520const struct dxil_mdnode *retval = mod->num_sig_inputs ?521dxil_get_metadata_node(mod, inputs, mod->num_sig_inputs) : NULL;522523return retval;524}525526static const char *out_sysvalue_name(nir_variable *var)527{528switch (var->data.location) {529case VARYING_SLOT_FACE:530return "FACE";531case VARYING_SLOT_POS:532return "POS";533case VARYING_SLOT_CLIP_DIST0:534case VARYING_SLOT_CLIP_DIST1:535return "CLIPDST";536case VARYING_SLOT_PRIMITIVE_ID:537return "PRIMID";538default:539return "NO";540}541}542543static const struct dxil_mdnode *544get_output_signature(struct dxil_module *mod, nir_shader *s, bool vulkan)545{546const struct dxil_mdnode *outputs[VARYING_SLOT_MAX];547unsigned num_outputs = 0;548unsigned next_row = 0;549nir_foreach_variable_with_modes(var, s, nir_var_shader_out) {550struct semantic_info semantic = {0};551552if (s->info.stage == MESA_SHADER_FRAGMENT) {553get_semantic_ps_outname(var, &semantic);554mod->outputs[num_outputs].sysvalue = "TARGET";555} else {556get_semantic_name(var, &semantic, var->type, vulkan);557mod->outputs[num_outputs].sysvalue = out_sysvalue_name(var);558}559next_row = get_additional_semantic_info(s, var, &semantic, next_row, false);560561mod->info.has_out_position |= semantic.kind== DXIL_SEM_POSITION;562mod->info.has_out_depth |= semantic.kind == DXIL_SEM_DEPTH;563564mod->outputs[num_outputs].name = ralloc_strdup(mod->ralloc_ctx,565semantic.name);566mod->outputs[num_outputs].num_elements = semantic.rows;567struct dxil_signature_element *elm = mod->outputs[num_outputs].elements;568569struct dxil_psv_signature_element *psv_elm = &mod->psv_outputs[num_outputs];570571if (!fill_io_signature(mod, num_outputs, &semantic,572&outputs[num_outputs], elm, psv_elm))573return NULL;574575/* This is fishy, logic suggests that the LHS should be 0xf, but from the576* validation it needs to be 0xff */577elm->never_writes_mask = 0xff & ~elm->mask;578579++num_outputs;580581if (!is_depth_output(semantic.kind))582++mod->num_psv_outputs;583584assert(num_outputs < ARRAY_SIZE(outputs));585}586587if (!num_outputs)588return NULL;589590const struct dxil_mdnode *retval = dxil_get_metadata_node(mod, outputs, num_outputs);591mod->num_sig_outputs = num_outputs;592return retval;593}594595const struct dxil_mdnode *596get_signatures(struct dxil_module *mod, nir_shader *s, bool vulkan)597{598/* DXC does the same: Add an empty string before everything else */599mod->sem_string_table = _mesa_string_buffer_create(mod->ralloc_ctx, 1024);600copy_semantic_name_to_string(mod->sem_string_table, "");601602const struct dxil_mdnode *input_signature = get_input_signature(mod, s, vulkan);603const struct dxil_mdnode *output_signature = get_output_signature(mod, s, vulkan);604605const struct dxil_mdnode *SV_nodes[3] = {606input_signature,607output_signature,608NULL609};610if (output_signature || input_signature)611return dxil_get_metadata_node(mod, SV_nodes, ARRAY_SIZE(SV_nodes));612else613return NULL;614}615616617