17ec681f3Smrg/* 27ec681f3Smrg * Copyright © Microsoft Corporation 37ec681f3Smrg * 47ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a 57ec681f3Smrg * copy of this software and associated documentation files (the "Software"), 67ec681f3Smrg * to deal in the Software without restriction, including without limitation 77ec681f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 87ec681f3Smrg * and/or sell copies of the Software, and to permit persons to whom the 97ec681f3Smrg * Software is furnished to do so, subject to the following conditions: 107ec681f3Smrg * 117ec681f3Smrg * The above copyright notice and this permission notice (including the next 127ec681f3Smrg * paragraph) shall be included in all copies or substantial portions of the 137ec681f3Smrg * Software. 147ec681f3Smrg * 157ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 167ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 177ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 187ec681f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 197ec681f3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 207ec681f3Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 217ec681f3Smrg * IN THE SOFTWARE. 227ec681f3Smrg */ 237ec681f3Smrg 247ec681f3Smrg#include "nir_to_dxil.h" 257ec681f3Smrg 267ec681f3Smrg#include "dxil_container.h" 277ec681f3Smrg#include "dxil_dump.h" 287ec681f3Smrg#include "dxil_enums.h" 297ec681f3Smrg#include "dxil_function.h" 307ec681f3Smrg#include "dxil_module.h" 317ec681f3Smrg#include "dxil_nir.h" 327ec681f3Smrg#include "dxil_signature.h" 337ec681f3Smrg 347ec681f3Smrg#include "nir/nir_builder.h" 357ec681f3Smrg#include "util/u_debug.h" 367ec681f3Smrg#include "util/u_dynarray.h" 377ec681f3Smrg#include "util/u_math.h" 387ec681f3Smrg 397ec681f3Smrg#include "git_sha1.h" 407ec681f3Smrg 417ec681f3Smrg#include "vulkan/vulkan_core.h" 427ec681f3Smrg 437ec681f3Smrg#include <stdint.h> 447ec681f3Smrg 457ec681f3Smrgint debug_dxil = 0; 467ec681f3Smrg 477ec681f3Smrgstatic const struct debug_named_value 487ec681f3Smrgdxil_debug_options[] = { 497ec681f3Smrg { "verbose", DXIL_DEBUG_VERBOSE, NULL }, 507ec681f3Smrg { "dump_blob", DXIL_DEBUG_DUMP_BLOB , "Write shader blobs" }, 517ec681f3Smrg { "trace", DXIL_DEBUG_TRACE , "Trace instruction conversion" }, 527ec681f3Smrg { "dump_module", DXIL_DEBUG_DUMP_MODULE, "dump module tree to stderr"}, 537ec681f3Smrg DEBUG_NAMED_VALUE_END 547ec681f3Smrg}; 557ec681f3Smrg 567ec681f3SmrgDEBUG_GET_ONCE_FLAGS_OPTION(debug_dxil, "DXIL_DEBUG", dxil_debug_options, 0) 577ec681f3Smrg 587ec681f3Smrg#define NIR_INSTR_UNSUPPORTED(instr) \ 597ec681f3Smrg if (debug_dxil & DXIL_DEBUG_VERBOSE) \ 607ec681f3Smrg do { \ 617ec681f3Smrg fprintf(stderr, "Unsupported instruction:"); \ 627ec681f3Smrg nir_print_instr(instr, stderr); \ 637ec681f3Smrg fprintf(stderr, "\n"); \ 647ec681f3Smrg } while (0) 657ec681f3Smrg 667ec681f3Smrg#define TRACE_CONVERSION(instr) \ 677ec681f3Smrg if (debug_dxil & DXIL_DEBUG_TRACE) \ 687ec681f3Smrg do { \ 697ec681f3Smrg fprintf(stderr, "Convert '"); \ 707ec681f3Smrg nir_print_instr(instr, stderr); \ 717ec681f3Smrg fprintf(stderr, "'\n"); \ 727ec681f3Smrg } while (0) 737ec681f3Smrg 747ec681f3Smrgstatic const nir_shader_compiler_options 757ec681f3Smrgnir_options = { 767ec681f3Smrg .lower_ineg = true, 777ec681f3Smrg .lower_fneg = true, 787ec681f3Smrg .lower_ffma16 = true, 797ec681f3Smrg .lower_ffma32 = true, 807ec681f3Smrg .lower_isign = true, 817ec681f3Smrg .lower_fsign = true, 827ec681f3Smrg .lower_iabs = true, 837ec681f3Smrg .lower_fmod = true, 847ec681f3Smrg .lower_fpow = true, 857ec681f3Smrg .lower_scmp = true, 867ec681f3Smrg .lower_ldexp = true, 877ec681f3Smrg .lower_flrp16 = true, 887ec681f3Smrg .lower_flrp32 = true, 897ec681f3Smrg .lower_flrp64 = true, 907ec681f3Smrg .lower_bitfield_extract_to_shifts = true, 917ec681f3Smrg .lower_extract_word = true, 927ec681f3Smrg .lower_extract_byte = true, 937ec681f3Smrg .lower_insert_word = true, 947ec681f3Smrg .lower_insert_byte = true, 957ec681f3Smrg .lower_all_io_to_elements = true, 967ec681f3Smrg .lower_all_io_to_temps = true, 977ec681f3Smrg .lower_hadd = true, 987ec681f3Smrg .lower_uadd_sat = true, 997ec681f3Smrg .lower_iadd_sat = true, 1007ec681f3Smrg .lower_uadd_carry = true, 1017ec681f3Smrg .lower_mul_high = true, 1027ec681f3Smrg .lower_rotate = true, 1037ec681f3Smrg .lower_pack_64_2x32_split = true, 1047ec681f3Smrg .lower_pack_32_2x16_split = true, 1057ec681f3Smrg .lower_unpack_64_2x32_split = true, 1067ec681f3Smrg .lower_unpack_32_2x16_split = true, 1077ec681f3Smrg .has_fsub = true, 1087ec681f3Smrg .has_isub = true, 1097ec681f3Smrg .use_scoped_barrier = true, 1107ec681f3Smrg .vertex_id_zero_based = true, 1117ec681f3Smrg .lower_base_vertex = true, 1127ec681f3Smrg .has_cs_global_id = true, 1137ec681f3Smrg .has_txs = true, 1147ec681f3Smrg}; 1157ec681f3Smrg 1167ec681f3Smrgconst nir_shader_compiler_options* 1177ec681f3Smrgdxil_get_nir_compiler_options(void) 1187ec681f3Smrg{ 1197ec681f3Smrg return &nir_options; 1207ec681f3Smrg} 1217ec681f3Smrg 1227ec681f3Smrgstatic bool 1237ec681f3Smrgemit_llvm_ident(struct dxil_module *m) 1247ec681f3Smrg{ 1257ec681f3Smrg const struct dxil_mdnode *compiler = dxil_get_metadata_string(m, "Mesa version " PACKAGE_VERSION MESA_GIT_SHA1); 1267ec681f3Smrg if (!compiler) 1277ec681f3Smrg return false; 1287ec681f3Smrg 1297ec681f3Smrg const struct dxil_mdnode *llvm_ident = dxil_get_metadata_node(m, &compiler, 1); 1307ec681f3Smrg return llvm_ident && 1317ec681f3Smrg dxil_add_metadata_named_node(m, "llvm.ident", &llvm_ident, 1); 1327ec681f3Smrg} 1337ec681f3Smrg 1347ec681f3Smrgstatic bool 1357ec681f3Smrgemit_named_version(struct dxil_module *m, const char *name, 1367ec681f3Smrg int major, int minor) 1377ec681f3Smrg{ 1387ec681f3Smrg const struct dxil_mdnode *major_node = dxil_get_metadata_int32(m, major); 1397ec681f3Smrg const struct dxil_mdnode *minor_node = dxil_get_metadata_int32(m, minor); 1407ec681f3Smrg const struct dxil_mdnode *version_nodes[] = { major_node, minor_node }; 1417ec681f3Smrg const struct dxil_mdnode *version = dxil_get_metadata_node(m, version_nodes, 1427ec681f3Smrg ARRAY_SIZE(version_nodes)); 1437ec681f3Smrg return dxil_add_metadata_named_node(m, name, &version, 1); 1447ec681f3Smrg} 1457ec681f3Smrg 1467ec681f3Smrgstatic const char * 1477ec681f3Smrgget_shader_kind_str(enum dxil_shader_kind kind) 1487ec681f3Smrg{ 1497ec681f3Smrg switch (kind) { 1507ec681f3Smrg case DXIL_PIXEL_SHADER: 1517ec681f3Smrg return "ps"; 1527ec681f3Smrg case DXIL_VERTEX_SHADER: 1537ec681f3Smrg return "vs"; 1547ec681f3Smrg case DXIL_GEOMETRY_SHADER: 1557ec681f3Smrg return "gs"; 1567ec681f3Smrg case DXIL_HULL_SHADER: 1577ec681f3Smrg return "hs"; 1587ec681f3Smrg case DXIL_DOMAIN_SHADER: 1597ec681f3Smrg return "ds"; 1607ec681f3Smrg case DXIL_COMPUTE_SHADER: 1617ec681f3Smrg return "cs"; 1627ec681f3Smrg default: 1637ec681f3Smrg unreachable("invalid shader kind"); 1647ec681f3Smrg } 1657ec681f3Smrg} 1667ec681f3Smrg 1677ec681f3Smrgstatic bool 1687ec681f3Smrgemit_dx_shader_model(struct dxil_module *m) 1697ec681f3Smrg{ 1707ec681f3Smrg const struct dxil_mdnode *type_node = dxil_get_metadata_string(m, get_shader_kind_str(m->shader_kind)); 1717ec681f3Smrg const struct dxil_mdnode *major_node = dxil_get_metadata_int32(m, m->major_version); 1727ec681f3Smrg const struct dxil_mdnode *minor_node = dxil_get_metadata_int32(m, m->minor_version); 1737ec681f3Smrg const struct dxil_mdnode *shader_model[] = { type_node, major_node, 1747ec681f3Smrg minor_node }; 1757ec681f3Smrg const struct dxil_mdnode *dx_shader_model = dxil_get_metadata_node(m, shader_model, ARRAY_SIZE(shader_model)); 1767ec681f3Smrg 1777ec681f3Smrg return dxil_add_metadata_named_node(m, "dx.shaderModel", 1787ec681f3Smrg &dx_shader_model, 1); 1797ec681f3Smrg} 1807ec681f3Smrg 1817ec681f3Smrgenum { 1827ec681f3Smrg DXIL_TYPED_BUFFER_ELEMENT_TYPE_TAG = 0, 1837ec681f3Smrg DXIL_STRUCTURED_BUFFER_ELEMENT_STRIDE_TAG = 1 1847ec681f3Smrg}; 1857ec681f3Smrg 1867ec681f3Smrgenum dxil_intr { 1877ec681f3Smrg DXIL_INTR_LOAD_INPUT = 4, 1887ec681f3Smrg DXIL_INTR_STORE_OUTPUT = 5, 1897ec681f3Smrg DXIL_INTR_FABS = 6, 1907ec681f3Smrg DXIL_INTR_SATURATE = 7, 1917ec681f3Smrg 1927ec681f3Smrg DXIL_INTR_ISFINITE = 10, 1937ec681f3Smrg DXIL_INTR_ISNORMAL = 11, 1947ec681f3Smrg 1957ec681f3Smrg DXIL_INTR_FCOS = 12, 1967ec681f3Smrg DXIL_INTR_FSIN = 13, 1977ec681f3Smrg 1987ec681f3Smrg DXIL_INTR_FEXP2 = 21, 1997ec681f3Smrg DXIL_INTR_FRC = 22, 2007ec681f3Smrg DXIL_INTR_FLOG2 = 23, 2017ec681f3Smrg 2027ec681f3Smrg DXIL_INTR_SQRT = 24, 2037ec681f3Smrg DXIL_INTR_RSQRT = 25, 2047ec681f3Smrg DXIL_INTR_ROUND_NE = 26, 2057ec681f3Smrg DXIL_INTR_ROUND_NI = 27, 2067ec681f3Smrg DXIL_INTR_ROUND_PI = 28, 2077ec681f3Smrg DXIL_INTR_ROUND_Z = 29, 2087ec681f3Smrg 2097ec681f3Smrg DXIL_INTR_COUNTBITS = 31, 2107ec681f3Smrg DXIL_INTR_FIRSTBIT_HI = 33, 2117ec681f3Smrg 2127ec681f3Smrg DXIL_INTR_FMAX = 35, 2137ec681f3Smrg DXIL_INTR_FMIN = 36, 2147ec681f3Smrg DXIL_INTR_IMAX = 37, 2157ec681f3Smrg DXIL_INTR_IMIN = 38, 2167ec681f3Smrg DXIL_INTR_UMAX = 39, 2177ec681f3Smrg DXIL_INTR_UMIN = 40, 2187ec681f3Smrg 2197ec681f3Smrg DXIL_INTR_FMA = 47, 2207ec681f3Smrg 2217ec681f3Smrg DXIL_INTR_CREATE_HANDLE = 57, 2227ec681f3Smrg DXIL_INTR_CBUFFER_LOAD_LEGACY = 59, 2237ec681f3Smrg 2247ec681f3Smrg DXIL_INTR_SAMPLE = 60, 2257ec681f3Smrg DXIL_INTR_SAMPLE_BIAS = 61, 2267ec681f3Smrg DXIL_INTR_SAMPLE_LEVEL = 62, 2277ec681f3Smrg DXIL_INTR_SAMPLE_GRAD = 63, 2287ec681f3Smrg DXIL_INTR_SAMPLE_CMP = 64, 2297ec681f3Smrg DXIL_INTR_SAMPLE_CMP_LVL_ZERO = 65, 2307ec681f3Smrg 2317ec681f3Smrg DXIL_INTR_TEXTURE_LOAD = 66, 2327ec681f3Smrg DXIL_INTR_TEXTURE_STORE = 67, 2337ec681f3Smrg 2347ec681f3Smrg DXIL_INTR_BUFFER_LOAD = 68, 2357ec681f3Smrg DXIL_INTR_BUFFER_STORE = 69, 2367ec681f3Smrg 2377ec681f3Smrg DXIL_INTR_TEXTURE_SIZE = 72, 2387ec681f3Smrg 2397ec681f3Smrg DXIL_INTR_ATOMIC_BINOP = 78, 2407ec681f3Smrg DXIL_INTR_ATOMIC_CMPXCHG = 79, 2417ec681f3Smrg DXIL_INTR_BARRIER = 80, 2427ec681f3Smrg DXIL_INTR_TEXTURE_LOD = 81, 2437ec681f3Smrg 2447ec681f3Smrg DXIL_INTR_DISCARD = 82, 2457ec681f3Smrg DXIL_INTR_DDX_COARSE = 83, 2467ec681f3Smrg DXIL_INTR_DDY_COARSE = 84, 2477ec681f3Smrg DXIL_INTR_DDX_FINE = 85, 2487ec681f3Smrg DXIL_INTR_DDY_FINE = 86, 2497ec681f3Smrg 2507ec681f3Smrg DXIL_INTR_SAMPLE_INDEX = 90, 2517ec681f3Smrg 2527ec681f3Smrg DXIL_INTR_THREAD_ID = 93, 2537ec681f3Smrg DXIL_INTR_GROUP_ID = 94, 2547ec681f3Smrg DXIL_INTR_THREAD_ID_IN_GROUP = 95, 2557ec681f3Smrg DXIL_INTR_FLATTENED_THREAD_ID_IN_GROUP = 96, 2567ec681f3Smrg 2577ec681f3Smrg DXIL_INTR_EMIT_STREAM = 97, 2587ec681f3Smrg DXIL_INTR_CUT_STREAM = 98, 2597ec681f3Smrg 2607ec681f3Smrg DXIL_INTR_MAKE_DOUBLE = 101, 2617ec681f3Smrg DXIL_INTR_SPLIT_DOUBLE = 102, 2627ec681f3Smrg 2637ec681f3Smrg DXIL_INTR_PRIMITIVE_ID = 108, 2647ec681f3Smrg 2657ec681f3Smrg DXIL_INTR_LEGACY_F32TOF16 = 130, 2667ec681f3Smrg DXIL_INTR_LEGACY_F16TOF32 = 131, 2677ec681f3Smrg 2687ec681f3Smrg DXIL_INTR_ATTRIBUTE_AT_VERTEX = 137, 2697ec681f3Smrg}; 2707ec681f3Smrg 2717ec681f3Smrgenum dxil_atomic_op { 2727ec681f3Smrg DXIL_ATOMIC_ADD = 0, 2737ec681f3Smrg DXIL_ATOMIC_AND = 1, 2747ec681f3Smrg DXIL_ATOMIC_OR = 2, 2757ec681f3Smrg DXIL_ATOMIC_XOR = 3, 2767ec681f3Smrg DXIL_ATOMIC_IMIN = 4, 2777ec681f3Smrg DXIL_ATOMIC_IMAX = 5, 2787ec681f3Smrg DXIL_ATOMIC_UMIN = 6, 2797ec681f3Smrg DXIL_ATOMIC_UMAX = 7, 2807ec681f3Smrg DXIL_ATOMIC_EXCHANGE = 8, 2817ec681f3Smrg}; 2827ec681f3Smrg 2837ec681f3Smrgtypedef struct { 2847ec681f3Smrg unsigned id; 2857ec681f3Smrg unsigned binding; 2867ec681f3Smrg unsigned size; 2877ec681f3Smrg unsigned space; 2887ec681f3Smrg} resource_array_layout; 2897ec681f3Smrg 2907ec681f3Smrgstatic void 2917ec681f3Smrgfill_resource_metadata(struct dxil_module *m, const struct dxil_mdnode **fields, 2927ec681f3Smrg const struct dxil_type *struct_type, 2937ec681f3Smrg const char *name, const resource_array_layout *layout) 2947ec681f3Smrg{ 2957ec681f3Smrg const struct dxil_type *pointer_type = dxil_module_get_pointer_type(m, struct_type); 2967ec681f3Smrg const struct dxil_value *pointer_undef = dxil_module_get_undef(m, pointer_type); 2977ec681f3Smrg 2987ec681f3Smrg fields[0] = dxil_get_metadata_int32(m, layout->id); // resource ID 2997ec681f3Smrg fields[1] = dxil_get_metadata_value(m, pointer_type, pointer_undef); // global constant symbol 3007ec681f3Smrg fields[2] = dxil_get_metadata_string(m, name ? name : ""); // name 3017ec681f3Smrg fields[3] = dxil_get_metadata_int32(m, layout->space); // space ID 3027ec681f3Smrg fields[4] = dxil_get_metadata_int32(m, layout->binding); // lower bound 3037ec681f3Smrg fields[5] = dxil_get_metadata_int32(m, layout->size); // range size 3047ec681f3Smrg} 3057ec681f3Smrg 3067ec681f3Smrgstatic const struct dxil_mdnode * 3077ec681f3Smrgemit_srv_metadata(struct dxil_module *m, const struct dxil_type *elem_type, 3087ec681f3Smrg const char *name, const resource_array_layout *layout, 3097ec681f3Smrg enum dxil_component_type comp_type, 3107ec681f3Smrg enum dxil_resource_kind res_kind) 3117ec681f3Smrg{ 3127ec681f3Smrg const struct dxil_mdnode *fields[9]; 3137ec681f3Smrg 3147ec681f3Smrg const struct dxil_mdnode *metadata_tag_nodes[2]; 3157ec681f3Smrg 3167ec681f3Smrg fill_resource_metadata(m, fields, elem_type, name, layout); 3177ec681f3Smrg fields[6] = dxil_get_metadata_int32(m, res_kind); // resource shape 3187ec681f3Smrg fields[7] = dxil_get_metadata_int1(m, 0); // sample count 3197ec681f3Smrg if (res_kind != DXIL_RESOURCE_KIND_RAW_BUFFER && 3207ec681f3Smrg res_kind != DXIL_RESOURCE_KIND_STRUCTURED_BUFFER) { 3217ec681f3Smrg metadata_tag_nodes[0] = dxil_get_metadata_int32(m, DXIL_TYPED_BUFFER_ELEMENT_TYPE_TAG); 3227ec681f3Smrg metadata_tag_nodes[1] = dxil_get_metadata_int32(m, comp_type); 3237ec681f3Smrg fields[8] = dxil_get_metadata_node(m, metadata_tag_nodes, ARRAY_SIZE(metadata_tag_nodes)); // metadata 3247ec681f3Smrg } else if (res_kind == DXIL_RESOURCE_KIND_RAW_BUFFER) 3257ec681f3Smrg fields[8] = NULL; 3267ec681f3Smrg else 3277ec681f3Smrg unreachable("Structured buffers not supported yet"); 3287ec681f3Smrg 3297ec681f3Smrg return dxil_get_metadata_node(m, fields, ARRAY_SIZE(fields)); 3307ec681f3Smrg} 3317ec681f3Smrg 3327ec681f3Smrgstatic const struct dxil_mdnode * 3337ec681f3Smrgemit_uav_metadata(struct dxil_module *m, const struct dxil_type *struct_type, 3347ec681f3Smrg const char *name, const resource_array_layout *layout, 3357ec681f3Smrg enum dxil_component_type comp_type, 3367ec681f3Smrg enum dxil_resource_kind res_kind) 3377ec681f3Smrg{ 3387ec681f3Smrg const struct dxil_mdnode *fields[11]; 3397ec681f3Smrg 3407ec681f3Smrg const struct dxil_mdnode *metadata_tag_nodes[2]; 3417ec681f3Smrg 3427ec681f3Smrg fill_resource_metadata(m, fields, struct_type, name, layout); 3437ec681f3Smrg fields[6] = dxil_get_metadata_int32(m, res_kind); // resource shape 3447ec681f3Smrg fields[7] = dxil_get_metadata_int1(m, false); // globally-coherent 3457ec681f3Smrg fields[8] = dxil_get_metadata_int1(m, false); // has counter 3467ec681f3Smrg fields[9] = dxil_get_metadata_int1(m, false); // is ROV 3477ec681f3Smrg if (res_kind != DXIL_RESOURCE_KIND_RAW_BUFFER && 3487ec681f3Smrg res_kind != DXIL_RESOURCE_KIND_STRUCTURED_BUFFER) { 3497ec681f3Smrg metadata_tag_nodes[0] = dxil_get_metadata_int32(m, DXIL_TYPED_BUFFER_ELEMENT_TYPE_TAG); 3507ec681f3Smrg metadata_tag_nodes[1] = dxil_get_metadata_int32(m, comp_type); 3517ec681f3Smrg fields[10] = dxil_get_metadata_node(m, metadata_tag_nodes, ARRAY_SIZE(metadata_tag_nodes)); // metadata 3527ec681f3Smrg } else if (res_kind == DXIL_RESOURCE_KIND_RAW_BUFFER) 3537ec681f3Smrg fields[10] = NULL; 3547ec681f3Smrg else 3557ec681f3Smrg unreachable("Structured buffers not supported yet"); 3567ec681f3Smrg 3577ec681f3Smrg return dxil_get_metadata_node(m, fields, ARRAY_SIZE(fields)); 3587ec681f3Smrg} 3597ec681f3Smrg 3607ec681f3Smrgstatic const struct dxil_mdnode * 3617ec681f3Smrgemit_cbv_metadata(struct dxil_module *m, const struct dxil_type *struct_type, 3627ec681f3Smrg const char *name, const resource_array_layout *layout, 3637ec681f3Smrg unsigned size) 3647ec681f3Smrg{ 3657ec681f3Smrg const struct dxil_mdnode *fields[8]; 3667ec681f3Smrg 3677ec681f3Smrg fill_resource_metadata(m, fields, struct_type, name, layout); 3687ec681f3Smrg fields[6] = dxil_get_metadata_int32(m, size); // constant buffer size 3697ec681f3Smrg fields[7] = NULL; // metadata 3707ec681f3Smrg 3717ec681f3Smrg return dxil_get_metadata_node(m, fields, ARRAY_SIZE(fields)); 3727ec681f3Smrg} 3737ec681f3Smrg 3747ec681f3Smrgstatic const struct dxil_mdnode * 3757ec681f3Smrgemit_sampler_metadata(struct dxil_module *m, const struct dxil_type *struct_type, 3767ec681f3Smrg nir_variable *var, const resource_array_layout *layout) 3777ec681f3Smrg{ 3787ec681f3Smrg const struct dxil_mdnode *fields[8]; 3797ec681f3Smrg const struct glsl_type *type = glsl_without_array(var->type); 3807ec681f3Smrg 3817ec681f3Smrg fill_resource_metadata(m, fields, struct_type, var->name, layout); 3827ec681f3Smrg fields[6] = dxil_get_metadata_int32(m, DXIL_SAMPLER_KIND_DEFAULT); // sampler kind 3837ec681f3Smrg enum dxil_sampler_kind sampler_kind = glsl_sampler_type_is_shadow(type) ? 3847ec681f3Smrg DXIL_SAMPLER_KIND_COMPARISON : DXIL_SAMPLER_KIND_DEFAULT; 3857ec681f3Smrg fields[6] = dxil_get_metadata_int32(m, sampler_kind); // sampler kind 3867ec681f3Smrg fields[7] = NULL; // metadata 3877ec681f3Smrg 3887ec681f3Smrg return dxil_get_metadata_node(m, fields, ARRAY_SIZE(fields)); 3897ec681f3Smrg} 3907ec681f3Smrg 3917ec681f3Smrg 3927ec681f3Smrg#define MAX_SRVS 128 3937ec681f3Smrg#define MAX_UAVS 64 3947ec681f3Smrg#define MAX_CBVS 64 // ?? 3957ec681f3Smrg#define MAX_SAMPLERS 64 // ?? 3967ec681f3Smrg 3977ec681f3Smrgstruct dxil_def { 3987ec681f3Smrg const struct dxil_value *chans[NIR_MAX_VEC_COMPONENTS]; 3997ec681f3Smrg}; 4007ec681f3Smrg 4017ec681f3Smrgstruct ntd_context { 4027ec681f3Smrg void *ralloc_ctx; 4037ec681f3Smrg const struct nir_to_dxil_options *opts; 4047ec681f3Smrg struct nir_shader *shader; 4057ec681f3Smrg 4067ec681f3Smrg struct dxil_module mod; 4077ec681f3Smrg 4087ec681f3Smrg struct util_dynarray srv_metadata_nodes; 4097ec681f3Smrg const struct dxil_value *srv_handles[MAX_SRVS]; 4107ec681f3Smrg 4117ec681f3Smrg struct util_dynarray uav_metadata_nodes; 4127ec681f3Smrg const struct dxil_value *uav_handles[MAX_UAVS]; 4137ec681f3Smrg 4147ec681f3Smrg struct util_dynarray cbv_metadata_nodes; 4157ec681f3Smrg const struct dxil_value *cbv_handles[MAX_CBVS]; 4167ec681f3Smrg 4177ec681f3Smrg struct util_dynarray sampler_metadata_nodes; 4187ec681f3Smrg const struct dxil_value *sampler_handles[MAX_SAMPLERS]; 4197ec681f3Smrg 4207ec681f3Smrg struct util_dynarray resources; 4217ec681f3Smrg 4227ec681f3Smrg const struct dxil_mdnode *shader_property_nodes[6]; 4237ec681f3Smrg size_t num_shader_property_nodes; 4247ec681f3Smrg 4257ec681f3Smrg struct dxil_def *defs; 4267ec681f3Smrg unsigned num_defs; 4277ec681f3Smrg struct hash_table *phis; 4287ec681f3Smrg 4297ec681f3Smrg const struct dxil_value *sharedvars; 4307ec681f3Smrg const struct dxil_value *scratchvars; 4317ec681f3Smrg struct hash_table *consts; 4327ec681f3Smrg 4337ec681f3Smrg nir_variable *ps_front_face; 4347ec681f3Smrg nir_variable *system_value[SYSTEM_VALUE_MAX]; 4357ec681f3Smrg}; 4367ec681f3Smrg 4377ec681f3Smrgstatic const char* 4387ec681f3Smrgunary_func_name(enum dxil_intr intr) 4397ec681f3Smrg{ 4407ec681f3Smrg switch (intr) { 4417ec681f3Smrg case DXIL_INTR_COUNTBITS: 4427ec681f3Smrg case DXIL_INTR_FIRSTBIT_HI: 4437ec681f3Smrg return "dx.op.unaryBits"; 4447ec681f3Smrg case DXIL_INTR_ISFINITE: 4457ec681f3Smrg case DXIL_INTR_ISNORMAL: 4467ec681f3Smrg return "dx.op.isSpecialFloat"; 4477ec681f3Smrg default: 4487ec681f3Smrg return "dx.op.unary"; 4497ec681f3Smrg } 4507ec681f3Smrg} 4517ec681f3Smrg 4527ec681f3Smrgstatic const struct dxil_value * 4537ec681f3Smrgemit_unary_call(struct ntd_context *ctx, enum overload_type overload, 4547ec681f3Smrg enum dxil_intr intr, 4557ec681f3Smrg const struct dxil_value *op0) 4567ec681f3Smrg{ 4577ec681f3Smrg const struct dxil_func *func = dxil_get_function(&ctx->mod, 4587ec681f3Smrg unary_func_name(intr), 4597ec681f3Smrg overload); 4607ec681f3Smrg if (!func) 4617ec681f3Smrg return NULL; 4627ec681f3Smrg 4637ec681f3Smrg const struct dxil_value *opcode = dxil_module_get_int32_const(&ctx->mod, intr); 4647ec681f3Smrg if (!opcode) 4657ec681f3Smrg return NULL; 4667ec681f3Smrg 4677ec681f3Smrg const struct dxil_value *args[] = { 4687ec681f3Smrg opcode, 4697ec681f3Smrg op0 4707ec681f3Smrg }; 4717ec681f3Smrg 4727ec681f3Smrg return dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args)); 4737ec681f3Smrg} 4747ec681f3Smrg 4757ec681f3Smrgstatic const struct dxil_value * 4767ec681f3Smrgemit_binary_call(struct ntd_context *ctx, enum overload_type overload, 4777ec681f3Smrg enum dxil_intr intr, 4787ec681f3Smrg const struct dxil_value *op0, const struct dxil_value *op1) 4797ec681f3Smrg{ 4807ec681f3Smrg const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.binary", overload); 4817ec681f3Smrg if (!func) 4827ec681f3Smrg return NULL; 4837ec681f3Smrg 4847ec681f3Smrg const struct dxil_value *opcode = dxil_module_get_int32_const(&ctx->mod, intr); 4857ec681f3Smrg if (!opcode) 4867ec681f3Smrg return NULL; 4877ec681f3Smrg 4887ec681f3Smrg const struct dxil_value *args[] = { 4897ec681f3Smrg opcode, 4907ec681f3Smrg op0, 4917ec681f3Smrg op1 4927ec681f3Smrg }; 4937ec681f3Smrg 4947ec681f3Smrg return dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args)); 4957ec681f3Smrg} 4967ec681f3Smrg 4977ec681f3Smrgstatic const struct dxil_value * 4987ec681f3Smrgemit_tertiary_call(struct ntd_context *ctx, enum overload_type overload, 4997ec681f3Smrg enum dxil_intr intr, 5007ec681f3Smrg const struct dxil_value *op0, 5017ec681f3Smrg const struct dxil_value *op1, 5027ec681f3Smrg const struct dxil_value *op2) 5037ec681f3Smrg{ 5047ec681f3Smrg const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.tertiary", overload); 5057ec681f3Smrg if (!func) 5067ec681f3Smrg return NULL; 5077ec681f3Smrg 5087ec681f3Smrg const struct dxil_value *opcode = dxil_module_get_int32_const(&ctx->mod, intr); 5097ec681f3Smrg if (!opcode) 5107ec681f3Smrg return NULL; 5117ec681f3Smrg 5127ec681f3Smrg const struct dxil_value *args[] = { 5137ec681f3Smrg opcode, 5147ec681f3Smrg op0, 5157ec681f3Smrg op1, 5167ec681f3Smrg op2 5177ec681f3Smrg }; 5187ec681f3Smrg 5197ec681f3Smrg return dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args)); 5207ec681f3Smrg} 5217ec681f3Smrg 5227ec681f3Smrgstatic const struct dxil_value * 5237ec681f3Smrgemit_threadid_call(struct ntd_context *ctx, const struct dxil_value *comp) 5247ec681f3Smrg{ 5257ec681f3Smrg const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.threadId", DXIL_I32); 5267ec681f3Smrg if (!func) 5277ec681f3Smrg return NULL; 5287ec681f3Smrg 5297ec681f3Smrg const struct dxil_value *opcode = dxil_module_get_int32_const(&ctx->mod, 5307ec681f3Smrg DXIL_INTR_THREAD_ID); 5317ec681f3Smrg if (!opcode) 5327ec681f3Smrg return NULL; 5337ec681f3Smrg 5347ec681f3Smrg const struct dxil_value *args[] = { 5357ec681f3Smrg opcode, 5367ec681f3Smrg comp 5377ec681f3Smrg }; 5387ec681f3Smrg 5397ec681f3Smrg return dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args)); 5407ec681f3Smrg} 5417ec681f3Smrg 5427ec681f3Smrgstatic const struct dxil_value * 5437ec681f3Smrgemit_threadidingroup_call(struct ntd_context *ctx, 5447ec681f3Smrg const struct dxil_value *comp) 5457ec681f3Smrg{ 5467ec681f3Smrg const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.threadIdInGroup", DXIL_I32); 5477ec681f3Smrg 5487ec681f3Smrg if (!func) 5497ec681f3Smrg return NULL; 5507ec681f3Smrg 5517ec681f3Smrg const struct dxil_value *opcode = dxil_module_get_int32_const(&ctx->mod, 5527ec681f3Smrg DXIL_INTR_THREAD_ID_IN_GROUP); 5537ec681f3Smrg if (!opcode) 5547ec681f3Smrg return NULL; 5557ec681f3Smrg 5567ec681f3Smrg const struct dxil_value *args[] = { 5577ec681f3Smrg opcode, 5587ec681f3Smrg comp 5597ec681f3Smrg }; 5607ec681f3Smrg 5617ec681f3Smrg return dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args)); 5627ec681f3Smrg} 5637ec681f3Smrg 5647ec681f3Smrgstatic const struct dxil_value * 5657ec681f3Smrgemit_flattenedthreadidingroup_call(struct ntd_context *ctx) 5667ec681f3Smrg{ 5677ec681f3Smrg const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.flattenedThreadIdInGroup", DXIL_I32); 5687ec681f3Smrg 5697ec681f3Smrg if (!func) 5707ec681f3Smrg return NULL; 5717ec681f3Smrg 5727ec681f3Smrg const struct dxil_value *opcode = dxil_module_get_int32_const(&ctx->mod, 5737ec681f3Smrg DXIL_INTR_FLATTENED_THREAD_ID_IN_GROUP); 5747ec681f3Smrg if (!opcode) 5757ec681f3Smrg return NULL; 5767ec681f3Smrg 5777ec681f3Smrg const struct dxil_value *args[] = { 5787ec681f3Smrg opcode 5797ec681f3Smrg }; 5807ec681f3Smrg 5817ec681f3Smrg return dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args)); 5827ec681f3Smrg} 5837ec681f3Smrg 5847ec681f3Smrgstatic const struct dxil_value * 5857ec681f3Smrgemit_groupid_call(struct ntd_context *ctx, const struct dxil_value *comp) 5867ec681f3Smrg{ 5877ec681f3Smrg const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.groupId", DXIL_I32); 5887ec681f3Smrg 5897ec681f3Smrg if (!func) 5907ec681f3Smrg return NULL; 5917ec681f3Smrg 5927ec681f3Smrg const struct dxil_value *opcode = dxil_module_get_int32_const(&ctx->mod, 5937ec681f3Smrg DXIL_INTR_GROUP_ID); 5947ec681f3Smrg if (!opcode) 5957ec681f3Smrg return NULL; 5967ec681f3Smrg 5977ec681f3Smrg const struct dxil_value *args[] = { 5987ec681f3Smrg opcode, 5997ec681f3Smrg comp 6007ec681f3Smrg }; 6017ec681f3Smrg 6027ec681f3Smrg return dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args)); 6037ec681f3Smrg} 6047ec681f3Smrg 6057ec681f3Smrgstatic const struct dxil_value * 6067ec681f3Smrgemit_bufferload_call(struct ntd_context *ctx, 6077ec681f3Smrg const struct dxil_value *handle, 6087ec681f3Smrg const struct dxil_value *coord[2], 6097ec681f3Smrg enum overload_type overload) 6107ec681f3Smrg{ 6117ec681f3Smrg const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.bufferLoad", overload); 6127ec681f3Smrg if (!func) 6137ec681f3Smrg return NULL; 6147ec681f3Smrg 6157ec681f3Smrg const struct dxil_value *opcode = dxil_module_get_int32_const(&ctx->mod, 6167ec681f3Smrg DXIL_INTR_BUFFER_LOAD); 6177ec681f3Smrg const struct dxil_value *args[] = { opcode, handle, coord[0], coord[1] }; 6187ec681f3Smrg 6197ec681f3Smrg return dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args)); 6207ec681f3Smrg} 6217ec681f3Smrg 6227ec681f3Smrgstatic bool 6237ec681f3Smrgemit_bufferstore_call(struct ntd_context *ctx, 6247ec681f3Smrg const struct dxil_value *handle, 6257ec681f3Smrg const struct dxil_value *coord[2], 6267ec681f3Smrg const struct dxil_value *value[4], 6277ec681f3Smrg const struct dxil_value *write_mask, 6287ec681f3Smrg enum overload_type overload) 6297ec681f3Smrg{ 6307ec681f3Smrg const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.bufferStore", overload); 6317ec681f3Smrg 6327ec681f3Smrg if (!func) 6337ec681f3Smrg return false; 6347ec681f3Smrg 6357ec681f3Smrg const struct dxil_value *opcode = dxil_module_get_int32_const(&ctx->mod, 6367ec681f3Smrg DXIL_INTR_BUFFER_STORE); 6377ec681f3Smrg const struct dxil_value *args[] = { 6387ec681f3Smrg opcode, handle, coord[0], coord[1], 6397ec681f3Smrg value[0], value[1], value[2], value[3], 6407ec681f3Smrg write_mask 6417ec681f3Smrg }; 6427ec681f3Smrg 6437ec681f3Smrg return dxil_emit_call_void(&ctx->mod, func, 6447ec681f3Smrg args, ARRAY_SIZE(args)); 6457ec681f3Smrg} 6467ec681f3Smrg 6477ec681f3Smrgstatic const struct dxil_value * 6487ec681f3Smrgemit_textureload_call(struct ntd_context *ctx, 6497ec681f3Smrg const struct dxil_value *handle, 6507ec681f3Smrg const struct dxil_value *coord[3], 6517ec681f3Smrg enum overload_type overload) 6527ec681f3Smrg{ 6537ec681f3Smrg const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.textureLoad", overload); 6547ec681f3Smrg if (!func) 6557ec681f3Smrg return NULL; 6567ec681f3Smrg const struct dxil_type *int_type = dxil_module_get_int_type(&ctx->mod, 32); 6577ec681f3Smrg const struct dxil_value *int_undef = dxil_module_get_undef(&ctx->mod, int_type); 6587ec681f3Smrg 6597ec681f3Smrg const struct dxil_value *opcode = dxil_module_get_int32_const(&ctx->mod, 6607ec681f3Smrg DXIL_INTR_TEXTURE_LOAD); 6617ec681f3Smrg const struct dxil_value *args[] = { opcode, handle, 6627ec681f3Smrg /*lod_or_sample*/ int_undef, 6637ec681f3Smrg coord[0], coord[1], coord[2], 6647ec681f3Smrg /* offsets */ int_undef, int_undef, int_undef}; 6657ec681f3Smrg 6667ec681f3Smrg return dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args)); 6677ec681f3Smrg} 6687ec681f3Smrg 6697ec681f3Smrgstatic bool 6707ec681f3Smrgemit_texturestore_call(struct ntd_context *ctx, 6717ec681f3Smrg const struct dxil_value *handle, 6727ec681f3Smrg const struct dxil_value *coord[3], 6737ec681f3Smrg const struct dxil_value *value[4], 6747ec681f3Smrg const struct dxil_value *write_mask, 6757ec681f3Smrg enum overload_type overload) 6767ec681f3Smrg{ 6777ec681f3Smrg const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.textureStore", overload); 6787ec681f3Smrg 6797ec681f3Smrg if (!func) 6807ec681f3Smrg return false; 6817ec681f3Smrg 6827ec681f3Smrg const struct dxil_value *opcode = dxil_module_get_int32_const(&ctx->mod, 6837ec681f3Smrg DXIL_INTR_TEXTURE_STORE); 6847ec681f3Smrg const struct dxil_value *args[] = { 6857ec681f3Smrg opcode, handle, coord[0], coord[1], coord[2], 6867ec681f3Smrg value[0], value[1], value[2], value[3], 6877ec681f3Smrg write_mask 6887ec681f3Smrg }; 6897ec681f3Smrg 6907ec681f3Smrg return dxil_emit_call_void(&ctx->mod, func, 6917ec681f3Smrg args, ARRAY_SIZE(args)); 6927ec681f3Smrg} 6937ec681f3Smrg 6947ec681f3Smrgstatic const struct dxil_value * 6957ec681f3Smrgemit_atomic_binop(struct ntd_context *ctx, 6967ec681f3Smrg const struct dxil_value *handle, 6977ec681f3Smrg enum dxil_atomic_op atomic_op, 6987ec681f3Smrg const struct dxil_value *coord[3], 6997ec681f3Smrg const struct dxil_value *value) 7007ec681f3Smrg{ 7017ec681f3Smrg const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.atomicBinOp", DXIL_I32); 7027ec681f3Smrg 7037ec681f3Smrg if (!func) 7047ec681f3Smrg return false; 7057ec681f3Smrg 7067ec681f3Smrg const struct dxil_value *opcode = 7077ec681f3Smrg dxil_module_get_int32_const(&ctx->mod, DXIL_INTR_ATOMIC_BINOP); 7087ec681f3Smrg const struct dxil_value *atomic_op_value = 7097ec681f3Smrg dxil_module_get_int32_const(&ctx->mod, atomic_op); 7107ec681f3Smrg const struct dxil_value *args[] = { 7117ec681f3Smrg opcode, handle, atomic_op_value, 7127ec681f3Smrg coord[0], coord[1], coord[2], value 7137ec681f3Smrg }; 7147ec681f3Smrg 7157ec681f3Smrg return dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args)); 7167ec681f3Smrg} 7177ec681f3Smrg 7187ec681f3Smrgstatic const struct dxil_value * 7197ec681f3Smrgemit_atomic_cmpxchg(struct ntd_context *ctx, 7207ec681f3Smrg const struct dxil_value *handle, 7217ec681f3Smrg const struct dxil_value *coord[3], 7227ec681f3Smrg const struct dxil_value *cmpval, 7237ec681f3Smrg const struct dxil_value *newval) 7247ec681f3Smrg{ 7257ec681f3Smrg const struct dxil_func *func = 7267ec681f3Smrg dxil_get_function(&ctx->mod, "dx.op.atomicCompareExchange", DXIL_I32); 7277ec681f3Smrg 7287ec681f3Smrg if (!func) 7297ec681f3Smrg return false; 7307ec681f3Smrg 7317ec681f3Smrg const struct dxil_value *opcode = 7327ec681f3Smrg dxil_module_get_int32_const(&ctx->mod, DXIL_INTR_ATOMIC_CMPXCHG); 7337ec681f3Smrg const struct dxil_value *args[] = { 7347ec681f3Smrg opcode, handle, coord[0], coord[1], coord[2], cmpval, newval 7357ec681f3Smrg }; 7367ec681f3Smrg 7377ec681f3Smrg return dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args)); 7387ec681f3Smrg} 7397ec681f3Smrg 7407ec681f3Smrgstatic const struct dxil_value * 7417ec681f3Smrgemit_createhandle_call(struct ntd_context *ctx, 7427ec681f3Smrg enum dxil_resource_class resource_class, 7437ec681f3Smrg unsigned resource_range_id, 7447ec681f3Smrg const struct dxil_value *resource_range_index, 7457ec681f3Smrg bool non_uniform_resource_index) 7467ec681f3Smrg{ 7477ec681f3Smrg const struct dxil_value *opcode = dxil_module_get_int32_const(&ctx->mod, DXIL_INTR_CREATE_HANDLE); 7487ec681f3Smrg const struct dxil_value *resource_class_value = dxil_module_get_int8_const(&ctx->mod, resource_class); 7497ec681f3Smrg const struct dxil_value *resource_range_id_value = dxil_module_get_int32_const(&ctx->mod, resource_range_id); 7507ec681f3Smrg const struct dxil_value *non_uniform_resource_index_value = dxil_module_get_int1_const(&ctx->mod, non_uniform_resource_index); 7517ec681f3Smrg if (!opcode || !resource_class_value || !resource_range_id_value || 7527ec681f3Smrg !non_uniform_resource_index_value) 7537ec681f3Smrg return NULL; 7547ec681f3Smrg 7557ec681f3Smrg const struct dxil_value *args[] = { 7567ec681f3Smrg opcode, 7577ec681f3Smrg resource_class_value, 7587ec681f3Smrg resource_range_id_value, 7597ec681f3Smrg resource_range_index, 7607ec681f3Smrg non_uniform_resource_index_value 7617ec681f3Smrg }; 7627ec681f3Smrg 7637ec681f3Smrg const struct dxil_func *func = 7647ec681f3Smrg dxil_get_function(&ctx->mod, "dx.op.createHandle", DXIL_NONE); 7657ec681f3Smrg 7667ec681f3Smrg if (!func) 7677ec681f3Smrg return NULL; 7687ec681f3Smrg 7697ec681f3Smrg return dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args)); 7707ec681f3Smrg} 7717ec681f3Smrg 7727ec681f3Smrgstatic const struct dxil_value * 7737ec681f3Smrgemit_createhandle_call_const_index(struct ntd_context *ctx, 7747ec681f3Smrg enum dxil_resource_class resource_class, 7757ec681f3Smrg unsigned resource_range_id, 7767ec681f3Smrg unsigned resource_range_index, 7777ec681f3Smrg bool non_uniform_resource_index) 7787ec681f3Smrg{ 7797ec681f3Smrg 7807ec681f3Smrg const struct dxil_value *resource_range_index_value = dxil_module_get_int32_const(&ctx->mod, resource_range_index); 7817ec681f3Smrg if (!resource_range_index_value) 7827ec681f3Smrg return NULL; 7837ec681f3Smrg 7847ec681f3Smrg return emit_createhandle_call(ctx, resource_class, resource_range_id, 7857ec681f3Smrg resource_range_index_value, 7867ec681f3Smrg non_uniform_resource_index); 7877ec681f3Smrg} 7887ec681f3Smrg 7897ec681f3Smrgstatic void 7907ec681f3Smrgadd_resource(struct ntd_context *ctx, enum dxil_resource_type type, 7917ec681f3Smrg const resource_array_layout *layout) 7927ec681f3Smrg{ 7937ec681f3Smrg struct dxil_resource *resource = util_dynarray_grow(&ctx->resources, struct dxil_resource, 1); 7947ec681f3Smrg resource->resource_type = type; 7957ec681f3Smrg resource->space = layout->space; 7967ec681f3Smrg resource->lower_bound = layout->binding; 7977ec681f3Smrg if (layout->size == 0 || (uint64_t)layout->size + layout->binding >= UINT_MAX) 7987ec681f3Smrg resource->upper_bound = UINT_MAX; 7997ec681f3Smrg else 8007ec681f3Smrg resource->upper_bound = layout->binding + layout->size - 1; 8017ec681f3Smrg} 8027ec681f3Smrg 8037ec681f3Smrgstatic unsigned 8047ec681f3Smrgget_resource_id(struct ntd_context *ctx, enum dxil_resource_class class, 8057ec681f3Smrg unsigned space, unsigned binding) 8067ec681f3Smrg{ 8077ec681f3Smrg unsigned offset = 0; 8087ec681f3Smrg unsigned count = 0; 8097ec681f3Smrg 8107ec681f3Smrg unsigned num_srvs = util_dynarray_num_elements(&ctx->srv_metadata_nodes, const struct dxil_mdnode *); 8117ec681f3Smrg unsigned num_uavs = util_dynarray_num_elements(&ctx->uav_metadata_nodes, const struct dxil_mdnode *); 8127ec681f3Smrg unsigned num_cbvs = util_dynarray_num_elements(&ctx->cbv_metadata_nodes, const struct dxil_mdnode *); 8137ec681f3Smrg unsigned num_samplers = util_dynarray_num_elements(&ctx->sampler_metadata_nodes, const struct dxil_mdnode *); 8147ec681f3Smrg 8157ec681f3Smrg switch (class) { 8167ec681f3Smrg case DXIL_RESOURCE_CLASS_UAV: 8177ec681f3Smrg offset = num_srvs + num_samplers + num_cbvs; 8187ec681f3Smrg count = num_uavs; 8197ec681f3Smrg break; 8207ec681f3Smrg case DXIL_RESOURCE_CLASS_SRV: 8217ec681f3Smrg offset = num_samplers + num_cbvs; 8227ec681f3Smrg count = num_srvs; 8237ec681f3Smrg break; 8247ec681f3Smrg case DXIL_RESOURCE_CLASS_SAMPLER: 8257ec681f3Smrg offset = num_cbvs; 8267ec681f3Smrg count = num_samplers; 8277ec681f3Smrg break; 8287ec681f3Smrg case DXIL_RESOURCE_CLASS_CBV: 8297ec681f3Smrg offset = 0; 8307ec681f3Smrg count = num_cbvs; 8317ec681f3Smrg break; 8327ec681f3Smrg } 8337ec681f3Smrg 8347ec681f3Smrg assert(offset + count <= util_dynarray_num_elements(&ctx->resources, struct dxil_resource)); 8357ec681f3Smrg for (unsigned i = offset; i < offset + count; ++i) { 8367ec681f3Smrg const struct dxil_resource *resource = util_dynarray_element(&ctx->resources, struct dxil_resource, i); 8377ec681f3Smrg if (resource->space == space && 8387ec681f3Smrg resource->lower_bound <= binding && 8397ec681f3Smrg resource->upper_bound >= binding) { 8407ec681f3Smrg return i - offset; 8417ec681f3Smrg } 8427ec681f3Smrg } 8437ec681f3Smrg 8447ec681f3Smrg unreachable("Resource access for undeclared range"); 8457ec681f3Smrg return 0; 8467ec681f3Smrg} 8477ec681f3Smrg 8487ec681f3Smrgstatic bool 8497ec681f3Smrgemit_srv(struct ntd_context *ctx, nir_variable *var, unsigned count) 8507ec681f3Smrg{ 8517ec681f3Smrg unsigned id = util_dynarray_num_elements(&ctx->srv_metadata_nodes, const struct dxil_mdnode *); 8527ec681f3Smrg unsigned binding = var->data.binding; 8537ec681f3Smrg resource_array_layout layout = {id, binding, count, var->data.descriptor_set}; 8547ec681f3Smrg 8557ec681f3Smrg enum dxil_component_type comp_type; 8567ec681f3Smrg enum dxil_resource_kind res_kind; 8577ec681f3Smrg enum dxil_resource_type res_type; 8587ec681f3Smrg if (var->data.mode == nir_var_mem_ssbo) { 8597ec681f3Smrg comp_type = DXIL_COMP_TYPE_INVALID; 8607ec681f3Smrg res_kind = DXIL_RESOURCE_KIND_RAW_BUFFER; 8617ec681f3Smrg res_type = DXIL_RES_SRV_RAW; 8627ec681f3Smrg } else { 8637ec681f3Smrg comp_type = dxil_get_comp_type(var->type); 8647ec681f3Smrg res_kind = dxil_get_resource_kind(var->type); 8657ec681f3Smrg res_type = DXIL_RES_SRV_TYPED; 8667ec681f3Smrg } 8677ec681f3Smrg const struct dxil_type *res_type_as_type = dxil_module_get_res_type(&ctx->mod, res_kind, comp_type, false /* readwrite */); 8687ec681f3Smrg const struct dxil_mdnode *srv_meta = emit_srv_metadata(&ctx->mod, res_type_as_type, var->name, 8697ec681f3Smrg &layout, comp_type, res_kind); 8707ec681f3Smrg 8717ec681f3Smrg if (!srv_meta) 8727ec681f3Smrg return false; 8737ec681f3Smrg 8747ec681f3Smrg util_dynarray_append(&ctx->srv_metadata_nodes, const struct dxil_mdnode *, srv_meta); 8757ec681f3Smrg add_resource(ctx, res_type, &layout); 8767ec681f3Smrg if (res_type == DXIL_RES_SRV_RAW) 8777ec681f3Smrg ctx->mod.raw_and_structured_buffers = true; 8787ec681f3Smrg 8797ec681f3Smrg if (!ctx->opts->vulkan_environment) { 8807ec681f3Smrg for (unsigned i = 0; i < count; ++i) { 8817ec681f3Smrg const struct dxil_value *handle = 8827ec681f3Smrg emit_createhandle_call_const_index(ctx, DXIL_RESOURCE_CLASS_SRV, 8837ec681f3Smrg id, binding + i, false); 8847ec681f3Smrg if (!handle) 8857ec681f3Smrg return false; 8867ec681f3Smrg 8877ec681f3Smrg int idx = var->data.binding + i; 8887ec681f3Smrg ctx->srv_handles[idx] = handle; 8897ec681f3Smrg } 8907ec681f3Smrg } 8917ec681f3Smrg 8927ec681f3Smrg return true; 8937ec681f3Smrg} 8947ec681f3Smrg 8957ec681f3Smrgstatic bool 8967ec681f3Smrgemit_globals(struct ntd_context *ctx, unsigned size) 8977ec681f3Smrg{ 8987ec681f3Smrg nir_foreach_variable_with_modes(var, ctx->shader, nir_var_mem_ssbo) 8997ec681f3Smrg size++; 9007ec681f3Smrg 9017ec681f3Smrg if (!size) 9027ec681f3Smrg return true; 9037ec681f3Smrg 9047ec681f3Smrg const struct dxil_type *struct_type = dxil_module_get_res_type(&ctx->mod, 9057ec681f3Smrg DXIL_RESOURCE_KIND_RAW_BUFFER, DXIL_COMP_TYPE_INVALID, true /* readwrite */); 9067ec681f3Smrg if (!struct_type) 9077ec681f3Smrg return false; 9087ec681f3Smrg 9097ec681f3Smrg const struct dxil_type *array_type = 9107ec681f3Smrg dxil_module_get_array_type(&ctx->mod, struct_type, size); 9117ec681f3Smrg if (!array_type) 9127ec681f3Smrg return false; 9137ec681f3Smrg 9147ec681f3Smrg resource_array_layout layout = {0, 0, size, 0}; 9157ec681f3Smrg const struct dxil_mdnode *uav_meta = 9167ec681f3Smrg emit_uav_metadata(&ctx->mod, array_type, 9177ec681f3Smrg "globals", &layout, 9187ec681f3Smrg DXIL_COMP_TYPE_INVALID, 9197ec681f3Smrg DXIL_RESOURCE_KIND_RAW_BUFFER); 9207ec681f3Smrg if (!uav_meta) 9217ec681f3Smrg return false; 9227ec681f3Smrg 9237ec681f3Smrg util_dynarray_append(&ctx->uav_metadata_nodes, const struct dxil_mdnode *, uav_meta); 9247ec681f3Smrg if (util_dynarray_num_elements(&ctx->uav_metadata_nodes, const struct dxil_mdnode *) > 8) 9257ec681f3Smrg ctx->mod.feats.use_64uavs = 1; 9267ec681f3Smrg /* Handles to UAVs used for kernel globals are created on-demand */ 9277ec681f3Smrg add_resource(ctx, DXIL_RES_UAV_RAW, &layout); 9287ec681f3Smrg ctx->mod.raw_and_structured_buffers = true; 9297ec681f3Smrg return true; 9307ec681f3Smrg} 9317ec681f3Smrg 9327ec681f3Smrgstatic bool 9337ec681f3Smrgemit_uav(struct ntd_context *ctx, unsigned binding, unsigned space, unsigned count, 9347ec681f3Smrg enum dxil_component_type comp_type, enum dxil_resource_kind res_kind, const char *name) 9357ec681f3Smrg{ 9367ec681f3Smrg unsigned id = util_dynarray_num_elements(&ctx->uav_metadata_nodes, const struct dxil_mdnode *); 9377ec681f3Smrg resource_array_layout layout = { id, binding, count, space }; 9387ec681f3Smrg 9397ec681f3Smrg const struct dxil_type *res_type = dxil_module_get_res_type(&ctx->mod, res_kind, comp_type, true /* readwrite */); 9407ec681f3Smrg const struct dxil_mdnode *uav_meta = emit_uav_metadata(&ctx->mod, res_type, name, 9417ec681f3Smrg &layout, comp_type, res_kind); 9427ec681f3Smrg 9437ec681f3Smrg if (!uav_meta) 9447ec681f3Smrg return false; 9457ec681f3Smrg 9467ec681f3Smrg util_dynarray_append(&ctx->uav_metadata_nodes, const struct dxil_mdnode *, uav_meta); 9477ec681f3Smrg if (util_dynarray_num_elements(&ctx->uav_metadata_nodes, const struct dxil_mdnode *) > 8) 9487ec681f3Smrg ctx->mod.feats.use_64uavs = 1; 9497ec681f3Smrg 9507ec681f3Smrg add_resource(ctx, res_kind == DXIL_RESOURCE_KIND_RAW_BUFFER ? DXIL_RES_UAV_RAW : DXIL_RES_UAV_TYPED, &layout); 9517ec681f3Smrg if (res_kind == DXIL_RESOURCE_KIND_RAW_BUFFER) 9527ec681f3Smrg ctx->mod.raw_and_structured_buffers = true; 9537ec681f3Smrg 9547ec681f3Smrg if (!ctx->opts->vulkan_environment) { 9557ec681f3Smrg for (unsigned i = 0; i < count; ++i) { 9567ec681f3Smrg const struct dxil_value *handle = emit_createhandle_call_const_index(ctx, DXIL_RESOURCE_CLASS_UAV, 9577ec681f3Smrg id, binding + i, false); 9587ec681f3Smrg if (!handle) 9597ec681f3Smrg return false; 9607ec681f3Smrg 9617ec681f3Smrg ctx->uav_handles[binding + i] = handle; 9627ec681f3Smrg } 9637ec681f3Smrg } 9647ec681f3Smrg 9657ec681f3Smrg return true; 9667ec681f3Smrg} 9677ec681f3Smrg 9687ec681f3Smrgstatic bool 9697ec681f3Smrgemit_uav_var(struct ntd_context *ctx, nir_variable *var, unsigned count) 9707ec681f3Smrg{ 9717ec681f3Smrg unsigned binding = var->data.binding; 9727ec681f3Smrg unsigned space = var->data.descriptor_set; 9737ec681f3Smrg enum dxil_component_type comp_type = dxil_get_comp_type(var->type); 9747ec681f3Smrg enum dxil_resource_kind res_kind = dxil_get_resource_kind(var->type); 9757ec681f3Smrg const char *name = var->name; 9767ec681f3Smrg 9777ec681f3Smrg return emit_uav(ctx, binding, space, count, comp_type, res_kind, name); 9787ec681f3Smrg} 9797ec681f3Smrg 9807ec681f3Smrgstatic unsigned get_dword_size(const struct glsl_type *type) 9817ec681f3Smrg{ 9827ec681f3Smrg if (glsl_type_is_array(type)) { 9837ec681f3Smrg type = glsl_without_array(type); 9847ec681f3Smrg } 9857ec681f3Smrg assert(glsl_type_is_struct(type) || glsl_type_is_interface(type)); 9867ec681f3Smrg return glsl_get_explicit_size(type, false); 9877ec681f3Smrg} 9887ec681f3Smrg 9897ec681f3Smrgstatic void 9907ec681f3Smrgvar_fill_const_array_with_vector_or_scalar(struct ntd_context *ctx, 9917ec681f3Smrg const struct nir_constant *c, 9927ec681f3Smrg const struct glsl_type *type, 9937ec681f3Smrg void *const_vals, 9947ec681f3Smrg unsigned int offset) 9957ec681f3Smrg{ 9967ec681f3Smrg assert(glsl_type_is_vector_or_scalar(type)); 9977ec681f3Smrg unsigned int components = glsl_get_vector_elements(type); 9987ec681f3Smrg unsigned bit_size = glsl_get_bit_size(type); 9997ec681f3Smrg unsigned int increment = bit_size / 8; 10007ec681f3Smrg 10017ec681f3Smrg for (unsigned int comp = 0; comp < components; comp++) { 10027ec681f3Smrg uint8_t *dst = (uint8_t *)const_vals + offset; 10037ec681f3Smrg 10047ec681f3Smrg switch (bit_size) { 10057ec681f3Smrg case 64: 10067ec681f3Smrg memcpy(dst, &c->values[comp].u64, sizeof(c->values[0].u64)); 10077ec681f3Smrg break; 10087ec681f3Smrg case 32: 10097ec681f3Smrg memcpy(dst, &c->values[comp].u32, sizeof(c->values[0].u32)); 10107ec681f3Smrg break; 10117ec681f3Smrg case 16: 10127ec681f3Smrg memcpy(dst, &c->values[comp].u16, sizeof(c->values[0].u16)); 10137ec681f3Smrg break; 10147ec681f3Smrg case 8: 10157ec681f3Smrg assert(glsl_base_type_is_integer(glsl_get_base_type(type))); 10167ec681f3Smrg memcpy(dst, &c->values[comp].u8, sizeof(c->values[0].u8)); 10177ec681f3Smrg break; 10187ec681f3Smrg default: 10197ec681f3Smrg unreachable("unexpeted bit-size"); 10207ec681f3Smrg } 10217ec681f3Smrg 10227ec681f3Smrg offset += increment; 10237ec681f3Smrg } 10247ec681f3Smrg} 10257ec681f3Smrg 10267ec681f3Smrgstatic void 10277ec681f3Smrgvar_fill_const_array(struct ntd_context *ctx, const struct nir_constant *c, 10287ec681f3Smrg const struct glsl_type *type, void *const_vals, 10297ec681f3Smrg unsigned int offset) 10307ec681f3Smrg{ 10317ec681f3Smrg assert(!glsl_type_is_interface(type)); 10327ec681f3Smrg 10337ec681f3Smrg if (glsl_type_is_vector_or_scalar(type)) { 10347ec681f3Smrg var_fill_const_array_with_vector_or_scalar(ctx, c, type, 10357ec681f3Smrg const_vals, 10367ec681f3Smrg offset); 10377ec681f3Smrg } else if (glsl_type_is_array(type)) { 10387ec681f3Smrg assert(!glsl_type_is_unsized_array(type)); 10397ec681f3Smrg const struct glsl_type *without = glsl_without_array(type); 10407ec681f3Smrg unsigned stride = glsl_get_explicit_stride(without); 10417ec681f3Smrg 10427ec681f3Smrg for (unsigned elt = 0; elt < glsl_get_length(type); elt++) { 10437ec681f3Smrg var_fill_const_array(ctx, c->elements[elt], without, 10447ec681f3Smrg const_vals, offset + (elt * stride)); 10457ec681f3Smrg offset += glsl_get_cl_size(without); 10467ec681f3Smrg } 10477ec681f3Smrg } else if (glsl_type_is_struct(type)) { 10487ec681f3Smrg for (unsigned int elt = 0; elt < glsl_get_length(type); elt++) { 10497ec681f3Smrg const struct glsl_type *elt_type = glsl_get_struct_field(type, elt); 10507ec681f3Smrg unsigned field_offset = glsl_get_struct_field_offset(type, elt); 10517ec681f3Smrg 10527ec681f3Smrg var_fill_const_array(ctx, c->elements[elt], 10537ec681f3Smrg elt_type, const_vals, 10547ec681f3Smrg offset + field_offset); 10557ec681f3Smrg } 10567ec681f3Smrg } else 10577ec681f3Smrg unreachable("unknown GLSL type in var_fill_const_array"); 10587ec681f3Smrg} 10597ec681f3Smrg 10607ec681f3Smrgstatic bool 10617ec681f3Smrgemit_global_consts(struct ntd_context *ctx) 10627ec681f3Smrg{ 10637ec681f3Smrg nir_foreach_variable_with_modes(var, ctx->shader, nir_var_shader_temp) { 10647ec681f3Smrg assert(var->constant_initializer); 10657ec681f3Smrg 10667ec681f3Smrg unsigned int num_members = DIV_ROUND_UP(glsl_get_cl_size(var->type), 4); 10677ec681f3Smrg uint32_t *const_ints = ralloc_array(ctx->ralloc_ctx, uint32_t, num_members); 10687ec681f3Smrg var_fill_const_array(ctx, var->constant_initializer, var->type, 10697ec681f3Smrg const_ints, 0); 10707ec681f3Smrg const struct dxil_value **const_vals = 10717ec681f3Smrg ralloc_array(ctx->ralloc_ctx, const struct dxil_value *, num_members); 10727ec681f3Smrg if (!const_vals) 10737ec681f3Smrg return false; 10747ec681f3Smrg for (int i = 0; i < num_members; i++) 10757ec681f3Smrg const_vals[i] = dxil_module_get_int32_const(&ctx->mod, const_ints[i]); 10767ec681f3Smrg 10777ec681f3Smrg const struct dxil_type *elt_type = dxil_module_get_int_type(&ctx->mod, 32); 10787ec681f3Smrg if (!elt_type) 10797ec681f3Smrg return false; 10807ec681f3Smrg const struct dxil_type *type = 10817ec681f3Smrg dxil_module_get_array_type(&ctx->mod, elt_type, num_members); 10827ec681f3Smrg if (!type) 10837ec681f3Smrg return false; 10847ec681f3Smrg const struct dxil_value *agg_vals = 10857ec681f3Smrg dxil_module_get_array_const(&ctx->mod, type, const_vals); 10867ec681f3Smrg if (!agg_vals) 10877ec681f3Smrg return false; 10887ec681f3Smrg 10897ec681f3Smrg const struct dxil_value *gvar = dxil_add_global_ptr_var(&ctx->mod, var->name, type, 10907ec681f3Smrg DXIL_AS_DEFAULT, 4, 10917ec681f3Smrg agg_vals); 10927ec681f3Smrg if (!gvar) 10937ec681f3Smrg return false; 10947ec681f3Smrg 10957ec681f3Smrg if (!_mesa_hash_table_insert(ctx->consts, var, (void *)gvar)) 10967ec681f3Smrg return false; 10977ec681f3Smrg } 10987ec681f3Smrg 10997ec681f3Smrg return true; 11007ec681f3Smrg} 11017ec681f3Smrg 11027ec681f3Smrgstatic bool 11037ec681f3Smrgemit_cbv(struct ntd_context *ctx, unsigned binding, unsigned space, 11047ec681f3Smrg unsigned size, unsigned count, char *name) 11057ec681f3Smrg{ 11067ec681f3Smrg unsigned idx = util_dynarray_num_elements(&ctx->cbv_metadata_nodes, const struct dxil_mdnode *); 11077ec681f3Smrg 11087ec681f3Smrg const struct dxil_type *float32 = dxil_module_get_float_type(&ctx->mod, 32); 11097ec681f3Smrg const struct dxil_type *array_type = dxil_module_get_array_type(&ctx->mod, float32, size); 11107ec681f3Smrg const struct dxil_type *buffer_type = dxil_module_get_struct_type(&ctx->mod, name, 11117ec681f3Smrg &array_type, 1); 11127ec681f3Smrg const struct dxil_type *final_type = count != 1 ? dxil_module_get_array_type(&ctx->mod, buffer_type, count) : buffer_type; 11137ec681f3Smrg resource_array_layout layout = {idx, binding, count, space}; 11147ec681f3Smrg const struct dxil_mdnode *cbv_meta = emit_cbv_metadata(&ctx->mod, final_type, 11157ec681f3Smrg name, &layout, 4 * size); 11167ec681f3Smrg 11177ec681f3Smrg if (!cbv_meta) 11187ec681f3Smrg return false; 11197ec681f3Smrg 11207ec681f3Smrg util_dynarray_append(&ctx->cbv_metadata_nodes, const struct dxil_mdnode *, cbv_meta); 11217ec681f3Smrg add_resource(ctx, DXIL_RES_CBV, &layout); 11227ec681f3Smrg 11237ec681f3Smrg if (!ctx->opts->vulkan_environment) { 11247ec681f3Smrg for (unsigned i = 0; i < count; ++i) { 11257ec681f3Smrg const struct dxil_value *handle = emit_createhandle_call_const_index(ctx, DXIL_RESOURCE_CLASS_CBV, 11267ec681f3Smrg idx, binding + i, false); 11277ec681f3Smrg if (!handle) 11287ec681f3Smrg return false; 11297ec681f3Smrg 11307ec681f3Smrg assert(!ctx->cbv_handles[binding + i]); 11317ec681f3Smrg ctx->cbv_handles[binding + i] = handle; 11327ec681f3Smrg } 11337ec681f3Smrg } 11347ec681f3Smrg 11357ec681f3Smrg return true; 11367ec681f3Smrg} 11377ec681f3Smrg 11387ec681f3Smrgstatic bool 11397ec681f3Smrgemit_ubo_var(struct ntd_context *ctx, nir_variable *var) 11407ec681f3Smrg{ 11417ec681f3Smrg unsigned count = 1; 11427ec681f3Smrg if (glsl_type_is_array(var->type)) 11437ec681f3Smrg count = glsl_get_length(var->type); 11447ec681f3Smrg return emit_cbv(ctx, var->data.binding, var->data.descriptor_set, get_dword_size(var->type), count, var->name); 11457ec681f3Smrg} 11467ec681f3Smrg 11477ec681f3Smrgstatic bool 11487ec681f3Smrgemit_sampler(struct ntd_context *ctx, nir_variable *var, unsigned count) 11497ec681f3Smrg{ 11507ec681f3Smrg unsigned id = util_dynarray_num_elements(&ctx->sampler_metadata_nodes, const struct dxil_mdnode *); 11517ec681f3Smrg unsigned binding = var->data.binding; 11527ec681f3Smrg resource_array_layout layout = {id, binding, count, var->data.descriptor_set}; 11537ec681f3Smrg const struct dxil_type *int32_type = dxil_module_get_int_type(&ctx->mod, 32); 11547ec681f3Smrg const struct dxil_type *sampler_type = dxil_module_get_struct_type(&ctx->mod, "struct.SamplerState", &int32_type, 1); 11557ec681f3Smrg const struct dxil_mdnode *sampler_meta = emit_sampler_metadata(&ctx->mod, sampler_type, var, &layout); 11567ec681f3Smrg 11577ec681f3Smrg if (!sampler_meta) 11587ec681f3Smrg return false; 11597ec681f3Smrg 11607ec681f3Smrg util_dynarray_append(&ctx->sampler_metadata_nodes, const struct dxil_mdnode *, sampler_meta); 11617ec681f3Smrg add_resource(ctx, DXIL_RES_SAMPLER, &layout); 11627ec681f3Smrg 11637ec681f3Smrg if (!ctx->opts->vulkan_environment) { 11647ec681f3Smrg for (unsigned i = 0; i < count; ++i) { 11657ec681f3Smrg const struct dxil_value *handle = 11667ec681f3Smrg emit_createhandle_call_const_index(ctx, DXIL_RESOURCE_CLASS_SAMPLER, 11677ec681f3Smrg id, binding + i, false); 11687ec681f3Smrg if (!handle) 11697ec681f3Smrg return false; 11707ec681f3Smrg 11717ec681f3Smrg unsigned idx = var->data.binding + i; 11727ec681f3Smrg ctx->sampler_handles[idx] = handle; 11737ec681f3Smrg } 11747ec681f3Smrg } 11757ec681f3Smrg 11767ec681f3Smrg return true; 11777ec681f3Smrg} 11787ec681f3Smrg 11797ec681f3Smrgstatic const struct dxil_mdnode * 11807ec681f3Smrgemit_gs_state(struct ntd_context *ctx) 11817ec681f3Smrg{ 11827ec681f3Smrg const struct dxil_mdnode *gs_state_nodes[5]; 11837ec681f3Smrg const nir_shader *s = ctx->shader; 11847ec681f3Smrg 11857ec681f3Smrg gs_state_nodes[0] = dxil_get_metadata_int32(&ctx->mod, dxil_get_input_primitive(s->info.gs.input_primitive)); 11867ec681f3Smrg gs_state_nodes[1] = dxil_get_metadata_int32(&ctx->mod, s->info.gs.vertices_out); 11877ec681f3Smrg gs_state_nodes[2] = dxil_get_metadata_int32(&ctx->mod, s->info.gs.active_stream_mask); 11887ec681f3Smrg gs_state_nodes[3] = dxil_get_metadata_int32(&ctx->mod, dxil_get_primitive_topology(s->info.gs.output_primitive)); 11897ec681f3Smrg gs_state_nodes[4] = dxil_get_metadata_int32(&ctx->mod, s->info.gs.invocations); 11907ec681f3Smrg 11917ec681f3Smrg for (unsigned i = 0; i < ARRAY_SIZE(gs_state_nodes); ++i) { 11927ec681f3Smrg if (!gs_state_nodes[i]) 11937ec681f3Smrg return NULL; 11947ec681f3Smrg } 11957ec681f3Smrg 11967ec681f3Smrg return dxil_get_metadata_node(&ctx->mod, gs_state_nodes, ARRAY_SIZE(gs_state_nodes)); 11977ec681f3Smrg} 11987ec681f3Smrg 11997ec681f3Smrgstatic const struct dxil_mdnode * 12007ec681f3Smrgemit_threads(struct ntd_context *ctx) 12017ec681f3Smrg{ 12027ec681f3Smrg const nir_shader *s = ctx->shader; 12037ec681f3Smrg const struct dxil_mdnode *threads_x = dxil_get_metadata_int32(&ctx->mod, MAX2(s->info.workgroup_size[0], 1)); 12047ec681f3Smrg const struct dxil_mdnode *threads_y = dxil_get_metadata_int32(&ctx->mod, MAX2(s->info.workgroup_size[1], 1)); 12057ec681f3Smrg const struct dxil_mdnode *threads_z = dxil_get_metadata_int32(&ctx->mod, MAX2(s->info.workgroup_size[2], 1)); 12067ec681f3Smrg if (!threads_x || !threads_y || !threads_z) 12077ec681f3Smrg return false; 12087ec681f3Smrg 12097ec681f3Smrg const struct dxil_mdnode *threads_nodes[] = { threads_x, threads_y, threads_z }; 12107ec681f3Smrg return dxil_get_metadata_node(&ctx->mod, threads_nodes, ARRAY_SIZE(threads_nodes)); 12117ec681f3Smrg} 12127ec681f3Smrg 12137ec681f3Smrgstatic int64_t 12147ec681f3Smrgget_module_flags(struct ntd_context *ctx) 12157ec681f3Smrg{ 12167ec681f3Smrg /* See the DXIL documentation for the definition of these flags: 12177ec681f3Smrg * 12187ec681f3Smrg * https://github.com/Microsoft/DirectXShaderCompiler/blob/master/docs/DXIL.rst#shader-flags 12197ec681f3Smrg */ 12207ec681f3Smrg 12217ec681f3Smrg uint64_t flags = 0; 12227ec681f3Smrg if (ctx->mod.feats.doubles) 12237ec681f3Smrg flags |= (1 << 2); 12247ec681f3Smrg if (ctx->mod.raw_and_structured_buffers) 12257ec681f3Smrg flags |= (1 << 4); 12267ec681f3Smrg if (ctx->mod.feats.min_precision) 12277ec681f3Smrg flags |= (1 << 5); 12287ec681f3Smrg if (ctx->mod.feats.dx11_1_double_extensions) 12297ec681f3Smrg flags |= (1 << 6); 12307ec681f3Smrg if (ctx->mod.feats.inner_coverage) 12317ec681f3Smrg flags |= (1 << 10); 12327ec681f3Smrg if (ctx->mod.feats.typed_uav_load_additional_formats) 12337ec681f3Smrg flags |= (1 << 13); 12347ec681f3Smrg if (ctx->mod.feats.use_64uavs) 12357ec681f3Smrg flags |= (1 << 15); 12367ec681f3Smrg if (ctx->mod.feats.cs_4x_raw_sb) 12377ec681f3Smrg flags |= (1 << 17); 12387ec681f3Smrg if (ctx->mod.feats.wave_ops) 12397ec681f3Smrg flags |= (1 << 19); 12407ec681f3Smrg if (ctx->mod.feats.int64_ops) 12417ec681f3Smrg flags |= (1 << 20); 12427ec681f3Smrg if (ctx->mod.feats.stencil_ref) 12437ec681f3Smrg flags |= (1 << 11); 12447ec681f3Smrg if (ctx->mod.feats.native_low_precision) 12457ec681f3Smrg flags |= (1 << 23) | (1 << 5); 12467ec681f3Smrg 12477ec681f3Smrg if (ctx->opts->disable_math_refactoring) 12487ec681f3Smrg flags |= (1 << 1); 12497ec681f3Smrg 12507ec681f3Smrg return flags; 12517ec681f3Smrg} 12527ec681f3Smrg 12537ec681f3Smrgstatic const struct dxil_mdnode * 12547ec681f3Smrgemit_entrypoint(struct ntd_context *ctx, 12557ec681f3Smrg const struct dxil_func *func, const char *name, 12567ec681f3Smrg const struct dxil_mdnode *signatures, 12577ec681f3Smrg const struct dxil_mdnode *resources, 12587ec681f3Smrg const struct dxil_mdnode *shader_props) 12597ec681f3Smrg{ 12607ec681f3Smrg const struct dxil_mdnode *func_md = dxil_get_metadata_func(&ctx->mod, func); 12617ec681f3Smrg const struct dxil_mdnode *name_md = dxil_get_metadata_string(&ctx->mod, name); 12627ec681f3Smrg const struct dxil_mdnode *nodes[] = { 12637ec681f3Smrg func_md, 12647ec681f3Smrg name_md, 12657ec681f3Smrg signatures, 12667ec681f3Smrg resources, 12677ec681f3Smrg shader_props 12687ec681f3Smrg }; 12697ec681f3Smrg return dxil_get_metadata_node(&ctx->mod, nodes, 12707ec681f3Smrg ARRAY_SIZE(nodes)); 12717ec681f3Smrg} 12727ec681f3Smrg 12737ec681f3Smrgstatic const struct dxil_mdnode * 12747ec681f3Smrgemit_resources(struct ntd_context *ctx) 12757ec681f3Smrg{ 12767ec681f3Smrg bool emit_resources = false; 12777ec681f3Smrg const struct dxil_mdnode *resources_nodes[] = { 12787ec681f3Smrg NULL, NULL, NULL, NULL 12797ec681f3Smrg }; 12807ec681f3Smrg 12817ec681f3Smrg#define ARRAY_AND_SIZE(arr) arr.data, util_dynarray_num_elements(&arr, const struct dxil_mdnode *) 12827ec681f3Smrg 12837ec681f3Smrg if (ctx->srv_metadata_nodes.size) { 12847ec681f3Smrg resources_nodes[0] = dxil_get_metadata_node(&ctx->mod, ARRAY_AND_SIZE(ctx->srv_metadata_nodes)); 12857ec681f3Smrg emit_resources = true; 12867ec681f3Smrg } 12877ec681f3Smrg 12887ec681f3Smrg if (ctx->uav_metadata_nodes.size) { 12897ec681f3Smrg resources_nodes[1] = dxil_get_metadata_node(&ctx->mod, ARRAY_AND_SIZE(ctx->uav_metadata_nodes)); 12907ec681f3Smrg emit_resources = true; 12917ec681f3Smrg } 12927ec681f3Smrg 12937ec681f3Smrg if (ctx->cbv_metadata_nodes.size) { 12947ec681f3Smrg resources_nodes[2] = dxil_get_metadata_node(&ctx->mod, ARRAY_AND_SIZE(ctx->cbv_metadata_nodes)); 12957ec681f3Smrg emit_resources = true; 12967ec681f3Smrg } 12977ec681f3Smrg 12987ec681f3Smrg if (ctx->sampler_metadata_nodes.size) { 12997ec681f3Smrg resources_nodes[3] = dxil_get_metadata_node(&ctx->mod, ARRAY_AND_SIZE(ctx->sampler_metadata_nodes)); 13007ec681f3Smrg emit_resources = true; 13017ec681f3Smrg } 13027ec681f3Smrg 13037ec681f3Smrg#undef ARRAY_AND_SIZE 13047ec681f3Smrg 13057ec681f3Smrg return emit_resources ? 13067ec681f3Smrg dxil_get_metadata_node(&ctx->mod, resources_nodes, ARRAY_SIZE(resources_nodes)): NULL; 13077ec681f3Smrg} 13087ec681f3Smrg 13097ec681f3Smrgstatic boolean 13107ec681f3Smrgemit_tag(struct ntd_context *ctx, enum dxil_shader_tag tag, 13117ec681f3Smrg const struct dxil_mdnode *value_node) 13127ec681f3Smrg{ 13137ec681f3Smrg const struct dxil_mdnode *tag_node = dxil_get_metadata_int32(&ctx->mod, tag); 13147ec681f3Smrg if (!tag_node || !value_node) 13157ec681f3Smrg return false; 13167ec681f3Smrg assert(ctx->num_shader_property_nodes <= ARRAY_SIZE(ctx->shader_property_nodes) - 2); 13177ec681f3Smrg ctx->shader_property_nodes[ctx->num_shader_property_nodes++] = tag_node; 13187ec681f3Smrg ctx->shader_property_nodes[ctx->num_shader_property_nodes++] = value_node; 13197ec681f3Smrg 13207ec681f3Smrg return true; 13217ec681f3Smrg} 13227ec681f3Smrg 13237ec681f3Smrgstatic bool 13247ec681f3Smrgemit_metadata(struct ntd_context *ctx) 13257ec681f3Smrg{ 13267ec681f3Smrg unsigned dxilMinor = ctx->mod.minor_version; 13277ec681f3Smrg if (!emit_llvm_ident(&ctx->mod) || 13287ec681f3Smrg !emit_named_version(&ctx->mod, "dx.version", 1, dxilMinor) || 13297ec681f3Smrg !emit_named_version(&ctx->mod, "dx.valver", 1, 4) || 13307ec681f3Smrg !emit_dx_shader_model(&ctx->mod)) 13317ec681f3Smrg return false; 13327ec681f3Smrg 13337ec681f3Smrg const struct dxil_type *void_type = dxil_module_get_void_type(&ctx->mod); 13347ec681f3Smrg const struct dxil_type *main_func_type = dxil_module_add_function_type(&ctx->mod, void_type, NULL, 0); 13357ec681f3Smrg const struct dxil_func *main_func = dxil_add_function_def(&ctx->mod, "main", main_func_type); 13367ec681f3Smrg if (!main_func) 13377ec681f3Smrg return false; 13387ec681f3Smrg 13397ec681f3Smrg const struct dxil_mdnode *resources_node = emit_resources(ctx); 13407ec681f3Smrg 13417ec681f3Smrg const struct dxil_mdnode *main_entrypoint = dxil_get_metadata_func(&ctx->mod, main_func); 13427ec681f3Smrg const struct dxil_mdnode *node27 = dxil_get_metadata_node(&ctx->mod, NULL, 0); 13437ec681f3Smrg 13447ec681f3Smrg const struct dxil_mdnode *node4 = dxil_get_metadata_int32(&ctx->mod, 0); 13457ec681f3Smrg const struct dxil_mdnode *nodes_4_27_27[] = { 13467ec681f3Smrg node4, node27, node27 13477ec681f3Smrg }; 13487ec681f3Smrg const struct dxil_mdnode *node28 = dxil_get_metadata_node(&ctx->mod, nodes_4_27_27, 13497ec681f3Smrg ARRAY_SIZE(nodes_4_27_27)); 13507ec681f3Smrg 13517ec681f3Smrg const struct dxil_mdnode *node29 = dxil_get_metadata_node(&ctx->mod, &node28, 1); 13527ec681f3Smrg 13537ec681f3Smrg const struct dxil_mdnode *node3 = dxil_get_metadata_int32(&ctx->mod, 1); 13547ec681f3Smrg const struct dxil_mdnode *main_type_annotation_nodes[] = { 13557ec681f3Smrg node3, main_entrypoint, node29 13567ec681f3Smrg }; 13577ec681f3Smrg const struct dxil_mdnode *main_type_annotation = dxil_get_metadata_node(&ctx->mod, main_type_annotation_nodes, 13587ec681f3Smrg ARRAY_SIZE(main_type_annotation_nodes)); 13597ec681f3Smrg 13607ec681f3Smrg if (ctx->mod.shader_kind == DXIL_GEOMETRY_SHADER) { 13617ec681f3Smrg if (!emit_tag(ctx, DXIL_SHADER_TAG_GS_STATE, emit_gs_state(ctx))) 13627ec681f3Smrg return false; 13637ec681f3Smrg } else if (ctx->mod.shader_kind == DXIL_COMPUTE_SHADER) { 13647ec681f3Smrg if (!emit_tag(ctx, DXIL_SHADER_TAG_NUM_THREADS, emit_threads(ctx))) 13657ec681f3Smrg return false; 13667ec681f3Smrg } 13677ec681f3Smrg 13687ec681f3Smrg uint64_t flags = get_module_flags(ctx); 13697ec681f3Smrg if (flags != 0) { 13707ec681f3Smrg if (!emit_tag(ctx, DXIL_SHADER_TAG_FLAGS, dxil_get_metadata_int64(&ctx->mod, flags))) 13717ec681f3Smrg return false; 13727ec681f3Smrg } 13737ec681f3Smrg const struct dxil_mdnode *shader_properties = NULL; 13747ec681f3Smrg if (ctx->num_shader_property_nodes > 0) { 13757ec681f3Smrg shader_properties = dxil_get_metadata_node(&ctx->mod, ctx->shader_property_nodes, 13767ec681f3Smrg ctx->num_shader_property_nodes); 13777ec681f3Smrg if (!shader_properties) 13787ec681f3Smrg return false; 13797ec681f3Smrg } 13807ec681f3Smrg 13817ec681f3Smrg const struct dxil_mdnode *signatures = get_signatures(&ctx->mod, ctx->shader, 13827ec681f3Smrg ctx->opts->vulkan_environment); 13837ec681f3Smrg 13847ec681f3Smrg const struct dxil_mdnode *dx_entry_point = emit_entrypoint(ctx, main_func, 13857ec681f3Smrg "main", signatures, resources_node, shader_properties); 13867ec681f3Smrg if (!dx_entry_point) 13877ec681f3Smrg return false; 13887ec681f3Smrg 13897ec681f3Smrg if (resources_node) { 13907ec681f3Smrg const struct dxil_mdnode *dx_resources = resources_node; 13917ec681f3Smrg dxil_add_metadata_named_node(&ctx->mod, "dx.resources", 13927ec681f3Smrg &dx_resources, 1); 13937ec681f3Smrg } 13947ec681f3Smrg 13957ec681f3Smrg const struct dxil_mdnode *dx_type_annotations[] = { main_type_annotation }; 13967ec681f3Smrg return dxil_add_metadata_named_node(&ctx->mod, "dx.typeAnnotations", 13977ec681f3Smrg dx_type_annotations, 13987ec681f3Smrg ARRAY_SIZE(dx_type_annotations)) && 13997ec681f3Smrg dxil_add_metadata_named_node(&ctx->mod, "dx.entryPoints", 14007ec681f3Smrg &dx_entry_point, 1); 14017ec681f3Smrg} 14027ec681f3Smrg 14037ec681f3Smrgstatic const struct dxil_value * 14047ec681f3Smrgbitcast_to_int(struct ntd_context *ctx, unsigned bit_size, 14057ec681f3Smrg const struct dxil_value *value) 14067ec681f3Smrg{ 14077ec681f3Smrg const struct dxil_type *type = dxil_module_get_int_type(&ctx->mod, bit_size); 14087ec681f3Smrg if (!type) 14097ec681f3Smrg return NULL; 14107ec681f3Smrg 14117ec681f3Smrg return dxil_emit_cast(&ctx->mod, DXIL_CAST_BITCAST, type, value); 14127ec681f3Smrg} 14137ec681f3Smrg 14147ec681f3Smrgstatic const struct dxil_value * 14157ec681f3Smrgbitcast_to_float(struct ntd_context *ctx, unsigned bit_size, 14167ec681f3Smrg const struct dxil_value *value) 14177ec681f3Smrg{ 14187ec681f3Smrg const struct dxil_type *type = dxil_module_get_float_type(&ctx->mod, bit_size); 14197ec681f3Smrg if (!type) 14207ec681f3Smrg return NULL; 14217ec681f3Smrg 14227ec681f3Smrg return dxil_emit_cast(&ctx->mod, DXIL_CAST_BITCAST, type, value); 14237ec681f3Smrg} 14247ec681f3Smrg 14257ec681f3Smrgstatic void 14267ec681f3Smrgstore_ssa_def(struct ntd_context *ctx, nir_ssa_def *ssa, unsigned chan, 14277ec681f3Smrg const struct dxil_value *value) 14287ec681f3Smrg{ 14297ec681f3Smrg assert(ssa->index < ctx->num_defs); 14307ec681f3Smrg assert(chan < ssa->num_components); 14317ec681f3Smrg /* We pre-defined the dest value because of a phi node, so bitcast while storing if the 14327ec681f3Smrg * base type differs */ 14337ec681f3Smrg if (ctx->defs[ssa->index].chans[chan]) { 14347ec681f3Smrg const struct dxil_type *expect_type = dxil_value_get_type(ctx->defs[ssa->index].chans[chan]); 14357ec681f3Smrg const struct dxil_type *value_type = dxil_value_get_type(value); 14367ec681f3Smrg if (dxil_type_to_nir_type(expect_type) != dxil_type_to_nir_type(value_type)) 14377ec681f3Smrg value = dxil_emit_cast(&ctx->mod, DXIL_CAST_BITCAST, expect_type, value); 14387ec681f3Smrg } 14397ec681f3Smrg ctx->defs[ssa->index].chans[chan] = value; 14407ec681f3Smrg} 14417ec681f3Smrg 14427ec681f3Smrgstatic void 14437ec681f3Smrgstore_dest_value(struct ntd_context *ctx, nir_dest *dest, unsigned chan, 14447ec681f3Smrg const struct dxil_value *value) 14457ec681f3Smrg{ 14467ec681f3Smrg assert(dest->is_ssa); 14477ec681f3Smrg assert(value); 14487ec681f3Smrg store_ssa_def(ctx, &dest->ssa, chan, value); 14497ec681f3Smrg} 14507ec681f3Smrg 14517ec681f3Smrgstatic void 14527ec681f3Smrgstore_dest(struct ntd_context *ctx, nir_dest *dest, unsigned chan, 14537ec681f3Smrg const struct dxil_value *value, nir_alu_type type) 14547ec681f3Smrg{ 14557ec681f3Smrg switch (nir_alu_type_get_base_type(type)) { 14567ec681f3Smrg case nir_type_float: 14577ec681f3Smrg if (nir_dest_bit_size(*dest) == 64) 14587ec681f3Smrg ctx->mod.feats.doubles = true; 14597ec681f3Smrg FALLTHROUGH; 14607ec681f3Smrg case nir_type_uint: 14617ec681f3Smrg case nir_type_int: 14627ec681f3Smrg if (nir_dest_bit_size(*dest) == 16) 14637ec681f3Smrg ctx->mod.feats.native_low_precision = true; 14647ec681f3Smrg if (nir_dest_bit_size(*dest) == 64) 14657ec681f3Smrg ctx->mod.feats.int64_ops = true; 14667ec681f3Smrg FALLTHROUGH; 14677ec681f3Smrg case nir_type_bool: 14687ec681f3Smrg store_dest_value(ctx, dest, chan, value); 14697ec681f3Smrg break; 14707ec681f3Smrg default: 14717ec681f3Smrg unreachable("unexpected nir_alu_type"); 14727ec681f3Smrg } 14737ec681f3Smrg} 14747ec681f3Smrg 14757ec681f3Smrgstatic void 14767ec681f3Smrgstore_alu_dest(struct ntd_context *ctx, nir_alu_instr *alu, unsigned chan, 14777ec681f3Smrg const struct dxil_value *value) 14787ec681f3Smrg{ 14797ec681f3Smrg assert(!alu->dest.saturate); 14807ec681f3Smrg store_dest(ctx, &alu->dest.dest, chan, value, 14817ec681f3Smrg nir_op_infos[alu->op].output_type); 14827ec681f3Smrg} 14837ec681f3Smrg 14847ec681f3Smrgstatic const struct dxil_value * 14857ec681f3Smrgget_src_ssa(struct ntd_context *ctx, const nir_ssa_def *ssa, unsigned chan) 14867ec681f3Smrg{ 14877ec681f3Smrg assert(ssa->index < ctx->num_defs); 14887ec681f3Smrg assert(chan < ssa->num_components); 14897ec681f3Smrg assert(ctx->defs[ssa->index].chans[chan]); 14907ec681f3Smrg return ctx->defs[ssa->index].chans[chan]; 14917ec681f3Smrg} 14927ec681f3Smrg 14937ec681f3Smrgstatic const struct dxil_value * 14947ec681f3Smrgget_src(struct ntd_context *ctx, nir_src *src, unsigned chan, 14957ec681f3Smrg nir_alu_type type) 14967ec681f3Smrg{ 14977ec681f3Smrg assert(src->is_ssa); 14987ec681f3Smrg const struct dxil_value *value = get_src_ssa(ctx, src->ssa, chan); 14997ec681f3Smrg 15007ec681f3Smrg const int bit_size = nir_src_bit_size(*src); 15017ec681f3Smrg 15027ec681f3Smrg switch (nir_alu_type_get_base_type(type)) { 15037ec681f3Smrg case nir_type_int: 15047ec681f3Smrg case nir_type_uint: { 15057ec681f3Smrg assert(bit_size != 64 || ctx->mod.feats.int64_ops); 15067ec681f3Smrg const struct dxil_type *expect_type = dxil_module_get_int_type(&ctx->mod, bit_size); 15077ec681f3Smrg /* nohing to do */ 15087ec681f3Smrg if (dxil_value_type_equal_to(value, expect_type)) 15097ec681f3Smrg return value; 15107ec681f3Smrg assert(dxil_value_type_bitsize_equal_to(value, bit_size)); 15117ec681f3Smrg return bitcast_to_int(ctx, bit_size, value); 15127ec681f3Smrg } 15137ec681f3Smrg 15147ec681f3Smrg case nir_type_float: 15157ec681f3Smrg assert(nir_src_bit_size(*src) >= 16); 15167ec681f3Smrg assert(nir_src_bit_size(*src) != 64 || (ctx->mod.feats.doubles && 15177ec681f3Smrg ctx->mod.feats.int64_ops)); 15187ec681f3Smrg if (dxil_value_type_equal_to(value, dxil_module_get_float_type(&ctx->mod, bit_size))) 15197ec681f3Smrg return value; 15207ec681f3Smrg assert(dxil_value_type_bitsize_equal_to(value, bit_size)); 15217ec681f3Smrg return bitcast_to_float(ctx, bit_size, value); 15227ec681f3Smrg 15237ec681f3Smrg case nir_type_bool: 15247ec681f3Smrg if (!dxil_value_type_bitsize_equal_to(value, 1)) { 15257ec681f3Smrg return dxil_emit_cast(&ctx->mod, DXIL_CAST_TRUNC, 15267ec681f3Smrg dxil_module_get_int_type(&ctx->mod, 1), value); 15277ec681f3Smrg } 15287ec681f3Smrg return value; 15297ec681f3Smrg 15307ec681f3Smrg default: 15317ec681f3Smrg unreachable("unexpected nir_alu_type"); 15327ec681f3Smrg } 15337ec681f3Smrg} 15347ec681f3Smrg 15357ec681f3Smrgstatic const struct dxil_type * 15367ec681f3Smrgget_alu_src_type(struct ntd_context *ctx, nir_alu_instr *alu, unsigned src) 15377ec681f3Smrg{ 15387ec681f3Smrg assert(!alu->src[src].abs); 15397ec681f3Smrg assert(!alu->src[src].negate); 15407ec681f3Smrg nir_ssa_def *ssa_src = alu->src[src].src.ssa; 15417ec681f3Smrg unsigned chan = alu->src[src].swizzle[0]; 15427ec681f3Smrg const struct dxil_value *value = get_src_ssa(ctx, ssa_src, chan); 15437ec681f3Smrg return dxil_value_get_type(value); 15447ec681f3Smrg} 15457ec681f3Smrg 15467ec681f3Smrgstatic const struct dxil_value * 15477ec681f3Smrgget_alu_src(struct ntd_context *ctx, nir_alu_instr *alu, unsigned src) 15487ec681f3Smrg{ 15497ec681f3Smrg assert(!alu->src[src].abs); 15507ec681f3Smrg assert(!alu->src[src].negate); 15517ec681f3Smrg 15527ec681f3Smrg unsigned chan = alu->src[src].swizzle[0]; 15537ec681f3Smrg return get_src(ctx, &alu->src[src].src, chan, 15547ec681f3Smrg nir_op_infos[alu->op].input_types[src]); 15557ec681f3Smrg} 15567ec681f3Smrg 15577ec681f3Smrgstatic bool 15587ec681f3Smrgemit_binop(struct ntd_context *ctx, nir_alu_instr *alu, 15597ec681f3Smrg enum dxil_bin_opcode opcode, 15607ec681f3Smrg const struct dxil_value *op0, const struct dxil_value *op1) 15617ec681f3Smrg{ 15627ec681f3Smrg bool is_float_op = nir_alu_type_get_base_type(nir_op_infos[alu->op].output_type) == nir_type_float; 15637ec681f3Smrg 15647ec681f3Smrg enum dxil_opt_flags flags = 0; 15657ec681f3Smrg if (is_float_op && !alu->exact) 15667ec681f3Smrg flags |= DXIL_UNSAFE_ALGEBRA; 15677ec681f3Smrg 15687ec681f3Smrg const struct dxil_value *v = dxil_emit_binop(&ctx->mod, opcode, op0, op1, flags); 15697ec681f3Smrg if (!v) 15707ec681f3Smrg return false; 15717ec681f3Smrg store_alu_dest(ctx, alu, 0, v); 15727ec681f3Smrg return true; 15737ec681f3Smrg} 15747ec681f3Smrg 15757ec681f3Smrgstatic bool 15767ec681f3Smrgemit_shift(struct ntd_context *ctx, nir_alu_instr *alu, 15777ec681f3Smrg enum dxil_bin_opcode opcode, 15787ec681f3Smrg const struct dxil_value *op0, const struct dxil_value *op1) 15797ec681f3Smrg{ 15807ec681f3Smrg unsigned op0_bit_size = nir_src_bit_size(alu->src[0].src); 15817ec681f3Smrg unsigned op1_bit_size = nir_src_bit_size(alu->src[1].src); 15827ec681f3Smrg if (op0_bit_size != op1_bit_size) { 15837ec681f3Smrg const struct dxil_type *type = 15847ec681f3Smrg dxil_module_get_int_type(&ctx->mod, op0_bit_size); 15857ec681f3Smrg enum dxil_cast_opcode cast_op = 15867ec681f3Smrg op1_bit_size < op0_bit_size ? DXIL_CAST_ZEXT : DXIL_CAST_TRUNC; 15877ec681f3Smrg op1 = dxil_emit_cast(&ctx->mod, cast_op, type, op1); 15887ec681f3Smrg } 15897ec681f3Smrg 15907ec681f3Smrg const struct dxil_value *v = 15917ec681f3Smrg dxil_emit_binop(&ctx->mod, opcode, op0, op1, 0); 15927ec681f3Smrg if (!v) 15937ec681f3Smrg return false; 15947ec681f3Smrg store_alu_dest(ctx, alu, 0, v); 15957ec681f3Smrg return true; 15967ec681f3Smrg} 15977ec681f3Smrg 15987ec681f3Smrgstatic bool 15997ec681f3Smrgemit_cmp(struct ntd_context *ctx, nir_alu_instr *alu, 16007ec681f3Smrg enum dxil_cmp_pred pred, 16017ec681f3Smrg const struct dxil_value *op0, const struct dxil_value *op1) 16027ec681f3Smrg{ 16037ec681f3Smrg const struct dxil_value *v = dxil_emit_cmp(&ctx->mod, pred, op0, op1); 16047ec681f3Smrg if (!v) 16057ec681f3Smrg return false; 16067ec681f3Smrg store_alu_dest(ctx, alu, 0, v); 16077ec681f3Smrg return true; 16087ec681f3Smrg} 16097ec681f3Smrg 16107ec681f3Smrgstatic enum dxil_cast_opcode 16117ec681f3Smrgget_cast_op(nir_alu_instr *alu) 16127ec681f3Smrg{ 16137ec681f3Smrg unsigned dst_bits = nir_dest_bit_size(alu->dest.dest); 16147ec681f3Smrg unsigned src_bits = nir_src_bit_size(alu->src[0].src); 16157ec681f3Smrg 16167ec681f3Smrg switch (alu->op) { 16177ec681f3Smrg /* bool -> int */ 16187ec681f3Smrg case nir_op_b2i16: 16197ec681f3Smrg case nir_op_b2i32: 16207ec681f3Smrg case nir_op_b2i64: 16217ec681f3Smrg return DXIL_CAST_ZEXT; 16227ec681f3Smrg 16237ec681f3Smrg /* float -> float */ 16247ec681f3Smrg case nir_op_f2f16_rtz: 16257ec681f3Smrg case nir_op_f2f32: 16267ec681f3Smrg case nir_op_f2f64: 16277ec681f3Smrg assert(dst_bits != src_bits); 16287ec681f3Smrg if (dst_bits < src_bits) 16297ec681f3Smrg return DXIL_CAST_FPTRUNC; 16307ec681f3Smrg else 16317ec681f3Smrg return DXIL_CAST_FPEXT; 16327ec681f3Smrg 16337ec681f3Smrg /* int -> int */ 16347ec681f3Smrg case nir_op_i2i16: 16357ec681f3Smrg case nir_op_i2i32: 16367ec681f3Smrg case nir_op_i2i64: 16377ec681f3Smrg assert(dst_bits != src_bits); 16387ec681f3Smrg if (dst_bits < src_bits) 16397ec681f3Smrg return DXIL_CAST_TRUNC; 16407ec681f3Smrg else 16417ec681f3Smrg return DXIL_CAST_SEXT; 16427ec681f3Smrg 16437ec681f3Smrg /* uint -> uint */ 16447ec681f3Smrg case nir_op_u2u16: 16457ec681f3Smrg case nir_op_u2u32: 16467ec681f3Smrg case nir_op_u2u64: 16477ec681f3Smrg assert(dst_bits != src_bits); 16487ec681f3Smrg if (dst_bits < src_bits) 16497ec681f3Smrg return DXIL_CAST_TRUNC; 16507ec681f3Smrg else 16517ec681f3Smrg return DXIL_CAST_ZEXT; 16527ec681f3Smrg 16537ec681f3Smrg /* float -> int */ 16547ec681f3Smrg case nir_op_f2i16: 16557ec681f3Smrg case nir_op_f2i32: 16567ec681f3Smrg case nir_op_f2i64: 16577ec681f3Smrg return DXIL_CAST_FPTOSI; 16587ec681f3Smrg 16597ec681f3Smrg /* float -> uint */ 16607ec681f3Smrg case nir_op_f2u16: 16617ec681f3Smrg case nir_op_f2u32: 16627ec681f3Smrg case nir_op_f2u64: 16637ec681f3Smrg return DXIL_CAST_FPTOUI; 16647ec681f3Smrg 16657ec681f3Smrg /* int -> float */ 16667ec681f3Smrg case nir_op_i2f16: 16677ec681f3Smrg case nir_op_i2f32: 16687ec681f3Smrg case nir_op_i2f64: 16697ec681f3Smrg return DXIL_CAST_SITOFP; 16707ec681f3Smrg 16717ec681f3Smrg /* uint -> float */ 16727ec681f3Smrg case nir_op_u2f16: 16737ec681f3Smrg case nir_op_u2f32: 16747ec681f3Smrg case nir_op_u2f64: 16757ec681f3Smrg return DXIL_CAST_UITOFP; 16767ec681f3Smrg 16777ec681f3Smrg default: 16787ec681f3Smrg unreachable("unexpected cast op"); 16797ec681f3Smrg } 16807ec681f3Smrg} 16817ec681f3Smrg 16827ec681f3Smrgstatic const struct dxil_type * 16837ec681f3Smrgget_cast_dest_type(struct ntd_context *ctx, nir_alu_instr *alu) 16847ec681f3Smrg{ 16857ec681f3Smrg unsigned dst_bits = nir_dest_bit_size(alu->dest.dest); 16867ec681f3Smrg switch (nir_alu_type_get_base_type(nir_op_infos[alu->op].output_type)) { 16877ec681f3Smrg case nir_type_bool: 16887ec681f3Smrg assert(dst_bits == 1); 16897ec681f3Smrg FALLTHROUGH; 16907ec681f3Smrg case nir_type_int: 16917ec681f3Smrg case nir_type_uint: 16927ec681f3Smrg return dxil_module_get_int_type(&ctx->mod, dst_bits); 16937ec681f3Smrg 16947ec681f3Smrg case nir_type_float: 16957ec681f3Smrg return dxil_module_get_float_type(&ctx->mod, dst_bits); 16967ec681f3Smrg 16977ec681f3Smrg default: 16987ec681f3Smrg unreachable("unknown nir_alu_type"); 16997ec681f3Smrg } 17007ec681f3Smrg} 17017ec681f3Smrg 17027ec681f3Smrgstatic bool 17037ec681f3Smrgis_double(nir_alu_type alu_type, unsigned bit_size) 17047ec681f3Smrg{ 17057ec681f3Smrg return nir_alu_type_get_base_type(alu_type) == nir_type_float && 17067ec681f3Smrg bit_size == 64; 17077ec681f3Smrg} 17087ec681f3Smrg 17097ec681f3Smrgstatic bool 17107ec681f3Smrgemit_cast(struct ntd_context *ctx, nir_alu_instr *alu, 17117ec681f3Smrg const struct dxil_value *value) 17127ec681f3Smrg{ 17137ec681f3Smrg enum dxil_cast_opcode opcode = get_cast_op(alu); 17147ec681f3Smrg const struct dxil_type *type = get_cast_dest_type(ctx, alu); 17157ec681f3Smrg if (!type) 17167ec681f3Smrg return false; 17177ec681f3Smrg 17187ec681f3Smrg const nir_op_info *info = &nir_op_infos[alu->op]; 17197ec681f3Smrg switch (opcode) { 17207ec681f3Smrg case DXIL_CAST_UITOFP: 17217ec681f3Smrg case DXIL_CAST_SITOFP: 17227ec681f3Smrg if (is_double(info->output_type, nir_dest_bit_size(alu->dest.dest))) 17237ec681f3Smrg ctx->mod.feats.dx11_1_double_extensions = true; 17247ec681f3Smrg break; 17257ec681f3Smrg case DXIL_CAST_FPTOUI: 17267ec681f3Smrg case DXIL_CAST_FPTOSI: 17277ec681f3Smrg if (is_double(info->input_types[0], nir_src_bit_size(alu->src[0].src))) 17287ec681f3Smrg ctx->mod.feats.dx11_1_double_extensions = true; 17297ec681f3Smrg break; 17307ec681f3Smrg default: 17317ec681f3Smrg break; 17327ec681f3Smrg } 17337ec681f3Smrg 17347ec681f3Smrg const struct dxil_value *v = dxil_emit_cast(&ctx->mod, opcode, type, 17357ec681f3Smrg value); 17367ec681f3Smrg if (!v) 17377ec681f3Smrg return false; 17387ec681f3Smrg store_alu_dest(ctx, alu, 0, v); 17397ec681f3Smrg return true; 17407ec681f3Smrg} 17417ec681f3Smrg 17427ec681f3Smrgstatic enum overload_type 17437ec681f3Smrgget_overload(nir_alu_type alu_type, unsigned bit_size) 17447ec681f3Smrg{ 17457ec681f3Smrg switch (nir_alu_type_get_base_type(alu_type)) { 17467ec681f3Smrg case nir_type_int: 17477ec681f3Smrg case nir_type_uint: 17487ec681f3Smrg switch (bit_size) { 17497ec681f3Smrg case 16: return DXIL_I16; 17507ec681f3Smrg case 32: return DXIL_I32; 17517ec681f3Smrg case 64: return DXIL_I64; 17527ec681f3Smrg default: 17537ec681f3Smrg unreachable("unexpected bit_size"); 17547ec681f3Smrg } 17557ec681f3Smrg case nir_type_float: 17567ec681f3Smrg switch (bit_size) { 17577ec681f3Smrg case 16: return DXIL_F16; 17587ec681f3Smrg case 32: return DXIL_F32; 17597ec681f3Smrg case 64: return DXIL_F64; 17607ec681f3Smrg default: 17617ec681f3Smrg unreachable("unexpected bit_size"); 17627ec681f3Smrg } 17637ec681f3Smrg default: 17647ec681f3Smrg unreachable("unexpected output type"); 17657ec681f3Smrg } 17667ec681f3Smrg} 17677ec681f3Smrg 17687ec681f3Smrgstatic bool 17697ec681f3Smrgemit_unary_intin(struct ntd_context *ctx, nir_alu_instr *alu, 17707ec681f3Smrg enum dxil_intr intr, const struct dxil_value *op) 17717ec681f3Smrg{ 17727ec681f3Smrg const nir_op_info *info = &nir_op_infos[alu->op]; 17737ec681f3Smrg unsigned src_bits = nir_src_bit_size(alu->src[0].src); 17747ec681f3Smrg enum overload_type overload = get_overload(info->input_types[0], src_bits); 17757ec681f3Smrg 17767ec681f3Smrg const struct dxil_value *v = emit_unary_call(ctx, overload, intr, op); 17777ec681f3Smrg if (!v) 17787ec681f3Smrg return false; 17797ec681f3Smrg store_alu_dest(ctx, alu, 0, v); 17807ec681f3Smrg return true; 17817ec681f3Smrg} 17827ec681f3Smrg 17837ec681f3Smrgstatic bool 17847ec681f3Smrgemit_binary_intin(struct ntd_context *ctx, nir_alu_instr *alu, 17857ec681f3Smrg enum dxil_intr intr, 17867ec681f3Smrg const struct dxil_value *op0, const struct dxil_value *op1) 17877ec681f3Smrg{ 17887ec681f3Smrg const nir_op_info *info = &nir_op_infos[alu->op]; 17897ec681f3Smrg assert(info->output_type == info->input_types[0]); 17907ec681f3Smrg assert(info->output_type == info->input_types[1]); 17917ec681f3Smrg unsigned dst_bits = nir_dest_bit_size(alu->dest.dest); 17927ec681f3Smrg assert(nir_src_bit_size(alu->src[0].src) == dst_bits); 17937ec681f3Smrg assert(nir_src_bit_size(alu->src[1].src) == dst_bits); 17947ec681f3Smrg enum overload_type overload = get_overload(info->output_type, dst_bits); 17957ec681f3Smrg 17967ec681f3Smrg const struct dxil_value *v = emit_binary_call(ctx, overload, intr, 17977ec681f3Smrg op0, op1); 17987ec681f3Smrg if (!v) 17997ec681f3Smrg return false; 18007ec681f3Smrg store_alu_dest(ctx, alu, 0, v); 18017ec681f3Smrg return true; 18027ec681f3Smrg} 18037ec681f3Smrg 18047ec681f3Smrgstatic bool 18057ec681f3Smrgemit_tertiary_intin(struct ntd_context *ctx, nir_alu_instr *alu, 18067ec681f3Smrg enum dxil_intr intr, 18077ec681f3Smrg const struct dxil_value *op0, 18087ec681f3Smrg const struct dxil_value *op1, 18097ec681f3Smrg const struct dxil_value *op2) 18107ec681f3Smrg{ 18117ec681f3Smrg const nir_op_info *info = &nir_op_infos[alu->op]; 18127ec681f3Smrg assert(info->output_type == info->input_types[0]); 18137ec681f3Smrg assert(info->output_type == info->input_types[1]); 18147ec681f3Smrg assert(info->output_type == info->input_types[2]); 18157ec681f3Smrg 18167ec681f3Smrg unsigned dst_bits = nir_dest_bit_size(alu->dest.dest); 18177ec681f3Smrg assert(nir_src_bit_size(alu->src[0].src) == dst_bits); 18187ec681f3Smrg assert(nir_src_bit_size(alu->src[1].src) == dst_bits); 18197ec681f3Smrg assert(nir_src_bit_size(alu->src[2].src) == dst_bits); 18207ec681f3Smrg 18217ec681f3Smrg enum overload_type overload = get_overload(info->output_type, dst_bits); 18227ec681f3Smrg 18237ec681f3Smrg const struct dxil_value *v = emit_tertiary_call(ctx, overload, intr, 18247ec681f3Smrg op0, op1, op2); 18257ec681f3Smrg if (!v) 18267ec681f3Smrg return false; 18277ec681f3Smrg store_alu_dest(ctx, alu, 0, v); 18287ec681f3Smrg return true; 18297ec681f3Smrg} 18307ec681f3Smrg 18317ec681f3Smrgstatic bool emit_select(struct ntd_context *ctx, nir_alu_instr *alu, 18327ec681f3Smrg const struct dxil_value *sel, 18337ec681f3Smrg const struct dxil_value *val_true, 18347ec681f3Smrg const struct dxil_value *val_false) 18357ec681f3Smrg{ 18367ec681f3Smrg assert(sel); 18377ec681f3Smrg assert(val_true); 18387ec681f3Smrg assert(val_false); 18397ec681f3Smrg 18407ec681f3Smrg const struct dxil_value *v = dxil_emit_select(&ctx->mod, sel, val_true, val_false); 18417ec681f3Smrg if (!v) 18427ec681f3Smrg return false; 18437ec681f3Smrg 18447ec681f3Smrg store_alu_dest(ctx, alu, 0, v); 18457ec681f3Smrg return true; 18467ec681f3Smrg} 18477ec681f3Smrg 18487ec681f3Smrgstatic bool 18497ec681f3Smrgemit_b2f16(struct ntd_context *ctx, nir_alu_instr *alu, const struct dxil_value *val) 18507ec681f3Smrg{ 18517ec681f3Smrg assert(val); 18527ec681f3Smrg 18537ec681f3Smrg struct dxil_module *m = &ctx->mod; 18547ec681f3Smrg 18557ec681f3Smrg const struct dxil_value *c1 = dxil_module_get_float16_const(m, 0x3C00); 18567ec681f3Smrg const struct dxil_value *c0 = dxil_module_get_float16_const(m, 0); 18577ec681f3Smrg 18587ec681f3Smrg if (!c0 || !c1) 18597ec681f3Smrg return false; 18607ec681f3Smrg 18617ec681f3Smrg return emit_select(ctx, alu, val, c1, c0); 18627ec681f3Smrg} 18637ec681f3Smrg 18647ec681f3Smrgstatic bool 18657ec681f3Smrgemit_b2f32(struct ntd_context *ctx, nir_alu_instr *alu, const struct dxil_value *val) 18667ec681f3Smrg{ 18677ec681f3Smrg assert(val); 18687ec681f3Smrg 18697ec681f3Smrg struct dxil_module *m = &ctx->mod; 18707ec681f3Smrg 18717ec681f3Smrg const struct dxil_value *c1 = dxil_module_get_float_const(m, 1.0f); 18727ec681f3Smrg const struct dxil_value *c0 = dxil_module_get_float_const(m, 0.0f); 18737ec681f3Smrg 18747ec681f3Smrg if (!c0 || !c1) 18757ec681f3Smrg return false; 18767ec681f3Smrg 18777ec681f3Smrg return emit_select(ctx, alu, val, c1, c0); 18787ec681f3Smrg} 18797ec681f3Smrg 18807ec681f3Smrgstatic bool 18817ec681f3Smrgemit_f2b32(struct ntd_context *ctx, nir_alu_instr *alu, const struct dxil_value *val) 18827ec681f3Smrg{ 18837ec681f3Smrg assert(val); 18847ec681f3Smrg 18857ec681f3Smrg const struct dxil_value *zero = dxil_module_get_float_const(&ctx->mod, 0.0f); 18867ec681f3Smrg return emit_cmp(ctx, alu, DXIL_FCMP_UNE, val, zero); 18877ec681f3Smrg} 18887ec681f3Smrg 18897ec681f3Smrgstatic bool 18907ec681f3Smrgemit_ufind_msb(struct ntd_context *ctx, nir_alu_instr *alu, 18917ec681f3Smrg const struct dxil_value *val) 18927ec681f3Smrg{ 18937ec681f3Smrg const nir_op_info *info = &nir_op_infos[alu->op]; 18947ec681f3Smrg unsigned dst_bits = nir_dest_bit_size(alu->dest.dest); 18957ec681f3Smrg unsigned src_bits = nir_src_bit_size(alu->src[0].src); 18967ec681f3Smrg enum overload_type overload = get_overload(info->output_type, src_bits); 18977ec681f3Smrg 18987ec681f3Smrg const struct dxil_value *v = emit_unary_call(ctx, overload, 18997ec681f3Smrg DXIL_INTR_FIRSTBIT_HI, val); 19007ec681f3Smrg if (!v) 19017ec681f3Smrg return false; 19027ec681f3Smrg 19037ec681f3Smrg const struct dxil_value *size = dxil_module_get_int32_const(&ctx->mod, 19047ec681f3Smrg src_bits - 1); 19057ec681f3Smrg const struct dxil_value *zero = dxil_module_get_int_const(&ctx->mod, 0, 19067ec681f3Smrg src_bits); 19077ec681f3Smrg if (!size || !zero) 19087ec681f3Smrg return false; 19097ec681f3Smrg 19107ec681f3Smrg v = dxil_emit_binop(&ctx->mod, DXIL_BINOP_SUB, size, v, 0); 19117ec681f3Smrg const struct dxil_value *cnd = dxil_emit_cmp(&ctx->mod, DXIL_ICMP_NE, 19127ec681f3Smrg val, zero); 19137ec681f3Smrg if (!v || !cnd) 19147ec681f3Smrg return false; 19157ec681f3Smrg 19167ec681f3Smrg const struct dxil_value *minus_one = 19177ec681f3Smrg dxil_module_get_int_const(&ctx->mod, -1, dst_bits); 19187ec681f3Smrg if (!minus_one) 19197ec681f3Smrg return false; 19207ec681f3Smrg 19217ec681f3Smrg v = dxil_emit_select(&ctx->mod, cnd, v, minus_one); 19227ec681f3Smrg if (!v) 19237ec681f3Smrg return false; 19247ec681f3Smrg 19257ec681f3Smrg store_alu_dest(ctx, alu, 0, v); 19267ec681f3Smrg return true; 19277ec681f3Smrg} 19287ec681f3Smrg 19297ec681f3Smrgstatic bool 19307ec681f3Smrgemit_f16tof32(struct ntd_context *ctx, nir_alu_instr *alu, const struct dxil_value *val) 19317ec681f3Smrg{ 19327ec681f3Smrg const struct dxil_func *func = dxil_get_function(&ctx->mod, 19337ec681f3Smrg "dx.op.legacyF16ToF32", 19347ec681f3Smrg DXIL_NONE); 19357ec681f3Smrg if (!func) 19367ec681f3Smrg return false; 19377ec681f3Smrg 19387ec681f3Smrg const struct dxil_value *opcode = dxil_module_get_int32_const(&ctx->mod, DXIL_INTR_LEGACY_F16TOF32); 19397ec681f3Smrg if (!opcode) 19407ec681f3Smrg return false; 19417ec681f3Smrg 19427ec681f3Smrg const struct dxil_value *args[] = { 19437ec681f3Smrg opcode, 19447ec681f3Smrg val 19457ec681f3Smrg }; 19467ec681f3Smrg 19477ec681f3Smrg const struct dxil_value *v = dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args)); 19487ec681f3Smrg if (!v) 19497ec681f3Smrg return false; 19507ec681f3Smrg store_alu_dest(ctx, alu, 0, v); 19517ec681f3Smrg return true; 19527ec681f3Smrg} 19537ec681f3Smrg 19547ec681f3Smrgstatic bool 19557ec681f3Smrgemit_f32tof16(struct ntd_context *ctx, nir_alu_instr *alu, const struct dxil_value *val) 19567ec681f3Smrg{ 19577ec681f3Smrg const struct dxil_func *func = dxil_get_function(&ctx->mod, 19587ec681f3Smrg "dx.op.legacyF32ToF16", 19597ec681f3Smrg DXIL_NONE); 19607ec681f3Smrg if (!func) 19617ec681f3Smrg return false; 19627ec681f3Smrg 19637ec681f3Smrg const struct dxil_value *opcode = dxil_module_get_int32_const(&ctx->mod, DXIL_INTR_LEGACY_F32TOF16); 19647ec681f3Smrg if (!opcode) 19657ec681f3Smrg return false; 19667ec681f3Smrg 19677ec681f3Smrg const struct dxil_value *args[] = { 19687ec681f3Smrg opcode, 19697ec681f3Smrg val 19707ec681f3Smrg }; 19717ec681f3Smrg 19727ec681f3Smrg const struct dxil_value *v = dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args)); 19737ec681f3Smrg if (!v) 19747ec681f3Smrg return false; 19757ec681f3Smrg store_alu_dest(ctx, alu, 0, v); 19767ec681f3Smrg return true; 19777ec681f3Smrg} 19787ec681f3Smrg 19797ec681f3Smrgstatic bool 19807ec681f3Smrgemit_vec(struct ntd_context *ctx, nir_alu_instr *alu, unsigned num_inputs) 19817ec681f3Smrg{ 19827ec681f3Smrg const struct dxil_type *type = get_alu_src_type(ctx, alu, 0); 19837ec681f3Smrg nir_alu_type t = dxil_type_to_nir_type(type); 19847ec681f3Smrg 19857ec681f3Smrg for (unsigned i = 0; i < num_inputs; i++) { 19867ec681f3Smrg const struct dxil_value *src = 19877ec681f3Smrg get_src(ctx, &alu->src[i].src, alu->src[i].swizzle[0], t); 19887ec681f3Smrg if (!src) 19897ec681f3Smrg return false; 19907ec681f3Smrg 19917ec681f3Smrg store_alu_dest(ctx, alu, i, src); 19927ec681f3Smrg } 19937ec681f3Smrg return true; 19947ec681f3Smrg} 19957ec681f3Smrg 19967ec681f3Smrgstatic bool 19977ec681f3Smrgemit_make_double(struct ntd_context *ctx, nir_alu_instr *alu) 19987ec681f3Smrg{ 19997ec681f3Smrg const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.makeDouble", DXIL_F64); 20007ec681f3Smrg if (!func) 20017ec681f3Smrg return false; 20027ec681f3Smrg 20037ec681f3Smrg const struct dxil_value *opcode = dxil_module_get_int32_const(&ctx->mod, DXIL_INTR_MAKE_DOUBLE); 20047ec681f3Smrg if (!opcode) 20057ec681f3Smrg return false; 20067ec681f3Smrg 20077ec681f3Smrg const struct dxil_value *args[3] = { 20087ec681f3Smrg opcode, 20097ec681f3Smrg get_src(ctx, &alu->src[0].src, 0, nir_type_uint32), 20107ec681f3Smrg get_src(ctx, &alu->src[0].src, 1, nir_type_uint32), 20117ec681f3Smrg }; 20127ec681f3Smrg if (!args[1] || !args[2]) 20137ec681f3Smrg return false; 20147ec681f3Smrg 20157ec681f3Smrg const struct dxil_value *v = dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args)); 20167ec681f3Smrg if (!v) 20177ec681f3Smrg return false; 20187ec681f3Smrg store_dest(ctx, &alu->dest.dest, 0, v, nir_type_float64); 20197ec681f3Smrg return true; 20207ec681f3Smrg} 20217ec681f3Smrg 20227ec681f3Smrgstatic bool 20237ec681f3Smrgemit_split_double(struct ntd_context *ctx, nir_alu_instr *alu) 20247ec681f3Smrg{ 20257ec681f3Smrg const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.splitDouble", DXIL_F64); 20267ec681f3Smrg if (!func) 20277ec681f3Smrg return false; 20287ec681f3Smrg 20297ec681f3Smrg const struct dxil_value *opcode = dxil_module_get_int32_const(&ctx->mod, DXIL_INTR_SPLIT_DOUBLE); 20307ec681f3Smrg if (!opcode) 20317ec681f3Smrg return false; 20327ec681f3Smrg 20337ec681f3Smrg const struct dxil_value *args[] = { 20347ec681f3Smrg opcode, 20357ec681f3Smrg get_src(ctx, &alu->src[0].src, 0, nir_type_float64) 20367ec681f3Smrg }; 20377ec681f3Smrg if (!args[1]) 20387ec681f3Smrg return false; 20397ec681f3Smrg 20407ec681f3Smrg const struct dxil_value *v = dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args)); 20417ec681f3Smrg if (!v) 20427ec681f3Smrg return false; 20437ec681f3Smrg 20447ec681f3Smrg const struct dxil_value *hi = dxil_emit_extractval(&ctx->mod, v, 0); 20457ec681f3Smrg const struct dxil_value *lo = dxil_emit_extractval(&ctx->mod, v, 1); 20467ec681f3Smrg if (!hi || !lo) 20477ec681f3Smrg return false; 20487ec681f3Smrg 20497ec681f3Smrg store_dest_value(ctx, &alu->dest.dest, 0, hi); 20507ec681f3Smrg store_dest_value(ctx, &alu->dest.dest, 1, lo); 20517ec681f3Smrg return true; 20527ec681f3Smrg} 20537ec681f3Smrg 20547ec681f3Smrgstatic bool 20557ec681f3Smrgemit_alu(struct ntd_context *ctx, nir_alu_instr *alu) 20567ec681f3Smrg{ 20577ec681f3Smrg /* handle vec-instructions first; they are the only ones that produce 20587ec681f3Smrg * vector results. 20597ec681f3Smrg */ 20607ec681f3Smrg switch (alu->op) { 20617ec681f3Smrg case nir_op_vec2: 20627ec681f3Smrg case nir_op_vec3: 20637ec681f3Smrg case nir_op_vec4: 20647ec681f3Smrg case nir_op_vec8: 20657ec681f3Smrg case nir_op_vec16: 20667ec681f3Smrg return emit_vec(ctx, alu, nir_op_infos[alu->op].num_inputs); 20677ec681f3Smrg case nir_op_mov: { 20687ec681f3Smrg assert(nir_dest_num_components(alu->dest.dest) == 1); 20697ec681f3Smrg store_ssa_def(ctx, &alu->dest.dest.ssa, 0, get_src_ssa(ctx, 20707ec681f3Smrg alu->src->src.ssa, alu->src->swizzle[0])); 20717ec681f3Smrg return true; 20727ec681f3Smrg } 20737ec681f3Smrg case nir_op_pack_double_2x32_dxil: 20747ec681f3Smrg return emit_make_double(ctx, alu); 20757ec681f3Smrg case nir_op_unpack_double_2x32_dxil: 20767ec681f3Smrg return emit_split_double(ctx, alu); 20777ec681f3Smrg default: 20787ec681f3Smrg /* silence warnings */ 20797ec681f3Smrg ; 20807ec681f3Smrg } 20817ec681f3Smrg 20827ec681f3Smrg /* other ops should be scalar */ 20837ec681f3Smrg assert(alu->dest.write_mask == 1); 20847ec681f3Smrg const struct dxil_value *src[4]; 20857ec681f3Smrg assert(nir_op_infos[alu->op].num_inputs <= 4); 20867ec681f3Smrg for (unsigned i = 0; i < nir_op_infos[alu->op].num_inputs; i++) { 20877ec681f3Smrg src[i] = get_alu_src(ctx, alu, i); 20887ec681f3Smrg if (!src[i]) 20897ec681f3Smrg return false; 20907ec681f3Smrg } 20917ec681f3Smrg 20927ec681f3Smrg switch (alu->op) { 20937ec681f3Smrg case nir_op_iadd: 20947ec681f3Smrg case nir_op_fadd: return emit_binop(ctx, alu, DXIL_BINOP_ADD, src[0], src[1]); 20957ec681f3Smrg 20967ec681f3Smrg case nir_op_isub: 20977ec681f3Smrg case nir_op_fsub: return emit_binop(ctx, alu, DXIL_BINOP_SUB, src[0], src[1]); 20987ec681f3Smrg 20997ec681f3Smrg case nir_op_imul: 21007ec681f3Smrg case nir_op_fmul: return emit_binop(ctx, alu, DXIL_BINOP_MUL, src[0], src[1]); 21017ec681f3Smrg 21027ec681f3Smrg case nir_op_idiv: 21037ec681f3Smrg case nir_op_fdiv: return emit_binop(ctx, alu, DXIL_BINOP_SDIV, src[0], src[1]); 21047ec681f3Smrg 21057ec681f3Smrg case nir_op_udiv: return emit_binop(ctx, alu, DXIL_BINOP_UDIV, src[0], src[1]); 21067ec681f3Smrg case nir_op_irem: return emit_binop(ctx, alu, DXIL_BINOP_SREM, src[0], src[1]); 21077ec681f3Smrg case nir_op_imod: return emit_binop(ctx, alu, DXIL_BINOP_UREM, src[0], src[1]); 21087ec681f3Smrg case nir_op_umod: return emit_binop(ctx, alu, DXIL_BINOP_UREM, src[0], src[1]); 21097ec681f3Smrg case nir_op_ishl: return emit_shift(ctx, alu, DXIL_BINOP_SHL, src[0], src[1]); 21107ec681f3Smrg case nir_op_ishr: return emit_shift(ctx, alu, DXIL_BINOP_ASHR, src[0], src[1]); 21117ec681f3Smrg case nir_op_ushr: return emit_shift(ctx, alu, DXIL_BINOP_LSHR, src[0], src[1]); 21127ec681f3Smrg case nir_op_iand: return emit_binop(ctx, alu, DXIL_BINOP_AND, src[0], src[1]); 21137ec681f3Smrg case nir_op_ior: return emit_binop(ctx, alu, DXIL_BINOP_OR, src[0], src[1]); 21147ec681f3Smrg case nir_op_ixor: return emit_binop(ctx, alu, DXIL_BINOP_XOR, src[0], src[1]); 21157ec681f3Smrg case nir_op_inot: { 21167ec681f3Smrg unsigned bit_size = alu->dest.dest.ssa.bit_size; 21177ec681f3Smrg intmax_t val = bit_size == 1 ? 1 : -1; 21187ec681f3Smrg const struct dxil_value *negative_one = dxil_module_get_int_const(&ctx->mod, val, bit_size); 21197ec681f3Smrg return emit_binop(ctx, alu, DXIL_BINOP_XOR, src[0], negative_one); 21207ec681f3Smrg } 21217ec681f3Smrg case nir_op_ieq: return emit_cmp(ctx, alu, DXIL_ICMP_EQ, src[0], src[1]); 21227ec681f3Smrg case nir_op_ine: return emit_cmp(ctx, alu, DXIL_ICMP_NE, src[0], src[1]); 21237ec681f3Smrg case nir_op_ige: return emit_cmp(ctx, alu, DXIL_ICMP_SGE, src[0], src[1]); 21247ec681f3Smrg case nir_op_uge: return emit_cmp(ctx, alu, DXIL_ICMP_UGE, src[0], src[1]); 21257ec681f3Smrg case nir_op_ilt: return emit_cmp(ctx, alu, DXIL_ICMP_SLT, src[0], src[1]); 21267ec681f3Smrg case nir_op_ult: return emit_cmp(ctx, alu, DXIL_ICMP_ULT, src[0], src[1]); 21277ec681f3Smrg case nir_op_feq: return emit_cmp(ctx, alu, DXIL_FCMP_OEQ, src[0], src[1]); 21287ec681f3Smrg case nir_op_fneu: return emit_cmp(ctx, alu, DXIL_FCMP_UNE, src[0], src[1]); 21297ec681f3Smrg case nir_op_flt: return emit_cmp(ctx, alu, DXIL_FCMP_OLT, src[0], src[1]); 21307ec681f3Smrg case nir_op_fge: return emit_cmp(ctx, alu, DXIL_FCMP_OGE, src[0], src[1]); 21317ec681f3Smrg case nir_op_bcsel: return emit_select(ctx, alu, src[0], src[1], src[2]); 21327ec681f3Smrg case nir_op_ftrunc: return emit_unary_intin(ctx, alu, DXIL_INTR_ROUND_Z, src[0]); 21337ec681f3Smrg case nir_op_fabs: return emit_unary_intin(ctx, alu, DXIL_INTR_FABS, src[0]); 21347ec681f3Smrg case nir_op_fcos: return emit_unary_intin(ctx, alu, DXIL_INTR_FCOS, src[0]); 21357ec681f3Smrg case nir_op_fsin: return emit_unary_intin(ctx, alu, DXIL_INTR_FSIN, src[0]); 21367ec681f3Smrg case nir_op_fceil: return emit_unary_intin(ctx, alu, DXIL_INTR_ROUND_PI, src[0]); 21377ec681f3Smrg case nir_op_fexp2: return emit_unary_intin(ctx, alu, DXIL_INTR_FEXP2, src[0]); 21387ec681f3Smrg case nir_op_flog2: return emit_unary_intin(ctx, alu, DXIL_INTR_FLOG2, src[0]); 21397ec681f3Smrg case nir_op_ffloor: return emit_unary_intin(ctx, alu, DXIL_INTR_ROUND_NI, src[0]); 21407ec681f3Smrg case nir_op_ffract: return emit_unary_intin(ctx, alu, DXIL_INTR_FRC, src[0]); 21417ec681f3Smrg case nir_op_fisnormal: return emit_unary_intin(ctx, alu, DXIL_INTR_ISNORMAL, src[0]); 21427ec681f3Smrg case nir_op_fisfinite: return emit_unary_intin(ctx, alu, DXIL_INTR_ISFINITE, src[0]); 21437ec681f3Smrg 21447ec681f3Smrg case nir_op_fddx: 21457ec681f3Smrg case nir_op_fddx_coarse: return emit_unary_intin(ctx, alu, DXIL_INTR_DDX_COARSE, src[0]); 21467ec681f3Smrg case nir_op_fddx_fine: return emit_unary_intin(ctx, alu, DXIL_INTR_DDX_FINE, src[0]); 21477ec681f3Smrg case nir_op_fddy: 21487ec681f3Smrg case nir_op_fddy_coarse: return emit_unary_intin(ctx, alu, DXIL_INTR_DDY_COARSE, src[0]); 21497ec681f3Smrg case nir_op_fddy_fine: return emit_unary_intin(ctx, alu, DXIL_INTR_DDY_FINE, src[0]); 21507ec681f3Smrg 21517ec681f3Smrg case nir_op_fround_even: return emit_unary_intin(ctx, alu, DXIL_INTR_ROUND_NE, src[0]); 21527ec681f3Smrg case nir_op_frcp: { 21537ec681f3Smrg const struct dxil_value *one = dxil_module_get_float_const(&ctx->mod, 1.0f); 21547ec681f3Smrg return emit_binop(ctx, alu, DXIL_BINOP_SDIV, one, src[0]); 21557ec681f3Smrg } 21567ec681f3Smrg case nir_op_fsat: return emit_unary_intin(ctx, alu, DXIL_INTR_SATURATE, src[0]); 21577ec681f3Smrg case nir_op_bit_count: return emit_unary_intin(ctx, alu, DXIL_INTR_COUNTBITS, src[0]); 21587ec681f3Smrg case nir_op_ufind_msb: return emit_ufind_msb(ctx, alu, src[0]); 21597ec681f3Smrg case nir_op_imax: return emit_binary_intin(ctx, alu, DXIL_INTR_IMAX, src[0], src[1]); 21607ec681f3Smrg case nir_op_imin: return emit_binary_intin(ctx, alu, DXIL_INTR_IMIN, src[0], src[1]); 21617ec681f3Smrg case nir_op_umax: return emit_binary_intin(ctx, alu, DXIL_INTR_UMAX, src[0], src[1]); 21627ec681f3Smrg case nir_op_umin: return emit_binary_intin(ctx, alu, DXIL_INTR_UMIN, src[0], src[1]); 21637ec681f3Smrg case nir_op_frsq: return emit_unary_intin(ctx, alu, DXIL_INTR_RSQRT, src[0]); 21647ec681f3Smrg case nir_op_fsqrt: return emit_unary_intin(ctx, alu, DXIL_INTR_SQRT, src[0]); 21657ec681f3Smrg case nir_op_fmax: return emit_binary_intin(ctx, alu, DXIL_INTR_FMAX, src[0], src[1]); 21667ec681f3Smrg case nir_op_fmin: return emit_binary_intin(ctx, alu, DXIL_INTR_FMIN, src[0], src[1]); 21677ec681f3Smrg case nir_op_ffma: return emit_tertiary_intin(ctx, alu, DXIL_INTR_FMA, src[0], src[1], src[2]); 21687ec681f3Smrg 21697ec681f3Smrg case nir_op_unpack_half_2x16_split_x: return emit_f16tof32(ctx, alu, src[0]); 21707ec681f3Smrg case nir_op_pack_half_2x16_split: return emit_f32tof16(ctx, alu, src[0]); 21717ec681f3Smrg 21727ec681f3Smrg case nir_op_b2i16: 21737ec681f3Smrg case nir_op_i2i16: 21747ec681f3Smrg case nir_op_f2i16: 21757ec681f3Smrg case nir_op_f2u16: 21767ec681f3Smrg case nir_op_u2u16: 21777ec681f3Smrg case nir_op_u2f16: 21787ec681f3Smrg case nir_op_i2f16: 21797ec681f3Smrg case nir_op_f2f16_rtz: 21807ec681f3Smrg case nir_op_b2i32: 21817ec681f3Smrg case nir_op_f2f32: 21827ec681f3Smrg case nir_op_f2i32: 21837ec681f3Smrg case nir_op_f2u32: 21847ec681f3Smrg case nir_op_i2f32: 21857ec681f3Smrg case nir_op_i2i32: 21867ec681f3Smrg case nir_op_u2f32: 21877ec681f3Smrg case nir_op_u2u32: 21887ec681f3Smrg case nir_op_b2i64: 21897ec681f3Smrg case nir_op_f2f64: 21907ec681f3Smrg case nir_op_f2i64: 21917ec681f3Smrg case nir_op_f2u64: 21927ec681f3Smrg case nir_op_i2f64: 21937ec681f3Smrg case nir_op_i2i64: 21947ec681f3Smrg case nir_op_u2f64: 21957ec681f3Smrg case nir_op_u2u64: 21967ec681f3Smrg return emit_cast(ctx, alu, src[0]); 21977ec681f3Smrg 21987ec681f3Smrg case nir_op_f2b32: return emit_f2b32(ctx, alu, src[0]); 21997ec681f3Smrg case nir_op_b2f16: return emit_b2f16(ctx, alu, src[0]); 22007ec681f3Smrg case nir_op_b2f32: return emit_b2f32(ctx, alu, src[0]); 22017ec681f3Smrg default: 22027ec681f3Smrg NIR_INSTR_UNSUPPORTED(&alu->instr); 22037ec681f3Smrg assert("Unimplemented ALU instruction"); 22047ec681f3Smrg return false; 22057ec681f3Smrg } 22067ec681f3Smrg} 22077ec681f3Smrg 22087ec681f3Smrgstatic const struct dxil_value * 22097ec681f3Smrgload_ubo(struct ntd_context *ctx, const struct dxil_value *handle, 22107ec681f3Smrg const struct dxil_value *offset, enum overload_type overload) 22117ec681f3Smrg{ 22127ec681f3Smrg assert(handle && offset); 22137ec681f3Smrg 22147ec681f3Smrg const struct dxil_value *opcode = dxil_module_get_int32_const(&ctx->mod, DXIL_INTR_CBUFFER_LOAD_LEGACY); 22157ec681f3Smrg if (!opcode) 22167ec681f3Smrg return NULL; 22177ec681f3Smrg 22187ec681f3Smrg const struct dxil_value *args[] = { 22197ec681f3Smrg opcode, handle, offset 22207ec681f3Smrg }; 22217ec681f3Smrg 22227ec681f3Smrg const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.cbufferLoadLegacy", overload); 22237ec681f3Smrg if (!func) 22247ec681f3Smrg return NULL; 22257ec681f3Smrg return dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args)); 22267ec681f3Smrg} 22277ec681f3Smrg 22287ec681f3Smrgstatic bool 22297ec681f3Smrgemit_barrier(struct ntd_context *ctx, nir_intrinsic_instr *intr) 22307ec681f3Smrg{ 22317ec681f3Smrg const struct dxil_value *opcode, *mode; 22327ec681f3Smrg const struct dxil_func *func; 22337ec681f3Smrg uint32_t flags = 0; 22347ec681f3Smrg 22357ec681f3Smrg if (nir_intrinsic_execution_scope(intr) == NIR_SCOPE_WORKGROUP) 22367ec681f3Smrg flags |= DXIL_BARRIER_MODE_SYNC_THREAD_GROUP; 22377ec681f3Smrg 22387ec681f3Smrg nir_variable_mode modes = nir_intrinsic_memory_modes(intr); 22397ec681f3Smrg nir_scope mem_scope = nir_intrinsic_memory_scope(intr); 22407ec681f3Smrg 22417ec681f3Smrg /* Currently vtn uses uniform to indicate image memory, which DXIL considers global */ 22427ec681f3Smrg if (modes & nir_var_uniform) 22437ec681f3Smrg modes |= nir_var_mem_global; 22447ec681f3Smrg 22457ec681f3Smrg if (modes & (nir_var_mem_ssbo | nir_var_mem_global)) { 22467ec681f3Smrg if (mem_scope > NIR_SCOPE_WORKGROUP) 22477ec681f3Smrg flags |= DXIL_BARRIER_MODE_UAV_FENCE_GLOBAL; 22487ec681f3Smrg else 22497ec681f3Smrg flags |= DXIL_BARRIER_MODE_UAV_FENCE_THREAD_GROUP; 22507ec681f3Smrg } 22517ec681f3Smrg 22527ec681f3Smrg if (modes & nir_var_mem_shared) 22537ec681f3Smrg flags |= DXIL_BARRIER_MODE_GROUPSHARED_MEM_FENCE; 22547ec681f3Smrg 22557ec681f3Smrg func = dxil_get_function(&ctx->mod, "dx.op.barrier", DXIL_NONE); 22567ec681f3Smrg if (!func) 22577ec681f3Smrg return false; 22587ec681f3Smrg 22597ec681f3Smrg opcode = dxil_module_get_int32_const(&ctx->mod, DXIL_INTR_BARRIER); 22607ec681f3Smrg if (!opcode) 22617ec681f3Smrg return false; 22627ec681f3Smrg 22637ec681f3Smrg mode = dxil_module_get_int32_const(&ctx->mod, flags); 22647ec681f3Smrg if (!mode) 22657ec681f3Smrg return false; 22667ec681f3Smrg 22677ec681f3Smrg const struct dxil_value *args[] = { opcode, mode }; 22687ec681f3Smrg 22697ec681f3Smrg return dxil_emit_call_void(&ctx->mod, func, 22707ec681f3Smrg args, ARRAY_SIZE(args)); 22717ec681f3Smrg} 22727ec681f3Smrg 22737ec681f3Smrgstatic bool 22747ec681f3Smrgemit_load_global_invocation_id(struct ntd_context *ctx, 22757ec681f3Smrg nir_intrinsic_instr *intr) 22767ec681f3Smrg{ 22777ec681f3Smrg assert(intr->dest.is_ssa); 22787ec681f3Smrg nir_component_mask_t comps = nir_ssa_def_components_read(&intr->dest.ssa); 22797ec681f3Smrg 22807ec681f3Smrg for (int i = 0; i < nir_intrinsic_dest_components(intr); i++) { 22817ec681f3Smrg if (comps & (1 << i)) { 22827ec681f3Smrg const struct dxil_value *idx = dxil_module_get_int32_const(&ctx->mod, i); 22837ec681f3Smrg if (!idx) 22847ec681f3Smrg return false; 22857ec681f3Smrg const struct dxil_value *globalid = emit_threadid_call(ctx, idx); 22867ec681f3Smrg 22877ec681f3Smrg if (!globalid) 22887ec681f3Smrg return false; 22897ec681f3Smrg 22907ec681f3Smrg store_dest_value(ctx, &intr->dest, i, globalid); 22917ec681f3Smrg } 22927ec681f3Smrg } 22937ec681f3Smrg return true; 22947ec681f3Smrg} 22957ec681f3Smrg 22967ec681f3Smrgstatic bool 22977ec681f3Smrgemit_load_local_invocation_id(struct ntd_context *ctx, 22987ec681f3Smrg nir_intrinsic_instr *intr) 22997ec681f3Smrg{ 23007ec681f3Smrg assert(intr->dest.is_ssa); 23017ec681f3Smrg nir_component_mask_t comps = nir_ssa_def_components_read(&intr->dest.ssa); 23027ec681f3Smrg 23037ec681f3Smrg for (int i = 0; i < nir_intrinsic_dest_components(intr); i++) { 23047ec681f3Smrg if (comps & (1 << i)) { 23057ec681f3Smrg const struct dxil_value 23067ec681f3Smrg *idx = dxil_module_get_int32_const(&ctx->mod, i); 23077ec681f3Smrg if (!idx) 23087ec681f3Smrg return false; 23097ec681f3Smrg const struct dxil_value 23107ec681f3Smrg *threadidingroup = emit_threadidingroup_call(ctx, idx); 23117ec681f3Smrg if (!threadidingroup) 23127ec681f3Smrg return false; 23137ec681f3Smrg store_dest_value(ctx, &intr->dest, i, threadidingroup); 23147ec681f3Smrg } 23157ec681f3Smrg } 23167ec681f3Smrg return true; 23177ec681f3Smrg} 23187ec681f3Smrg 23197ec681f3Smrgstatic bool 23207ec681f3Smrgemit_load_local_invocation_index(struct ntd_context *ctx, 23217ec681f3Smrg nir_intrinsic_instr *intr) 23227ec681f3Smrg{ 23237ec681f3Smrg assert(intr->dest.is_ssa); 23247ec681f3Smrg 23257ec681f3Smrg const struct dxil_value 23267ec681f3Smrg *flattenedthreadidingroup = emit_flattenedthreadidingroup_call(ctx); 23277ec681f3Smrg if (!flattenedthreadidingroup) 23287ec681f3Smrg return false; 23297ec681f3Smrg store_dest_value(ctx, &intr->dest, 0, flattenedthreadidingroup); 23307ec681f3Smrg 23317ec681f3Smrg return true; 23327ec681f3Smrg} 23337ec681f3Smrg 23347ec681f3Smrgstatic bool 23357ec681f3Smrgemit_load_local_workgroup_id(struct ntd_context *ctx, 23367ec681f3Smrg nir_intrinsic_instr *intr) 23377ec681f3Smrg{ 23387ec681f3Smrg assert(intr->dest.is_ssa); 23397ec681f3Smrg nir_component_mask_t comps = nir_ssa_def_components_read(&intr->dest.ssa); 23407ec681f3Smrg 23417ec681f3Smrg for (int i = 0; i < nir_intrinsic_dest_components(intr); i++) { 23427ec681f3Smrg if (comps & (1 << i)) { 23437ec681f3Smrg const struct dxil_value *idx = dxil_module_get_int32_const(&ctx->mod, i); 23447ec681f3Smrg if (!idx) 23457ec681f3Smrg return false; 23467ec681f3Smrg const struct dxil_value *groupid = emit_groupid_call(ctx, idx); 23477ec681f3Smrg if (!groupid) 23487ec681f3Smrg return false; 23497ec681f3Smrg store_dest_value(ctx, &intr->dest, i, groupid); 23507ec681f3Smrg } 23517ec681f3Smrg } 23527ec681f3Smrg return true; 23537ec681f3Smrg} 23547ec681f3Smrg 23557ec681f3Smrgstatic bool 23567ec681f3Smrgemit_load_unary_external_function(struct ntd_context *ctx, 23577ec681f3Smrg nir_intrinsic_instr *intr, const char *name, 23587ec681f3Smrg int32_t dxil_intr) 23597ec681f3Smrg{ 23607ec681f3Smrg const struct dxil_func *func = 23617ec681f3Smrg dxil_get_function(&ctx->mod, name, DXIL_I32); 23627ec681f3Smrg if (!func) 23637ec681f3Smrg return false; 23647ec681f3Smrg 23657ec681f3Smrg const struct dxil_value *opcode = 23667ec681f3Smrg dxil_module_get_int32_const(&ctx->mod, dxil_intr); 23677ec681f3Smrg if (!opcode) 23687ec681f3Smrg return false; 23697ec681f3Smrg 23707ec681f3Smrg const struct dxil_value *args[] = {opcode}; 23717ec681f3Smrg 23727ec681f3Smrg const struct dxil_value *value = 23737ec681f3Smrg dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args)); 23747ec681f3Smrg store_dest_value(ctx, &intr->dest, 0, value); 23757ec681f3Smrg 23767ec681f3Smrg return true; 23777ec681f3Smrg} 23787ec681f3Smrg 23797ec681f3Smrgstatic const struct dxil_value * 23807ec681f3Smrgget_int32_undef(struct dxil_module *m) 23817ec681f3Smrg{ 23827ec681f3Smrg const struct dxil_type *int32_type = 23837ec681f3Smrg dxil_module_get_int_type(m, 32); 23847ec681f3Smrg if (!int32_type) 23857ec681f3Smrg return NULL; 23867ec681f3Smrg 23877ec681f3Smrg return dxil_module_get_undef(m, int32_type); 23887ec681f3Smrg} 23897ec681f3Smrg 23907ec681f3Smrgstatic const struct dxil_value * 23917ec681f3Smrgemit_gep_for_index(struct ntd_context *ctx, const nir_variable *var, 23927ec681f3Smrg const struct dxil_value *index) 23937ec681f3Smrg{ 23947ec681f3Smrg assert(var->data.mode == nir_var_shader_temp); 23957ec681f3Smrg 23967ec681f3Smrg struct hash_entry *he = _mesa_hash_table_search(ctx->consts, var); 23977ec681f3Smrg assert(he != NULL); 23987ec681f3Smrg const struct dxil_value *ptr = he->data; 23997ec681f3Smrg 24007ec681f3Smrg const struct dxil_value *zero = dxil_module_get_int32_const(&ctx->mod, 0); 24017ec681f3Smrg if (!zero) 24027ec681f3Smrg return NULL; 24037ec681f3Smrg 24047ec681f3Smrg const struct dxil_value *ops[] = { ptr, zero, index }; 24057ec681f3Smrg return dxil_emit_gep_inbounds(&ctx->mod, ops, ARRAY_SIZE(ops)); 24067ec681f3Smrg} 24077ec681f3Smrg 24087ec681f3Smrgstatic const struct dxil_value * 24097ec681f3Smrgget_ubo_ssbo_handle(struct ntd_context *ctx, nir_src *src, enum dxil_resource_class class, unsigned base_binding) 24107ec681f3Smrg{ 24117ec681f3Smrg /* This source might be one of: 24127ec681f3Smrg * 1. Constant resource index - just look it up in precomputed handle arrays 24137ec681f3Smrg * If it's null in that array, create a handle, and store the result 24147ec681f3Smrg * 2. A handle from load_vulkan_descriptor - just get the stored SSA value 24157ec681f3Smrg * 3. Dynamic resource index - create a handle for it here 24167ec681f3Smrg */ 24177ec681f3Smrg assert(src->ssa->num_components == 1 && src->ssa->bit_size == 32); 24187ec681f3Smrg nir_const_value *const_block_index = nir_src_as_const_value(*src); 24197ec681f3Smrg const struct dxil_value **handle_entry = NULL; 24207ec681f3Smrg if (const_block_index) { 24217ec681f3Smrg assert(!ctx->opts->vulkan_environment); 24227ec681f3Smrg switch (class) { 24237ec681f3Smrg case DXIL_RESOURCE_CLASS_CBV: 24247ec681f3Smrg handle_entry = &ctx->cbv_handles[const_block_index->u32]; 24257ec681f3Smrg break; 24267ec681f3Smrg case DXIL_RESOURCE_CLASS_UAV: 24277ec681f3Smrg handle_entry = &ctx->uav_handles[const_block_index->u32]; 24287ec681f3Smrg break; 24297ec681f3Smrg case DXIL_RESOURCE_CLASS_SRV: 24307ec681f3Smrg handle_entry = &ctx->srv_handles[const_block_index->u32]; 24317ec681f3Smrg break; 24327ec681f3Smrg default: 24337ec681f3Smrg unreachable("Unexpected resource class"); 24347ec681f3Smrg } 24357ec681f3Smrg } 24367ec681f3Smrg 24377ec681f3Smrg if (handle_entry && *handle_entry) 24387ec681f3Smrg return *handle_entry; 24397ec681f3Smrg 24407ec681f3Smrg const struct dxil_value *value = get_src_ssa(ctx, src->ssa, 0); 24417ec681f3Smrg if (ctx->opts->vulkan_environment) { 24427ec681f3Smrg return value; 24437ec681f3Smrg } 24447ec681f3Smrg 24457ec681f3Smrg const struct dxil_value *handle = emit_createhandle_call(ctx, class, 24467ec681f3Smrg get_resource_id(ctx, class, 0, base_binding), value, !const_block_index); 24477ec681f3Smrg if (handle_entry) 24487ec681f3Smrg *handle_entry = handle; 24497ec681f3Smrg 24507ec681f3Smrg return handle; 24517ec681f3Smrg} 24527ec681f3Smrg 24537ec681f3Smrgstatic bool 24547ec681f3Smrgemit_load_ssbo(struct ntd_context *ctx, nir_intrinsic_instr *intr) 24557ec681f3Smrg{ 24567ec681f3Smrg const struct dxil_value *int32_undef = get_int32_undef(&ctx->mod); 24577ec681f3Smrg 24587ec681f3Smrg nir_variable *var = nir_get_binding_variable(ctx->shader, nir_chase_binding(intr->src[0])); 24597ec681f3Smrg enum dxil_resource_class class = DXIL_RESOURCE_CLASS_UAV; 24607ec681f3Smrg if (var && var->data.access & ACCESS_NON_WRITEABLE) 24617ec681f3Smrg class = DXIL_RESOURCE_CLASS_SRV; 24627ec681f3Smrg 24637ec681f3Smrg const struct dxil_value *handle = get_ubo_ssbo_handle(ctx, &intr->src[0], class, 0); 24647ec681f3Smrg const struct dxil_value *offset = 24657ec681f3Smrg get_src(ctx, &intr->src[1], 0, nir_type_uint); 24667ec681f3Smrg if (!int32_undef || !handle || !offset) 24677ec681f3Smrg return false; 24687ec681f3Smrg 24697ec681f3Smrg assert(nir_src_bit_size(intr->src[0]) == 32); 24707ec681f3Smrg assert(nir_intrinsic_dest_components(intr) <= 4); 24717ec681f3Smrg 24727ec681f3Smrg const struct dxil_value *coord[2] = { 24737ec681f3Smrg offset, 24747ec681f3Smrg int32_undef 24757ec681f3Smrg }; 24767ec681f3Smrg 24777ec681f3Smrg const struct dxil_value *load = emit_bufferload_call(ctx, handle, coord, DXIL_I32); 24787ec681f3Smrg if (!load) 24797ec681f3Smrg return false; 24807ec681f3Smrg 24817ec681f3Smrg for (int i = 0; i < nir_intrinsic_dest_components(intr); i++) { 24827ec681f3Smrg const struct dxil_value *val = 24837ec681f3Smrg dxil_emit_extractval(&ctx->mod, load, i); 24847ec681f3Smrg if (!val) 24857ec681f3Smrg return false; 24867ec681f3Smrg store_dest_value(ctx, &intr->dest, i, val); 24877ec681f3Smrg } 24887ec681f3Smrg return true; 24897ec681f3Smrg} 24907ec681f3Smrg 24917ec681f3Smrgstatic bool 24927ec681f3Smrgemit_store_ssbo(struct ntd_context *ctx, nir_intrinsic_instr *intr) 24937ec681f3Smrg{ 24947ec681f3Smrg const struct dxil_value* handle = get_ubo_ssbo_handle(ctx, &intr->src[1], DXIL_RESOURCE_CLASS_UAV, 0); 24957ec681f3Smrg const struct dxil_value *offset = 24967ec681f3Smrg get_src(ctx, &intr->src[2], 0, nir_type_uint); 24977ec681f3Smrg if (!handle || !offset) 24987ec681f3Smrg return false; 24997ec681f3Smrg 25007ec681f3Smrg assert(nir_src_bit_size(intr->src[0]) == 32); 25017ec681f3Smrg unsigned num_components = nir_src_num_components(intr->src[0]); 25027ec681f3Smrg assert(num_components <= 4); 25037ec681f3Smrg const struct dxil_value *value[4]; 25047ec681f3Smrg for (unsigned i = 0; i < num_components; ++i) { 25057ec681f3Smrg value[i] = get_src(ctx, &intr->src[0], i, nir_type_uint); 25067ec681f3Smrg if (!value[i]) 25077ec681f3Smrg return false; 25087ec681f3Smrg } 25097ec681f3Smrg 25107ec681f3Smrg const struct dxil_value *int32_undef = get_int32_undef(&ctx->mod); 25117ec681f3Smrg if (!int32_undef) 25127ec681f3Smrg return false; 25137ec681f3Smrg 25147ec681f3Smrg const struct dxil_value *coord[2] = { 25157ec681f3Smrg offset, 25167ec681f3Smrg int32_undef 25177ec681f3Smrg }; 25187ec681f3Smrg 25197ec681f3Smrg for (int i = num_components; i < 4; ++i) 25207ec681f3Smrg value[i] = int32_undef; 25217ec681f3Smrg 25227ec681f3Smrg const struct dxil_value *write_mask = 25237ec681f3Smrg dxil_module_get_int8_const(&ctx->mod, (1u << num_components) - 1); 25247ec681f3Smrg if (!write_mask) 25257ec681f3Smrg return false; 25267ec681f3Smrg 25277ec681f3Smrg return emit_bufferstore_call(ctx, handle, coord, value, write_mask, DXIL_I32); 25287ec681f3Smrg} 25297ec681f3Smrg 25307ec681f3Smrgstatic bool 25317ec681f3Smrgemit_store_ssbo_masked(struct ntd_context *ctx, nir_intrinsic_instr *intr) 25327ec681f3Smrg{ 25337ec681f3Smrg const struct dxil_value *value = 25347ec681f3Smrg get_src(ctx, &intr->src[0], 0, nir_type_uint); 25357ec681f3Smrg const struct dxil_value *mask = 25367ec681f3Smrg get_src(ctx, &intr->src[1], 0, nir_type_uint); 25377ec681f3Smrg const struct dxil_value* handle = get_ubo_ssbo_handle(ctx, &intr->src[2], DXIL_RESOURCE_CLASS_UAV, 0); 25387ec681f3Smrg const struct dxil_value *offset = 25397ec681f3Smrg get_src(ctx, &intr->src[3], 0, nir_type_uint); 25407ec681f3Smrg if (!value || !mask || !handle || !offset) 25417ec681f3Smrg return false; 25427ec681f3Smrg 25437ec681f3Smrg const struct dxil_value *int32_undef = get_int32_undef(&ctx->mod); 25447ec681f3Smrg if (!int32_undef) 25457ec681f3Smrg return false; 25467ec681f3Smrg 25477ec681f3Smrg const struct dxil_value *coord[3] = { 25487ec681f3Smrg offset, int32_undef, int32_undef 25497ec681f3Smrg }; 25507ec681f3Smrg 25517ec681f3Smrg return 25527ec681f3Smrg emit_atomic_binop(ctx, handle, DXIL_ATOMIC_AND, coord, mask) != NULL && 25537ec681f3Smrg emit_atomic_binop(ctx, handle, DXIL_ATOMIC_OR, coord, value) != NULL; 25547ec681f3Smrg} 25557ec681f3Smrg 25567ec681f3Smrgstatic bool 25577ec681f3Smrgemit_store_shared(struct ntd_context *ctx, nir_intrinsic_instr *intr) 25587ec681f3Smrg{ 25597ec681f3Smrg const struct dxil_value *zero, *index; 25607ec681f3Smrg 25617ec681f3Smrg /* All shared mem accesses should have been lowered to scalar 32bit 25627ec681f3Smrg * accesses. 25637ec681f3Smrg */ 25647ec681f3Smrg assert(nir_src_bit_size(intr->src[0]) == 32); 25657ec681f3Smrg assert(nir_src_num_components(intr->src[0]) == 1); 25667ec681f3Smrg 25677ec681f3Smrg zero = dxil_module_get_int32_const(&ctx->mod, 0); 25687ec681f3Smrg if (!zero) 25697ec681f3Smrg return false; 25707ec681f3Smrg 25717ec681f3Smrg if (intr->intrinsic == nir_intrinsic_store_shared_dxil) 25727ec681f3Smrg index = get_src(ctx, &intr->src[1], 0, nir_type_uint); 25737ec681f3Smrg else 25747ec681f3Smrg index = get_src(ctx, &intr->src[2], 0, nir_type_uint); 25757ec681f3Smrg if (!index) 25767ec681f3Smrg return false; 25777ec681f3Smrg 25787ec681f3Smrg const struct dxil_value *ops[] = { ctx->sharedvars, zero, index }; 25797ec681f3Smrg const struct dxil_value *ptr, *value; 25807ec681f3Smrg 25817ec681f3Smrg ptr = dxil_emit_gep_inbounds(&ctx->mod, ops, ARRAY_SIZE(ops)); 25827ec681f3Smrg if (!ptr) 25837ec681f3Smrg return false; 25847ec681f3Smrg 25857ec681f3Smrg value = get_src(ctx, &intr->src[0], 0, nir_type_uint); 25867ec681f3Smrg if (!value) 25877ec681f3Smrg return false; 25887ec681f3Smrg 25897ec681f3Smrg if (intr->intrinsic == nir_intrinsic_store_shared_dxil) 25907ec681f3Smrg return dxil_emit_store(&ctx->mod, value, ptr, 4, false); 25917ec681f3Smrg 25927ec681f3Smrg const struct dxil_value *mask = get_src(ctx, &intr->src[1], 0, nir_type_uint); 25937ec681f3Smrg if (!mask) 25947ec681f3Smrg return false; 25957ec681f3Smrg 25967ec681f3Smrg if (!dxil_emit_atomicrmw(&ctx->mod, mask, ptr, DXIL_RMWOP_AND, false, 25977ec681f3Smrg DXIL_ATOMIC_ORDERING_ACQREL, 25987ec681f3Smrg DXIL_SYNC_SCOPE_CROSSTHREAD)) 25997ec681f3Smrg return false; 26007ec681f3Smrg 26017ec681f3Smrg if (!dxil_emit_atomicrmw(&ctx->mod, value, ptr, DXIL_RMWOP_OR, false, 26027ec681f3Smrg DXIL_ATOMIC_ORDERING_ACQREL, 26037ec681f3Smrg DXIL_SYNC_SCOPE_CROSSTHREAD)) 26047ec681f3Smrg return false; 26057ec681f3Smrg 26067ec681f3Smrg return true; 26077ec681f3Smrg} 26087ec681f3Smrg 26097ec681f3Smrgstatic bool 26107ec681f3Smrgemit_store_scratch(struct ntd_context *ctx, nir_intrinsic_instr *intr) 26117ec681f3Smrg{ 26127ec681f3Smrg const struct dxil_value *zero, *index; 26137ec681f3Smrg 26147ec681f3Smrg /* All scratch mem accesses should have been lowered to scalar 32bit 26157ec681f3Smrg * accesses. 26167ec681f3Smrg */ 26177ec681f3Smrg assert(nir_src_bit_size(intr->src[0]) == 32); 26187ec681f3Smrg assert(nir_src_num_components(intr->src[0]) == 1); 26197ec681f3Smrg 26207ec681f3Smrg zero = dxil_module_get_int32_const(&ctx->mod, 0); 26217ec681f3Smrg if (!zero) 26227ec681f3Smrg return false; 26237ec681f3Smrg 26247ec681f3Smrg index = get_src(ctx, &intr->src[1], 0, nir_type_uint); 26257ec681f3Smrg if (!index) 26267ec681f3Smrg return false; 26277ec681f3Smrg 26287ec681f3Smrg const struct dxil_value *ops[] = { ctx->scratchvars, zero, index }; 26297ec681f3Smrg const struct dxil_value *ptr, *value; 26307ec681f3Smrg 26317ec681f3Smrg ptr = dxil_emit_gep_inbounds(&ctx->mod, ops, ARRAY_SIZE(ops)); 26327ec681f3Smrg if (!ptr) 26337ec681f3Smrg return false; 26347ec681f3Smrg 26357ec681f3Smrg value = get_src(ctx, &intr->src[0], 0, nir_type_uint); 26367ec681f3Smrg if (!value) 26377ec681f3Smrg return false; 26387ec681f3Smrg 26397ec681f3Smrg return dxil_emit_store(&ctx->mod, value, ptr, 4, false); 26407ec681f3Smrg} 26417ec681f3Smrg 26427ec681f3Smrgstatic bool 26437ec681f3Smrgemit_load_ubo(struct ntd_context *ctx, nir_intrinsic_instr *intr) 26447ec681f3Smrg{ 26457ec681f3Smrg const struct dxil_value* handle = get_ubo_ssbo_handle(ctx, &intr->src[0], DXIL_RESOURCE_CLASS_CBV, 0); 26467ec681f3Smrg if (!handle) 26477ec681f3Smrg return false; 26487ec681f3Smrg 26497ec681f3Smrg const struct dxil_value *offset; 26507ec681f3Smrg nir_const_value *const_offset = nir_src_as_const_value(intr->src[1]); 26517ec681f3Smrg if (const_offset) { 26527ec681f3Smrg offset = dxil_module_get_int32_const(&ctx->mod, const_offset->i32 >> 4); 26537ec681f3Smrg } else { 26547ec681f3Smrg const struct dxil_value *offset_src = get_src(ctx, &intr->src[1], 0, nir_type_uint); 26557ec681f3Smrg const struct dxil_value *c4 = dxil_module_get_int32_const(&ctx->mod, 4); 26567ec681f3Smrg if (!offset_src || !c4) 26577ec681f3Smrg return false; 26587ec681f3Smrg 26597ec681f3Smrg offset = dxil_emit_binop(&ctx->mod, DXIL_BINOP_ASHR, offset_src, c4, 0); 26607ec681f3Smrg } 26617ec681f3Smrg 26627ec681f3Smrg const struct dxil_value *agg = load_ubo(ctx, handle, offset, DXIL_F32); 26637ec681f3Smrg 26647ec681f3Smrg if (!agg) 26657ec681f3Smrg return false; 26667ec681f3Smrg 26677ec681f3Smrg for (unsigned i = 0; i < nir_dest_num_components(intr->dest); ++i) { 26687ec681f3Smrg const struct dxil_value *retval = dxil_emit_extractval(&ctx->mod, agg, i); 26697ec681f3Smrg store_dest(ctx, &intr->dest, i, retval, 26707ec681f3Smrg nir_dest_bit_size(intr->dest) > 1 ? nir_type_float : nir_type_bool); 26717ec681f3Smrg } 26727ec681f3Smrg return true; 26737ec681f3Smrg} 26747ec681f3Smrg 26757ec681f3Smrgstatic bool 26767ec681f3Smrgemit_load_ubo_dxil(struct ntd_context *ctx, nir_intrinsic_instr *intr) 26777ec681f3Smrg{ 26787ec681f3Smrg assert(nir_dest_num_components(intr->dest) <= 4); 26797ec681f3Smrg assert(nir_dest_bit_size(intr->dest) == 32); 26807ec681f3Smrg 26817ec681f3Smrg const struct dxil_value* handle = get_ubo_ssbo_handle(ctx, &intr->src[0], DXIL_RESOURCE_CLASS_CBV, 0); 26827ec681f3Smrg const struct dxil_value *offset = 26837ec681f3Smrg get_src(ctx, &intr->src[1], 0, nir_type_uint); 26847ec681f3Smrg 26857ec681f3Smrg if (!handle || !offset) 26867ec681f3Smrg return false; 26877ec681f3Smrg 26887ec681f3Smrg const struct dxil_value *agg = load_ubo(ctx, handle, offset, DXIL_I32); 26897ec681f3Smrg if (!agg) 26907ec681f3Smrg return false; 26917ec681f3Smrg 26927ec681f3Smrg for (unsigned i = 0; i < nir_dest_num_components(intr->dest); i++) 26937ec681f3Smrg store_dest_value(ctx, &intr->dest, i, 26947ec681f3Smrg dxil_emit_extractval(&ctx->mod, agg, i)); 26957ec681f3Smrg 26967ec681f3Smrg return true; 26977ec681f3Smrg} 26987ec681f3Smrg 26997ec681f3Smrgstatic bool 27007ec681f3Smrgemit_store_output(struct ntd_context *ctx, nir_intrinsic_instr *intr, 27017ec681f3Smrg nir_variable *output) 27027ec681f3Smrg{ 27037ec681f3Smrg nir_alu_type out_type = nir_get_nir_type_for_glsl_base_type(glsl_get_base_type(output->type)); 27047ec681f3Smrg enum overload_type overload = DXIL_F32; 27057ec681f3Smrg if (output->data.compact) 27067ec681f3Smrg out_type = nir_type_float; 27077ec681f3Smrg else 27087ec681f3Smrg overload = get_overload(out_type, glsl_get_bit_size(output->type)); 27097ec681f3Smrg const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.storeOutput", overload); 27107ec681f3Smrg 27117ec681f3Smrg if (!func) 27127ec681f3Smrg return false; 27137ec681f3Smrg 27147ec681f3Smrg const struct dxil_value *opcode = dxil_module_get_int32_const(&ctx->mod, DXIL_INTR_STORE_OUTPUT); 27157ec681f3Smrg const struct dxil_value *output_id = dxil_module_get_int32_const(&ctx->mod, (int)output->data.driver_location); 27167ec681f3Smrg const struct dxil_value *row = dxil_module_get_int32_const(&ctx->mod, 0); 27177ec681f3Smrg 27187ec681f3Smrg bool success = true; 27197ec681f3Smrg if (output->data.compact) { 27207ec681f3Smrg nir_deref_instr *array_deref = nir_instr_as_deref(intr->src[0].ssa->parent_instr); 27217ec681f3Smrg unsigned array_index = nir_src_as_uint(array_deref->arr.index); 27227ec681f3Smrg 27237ec681f3Smrg const struct dxil_value *col = dxil_module_get_int8_const(&ctx->mod, array_index); 27247ec681f3Smrg const struct dxil_value *value = get_src(ctx, &intr->src[1], 0, out_type); 27257ec681f3Smrg if (!col || !value) 27267ec681f3Smrg return false; 27277ec681f3Smrg 27287ec681f3Smrg const struct dxil_value *args[] = { 27297ec681f3Smrg opcode, output_id, row, col, value 27307ec681f3Smrg }; 27317ec681f3Smrg success = dxil_emit_call_void(&ctx->mod, func, args, ARRAY_SIZE(args)); 27327ec681f3Smrg } else { 27337ec681f3Smrg uint32_t writemask = nir_intrinsic_write_mask(intr); 27347ec681f3Smrg for (unsigned i = 0; i < nir_src_num_components(intr->src[1]) && success; ++i) { 27357ec681f3Smrg if (writemask & (1 << i)) { 27367ec681f3Smrg const struct dxil_value *col = dxil_module_get_int8_const(&ctx->mod, i); 27377ec681f3Smrg const struct dxil_value *value = get_src(ctx, &intr->src[1], i, out_type); 27387ec681f3Smrg if (!col || !value) 27397ec681f3Smrg return false; 27407ec681f3Smrg 27417ec681f3Smrg const struct dxil_value *args[] = { 27427ec681f3Smrg opcode, output_id, row, col, value 27437ec681f3Smrg }; 27447ec681f3Smrg success &= dxil_emit_call_void(&ctx->mod, func, args, ARRAY_SIZE(args)); 27457ec681f3Smrg } 27467ec681f3Smrg } 27477ec681f3Smrg } 27487ec681f3Smrg return success; 27497ec681f3Smrg} 27507ec681f3Smrg 27517ec681f3Smrgstatic bool 27527ec681f3Smrgemit_store_deref(struct ntd_context *ctx, nir_intrinsic_instr *intr) 27537ec681f3Smrg{ 27547ec681f3Smrg nir_deref_instr *deref = nir_src_as_deref(intr->src[0]); 27557ec681f3Smrg nir_variable *var = nir_deref_instr_get_variable(deref); 27567ec681f3Smrg 27577ec681f3Smrg switch (var->data.mode) { 27587ec681f3Smrg case nir_var_shader_out: 27597ec681f3Smrg return emit_store_output(ctx, intr, var); 27607ec681f3Smrg 27617ec681f3Smrg default: 27627ec681f3Smrg unreachable("unsupported nir_variable_mode"); 27637ec681f3Smrg } 27647ec681f3Smrg} 27657ec681f3Smrg 27667ec681f3Smrgstatic bool 27677ec681f3Smrgemit_load_input_array(struct ntd_context *ctx, nir_intrinsic_instr *intr, nir_variable *var, nir_src *index) 27687ec681f3Smrg{ 27697ec681f3Smrg assert(var); 27707ec681f3Smrg const struct dxil_value *opcode = dxil_module_get_int32_const(&ctx->mod, DXIL_INTR_LOAD_INPUT); 27717ec681f3Smrg const struct dxil_value *input_id = dxil_module_get_int32_const(&ctx->mod, var->data.driver_location); 27727ec681f3Smrg const struct dxil_value *vertex_id; 27737ec681f3Smrg const struct dxil_value *row; 27747ec681f3Smrg 27757ec681f3Smrg if (ctx->mod.shader_kind == DXIL_GEOMETRY_SHADER) { 27767ec681f3Smrg vertex_id = get_src(ctx, index, 0, nir_type_int); 27777ec681f3Smrg row = dxil_module_get_int32_const(&ctx->mod, 0); 27787ec681f3Smrg } else { 27797ec681f3Smrg const struct dxil_type *int32_type = dxil_module_get_int_type(&ctx->mod, 32); 27807ec681f3Smrg vertex_id = dxil_module_get_undef(&ctx->mod, int32_type); 27817ec681f3Smrg row = get_src(ctx, index, 0, nir_type_int); 27827ec681f3Smrg } 27837ec681f3Smrg 27847ec681f3Smrg if (!opcode || !input_id || !vertex_id || !row) 27857ec681f3Smrg return false; 27867ec681f3Smrg 27877ec681f3Smrg nir_alu_type out_type = nir_get_nir_type_for_glsl_base_type(glsl_get_base_type(glsl_get_array_element(var->type))); 27887ec681f3Smrg enum overload_type overload = get_overload(out_type, glsl_get_bit_size(glsl_get_array_element(var->type))); 27897ec681f3Smrg 27907ec681f3Smrg const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.loadInput", overload); 27917ec681f3Smrg 27927ec681f3Smrg if (!func) 27937ec681f3Smrg return false; 27947ec681f3Smrg 27957ec681f3Smrg for (unsigned i = 0; i < nir_dest_num_components(intr->dest); ++i) { 27967ec681f3Smrg const struct dxil_value *comp = dxil_module_get_int8_const(&ctx->mod, i); 27977ec681f3Smrg if (!comp) 27987ec681f3Smrg return false; 27997ec681f3Smrg 28007ec681f3Smrg const struct dxil_value *args[] = { 28017ec681f3Smrg opcode, input_id, row, comp, vertex_id 28027ec681f3Smrg }; 28037ec681f3Smrg 28047ec681f3Smrg const struct dxil_value *retval = dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args)); 28057ec681f3Smrg if (!retval) 28067ec681f3Smrg return false; 28077ec681f3Smrg store_dest(ctx, &intr->dest, i, retval, out_type); 28087ec681f3Smrg } 28097ec681f3Smrg return true; 28107ec681f3Smrg} 28117ec681f3Smrg 28127ec681f3Smrgstatic bool 28137ec681f3Smrgemit_load_compact_input_array(struct ntd_context *ctx, nir_intrinsic_instr *intr, nir_variable *var, nir_deref_instr *deref) 28147ec681f3Smrg{ 28157ec681f3Smrg assert(var); 28167ec681f3Smrg const struct dxil_value *opcode = dxil_module_get_int32_const(&ctx->mod, DXIL_INTR_LOAD_INPUT); 28177ec681f3Smrg const struct dxil_value *input_id = dxil_module_get_int32_const(&ctx->mod, var->data.driver_location); 28187ec681f3Smrg const struct dxil_value *row = dxil_module_get_int32_const(&ctx->mod, 0); 28197ec681f3Smrg const struct dxil_value *vertex_id; 28207ec681f3Smrg 28217ec681f3Smrg nir_src *col = &deref->arr.index; 28227ec681f3Smrg nir_src_is_const(*col); 28237ec681f3Smrg 28247ec681f3Smrg if (ctx->mod.shader_kind == DXIL_GEOMETRY_SHADER) { 28257ec681f3Smrg nir_deref_instr *deref_parent = nir_deref_instr_parent(deref); 28267ec681f3Smrg assert(deref_parent->deref_type == nir_deref_type_array); 28277ec681f3Smrg 28287ec681f3Smrg vertex_id = get_src(ctx, &deref_parent->arr.index, 0, nir_type_int); 28297ec681f3Smrg } else { 28307ec681f3Smrg const struct dxil_type *int32_type = dxil_module_get_int_type(&ctx->mod, 32); 28317ec681f3Smrg vertex_id = dxil_module_get_undef(&ctx->mod, int32_type); 28327ec681f3Smrg } 28337ec681f3Smrg 28347ec681f3Smrg if (!opcode || !input_id || !row || !vertex_id) 28357ec681f3Smrg return false; 28367ec681f3Smrg 28377ec681f3Smrg nir_alu_type out_type = nir_type_float; 28387ec681f3Smrg enum overload_type overload = get_overload(out_type, 32); 28397ec681f3Smrg 28407ec681f3Smrg const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.loadInput", overload); 28417ec681f3Smrg 28427ec681f3Smrg if (!func) 28437ec681f3Smrg return false; 28447ec681f3Smrg 28457ec681f3Smrg const struct dxil_value *comp = dxil_module_get_int8_const(&ctx->mod, nir_src_as_int(*col)); 28467ec681f3Smrg if (!comp) 28477ec681f3Smrg return false; 28487ec681f3Smrg 28497ec681f3Smrg const struct dxil_value *args[] = { 28507ec681f3Smrg opcode, input_id, row, comp, vertex_id 28517ec681f3Smrg }; 28527ec681f3Smrg 28537ec681f3Smrg const struct dxil_value *retval = dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args)); 28547ec681f3Smrg if (!retval) 28557ec681f3Smrg return false; 28567ec681f3Smrg store_dest(ctx, &intr->dest, 0, retval, out_type); 28577ec681f3Smrg return true; 28587ec681f3Smrg} 28597ec681f3Smrg 28607ec681f3Smrgstatic bool 28617ec681f3Smrgemit_load_input_interpolated(struct ntd_context *ctx, nir_intrinsic_instr *intr, nir_variable *var) 28627ec681f3Smrg{ 28637ec681f3Smrg assert(var); 28647ec681f3Smrg const struct dxil_value *opcode = dxil_module_get_int32_const(&ctx->mod, DXIL_INTR_LOAD_INPUT); 28657ec681f3Smrg const struct dxil_value *input_id = dxil_module_get_int32_const(&ctx->mod, var->data.driver_location); 28667ec681f3Smrg const struct dxil_value *row = dxil_module_get_int32_const(&ctx->mod, 0); 28677ec681f3Smrg const struct dxil_type *int32_type = dxil_module_get_int_type(&ctx->mod, 32); 28687ec681f3Smrg const struct dxil_value *vertex_id = dxil_module_get_undef(&ctx->mod, int32_type); 28697ec681f3Smrg 28707ec681f3Smrg if (!opcode || !input_id || !row || !int32_type || !vertex_id) 28717ec681f3Smrg return false; 28727ec681f3Smrg 28737ec681f3Smrg nir_alu_type out_type = nir_get_nir_type_for_glsl_base_type(glsl_get_base_type(var->type)); 28747ec681f3Smrg enum overload_type overload = get_overload(out_type, glsl_get_bit_size(var->type)); 28757ec681f3Smrg 28767ec681f3Smrg const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.loadInput", overload); 28777ec681f3Smrg 28787ec681f3Smrg if (!func) 28797ec681f3Smrg return false; 28807ec681f3Smrg 28817ec681f3Smrg for (unsigned i = 0; i < nir_dest_num_components(intr->dest); ++i) { 28827ec681f3Smrg const struct dxil_value *comp = dxil_module_get_int8_const(&ctx->mod, i); 28837ec681f3Smrg 28847ec681f3Smrg const struct dxil_value *args[] = { 28857ec681f3Smrg opcode, input_id, row, comp, vertex_id 28867ec681f3Smrg }; 28877ec681f3Smrg 28887ec681f3Smrg const struct dxil_value *retval = dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args)); 28897ec681f3Smrg if (!retval) 28907ec681f3Smrg return false; 28917ec681f3Smrg store_dest(ctx, &intr->dest, i, retval, out_type); 28927ec681f3Smrg } 28937ec681f3Smrg return true; 28947ec681f3Smrg} 28957ec681f3Smrg 28967ec681f3Smrgstatic bool 28977ec681f3Smrgemit_load_input_flat(struct ntd_context *ctx, nir_intrinsic_instr *intr, nir_variable* var) 28987ec681f3Smrg{ 28997ec681f3Smrg const struct dxil_value *opcode = dxil_module_get_int32_const(&ctx->mod, DXIL_INTR_ATTRIBUTE_AT_VERTEX); 29007ec681f3Smrg const struct dxil_value *input_id = dxil_module_get_int32_const(&ctx->mod, (int)var->data.driver_location); 29017ec681f3Smrg const struct dxil_value *row = dxil_module_get_int32_const(&ctx->mod, 0); 29027ec681f3Smrg const struct dxil_value *vertex_id = dxil_module_get_int8_const(&ctx->mod, ctx->opts->provoking_vertex); 29037ec681f3Smrg 29047ec681f3Smrg nir_alu_type out_type = nir_get_nir_type_for_glsl_base_type(glsl_get_base_type(var->type)); 29057ec681f3Smrg enum overload_type overload = get_overload(out_type, glsl_get_bit_size(var->type)); 29067ec681f3Smrg 29077ec681f3Smrg const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.attributeAtVertex", overload); 29087ec681f3Smrg if (!func) 29097ec681f3Smrg return false; 29107ec681f3Smrg 29117ec681f3Smrg for (unsigned i = 0; i < nir_dest_num_components(intr->dest); ++i) { 29127ec681f3Smrg const struct dxil_value *comp = dxil_module_get_int8_const(&ctx->mod, i); 29137ec681f3Smrg const struct dxil_value *args[] = { 29147ec681f3Smrg opcode, input_id, row, comp, vertex_id 29157ec681f3Smrg }; 29167ec681f3Smrg 29177ec681f3Smrg const struct dxil_value *retval = dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args)); 29187ec681f3Smrg if (!retval) 29197ec681f3Smrg return false; 29207ec681f3Smrg 29217ec681f3Smrg store_dest(ctx, &intr->dest, i, retval, out_type); 29227ec681f3Smrg } 29237ec681f3Smrg return true; 29247ec681f3Smrg} 29257ec681f3Smrg 29267ec681f3Smrgstatic bool 29277ec681f3Smrgemit_load_input(struct ntd_context *ctx, nir_intrinsic_instr *intr, 29287ec681f3Smrg nir_variable *input) 29297ec681f3Smrg{ 29307ec681f3Smrg if (ctx->mod.shader_kind != DXIL_PIXEL_SHADER || 29317ec681f3Smrg input->data.interpolation != INTERP_MODE_FLAT || 29327ec681f3Smrg !ctx->opts->interpolate_at_vertex || 29337ec681f3Smrg ctx->opts->provoking_vertex == 0 || 29347ec681f3Smrg glsl_type_is_integer(input->type)) 29357ec681f3Smrg return emit_load_input_interpolated(ctx, intr, input); 29367ec681f3Smrg else 29377ec681f3Smrg return emit_load_input_flat(ctx, intr, input); 29387ec681f3Smrg} 29397ec681f3Smrg 29407ec681f3Smrgstatic bool 29417ec681f3Smrgemit_load_ptr(struct ntd_context *ctx, nir_intrinsic_instr *intr) 29427ec681f3Smrg{ 29437ec681f3Smrg struct nir_variable *var = 29447ec681f3Smrg nir_deref_instr_get_variable(nir_src_as_deref(intr->src[0])); 29457ec681f3Smrg 29467ec681f3Smrg const struct dxil_value *index = 29477ec681f3Smrg get_src(ctx, &intr->src[1], 0, nir_type_uint); 29487ec681f3Smrg if (!index) 29497ec681f3Smrg return false; 29507ec681f3Smrg 29517ec681f3Smrg const struct dxil_value *ptr = emit_gep_for_index(ctx, var, index); 29527ec681f3Smrg if (!ptr) 29537ec681f3Smrg return false; 29547ec681f3Smrg 29557ec681f3Smrg const struct dxil_value *retval = 29567ec681f3Smrg dxil_emit_load(&ctx->mod, ptr, 4, false); 29577ec681f3Smrg if (!retval) 29587ec681f3Smrg return false; 29597ec681f3Smrg 29607ec681f3Smrg store_dest(ctx, &intr->dest, 0, retval, nir_type_uint); 29617ec681f3Smrg return true; 29627ec681f3Smrg} 29637ec681f3Smrg 29647ec681f3Smrgstatic bool 29657ec681f3Smrgemit_load_shared(struct ntd_context *ctx, nir_intrinsic_instr *intr) 29667ec681f3Smrg{ 29677ec681f3Smrg const struct dxil_value *zero, *index; 29687ec681f3Smrg unsigned bit_size = nir_dest_bit_size(intr->dest); 29697ec681f3Smrg unsigned align = bit_size / 8; 29707ec681f3Smrg 29717ec681f3Smrg /* All shared mem accesses should have been lowered to scalar 32bit 29727ec681f3Smrg * accesses. 29737ec681f3Smrg */ 29747ec681f3Smrg assert(bit_size == 32); 29757ec681f3Smrg assert(nir_dest_num_components(intr->dest) == 1); 29767ec681f3Smrg 29777ec681f3Smrg zero = dxil_module_get_int32_const(&ctx->mod, 0); 29787ec681f3Smrg if (!zero) 29797ec681f3Smrg return false; 29807ec681f3Smrg 29817ec681f3Smrg index = get_src(ctx, &intr->src[0], 0, nir_type_uint); 29827ec681f3Smrg if (!index) 29837ec681f3Smrg return false; 29847ec681f3Smrg 29857ec681f3Smrg const struct dxil_value *ops[] = { ctx->sharedvars, zero, index }; 29867ec681f3Smrg const struct dxil_value *ptr, *retval; 29877ec681f3Smrg 29887ec681f3Smrg ptr = dxil_emit_gep_inbounds(&ctx->mod, ops, ARRAY_SIZE(ops)); 29897ec681f3Smrg if (!ptr) 29907ec681f3Smrg return false; 29917ec681f3Smrg 29927ec681f3Smrg retval = dxil_emit_load(&ctx->mod, ptr, align, false); 29937ec681f3Smrg if (!retval) 29947ec681f3Smrg return false; 29957ec681f3Smrg 29967ec681f3Smrg store_dest(ctx, &intr->dest, 0, retval, nir_type_uint); 29977ec681f3Smrg return true; 29987ec681f3Smrg} 29997ec681f3Smrg 30007ec681f3Smrgstatic bool 30017ec681f3Smrgemit_load_scratch(struct ntd_context *ctx, nir_intrinsic_instr *intr) 30027ec681f3Smrg{ 30037ec681f3Smrg const struct dxil_value *zero, *index; 30047ec681f3Smrg unsigned bit_size = nir_dest_bit_size(intr->dest); 30057ec681f3Smrg unsigned align = bit_size / 8; 30067ec681f3Smrg 30077ec681f3Smrg /* All scratch mem accesses should have been lowered to scalar 32bit 30087ec681f3Smrg * accesses. 30097ec681f3Smrg */ 30107ec681f3Smrg assert(bit_size == 32); 30117ec681f3Smrg assert(nir_dest_num_components(intr->dest) == 1); 30127ec681f3Smrg 30137ec681f3Smrg zero = dxil_module_get_int32_const(&ctx->mod, 0); 30147ec681f3Smrg if (!zero) 30157ec681f3Smrg return false; 30167ec681f3Smrg 30177ec681f3Smrg index = get_src(ctx, &intr->src[0], 0, nir_type_uint); 30187ec681f3Smrg if (!index) 30197ec681f3Smrg return false; 30207ec681f3Smrg 30217ec681f3Smrg const struct dxil_value *ops[] = { ctx->scratchvars, zero, index }; 30227ec681f3Smrg const struct dxil_value *ptr, *retval; 30237ec681f3Smrg 30247ec681f3Smrg ptr = dxil_emit_gep_inbounds(&ctx->mod, ops, ARRAY_SIZE(ops)); 30257ec681f3Smrg if (!ptr) 30267ec681f3Smrg return false; 30277ec681f3Smrg 30287ec681f3Smrg retval = dxil_emit_load(&ctx->mod, ptr, align, false); 30297ec681f3Smrg if (!retval) 30307ec681f3Smrg return false; 30317ec681f3Smrg 30327ec681f3Smrg store_dest(ctx, &intr->dest, 0, retval, nir_type_uint); 30337ec681f3Smrg return true; 30347ec681f3Smrg} 30357ec681f3Smrg 30367ec681f3Smrgstatic bool 30377ec681f3Smrgemit_load_deref(struct ntd_context *ctx, nir_intrinsic_instr *intr) 30387ec681f3Smrg{ 30397ec681f3Smrg assert(intr->src[0].is_ssa); 30407ec681f3Smrg nir_deref_instr *deref = nir_instr_as_deref(intr->src[0].ssa->parent_instr); 30417ec681f3Smrg nir_variable *var = nir_deref_instr_get_variable(deref); 30427ec681f3Smrg 30437ec681f3Smrg switch (var->data.mode) { 30447ec681f3Smrg case nir_var_shader_in: 30457ec681f3Smrg if (glsl_type_is_array(var->type)) { 30467ec681f3Smrg if (var->data.compact) 30477ec681f3Smrg return emit_load_compact_input_array(ctx, intr, var, deref); 30487ec681f3Smrg else 30497ec681f3Smrg return emit_load_input_array(ctx, intr, var, &deref->arr.index); 30507ec681f3Smrg } 30517ec681f3Smrg return emit_load_input(ctx, intr, var); 30527ec681f3Smrg 30537ec681f3Smrg default: 30547ec681f3Smrg unreachable("unsupported nir_variable_mode"); 30557ec681f3Smrg } 30567ec681f3Smrg} 30577ec681f3Smrg 30587ec681f3Smrgstatic bool 30597ec681f3Smrgemit_discard_if_with_value(struct ntd_context *ctx, const struct dxil_value *value) 30607ec681f3Smrg{ 30617ec681f3Smrg const struct dxil_value *opcode = dxil_module_get_int32_const(&ctx->mod, DXIL_INTR_DISCARD); 30627ec681f3Smrg if (!opcode) 30637ec681f3Smrg return false; 30647ec681f3Smrg 30657ec681f3Smrg const struct dxil_value *args[] = { 30667ec681f3Smrg opcode, 30677ec681f3Smrg value 30687ec681f3Smrg }; 30697ec681f3Smrg 30707ec681f3Smrg const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.discard", DXIL_NONE); 30717ec681f3Smrg if (!func) 30727ec681f3Smrg return false; 30737ec681f3Smrg 30747ec681f3Smrg return dxil_emit_call_void(&ctx->mod, func, args, ARRAY_SIZE(args)); 30757ec681f3Smrg} 30767ec681f3Smrg 30777ec681f3Smrgstatic bool 30787ec681f3Smrgemit_discard_if(struct ntd_context *ctx, nir_intrinsic_instr *intr) 30797ec681f3Smrg{ 30807ec681f3Smrg const struct dxil_value *value = get_src(ctx, &intr->src[0], 0, nir_type_bool); 30817ec681f3Smrg if (!value) 30827ec681f3Smrg return false; 30837ec681f3Smrg 30847ec681f3Smrg return emit_discard_if_with_value(ctx, value); 30857ec681f3Smrg} 30867ec681f3Smrg 30877ec681f3Smrgstatic bool 30887ec681f3Smrgemit_discard(struct ntd_context *ctx) 30897ec681f3Smrg{ 30907ec681f3Smrg const struct dxil_value *value = dxil_module_get_int1_const(&ctx->mod, true); 30917ec681f3Smrg return emit_discard_if_with_value(ctx, value); 30927ec681f3Smrg} 30937ec681f3Smrg 30947ec681f3Smrgstatic bool 30957ec681f3Smrgemit_emit_vertex(struct ntd_context *ctx, nir_intrinsic_instr *intr) 30967ec681f3Smrg{ 30977ec681f3Smrg const struct dxil_value *opcode = dxil_module_get_int32_const(&ctx->mod, DXIL_INTR_EMIT_STREAM); 30987ec681f3Smrg const struct dxil_value *stream_id = dxil_module_get_int8_const(&ctx->mod, nir_intrinsic_stream_id(intr)); 30997ec681f3Smrg if (!opcode || !stream_id) 31007ec681f3Smrg return false; 31017ec681f3Smrg 31027ec681f3Smrg const struct dxil_value *args[] = { 31037ec681f3Smrg opcode, 31047ec681f3Smrg stream_id 31057ec681f3Smrg }; 31067ec681f3Smrg 31077ec681f3Smrg const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.emitStream", DXIL_NONE); 31087ec681f3Smrg if (!func) 31097ec681f3Smrg return false; 31107ec681f3Smrg 31117ec681f3Smrg return dxil_emit_call_void(&ctx->mod, func, args, ARRAY_SIZE(args)); 31127ec681f3Smrg} 31137ec681f3Smrg 31147ec681f3Smrgstatic bool 31157ec681f3Smrgemit_end_primitive(struct ntd_context *ctx, nir_intrinsic_instr *intr) 31167ec681f3Smrg{ 31177ec681f3Smrg const struct dxil_value *opcode = dxil_module_get_int32_const(&ctx->mod, DXIL_INTR_CUT_STREAM); 31187ec681f3Smrg const struct dxil_value *stream_id = dxil_module_get_int8_const(&ctx->mod, nir_intrinsic_stream_id(intr)); 31197ec681f3Smrg if (!opcode || !stream_id) 31207ec681f3Smrg return false; 31217ec681f3Smrg 31227ec681f3Smrg const struct dxil_value *args[] = { 31237ec681f3Smrg opcode, 31247ec681f3Smrg stream_id 31257ec681f3Smrg }; 31267ec681f3Smrg 31277ec681f3Smrg const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.cutStream", DXIL_NONE); 31287ec681f3Smrg if (!func) 31297ec681f3Smrg return false; 31307ec681f3Smrg 31317ec681f3Smrg return dxil_emit_call_void(&ctx->mod, func, args, ARRAY_SIZE(args)); 31327ec681f3Smrg} 31337ec681f3Smrg 31347ec681f3Smrgstatic bool 31357ec681f3Smrgemit_image_store(struct ntd_context *ctx, nir_intrinsic_instr *intr) 31367ec681f3Smrg{ 31377ec681f3Smrg const struct dxil_value *handle; 31387ec681f3Smrg bool is_array = false; 31397ec681f3Smrg if (ctx->opts->vulkan_environment) { 31407ec681f3Smrg assert(intr->intrinsic == nir_intrinsic_image_deref_store); 31417ec681f3Smrg handle = get_src_ssa(ctx, intr->src[0].ssa, 0); 31427ec681f3Smrg is_array = glsl_sampler_type_is_array(nir_src_as_deref(intr->src[0])->type); 31437ec681f3Smrg } else { 31447ec681f3Smrg assert(intr->intrinsic == nir_intrinsic_image_store); 31457ec681f3Smrg int binding = nir_src_as_int(intr->src[0]); 31467ec681f3Smrg is_array = nir_intrinsic_image_array(intr); 31477ec681f3Smrg handle = ctx->uav_handles[binding]; 31487ec681f3Smrg } 31497ec681f3Smrg if (!handle) 31507ec681f3Smrg return false; 31517ec681f3Smrg 31527ec681f3Smrg const struct dxil_value *int32_undef = get_int32_undef(&ctx->mod); 31537ec681f3Smrg if (!int32_undef) 31547ec681f3Smrg return false; 31557ec681f3Smrg 31567ec681f3Smrg const struct dxil_value *coord[3] = { int32_undef, int32_undef, int32_undef }; 31577ec681f3Smrg enum glsl_sampler_dim image_dim = intr->intrinsic == nir_intrinsic_image_store ? 31587ec681f3Smrg nir_intrinsic_image_dim(intr) : 31597ec681f3Smrg glsl_get_sampler_dim(nir_src_as_deref(intr->src[0])->type); 31607ec681f3Smrg unsigned num_coords = glsl_get_sampler_dim_coordinate_components(image_dim); 31617ec681f3Smrg if (is_array) 31627ec681f3Smrg ++num_coords; 31637ec681f3Smrg 31647ec681f3Smrg assert(num_coords <= nir_src_num_components(intr->src[1])); 31657ec681f3Smrg for (unsigned i = 0; i < num_coords; ++i) { 31667ec681f3Smrg coord[i] = get_src(ctx, &intr->src[1], i, nir_type_uint); 31677ec681f3Smrg if (!coord[i]) 31687ec681f3Smrg return false; 31697ec681f3Smrg } 31707ec681f3Smrg 31717ec681f3Smrg nir_alu_type in_type = nir_intrinsic_src_type(intr); 31727ec681f3Smrg enum overload_type overload = get_overload(in_type, 32); 31737ec681f3Smrg 31747ec681f3Smrg assert(nir_src_bit_size(intr->src[3]) == 32); 31757ec681f3Smrg unsigned num_components = nir_src_num_components(intr->src[3]); 31767ec681f3Smrg assert(num_components <= 4); 31777ec681f3Smrg const struct dxil_value *value[4]; 31787ec681f3Smrg for (unsigned i = 0; i < num_components; ++i) { 31797ec681f3Smrg value[i] = get_src(ctx, &intr->src[3], i, in_type); 31807ec681f3Smrg if (!value[i]) 31817ec681f3Smrg return false; 31827ec681f3Smrg } 31837ec681f3Smrg 31847ec681f3Smrg for (int i = num_components; i < 4; ++i) 31857ec681f3Smrg value[i] = int32_undef; 31867ec681f3Smrg 31877ec681f3Smrg const struct dxil_value *write_mask = 31887ec681f3Smrg dxil_module_get_int8_const(&ctx->mod, (1u << num_components) - 1); 31897ec681f3Smrg if (!write_mask) 31907ec681f3Smrg return false; 31917ec681f3Smrg 31927ec681f3Smrg if (image_dim == GLSL_SAMPLER_DIM_BUF) { 31937ec681f3Smrg coord[1] = int32_undef; 31947ec681f3Smrg return emit_bufferstore_call(ctx, handle, coord, value, write_mask, overload); 31957ec681f3Smrg } else 31967ec681f3Smrg return emit_texturestore_call(ctx, handle, coord, value, write_mask, overload); 31977ec681f3Smrg} 31987ec681f3Smrg 31997ec681f3Smrgstatic bool 32007ec681f3Smrgemit_image_load(struct ntd_context *ctx, nir_intrinsic_instr *intr) 32017ec681f3Smrg{ 32027ec681f3Smrg const struct dxil_value *handle; 32037ec681f3Smrg bool is_array = false; 32047ec681f3Smrg if (ctx->opts->vulkan_environment) { 32057ec681f3Smrg assert(intr->intrinsic == nir_intrinsic_image_deref_load); 32067ec681f3Smrg handle = get_src_ssa(ctx, intr->src[0].ssa, 0); 32077ec681f3Smrg is_array = glsl_sampler_type_is_array(nir_src_as_deref(intr->src[0])->type); 32087ec681f3Smrg } else { 32097ec681f3Smrg assert(intr->intrinsic == nir_intrinsic_image_load); 32107ec681f3Smrg int binding = nir_src_as_int(intr->src[0]); 32117ec681f3Smrg is_array = nir_intrinsic_image_array(intr); 32127ec681f3Smrg handle = ctx->uav_handles[binding]; 32137ec681f3Smrg } 32147ec681f3Smrg if (!handle) 32157ec681f3Smrg return false; 32167ec681f3Smrg 32177ec681f3Smrg const struct dxil_value *int32_undef = get_int32_undef(&ctx->mod); 32187ec681f3Smrg if (!int32_undef) 32197ec681f3Smrg return false; 32207ec681f3Smrg 32217ec681f3Smrg const struct dxil_value *coord[3] = { int32_undef, int32_undef, int32_undef }; 32227ec681f3Smrg enum glsl_sampler_dim image_dim = intr->intrinsic == nir_intrinsic_image_load ? 32237ec681f3Smrg nir_intrinsic_image_dim(intr) : 32247ec681f3Smrg glsl_get_sampler_dim(nir_src_as_deref(intr->src[0])->type); 32257ec681f3Smrg unsigned num_coords = glsl_get_sampler_dim_coordinate_components(image_dim); 32267ec681f3Smrg if (is_array) 32277ec681f3Smrg ++num_coords; 32287ec681f3Smrg 32297ec681f3Smrg assert(num_coords <= nir_src_num_components(intr->src[1])); 32307ec681f3Smrg for (unsigned i = 0; i < num_coords; ++i) { 32317ec681f3Smrg coord[i] = get_src(ctx, &intr->src[1], i, nir_type_uint); 32327ec681f3Smrg if (!coord[i]) 32337ec681f3Smrg return false; 32347ec681f3Smrg } 32357ec681f3Smrg 32367ec681f3Smrg nir_alu_type out_type = nir_intrinsic_dest_type(intr); 32377ec681f3Smrg enum overload_type overload = get_overload(out_type, 32); 32387ec681f3Smrg 32397ec681f3Smrg const struct dxil_value *load_result; 32407ec681f3Smrg if (image_dim == GLSL_SAMPLER_DIM_BUF) { 32417ec681f3Smrg coord[1] = int32_undef; 32427ec681f3Smrg load_result = emit_bufferload_call(ctx, handle, coord, overload); 32437ec681f3Smrg } else 32447ec681f3Smrg load_result = emit_textureload_call(ctx, handle, coord, overload); 32457ec681f3Smrg 32467ec681f3Smrg if (!load_result) 32477ec681f3Smrg return false; 32487ec681f3Smrg 32497ec681f3Smrg assert(nir_dest_bit_size(intr->dest) == 32); 32507ec681f3Smrg unsigned num_components = nir_dest_num_components(intr->dest); 32517ec681f3Smrg assert(num_components <= 4); 32527ec681f3Smrg for (unsigned i = 0; i < num_components; ++i) { 32537ec681f3Smrg const struct dxil_value *component = dxil_emit_extractval(&ctx->mod, load_result, i); 32547ec681f3Smrg if (!component) 32557ec681f3Smrg return false; 32567ec681f3Smrg store_dest(ctx, &intr->dest, i, component, out_type); 32577ec681f3Smrg } 32587ec681f3Smrg 32597ec681f3Smrg if (num_components > 1) 32607ec681f3Smrg ctx->mod.feats.typed_uav_load_additional_formats = true; 32617ec681f3Smrg 32627ec681f3Smrg return true; 32637ec681f3Smrg} 32647ec681f3Smrg 32657ec681f3Smrgstruct texop_parameters { 32667ec681f3Smrg const struct dxil_value *tex; 32677ec681f3Smrg const struct dxil_value *sampler; 32687ec681f3Smrg const struct dxil_value *bias, *lod_or_sample, *min_lod; 32697ec681f3Smrg const struct dxil_value *coord[4], *offset[3], *dx[3], *dy[3]; 32707ec681f3Smrg const struct dxil_value *cmp; 32717ec681f3Smrg enum overload_type overload; 32727ec681f3Smrg}; 32737ec681f3Smrg 32747ec681f3Smrgstatic const struct dxil_value * 32757ec681f3Smrgemit_texture_size(struct ntd_context *ctx, struct texop_parameters *params) 32767ec681f3Smrg{ 32777ec681f3Smrg const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.getDimensions", DXIL_NONE); 32787ec681f3Smrg if (!func) 32797ec681f3Smrg return false; 32807ec681f3Smrg 32817ec681f3Smrg const struct dxil_value *args[] = { 32827ec681f3Smrg dxil_module_get_int32_const(&ctx->mod, DXIL_INTR_TEXTURE_SIZE), 32837ec681f3Smrg params->tex, 32847ec681f3Smrg params->lod_or_sample 32857ec681f3Smrg }; 32867ec681f3Smrg 32877ec681f3Smrg return dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args)); 32887ec681f3Smrg} 32897ec681f3Smrg 32907ec681f3Smrgstatic bool 32917ec681f3Smrgemit_image_size(struct ntd_context *ctx, nir_intrinsic_instr *intr) 32927ec681f3Smrg{ 32937ec681f3Smrg const struct dxil_value *handle; 32947ec681f3Smrg if (ctx->opts->vulkan_environment) { 32957ec681f3Smrg assert(intr->intrinsic == nir_intrinsic_image_deref_size); 32967ec681f3Smrg handle = get_src_ssa(ctx, intr->src[0].ssa, 0); 32977ec681f3Smrg } 32987ec681f3Smrg else { 32997ec681f3Smrg assert(intr->intrinsic == nir_intrinsic_image_size); 33007ec681f3Smrg int binding = nir_src_as_int(intr->src[0]); 33017ec681f3Smrg handle = ctx->uav_handles[binding]; 33027ec681f3Smrg } 33037ec681f3Smrg if (!handle) 33047ec681f3Smrg return false; 33057ec681f3Smrg 33067ec681f3Smrg const struct dxil_value *lod = get_src(ctx, &intr->src[1], 0, nir_type_uint); 33077ec681f3Smrg if (!lod) 33087ec681f3Smrg return false; 33097ec681f3Smrg 33107ec681f3Smrg struct texop_parameters params = { 33117ec681f3Smrg .tex = handle, 33127ec681f3Smrg .lod_or_sample = lod 33137ec681f3Smrg }; 33147ec681f3Smrg const struct dxil_value *dimensions = emit_texture_size(ctx, ¶ms); 33157ec681f3Smrg if (!dimensions) 33167ec681f3Smrg return false; 33177ec681f3Smrg 33187ec681f3Smrg for (unsigned i = 0; i < nir_dest_num_components(intr->dest); ++i) { 33197ec681f3Smrg const struct dxil_value *retval = dxil_emit_extractval(&ctx->mod, dimensions, i); 33207ec681f3Smrg store_dest(ctx, &intr->dest, i, retval, nir_type_uint); 33217ec681f3Smrg } 33227ec681f3Smrg 33237ec681f3Smrg return true; 33247ec681f3Smrg} 33257ec681f3Smrg 33267ec681f3Smrgstatic bool 33277ec681f3Smrgemit_get_ssbo_size(struct ntd_context *ctx, nir_intrinsic_instr *intr) 33287ec681f3Smrg{ 33297ec681f3Smrg const struct dxil_value* handle = NULL; 33307ec681f3Smrg if (ctx->opts->vulkan_environment) { 33317ec681f3Smrg handle = get_src_ssa(ctx, intr->src[0].ssa, 0); 33327ec681f3Smrg } else { 33337ec681f3Smrg int binding = nir_src_as_int(intr->src[0]); 33347ec681f3Smrg handle = ctx->uav_handles[binding]; 33357ec681f3Smrg } 33367ec681f3Smrg 33377ec681f3Smrg if (!handle) 33387ec681f3Smrg return false; 33397ec681f3Smrg 33407ec681f3Smrg struct texop_parameters params = { 33417ec681f3Smrg .tex = handle, 33427ec681f3Smrg .lod_or_sample = dxil_module_get_undef( 33437ec681f3Smrg &ctx->mod, dxil_module_get_int_type(&ctx->mod, 32)) 33447ec681f3Smrg }; 33457ec681f3Smrg 33467ec681f3Smrg const struct dxil_value *dimensions = emit_texture_size(ctx, ¶ms); 33477ec681f3Smrg if (!dimensions) 33487ec681f3Smrg return false; 33497ec681f3Smrg 33507ec681f3Smrg const struct dxil_value *retval = dxil_emit_extractval(&ctx->mod, dimensions, 0); 33517ec681f3Smrg store_dest(ctx, &intr->dest, 0, retval, nir_type_uint); 33527ec681f3Smrg 33537ec681f3Smrg return true; 33547ec681f3Smrg} 33557ec681f3Smrg 33567ec681f3Smrgstatic bool 33577ec681f3Smrgemit_ssbo_atomic(struct ntd_context *ctx, nir_intrinsic_instr *intr, 33587ec681f3Smrg enum dxil_atomic_op op, nir_alu_type type) 33597ec681f3Smrg{ 33607ec681f3Smrg const struct dxil_value* handle = get_ubo_ssbo_handle(ctx, &intr->src[0], DXIL_RESOURCE_CLASS_UAV, 0); 33617ec681f3Smrg const struct dxil_value *offset = 33627ec681f3Smrg get_src(ctx, &intr->src[1], 0, nir_type_uint); 33637ec681f3Smrg const struct dxil_value *value = 33647ec681f3Smrg get_src(ctx, &intr->src[2], 0, type); 33657ec681f3Smrg 33667ec681f3Smrg if (!value || !handle || !offset) 33677ec681f3Smrg return false; 33687ec681f3Smrg 33697ec681f3Smrg const struct dxil_value *int32_undef = get_int32_undef(&ctx->mod); 33707ec681f3Smrg if (!int32_undef) 33717ec681f3Smrg return false; 33727ec681f3Smrg 33737ec681f3Smrg const struct dxil_value *coord[3] = { 33747ec681f3Smrg offset, int32_undef, int32_undef 33757ec681f3Smrg }; 33767ec681f3Smrg 33777ec681f3Smrg const struct dxil_value *retval = 33787ec681f3Smrg emit_atomic_binop(ctx, handle, op, coord, value); 33797ec681f3Smrg 33807ec681f3Smrg if (!retval) 33817ec681f3Smrg return false; 33827ec681f3Smrg 33837ec681f3Smrg store_dest(ctx, &intr->dest, 0, retval, type); 33847ec681f3Smrg return true; 33857ec681f3Smrg} 33867ec681f3Smrg 33877ec681f3Smrgstatic bool 33887ec681f3Smrgemit_ssbo_atomic_comp_swap(struct ntd_context *ctx, nir_intrinsic_instr *intr) 33897ec681f3Smrg{ 33907ec681f3Smrg const struct dxil_value* handle = get_ubo_ssbo_handle(ctx, &intr->src[0], DXIL_RESOURCE_CLASS_UAV, 0); 33917ec681f3Smrg const struct dxil_value *offset = 33927ec681f3Smrg get_src(ctx, &intr->src[1], 0, nir_type_uint); 33937ec681f3Smrg const struct dxil_value *cmpval = 33947ec681f3Smrg get_src(ctx, &intr->src[2], 0, nir_type_int); 33957ec681f3Smrg const struct dxil_value *newval = 33967ec681f3Smrg get_src(ctx, &intr->src[3], 0, nir_type_int); 33977ec681f3Smrg 33987ec681f3Smrg if (!cmpval || !newval || !handle || !offset) 33997ec681f3Smrg return false; 34007ec681f3Smrg 34017ec681f3Smrg const struct dxil_value *int32_undef = get_int32_undef(&ctx->mod); 34027ec681f3Smrg if (!int32_undef) 34037ec681f3Smrg return false; 34047ec681f3Smrg 34057ec681f3Smrg const struct dxil_value *coord[3] = { 34067ec681f3Smrg offset, int32_undef, int32_undef 34077ec681f3Smrg }; 34087ec681f3Smrg 34097ec681f3Smrg const struct dxil_value *retval = 34107ec681f3Smrg emit_atomic_cmpxchg(ctx, handle, coord, cmpval, newval); 34117ec681f3Smrg 34127ec681f3Smrg if (!retval) 34137ec681f3Smrg return false; 34147ec681f3Smrg 34157ec681f3Smrg store_dest(ctx, &intr->dest, 0, retval, nir_type_int); 34167ec681f3Smrg return true; 34177ec681f3Smrg} 34187ec681f3Smrg 34197ec681f3Smrgstatic bool 34207ec681f3Smrgemit_shared_atomic(struct ntd_context *ctx, nir_intrinsic_instr *intr, 34217ec681f3Smrg enum dxil_rmw_op op, nir_alu_type type) 34227ec681f3Smrg{ 34237ec681f3Smrg const struct dxil_value *zero, *index; 34247ec681f3Smrg 34257ec681f3Smrg assert(nir_src_bit_size(intr->src[1]) == 32); 34267ec681f3Smrg 34277ec681f3Smrg zero = dxil_module_get_int32_const(&ctx->mod, 0); 34287ec681f3Smrg if (!zero) 34297ec681f3Smrg return false; 34307ec681f3Smrg 34317ec681f3Smrg index = get_src(ctx, &intr->src[0], 0, nir_type_uint); 34327ec681f3Smrg if (!index) 34337ec681f3Smrg return false; 34347ec681f3Smrg 34357ec681f3Smrg const struct dxil_value *ops[] = { ctx->sharedvars, zero, index }; 34367ec681f3Smrg const struct dxil_value *ptr, *value, *retval; 34377ec681f3Smrg 34387ec681f3Smrg ptr = dxil_emit_gep_inbounds(&ctx->mod, ops, ARRAY_SIZE(ops)); 34397ec681f3Smrg if (!ptr) 34407ec681f3Smrg return false; 34417ec681f3Smrg 34427ec681f3Smrg value = get_src(ctx, &intr->src[1], 0, type); 34437ec681f3Smrg if (!value) 34447ec681f3Smrg return false; 34457ec681f3Smrg 34467ec681f3Smrg retval = dxil_emit_atomicrmw(&ctx->mod, value, ptr, op, false, 34477ec681f3Smrg DXIL_ATOMIC_ORDERING_ACQREL, 34487ec681f3Smrg DXIL_SYNC_SCOPE_CROSSTHREAD); 34497ec681f3Smrg if (!retval) 34507ec681f3Smrg return false; 34517ec681f3Smrg 34527ec681f3Smrg store_dest(ctx, &intr->dest, 0, retval, type); 34537ec681f3Smrg return true; 34547ec681f3Smrg} 34557ec681f3Smrg 34567ec681f3Smrgstatic bool 34577ec681f3Smrgemit_shared_atomic_comp_swap(struct ntd_context *ctx, nir_intrinsic_instr *intr) 34587ec681f3Smrg{ 34597ec681f3Smrg const struct dxil_value *zero, *index; 34607ec681f3Smrg 34617ec681f3Smrg assert(nir_src_bit_size(intr->src[1]) == 32); 34627ec681f3Smrg 34637ec681f3Smrg zero = dxil_module_get_int32_const(&ctx->mod, 0); 34647ec681f3Smrg if (!zero) 34657ec681f3Smrg return false; 34667ec681f3Smrg 34677ec681f3Smrg index = get_src(ctx, &intr->src[0], 0, nir_type_uint); 34687ec681f3Smrg if (!index) 34697ec681f3Smrg return false; 34707ec681f3Smrg 34717ec681f3Smrg const struct dxil_value *ops[] = { ctx->sharedvars, zero, index }; 34727ec681f3Smrg const struct dxil_value *ptr, *cmpval, *newval, *retval; 34737ec681f3Smrg 34747ec681f3Smrg ptr = dxil_emit_gep_inbounds(&ctx->mod, ops, ARRAY_SIZE(ops)); 34757ec681f3Smrg if (!ptr) 34767ec681f3Smrg return false; 34777ec681f3Smrg 34787ec681f3Smrg cmpval = get_src(ctx, &intr->src[1], 0, nir_type_uint); 34797ec681f3Smrg newval = get_src(ctx, &intr->src[2], 0, nir_type_uint); 34807ec681f3Smrg if (!cmpval || !newval) 34817ec681f3Smrg return false; 34827ec681f3Smrg 34837ec681f3Smrg retval = dxil_emit_cmpxchg(&ctx->mod, cmpval, newval, ptr, false, 34847ec681f3Smrg DXIL_ATOMIC_ORDERING_ACQREL, 34857ec681f3Smrg DXIL_SYNC_SCOPE_CROSSTHREAD); 34867ec681f3Smrg if (!retval) 34877ec681f3Smrg return false; 34887ec681f3Smrg 34897ec681f3Smrg store_dest(ctx, &intr->dest, 0, retval, nir_type_uint); 34907ec681f3Smrg return true; 34917ec681f3Smrg} 34927ec681f3Smrg 34937ec681f3Smrgstatic bool 34947ec681f3Smrgemit_vulkan_resource_index(struct ntd_context *ctx, nir_intrinsic_instr *intr) 34957ec681f3Smrg{ 34967ec681f3Smrg unsigned int binding = nir_intrinsic_binding(intr); 34977ec681f3Smrg 34987ec681f3Smrg bool const_index = nir_src_is_const(intr->src[0]); 34997ec681f3Smrg if (const_index) { 35007ec681f3Smrg binding += nir_src_as_const_value(intr->src[0])->u32; 35017ec681f3Smrg } 35027ec681f3Smrg 35037ec681f3Smrg const struct dxil_value *index_value = dxil_module_get_int32_const(&ctx->mod, binding); 35047ec681f3Smrg if (!index_value) 35057ec681f3Smrg return false; 35067ec681f3Smrg 35077ec681f3Smrg if (!const_index) { 35087ec681f3Smrg const struct dxil_value *offset = get_src(ctx, &intr->src[0], 0, nir_type_uint32); 35097ec681f3Smrg if (!offset) 35107ec681f3Smrg return false; 35117ec681f3Smrg 35127ec681f3Smrg index_value = dxil_emit_binop(&ctx->mod, DXIL_BINOP_ADD, index_value, offset, 0); 35137ec681f3Smrg if (!index_value) 35147ec681f3Smrg return false; 35157ec681f3Smrg } 35167ec681f3Smrg 35177ec681f3Smrg store_dest(ctx, &intr->dest, 0, index_value, nir_type_uint32); 35187ec681f3Smrg store_dest(ctx, &intr->dest, 1, dxil_module_get_int32_const(&ctx->mod, 0), nir_type_uint32); 35197ec681f3Smrg return true; 35207ec681f3Smrg} 35217ec681f3Smrg 35227ec681f3Smrgstatic bool 35237ec681f3Smrgemit_load_vulkan_descriptor(struct ntd_context *ctx, nir_intrinsic_instr *intr) 35247ec681f3Smrg{ 35257ec681f3Smrg nir_intrinsic_instr* index = nir_src_as_intrinsic(intr->src[0]); 35267ec681f3Smrg /* We currently do not support reindex */ 35277ec681f3Smrg assert(index && index->intrinsic == nir_intrinsic_vulkan_resource_index); 35287ec681f3Smrg 35297ec681f3Smrg unsigned binding = nir_intrinsic_binding(index); 35307ec681f3Smrg unsigned space = nir_intrinsic_desc_set(index); 35317ec681f3Smrg 35327ec681f3Smrg /* The descriptor_set field for variables is only 5 bits. We shouldn't have intrinsics trying to go beyond that. */ 35337ec681f3Smrg assert(space < 32); 35347ec681f3Smrg 35357ec681f3Smrg nir_variable *var = nir_get_binding_variable(ctx->shader, nir_chase_binding(intr->src[0])); 35367ec681f3Smrg 35377ec681f3Smrg const struct dxil_value *handle = NULL; 35387ec681f3Smrg enum dxil_resource_class resource_class; 35397ec681f3Smrg 35407ec681f3Smrg switch (nir_intrinsic_desc_type(intr)) { 35417ec681f3Smrg case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: 35427ec681f3Smrg resource_class = DXIL_RESOURCE_CLASS_CBV; 35437ec681f3Smrg break; 35447ec681f3Smrg case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: 35457ec681f3Smrg if (var->data.access & ACCESS_NON_WRITEABLE) 35467ec681f3Smrg resource_class = DXIL_RESOURCE_CLASS_SRV; 35477ec681f3Smrg else 35487ec681f3Smrg resource_class = DXIL_RESOURCE_CLASS_UAV; 35497ec681f3Smrg break; 35507ec681f3Smrg default: 35517ec681f3Smrg unreachable("unknown descriptor type"); 35527ec681f3Smrg return false; 35537ec681f3Smrg } 35547ec681f3Smrg 35557ec681f3Smrg const struct dxil_value *index_value = get_src(ctx, &intr->src[0], 0, nir_type_uint32); 35567ec681f3Smrg if (!index_value) 35577ec681f3Smrg return false; 35587ec681f3Smrg 35597ec681f3Smrg handle = emit_createhandle_call(ctx, resource_class, 35607ec681f3Smrg get_resource_id(ctx, resource_class, space, binding), 35617ec681f3Smrg index_value, false); 35627ec681f3Smrg 35637ec681f3Smrg store_dest_value(ctx, &intr->dest, 0, handle); 35647ec681f3Smrg store_dest(ctx, &intr->dest, 1, get_src(ctx, &intr->src[0], 1, nir_type_uint32), nir_type_uint32); 35657ec681f3Smrg 35667ec681f3Smrg return true; 35677ec681f3Smrg} 35687ec681f3Smrg 35697ec681f3Smrgstatic bool 35707ec681f3Smrgemit_intrinsic(struct ntd_context *ctx, nir_intrinsic_instr *intr) 35717ec681f3Smrg{ 35727ec681f3Smrg switch (intr->intrinsic) { 35737ec681f3Smrg case nir_intrinsic_load_global_invocation_id: 35747ec681f3Smrg case nir_intrinsic_load_global_invocation_id_zero_base: 35757ec681f3Smrg return emit_load_global_invocation_id(ctx, intr); 35767ec681f3Smrg case nir_intrinsic_load_local_invocation_id: 35777ec681f3Smrg return emit_load_local_invocation_id(ctx, intr); 35787ec681f3Smrg case nir_intrinsic_load_local_invocation_index: 35797ec681f3Smrg return emit_load_local_invocation_index(ctx, intr); 35807ec681f3Smrg case nir_intrinsic_load_workgroup_id: 35817ec681f3Smrg case nir_intrinsic_load_workgroup_id_zero_base: 35827ec681f3Smrg return emit_load_local_workgroup_id(ctx, intr); 35837ec681f3Smrg case nir_intrinsic_load_ssbo: 35847ec681f3Smrg return emit_load_ssbo(ctx, intr); 35857ec681f3Smrg case nir_intrinsic_store_ssbo: 35867ec681f3Smrg return emit_store_ssbo(ctx, intr); 35877ec681f3Smrg case nir_intrinsic_store_ssbo_masked_dxil: 35887ec681f3Smrg return emit_store_ssbo_masked(ctx, intr); 35897ec681f3Smrg case nir_intrinsic_store_deref: 35907ec681f3Smrg return emit_store_deref(ctx, intr); 35917ec681f3Smrg case nir_intrinsic_store_shared_dxil: 35927ec681f3Smrg case nir_intrinsic_store_shared_masked_dxil: 35937ec681f3Smrg return emit_store_shared(ctx, intr); 35947ec681f3Smrg case nir_intrinsic_store_scratch_dxil: 35957ec681f3Smrg return emit_store_scratch(ctx, intr); 35967ec681f3Smrg case nir_intrinsic_load_deref: 35977ec681f3Smrg return emit_load_deref(ctx, intr); 35987ec681f3Smrg case nir_intrinsic_load_ptr_dxil: 35997ec681f3Smrg return emit_load_ptr(ctx, intr); 36007ec681f3Smrg case nir_intrinsic_load_ubo: 36017ec681f3Smrg return emit_load_ubo(ctx, intr); 36027ec681f3Smrg case nir_intrinsic_load_ubo_dxil: 36037ec681f3Smrg return emit_load_ubo_dxil(ctx, intr); 36047ec681f3Smrg case nir_intrinsic_load_front_face: 36057ec681f3Smrg return emit_load_input_interpolated(ctx, intr, 36067ec681f3Smrg ctx->system_value[SYSTEM_VALUE_FRONT_FACE]); 36077ec681f3Smrg case nir_intrinsic_load_vertex_id_zero_base: 36087ec681f3Smrg return emit_load_input_interpolated(ctx, intr, 36097ec681f3Smrg ctx->system_value[SYSTEM_VALUE_VERTEX_ID_ZERO_BASE]); 36107ec681f3Smrg case nir_intrinsic_load_instance_id: 36117ec681f3Smrg return emit_load_input_interpolated(ctx, intr, 36127ec681f3Smrg ctx->system_value[SYSTEM_VALUE_INSTANCE_ID]); 36137ec681f3Smrg case nir_intrinsic_load_primitive_id: 36147ec681f3Smrg return emit_load_unary_external_function(ctx, intr, "dx.op.primitiveID", 36157ec681f3Smrg DXIL_INTR_PRIMITIVE_ID); 36167ec681f3Smrg case nir_intrinsic_load_sample_id: 36177ec681f3Smrg return emit_load_unary_external_function(ctx, intr, "dx.op.sampleIndex", 36187ec681f3Smrg DXIL_INTR_SAMPLE_INDEX); 36197ec681f3Smrg case nir_intrinsic_load_shared_dxil: 36207ec681f3Smrg return emit_load_shared(ctx, intr); 36217ec681f3Smrg case nir_intrinsic_load_scratch_dxil: 36227ec681f3Smrg return emit_load_scratch(ctx, intr); 36237ec681f3Smrg case nir_intrinsic_discard_if: 36247ec681f3Smrg return emit_discard_if(ctx, intr); 36257ec681f3Smrg case nir_intrinsic_discard: 36267ec681f3Smrg return emit_discard(ctx); 36277ec681f3Smrg case nir_intrinsic_emit_vertex: 36287ec681f3Smrg return emit_emit_vertex(ctx, intr); 36297ec681f3Smrg case nir_intrinsic_end_primitive: 36307ec681f3Smrg return emit_end_primitive(ctx, intr); 36317ec681f3Smrg case nir_intrinsic_scoped_barrier: 36327ec681f3Smrg return emit_barrier(ctx, intr); 36337ec681f3Smrg case nir_intrinsic_ssbo_atomic_add: 36347ec681f3Smrg return emit_ssbo_atomic(ctx, intr, DXIL_ATOMIC_ADD, nir_type_int); 36357ec681f3Smrg case nir_intrinsic_ssbo_atomic_imin: 36367ec681f3Smrg return emit_ssbo_atomic(ctx, intr, DXIL_ATOMIC_IMIN, nir_type_int); 36377ec681f3Smrg case nir_intrinsic_ssbo_atomic_umin: 36387ec681f3Smrg return emit_ssbo_atomic(ctx, intr, DXIL_ATOMIC_UMIN, nir_type_uint); 36397ec681f3Smrg case nir_intrinsic_ssbo_atomic_imax: 36407ec681f3Smrg return emit_ssbo_atomic(ctx, intr, DXIL_ATOMIC_IMAX, nir_type_int); 36417ec681f3Smrg case nir_intrinsic_ssbo_atomic_umax: 36427ec681f3Smrg return emit_ssbo_atomic(ctx, intr, DXIL_ATOMIC_UMAX, nir_type_uint); 36437ec681f3Smrg case nir_intrinsic_ssbo_atomic_and: 36447ec681f3Smrg return emit_ssbo_atomic(ctx, intr, DXIL_ATOMIC_AND, nir_type_uint); 36457ec681f3Smrg case nir_intrinsic_ssbo_atomic_or: 36467ec681f3Smrg return emit_ssbo_atomic(ctx, intr, DXIL_ATOMIC_OR, nir_type_uint); 36477ec681f3Smrg case nir_intrinsic_ssbo_atomic_xor: 36487ec681f3Smrg return emit_ssbo_atomic(ctx, intr, DXIL_ATOMIC_XOR, nir_type_uint); 36497ec681f3Smrg case nir_intrinsic_ssbo_atomic_exchange: 36507ec681f3Smrg return emit_ssbo_atomic(ctx, intr, DXIL_ATOMIC_EXCHANGE, nir_type_int); 36517ec681f3Smrg case nir_intrinsic_ssbo_atomic_comp_swap: 36527ec681f3Smrg return emit_ssbo_atomic_comp_swap(ctx, intr); 36537ec681f3Smrg case nir_intrinsic_shared_atomic_add_dxil: 36547ec681f3Smrg return emit_shared_atomic(ctx, intr, DXIL_RMWOP_ADD, nir_type_int); 36557ec681f3Smrg case nir_intrinsic_shared_atomic_imin_dxil: 36567ec681f3Smrg return emit_shared_atomic(ctx, intr, DXIL_RMWOP_MIN, nir_type_int); 36577ec681f3Smrg case nir_intrinsic_shared_atomic_umin_dxil: 36587ec681f3Smrg return emit_shared_atomic(ctx, intr, DXIL_RMWOP_UMIN, nir_type_uint); 36597ec681f3Smrg case nir_intrinsic_shared_atomic_imax_dxil: 36607ec681f3Smrg return emit_shared_atomic(ctx, intr, DXIL_RMWOP_MAX, nir_type_int); 36617ec681f3Smrg case nir_intrinsic_shared_atomic_umax_dxil: 36627ec681f3Smrg return emit_shared_atomic(ctx, intr, DXIL_RMWOP_UMAX, nir_type_uint); 36637ec681f3Smrg case nir_intrinsic_shared_atomic_and_dxil: 36647ec681f3Smrg return emit_shared_atomic(ctx, intr, DXIL_RMWOP_AND, nir_type_uint); 36657ec681f3Smrg case nir_intrinsic_shared_atomic_or_dxil: 36667ec681f3Smrg return emit_shared_atomic(ctx, intr, DXIL_RMWOP_OR, nir_type_uint); 36677ec681f3Smrg case nir_intrinsic_shared_atomic_xor_dxil: 36687ec681f3Smrg return emit_shared_atomic(ctx, intr, DXIL_RMWOP_XOR, nir_type_uint); 36697ec681f3Smrg case nir_intrinsic_shared_atomic_exchange_dxil: 36707ec681f3Smrg return emit_shared_atomic(ctx, intr, DXIL_RMWOP_XCHG, nir_type_int); 36717ec681f3Smrg case nir_intrinsic_shared_atomic_comp_swap_dxil: 36727ec681f3Smrg return emit_shared_atomic_comp_swap(ctx, intr); 36737ec681f3Smrg case nir_intrinsic_image_store: 36747ec681f3Smrg case nir_intrinsic_image_deref_store: 36757ec681f3Smrg return emit_image_store(ctx, intr); 36767ec681f3Smrg case nir_intrinsic_image_load: 36777ec681f3Smrg case nir_intrinsic_image_deref_load: 36787ec681f3Smrg return emit_image_load(ctx, intr); 36797ec681f3Smrg case nir_intrinsic_image_size: 36807ec681f3Smrg case nir_intrinsic_image_deref_size: 36817ec681f3Smrg return emit_image_size(ctx, intr); 36827ec681f3Smrg case nir_intrinsic_get_ssbo_size: 36837ec681f3Smrg return emit_get_ssbo_size(ctx, intr); 36847ec681f3Smrg 36857ec681f3Smrg case nir_intrinsic_vulkan_resource_index: 36867ec681f3Smrg return emit_vulkan_resource_index(ctx, intr); 36877ec681f3Smrg case nir_intrinsic_load_vulkan_descriptor: 36887ec681f3Smrg return emit_load_vulkan_descriptor(ctx, intr); 36897ec681f3Smrg 36907ec681f3Smrg case nir_intrinsic_load_num_workgroups: 36917ec681f3Smrg case nir_intrinsic_load_workgroup_size: 36927ec681f3Smrg default: 36937ec681f3Smrg NIR_INSTR_UNSUPPORTED(&intr->instr); 36947ec681f3Smrg assert("Unimplemented intrinsic instruction"); 36957ec681f3Smrg return false; 36967ec681f3Smrg } 36977ec681f3Smrg} 36987ec681f3Smrg 36997ec681f3Smrgstatic bool 37007ec681f3Smrgemit_load_const(struct ntd_context *ctx, nir_load_const_instr *load_const) 37017ec681f3Smrg{ 37027ec681f3Smrg for (int i = 0; i < load_const->def.num_components; ++i) { 37037ec681f3Smrg const struct dxil_value *value; 37047ec681f3Smrg switch (load_const->def.bit_size) { 37057ec681f3Smrg case 1: 37067ec681f3Smrg value = dxil_module_get_int1_const(&ctx->mod, 37077ec681f3Smrg load_const->value[i].b); 37087ec681f3Smrg break; 37097ec681f3Smrg case 16: 37107ec681f3Smrg ctx->mod.feats.native_low_precision = true; 37117ec681f3Smrg value = dxil_module_get_int16_const(&ctx->mod, 37127ec681f3Smrg load_const->value[i].u16); 37137ec681f3Smrg break; 37147ec681f3Smrg case 32: 37157ec681f3Smrg value = dxil_module_get_int32_const(&ctx->mod, 37167ec681f3Smrg load_const->value[i].u32); 37177ec681f3Smrg break; 37187ec681f3Smrg case 64: 37197ec681f3Smrg ctx->mod.feats.int64_ops = true; 37207ec681f3Smrg value = dxil_module_get_int64_const(&ctx->mod, 37217ec681f3Smrg load_const->value[i].u64); 37227ec681f3Smrg break; 37237ec681f3Smrg default: 37247ec681f3Smrg unreachable("unexpected bit_size"); 37257ec681f3Smrg } 37267ec681f3Smrg if (!value) 37277ec681f3Smrg return false; 37287ec681f3Smrg 37297ec681f3Smrg store_ssa_def(ctx, &load_const->def, i, value); 37307ec681f3Smrg } 37317ec681f3Smrg return true; 37327ec681f3Smrg} 37337ec681f3Smrg 37347ec681f3Smrgstatic bool 37357ec681f3Smrgemit_deref(struct ntd_context* ctx, nir_deref_instr* instr) 37367ec681f3Smrg{ 37377ec681f3Smrg assert(instr->deref_type == nir_deref_type_var || 37387ec681f3Smrg instr->deref_type == nir_deref_type_array); 37397ec681f3Smrg 37407ec681f3Smrg /* In the non-Vulkan environment, there's nothing to emit. Any references to 37417ec681f3Smrg * derefs will emit the necessary logic to handle scratch/shared GEP addressing 37427ec681f3Smrg */ 37437ec681f3Smrg if (!ctx->opts->vulkan_environment) 37447ec681f3Smrg return true; 37457ec681f3Smrg 37467ec681f3Smrg /* In the Vulkan environment, we don't have cached handles for textures or 37477ec681f3Smrg * samplers, so let's use the opportunity of walking through the derefs to 37487ec681f3Smrg * emit those. 37497ec681f3Smrg */ 37507ec681f3Smrg nir_variable *var = nir_deref_instr_get_variable(instr); 37517ec681f3Smrg assert(var); 37527ec681f3Smrg 37537ec681f3Smrg if (!glsl_type_is_sampler(glsl_without_array(var->type)) && 37547ec681f3Smrg !glsl_type_is_image(glsl_without_array(var->type))) 37557ec681f3Smrg return true; 37567ec681f3Smrg 37577ec681f3Smrg const struct glsl_type *type = instr->type; 37587ec681f3Smrg const struct dxil_value *binding; 37597ec681f3Smrg 37607ec681f3Smrg if (instr->deref_type == nir_deref_type_var) { 37617ec681f3Smrg binding = dxil_module_get_int32_const(&ctx->mod, var->data.binding); 37627ec681f3Smrg } else { 37637ec681f3Smrg const struct dxil_value *base = get_src(ctx, &instr->parent, 0, nir_type_uint32); 37647ec681f3Smrg const struct dxil_value *offset = get_src(ctx, &instr->arr.index, 0, nir_type_uint32); 37657ec681f3Smrg if (!base || !offset) 37667ec681f3Smrg return false; 37677ec681f3Smrg 37687ec681f3Smrg binding = dxil_emit_binop(&ctx->mod, DXIL_BINOP_ADD, base, offset, 0); 37697ec681f3Smrg } 37707ec681f3Smrg 37717ec681f3Smrg if (!binding) 37727ec681f3Smrg return false; 37737ec681f3Smrg 37747ec681f3Smrg /* Haven't finished chasing the deref chain yet, just store the value */ 37757ec681f3Smrg if (glsl_type_is_array(type)) { 37767ec681f3Smrg store_dest(ctx, &instr->dest, 0, binding, nir_type_uint32); 37777ec681f3Smrg return true; 37787ec681f3Smrg } 37797ec681f3Smrg 37807ec681f3Smrg assert(glsl_type_is_sampler(type) || glsl_type_is_image(type)); 37817ec681f3Smrg enum dxil_resource_class res_class; 37827ec681f3Smrg if (glsl_type_is_image(type)) 37837ec681f3Smrg res_class = DXIL_RESOURCE_CLASS_UAV; 37847ec681f3Smrg else if (glsl_get_sampler_result_type(type) == GLSL_TYPE_VOID) 37857ec681f3Smrg res_class = DXIL_RESOURCE_CLASS_SAMPLER; 37867ec681f3Smrg else 37877ec681f3Smrg res_class = DXIL_RESOURCE_CLASS_SRV; 37887ec681f3Smrg 37897ec681f3Smrg const struct dxil_value *handle = emit_createhandle_call(ctx, res_class, 37907ec681f3Smrg get_resource_id(ctx, res_class, var->data.descriptor_set, var->data.binding), binding, false); 37917ec681f3Smrg if (!handle) 37927ec681f3Smrg return false; 37937ec681f3Smrg 37947ec681f3Smrg store_dest_value(ctx, &instr->dest, 0, handle); 37957ec681f3Smrg return true; 37967ec681f3Smrg} 37977ec681f3Smrg 37987ec681f3Smrgstatic bool 37997ec681f3Smrgemit_cond_branch(struct ntd_context *ctx, const struct dxil_value *cond, 38007ec681f3Smrg int true_block, int false_block) 38017ec681f3Smrg{ 38027ec681f3Smrg assert(cond); 38037ec681f3Smrg assert(true_block >= 0); 38047ec681f3Smrg assert(false_block >= 0); 38057ec681f3Smrg return dxil_emit_branch(&ctx->mod, cond, true_block, false_block); 38067ec681f3Smrg} 38077ec681f3Smrg 38087ec681f3Smrgstatic bool 38097ec681f3Smrgemit_branch(struct ntd_context *ctx, int block) 38107ec681f3Smrg{ 38117ec681f3Smrg assert(block >= 0); 38127ec681f3Smrg return dxil_emit_branch(&ctx->mod, NULL, block, -1); 38137ec681f3Smrg} 38147ec681f3Smrg 38157ec681f3Smrgstatic bool 38167ec681f3Smrgemit_jump(struct ntd_context *ctx, nir_jump_instr *instr) 38177ec681f3Smrg{ 38187ec681f3Smrg switch (instr->type) { 38197ec681f3Smrg case nir_jump_break: 38207ec681f3Smrg case nir_jump_continue: 38217ec681f3Smrg assert(instr->instr.block->successors[0]); 38227ec681f3Smrg assert(!instr->instr.block->successors[1]); 38237ec681f3Smrg return emit_branch(ctx, instr->instr.block->successors[0]->index); 38247ec681f3Smrg 38257ec681f3Smrg default: 38267ec681f3Smrg unreachable("Unsupported jump type\n"); 38277ec681f3Smrg } 38287ec681f3Smrg} 38297ec681f3Smrg 38307ec681f3Smrgstruct phi_block { 38317ec681f3Smrg unsigned num_components; 38327ec681f3Smrg struct dxil_instr *comp[NIR_MAX_VEC_COMPONENTS]; 38337ec681f3Smrg}; 38347ec681f3Smrg 38357ec681f3Smrgstatic bool 38367ec681f3Smrgemit_phi(struct ntd_context *ctx, nir_phi_instr *instr) 38377ec681f3Smrg{ 38387ec681f3Smrg unsigned bit_size = nir_dest_bit_size(instr->dest); 38397ec681f3Smrg const struct dxil_type *type = dxil_module_get_int_type(&ctx->mod, 38407ec681f3Smrg bit_size); 38417ec681f3Smrg 38427ec681f3Smrg struct phi_block *vphi = ralloc(ctx->phis, struct phi_block); 38437ec681f3Smrg vphi->num_components = nir_dest_num_components(instr->dest); 38447ec681f3Smrg 38457ec681f3Smrg for (unsigned i = 0; i < vphi->num_components; ++i) { 38467ec681f3Smrg struct dxil_instr *phi = vphi->comp[i] = dxil_emit_phi(&ctx->mod, type); 38477ec681f3Smrg if (!phi) 38487ec681f3Smrg return false; 38497ec681f3Smrg store_dest_value(ctx, &instr->dest, i, dxil_instr_get_return_value(phi)); 38507ec681f3Smrg } 38517ec681f3Smrg _mesa_hash_table_insert(ctx->phis, instr, vphi); 38527ec681f3Smrg return true; 38537ec681f3Smrg} 38547ec681f3Smrg 38557ec681f3Smrgstatic void 38567ec681f3Smrgfixup_phi(struct ntd_context *ctx, nir_phi_instr *instr, 38577ec681f3Smrg struct phi_block *vphi) 38587ec681f3Smrg{ 38597ec681f3Smrg const struct dxil_value *values[128]; 38607ec681f3Smrg unsigned blocks[128]; 38617ec681f3Smrg for (unsigned i = 0; i < vphi->num_components; ++i) { 38627ec681f3Smrg size_t num_incoming = 0; 38637ec681f3Smrg nir_foreach_phi_src(src, instr) { 38647ec681f3Smrg assert(src->src.is_ssa); 38657ec681f3Smrg const struct dxil_value *val = get_src_ssa(ctx, src->src.ssa, i); 38667ec681f3Smrg assert(num_incoming < ARRAY_SIZE(values)); 38677ec681f3Smrg values[num_incoming] = val; 38687ec681f3Smrg assert(num_incoming < ARRAY_SIZE(blocks)); 38697ec681f3Smrg blocks[num_incoming] = src->pred->index; 38707ec681f3Smrg ++num_incoming; 38717ec681f3Smrg } 38727ec681f3Smrg dxil_phi_set_incoming(vphi->comp[i], values, blocks, num_incoming); 38737ec681f3Smrg } 38747ec681f3Smrg} 38757ec681f3Smrg 38767ec681f3Smrgstatic unsigned 38777ec681f3Smrgget_n_src(struct ntd_context *ctx, const struct dxil_value **values, 38787ec681f3Smrg unsigned max_components, nir_tex_src *src, nir_alu_type type) 38797ec681f3Smrg{ 38807ec681f3Smrg unsigned num_components = nir_src_num_components(src->src); 38817ec681f3Smrg unsigned i = 0; 38827ec681f3Smrg 38837ec681f3Smrg assert(num_components <= max_components); 38847ec681f3Smrg 38857ec681f3Smrg for (i = 0; i < num_components; ++i) { 38867ec681f3Smrg values[i] = get_src(ctx, &src->src, i, type); 38877ec681f3Smrg if (!values[i]) 38887ec681f3Smrg return 0; 38897ec681f3Smrg } 38907ec681f3Smrg 38917ec681f3Smrg return num_components; 38927ec681f3Smrg} 38937ec681f3Smrg 38947ec681f3Smrg#define PAD_SRC(ctx, array, components, undef) \ 38957ec681f3Smrg for (unsigned i = components; i < ARRAY_SIZE(array); ++i) { \ 38967ec681f3Smrg array[i] = undef; \ 38977ec681f3Smrg } 38987ec681f3Smrg 38997ec681f3Smrgstatic const struct dxil_value * 39007ec681f3Smrgemit_sample(struct ntd_context *ctx, struct texop_parameters *params) 39017ec681f3Smrg{ 39027ec681f3Smrg const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.sample", params->overload); 39037ec681f3Smrg if (!func) 39047ec681f3Smrg return NULL; 39057ec681f3Smrg 39067ec681f3Smrg const struct dxil_value *args[11] = { 39077ec681f3Smrg dxil_module_get_int32_const(&ctx->mod, DXIL_INTR_SAMPLE), 39087ec681f3Smrg params->tex, params->sampler, 39097ec681f3Smrg params->coord[0], params->coord[1], params->coord[2], params->coord[3], 39107ec681f3Smrg params->offset[0], params->offset[1], params->offset[2], 39117ec681f3Smrg params->min_lod 39127ec681f3Smrg }; 39137ec681f3Smrg 39147ec681f3Smrg return dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args)); 39157ec681f3Smrg} 39167ec681f3Smrg 39177ec681f3Smrgstatic const struct dxil_value * 39187ec681f3Smrgemit_sample_bias(struct ntd_context *ctx, struct texop_parameters *params) 39197ec681f3Smrg{ 39207ec681f3Smrg const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.sampleBias", params->overload); 39217ec681f3Smrg if (!func) 39227ec681f3Smrg return NULL; 39237ec681f3Smrg 39247ec681f3Smrg assert(params->bias != NULL); 39257ec681f3Smrg 39267ec681f3Smrg const struct dxil_value *args[12] = { 39277ec681f3Smrg dxil_module_get_int32_const(&ctx->mod, DXIL_INTR_SAMPLE_BIAS), 39287ec681f3Smrg params->tex, params->sampler, 39297ec681f3Smrg params->coord[0], params->coord[1], params->coord[2], params->coord[3], 39307ec681f3Smrg params->offset[0], params->offset[1], params->offset[2], 39317ec681f3Smrg params->bias, params->min_lod 39327ec681f3Smrg }; 39337ec681f3Smrg 39347ec681f3Smrg return dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args)); 39357ec681f3Smrg} 39367ec681f3Smrg 39377ec681f3Smrgstatic const struct dxil_value * 39387ec681f3Smrgemit_sample_level(struct ntd_context *ctx, struct texop_parameters *params) 39397ec681f3Smrg{ 39407ec681f3Smrg const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.sampleLevel", params->overload); 39417ec681f3Smrg if (!func) 39427ec681f3Smrg return NULL; 39437ec681f3Smrg 39447ec681f3Smrg assert(params->lod_or_sample != NULL); 39457ec681f3Smrg 39467ec681f3Smrg const struct dxil_value *args[11] = { 39477ec681f3Smrg dxil_module_get_int32_const(&ctx->mod, DXIL_INTR_SAMPLE_LEVEL), 39487ec681f3Smrg params->tex, params->sampler, 39497ec681f3Smrg params->coord[0], params->coord[1], params->coord[2], params->coord[3], 39507ec681f3Smrg params->offset[0], params->offset[1], params->offset[2], 39517ec681f3Smrg params->lod_or_sample 39527ec681f3Smrg }; 39537ec681f3Smrg 39547ec681f3Smrg return dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args)); 39557ec681f3Smrg} 39567ec681f3Smrg 39577ec681f3Smrgstatic const struct dxil_value * 39587ec681f3Smrgemit_sample_cmp(struct ntd_context *ctx, struct texop_parameters *params) 39597ec681f3Smrg{ 39607ec681f3Smrg const struct dxil_func *func; 39617ec681f3Smrg enum dxil_intr opcode; 39627ec681f3Smrg int numparam; 39637ec681f3Smrg 39647ec681f3Smrg if (ctx->mod.shader_kind == DXIL_PIXEL_SHADER) { 39657ec681f3Smrg func = dxil_get_function(&ctx->mod, "dx.op.sampleCmp", DXIL_F32); 39667ec681f3Smrg opcode = DXIL_INTR_SAMPLE_CMP; 39677ec681f3Smrg numparam = 12; 39687ec681f3Smrg } else { 39697ec681f3Smrg func = dxil_get_function(&ctx->mod, "dx.op.sampleCmpLevelZero", DXIL_F32); 39707ec681f3Smrg opcode = DXIL_INTR_SAMPLE_CMP_LVL_ZERO; 39717ec681f3Smrg numparam = 11; 39727ec681f3Smrg } 39737ec681f3Smrg 39747ec681f3Smrg if (!func) 39757ec681f3Smrg return NULL; 39767ec681f3Smrg 39777ec681f3Smrg const struct dxil_value *args[12] = { 39787ec681f3Smrg dxil_module_get_int32_const(&ctx->mod, opcode), 39797ec681f3Smrg params->tex, params->sampler, 39807ec681f3Smrg params->coord[0], params->coord[1], params->coord[2], params->coord[3], 39817ec681f3Smrg params->offset[0], params->offset[1], params->offset[2], 39827ec681f3Smrg params->cmp, params->min_lod 39837ec681f3Smrg }; 39847ec681f3Smrg 39857ec681f3Smrg return dxil_emit_call(&ctx->mod, func, args, numparam); 39867ec681f3Smrg} 39877ec681f3Smrg 39887ec681f3Smrgstatic const struct dxil_value * 39897ec681f3Smrgemit_sample_grad(struct ntd_context *ctx, struct texop_parameters *params) 39907ec681f3Smrg{ 39917ec681f3Smrg const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.sampleGrad", params->overload); 39927ec681f3Smrg if (!func) 39937ec681f3Smrg return false; 39947ec681f3Smrg 39957ec681f3Smrg const struct dxil_value *args[17] = { 39967ec681f3Smrg dxil_module_get_int32_const(&ctx->mod, DXIL_INTR_SAMPLE_GRAD), 39977ec681f3Smrg params->tex, params->sampler, 39987ec681f3Smrg params->coord[0], params->coord[1], params->coord[2], params->coord[3], 39997ec681f3Smrg params->offset[0], params->offset[1], params->offset[2], 40007ec681f3Smrg params->dx[0], params->dx[1], params->dx[2], 40017ec681f3Smrg params->dy[0], params->dy[1], params->dy[2], 40027ec681f3Smrg params->min_lod 40037ec681f3Smrg }; 40047ec681f3Smrg 40057ec681f3Smrg return dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args)); 40067ec681f3Smrg} 40077ec681f3Smrg 40087ec681f3Smrgstatic const struct dxil_value * 40097ec681f3Smrgemit_texel_fetch(struct ntd_context *ctx, struct texop_parameters *params) 40107ec681f3Smrg{ 40117ec681f3Smrg const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.textureLoad", params->overload); 40127ec681f3Smrg if (!func) 40137ec681f3Smrg return false; 40147ec681f3Smrg 40157ec681f3Smrg if (!params->lod_or_sample) 40167ec681f3Smrg params->lod_or_sample = dxil_module_get_undef(&ctx->mod, dxil_module_get_int_type(&ctx->mod, 32)); 40177ec681f3Smrg 40187ec681f3Smrg const struct dxil_value *args[] = { 40197ec681f3Smrg dxil_module_get_int32_const(&ctx->mod, DXIL_INTR_TEXTURE_LOAD), 40207ec681f3Smrg params->tex, 40217ec681f3Smrg params->lod_or_sample, params->coord[0], params->coord[1], params->coord[2], 40227ec681f3Smrg params->offset[0], params->offset[1], params->offset[2] 40237ec681f3Smrg }; 40247ec681f3Smrg 40257ec681f3Smrg return dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args)); 40267ec681f3Smrg} 40277ec681f3Smrg 40287ec681f3Smrgstatic const struct dxil_value * 40297ec681f3Smrgemit_texture_lod(struct ntd_context *ctx, struct texop_parameters *params) 40307ec681f3Smrg{ 40317ec681f3Smrg const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.calculateLOD", DXIL_F32); 40327ec681f3Smrg if (!func) 40337ec681f3Smrg return false; 40347ec681f3Smrg 40357ec681f3Smrg const struct dxil_value *args[] = { 40367ec681f3Smrg dxil_module_get_int32_const(&ctx->mod, DXIL_INTR_TEXTURE_LOD), 40377ec681f3Smrg params->tex, 40387ec681f3Smrg params->sampler, 40397ec681f3Smrg params->coord[0], 40407ec681f3Smrg params->coord[1], 40417ec681f3Smrg params->coord[2], 40427ec681f3Smrg dxil_module_get_int1_const(&ctx->mod, 1) 40437ec681f3Smrg }; 40447ec681f3Smrg 40457ec681f3Smrg return dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args)); 40467ec681f3Smrg} 40477ec681f3Smrg 40487ec681f3Smrgstatic bool 40497ec681f3Smrgemit_tex(struct ntd_context *ctx, nir_tex_instr *instr) 40507ec681f3Smrg{ 40517ec681f3Smrg struct texop_parameters params; 40527ec681f3Smrg memset(¶ms, 0, sizeof(struct texop_parameters)); 40537ec681f3Smrg if (!ctx->opts->vulkan_environment) { 40547ec681f3Smrg params.tex = ctx->srv_handles[instr->texture_index]; 40557ec681f3Smrg params.sampler = ctx->sampler_handles[instr->sampler_index]; 40567ec681f3Smrg } 40577ec681f3Smrg 40587ec681f3Smrg const struct dxil_type *int_type = dxil_module_get_int_type(&ctx->mod, 32); 40597ec681f3Smrg const struct dxil_type *float_type = dxil_module_get_float_type(&ctx->mod, 32); 40607ec681f3Smrg const struct dxil_value *int_undef = dxil_module_get_undef(&ctx->mod, int_type); 40617ec681f3Smrg const struct dxil_value *float_undef = dxil_module_get_undef(&ctx->mod, float_type); 40627ec681f3Smrg 40637ec681f3Smrg unsigned coord_components = 0, offset_components = 0, dx_components = 0, dy_components = 0; 40647ec681f3Smrg params.overload = get_overload(instr->dest_type, 32); 40657ec681f3Smrg 40667ec681f3Smrg for (unsigned i = 0; i < instr->num_srcs; i++) { 40677ec681f3Smrg nir_alu_type type = nir_tex_instr_src_type(instr, i); 40687ec681f3Smrg 40697ec681f3Smrg switch (instr->src[i].src_type) { 40707ec681f3Smrg case nir_tex_src_coord: 40717ec681f3Smrg coord_components = get_n_src(ctx, params.coord, ARRAY_SIZE(params.coord), 40727ec681f3Smrg &instr->src[i], type); 40737ec681f3Smrg if (!coord_components) 40747ec681f3Smrg return false; 40757ec681f3Smrg break; 40767ec681f3Smrg 40777ec681f3Smrg case nir_tex_src_offset: 40787ec681f3Smrg offset_components = get_n_src(ctx, params.offset, ARRAY_SIZE(params.offset), 40797ec681f3Smrg &instr->src[i], nir_type_int); 40807ec681f3Smrg if (!offset_components) 40817ec681f3Smrg return false; 40827ec681f3Smrg break; 40837ec681f3Smrg 40847ec681f3Smrg case nir_tex_src_bias: 40857ec681f3Smrg assert(instr->op == nir_texop_txb); 40867ec681f3Smrg assert(nir_src_num_components(instr->src[i].src) == 1); 40877ec681f3Smrg params.bias = get_src(ctx, &instr->src[i].src, 0, nir_type_float); 40887ec681f3Smrg if (!params.bias) 40897ec681f3Smrg return false; 40907ec681f3Smrg break; 40917ec681f3Smrg 40927ec681f3Smrg case nir_tex_src_lod: 40937ec681f3Smrg assert(nir_src_num_components(instr->src[i].src) == 1); 40947ec681f3Smrg /* Buffers don't have a LOD */ 40957ec681f3Smrg if (instr->sampler_dim != GLSL_SAMPLER_DIM_BUF) 40967ec681f3Smrg params.lod_or_sample = get_src(ctx, &instr->src[i].src, 0, type); 40977ec681f3Smrg else 40987ec681f3Smrg params.lod_or_sample = int_undef; 40997ec681f3Smrg if (!params.lod_or_sample) 41007ec681f3Smrg return false; 41017ec681f3Smrg break; 41027ec681f3Smrg 41037ec681f3Smrg case nir_tex_src_min_lod: 41047ec681f3Smrg assert(nir_src_num_components(instr->src[i].src) == 1); 41057ec681f3Smrg params.min_lod = get_src(ctx, &instr->src[i].src, 0, type); 41067ec681f3Smrg if (!params.min_lod) 41077ec681f3Smrg return false; 41087ec681f3Smrg break; 41097ec681f3Smrg 41107ec681f3Smrg case nir_tex_src_comparator: 41117ec681f3Smrg assert(nir_src_num_components(instr->src[i].src) == 1); 41127ec681f3Smrg params.cmp = get_src(ctx, &instr->src[i].src, 0, nir_type_float); 41137ec681f3Smrg if (!params.cmp) 41147ec681f3Smrg return false; 41157ec681f3Smrg break; 41167ec681f3Smrg 41177ec681f3Smrg case nir_tex_src_ddx: 41187ec681f3Smrg dx_components = get_n_src(ctx, params.dx, ARRAY_SIZE(params.dx), 41197ec681f3Smrg &instr->src[i], nir_type_float); 41207ec681f3Smrg if (!dx_components) 41217ec681f3Smrg return false; 41227ec681f3Smrg break; 41237ec681f3Smrg 41247ec681f3Smrg case nir_tex_src_ddy: 41257ec681f3Smrg dy_components = get_n_src(ctx, params.dy, ARRAY_SIZE(params.dy), 41267ec681f3Smrg &instr->src[i], nir_type_float); 41277ec681f3Smrg if (!dy_components) 41287ec681f3Smrg return false; 41297ec681f3Smrg break; 41307ec681f3Smrg 41317ec681f3Smrg case nir_tex_src_ms_index: 41327ec681f3Smrg params.lod_or_sample = get_src(ctx, &instr->src[i].src, 0, nir_type_int); 41337ec681f3Smrg if (!params.lod_or_sample) 41347ec681f3Smrg return false; 41357ec681f3Smrg break; 41367ec681f3Smrg 41377ec681f3Smrg case nir_tex_src_texture_deref: 41387ec681f3Smrg assert(ctx->opts->vulkan_environment); 41397ec681f3Smrg params.tex = get_src_ssa(ctx, instr->src[i].src.ssa, 0); 41407ec681f3Smrg break; 41417ec681f3Smrg 41427ec681f3Smrg case nir_tex_src_sampler_deref: 41437ec681f3Smrg assert(ctx->opts->vulkan_environment); 41447ec681f3Smrg params.sampler = get_src_ssa(ctx, instr->src[i].src.ssa, 0); 41457ec681f3Smrg break; 41467ec681f3Smrg 41477ec681f3Smrg case nir_tex_src_projector: 41487ec681f3Smrg unreachable("Texture projector should have been lowered"); 41497ec681f3Smrg 41507ec681f3Smrg default: 41517ec681f3Smrg fprintf(stderr, "texture source: %d\n", instr->src[i].src_type); 41527ec681f3Smrg unreachable("unknown texture source"); 41537ec681f3Smrg } 41547ec681f3Smrg } 41557ec681f3Smrg 41567ec681f3Smrg assert(params.tex != NULL); 41577ec681f3Smrg assert(instr->op == nir_texop_txf || 41587ec681f3Smrg instr->op == nir_texop_txf_ms || 41597ec681f3Smrg nir_tex_instr_is_query(instr) || 41607ec681f3Smrg params.sampler != NULL); 41617ec681f3Smrg 41627ec681f3Smrg PAD_SRC(ctx, params.coord, coord_components, float_undef); 41637ec681f3Smrg PAD_SRC(ctx, params.offset, offset_components, int_undef); 41647ec681f3Smrg if (!params.min_lod) params.min_lod = float_undef; 41657ec681f3Smrg 41667ec681f3Smrg const struct dxil_value *sample = NULL; 41677ec681f3Smrg switch (instr->op) { 41687ec681f3Smrg case nir_texop_txb: 41697ec681f3Smrg sample = emit_sample_bias(ctx, ¶ms); 41707ec681f3Smrg break; 41717ec681f3Smrg 41727ec681f3Smrg case nir_texop_tex: 41737ec681f3Smrg if (params.cmp != NULL) { 41747ec681f3Smrg sample = emit_sample_cmp(ctx, ¶ms); 41757ec681f3Smrg break; 41767ec681f3Smrg } else if (ctx->mod.shader_kind == DXIL_PIXEL_SHADER) { 41777ec681f3Smrg sample = emit_sample(ctx, ¶ms); 41787ec681f3Smrg break; 41797ec681f3Smrg } 41807ec681f3Smrg params.lod_or_sample = dxil_module_get_float_const(&ctx->mod, 0); 41817ec681f3Smrg FALLTHROUGH; 41827ec681f3Smrg case nir_texop_txl: 41837ec681f3Smrg sample = emit_sample_level(ctx, ¶ms); 41847ec681f3Smrg break; 41857ec681f3Smrg 41867ec681f3Smrg case nir_texop_txd: 41877ec681f3Smrg PAD_SRC(ctx, params.dx, dx_components, float_undef); 41887ec681f3Smrg PAD_SRC(ctx, params.dy, dy_components,float_undef); 41897ec681f3Smrg sample = emit_sample_grad(ctx, ¶ms); 41907ec681f3Smrg break; 41917ec681f3Smrg 41927ec681f3Smrg case nir_texop_txf: 41937ec681f3Smrg case nir_texop_txf_ms: 41947ec681f3Smrg if (instr->sampler_dim == GLSL_SAMPLER_DIM_BUF) { 41957ec681f3Smrg params.coord[1] = int_undef; 41967ec681f3Smrg sample = emit_bufferload_call(ctx, params.tex, params.coord, params.overload); 41977ec681f3Smrg } else { 41987ec681f3Smrg PAD_SRC(ctx, params.coord, coord_components, int_undef); 41997ec681f3Smrg sample = emit_texel_fetch(ctx, ¶ms); 42007ec681f3Smrg } 42017ec681f3Smrg break; 42027ec681f3Smrg 42037ec681f3Smrg case nir_texop_txs: 42047ec681f3Smrg sample = emit_texture_size(ctx, ¶ms); 42057ec681f3Smrg break; 42067ec681f3Smrg 42077ec681f3Smrg case nir_texop_lod: 42087ec681f3Smrg sample = emit_texture_lod(ctx, ¶ms); 42097ec681f3Smrg store_dest(ctx, &instr->dest, 0, sample, nir_alu_type_get_base_type(instr->dest_type)); 42107ec681f3Smrg return true; 42117ec681f3Smrg 42127ec681f3Smrg case nir_texop_query_levels: 42137ec681f3Smrg params.lod_or_sample = dxil_module_get_int_const(&ctx->mod, 0, 32); 42147ec681f3Smrg sample = emit_texture_size(ctx, ¶ms); 42157ec681f3Smrg const struct dxil_value *retval = dxil_emit_extractval(&ctx->mod, sample, 3); 42167ec681f3Smrg store_dest(ctx, &instr->dest, 0, retval, nir_alu_type_get_base_type(instr->dest_type)); 42177ec681f3Smrg return true; 42187ec681f3Smrg 42197ec681f3Smrg default: 42207ec681f3Smrg fprintf(stderr, "texture op: %d\n", instr->op); 42217ec681f3Smrg unreachable("unknown texture op"); 42227ec681f3Smrg } 42237ec681f3Smrg 42247ec681f3Smrg if (!sample) 42257ec681f3Smrg return false; 42267ec681f3Smrg 42277ec681f3Smrg for (unsigned i = 0; i < nir_dest_num_components(instr->dest); ++i) { 42287ec681f3Smrg const struct dxil_value *retval = dxil_emit_extractval(&ctx->mod, sample, i); 42297ec681f3Smrg store_dest(ctx, &instr->dest, i, retval, nir_alu_type_get_base_type(instr->dest_type)); 42307ec681f3Smrg } 42317ec681f3Smrg 42327ec681f3Smrg return true; 42337ec681f3Smrg} 42347ec681f3Smrg 42357ec681f3Smrgstatic bool 42367ec681f3Smrgemit_undefined(struct ntd_context *ctx, nir_ssa_undef_instr *undef) 42377ec681f3Smrg{ 42387ec681f3Smrg for (unsigned i = 0; i < undef->def.num_components; ++i) 42397ec681f3Smrg store_ssa_def(ctx, &undef->def, i, dxil_module_get_int32_const(&ctx->mod, 0)); 42407ec681f3Smrg return true; 42417ec681f3Smrg} 42427ec681f3Smrg 42437ec681f3Smrgstatic bool emit_instr(struct ntd_context *ctx, struct nir_instr* instr) 42447ec681f3Smrg{ 42457ec681f3Smrg switch (instr->type) { 42467ec681f3Smrg case nir_instr_type_alu: 42477ec681f3Smrg return emit_alu(ctx, nir_instr_as_alu(instr)); 42487ec681f3Smrg case nir_instr_type_intrinsic: 42497ec681f3Smrg return emit_intrinsic(ctx, nir_instr_as_intrinsic(instr)); 42507ec681f3Smrg case nir_instr_type_load_const: 42517ec681f3Smrg return emit_load_const(ctx, nir_instr_as_load_const(instr)); 42527ec681f3Smrg case nir_instr_type_deref: 42537ec681f3Smrg return emit_deref(ctx, nir_instr_as_deref(instr)); 42547ec681f3Smrg case nir_instr_type_jump: 42557ec681f3Smrg return emit_jump(ctx, nir_instr_as_jump(instr)); 42567ec681f3Smrg case nir_instr_type_phi: 42577ec681f3Smrg return emit_phi(ctx, nir_instr_as_phi(instr)); 42587ec681f3Smrg case nir_instr_type_tex: 42597ec681f3Smrg return emit_tex(ctx, nir_instr_as_tex(instr)); 42607ec681f3Smrg case nir_instr_type_ssa_undef: 42617ec681f3Smrg return emit_undefined(ctx, nir_instr_as_ssa_undef(instr)); 42627ec681f3Smrg default: 42637ec681f3Smrg NIR_INSTR_UNSUPPORTED(instr); 42647ec681f3Smrg unreachable("Unimplemented instruction type"); 42657ec681f3Smrg return false; 42667ec681f3Smrg } 42677ec681f3Smrg} 42687ec681f3Smrg 42697ec681f3Smrg 42707ec681f3Smrgstatic bool 42717ec681f3Smrgemit_block(struct ntd_context *ctx, struct nir_block *block) 42727ec681f3Smrg{ 42737ec681f3Smrg assert(block->index < ctx->mod.num_basic_block_ids); 42747ec681f3Smrg ctx->mod.basic_block_ids[block->index] = ctx->mod.curr_block; 42757ec681f3Smrg 42767ec681f3Smrg nir_foreach_instr(instr, block) { 42777ec681f3Smrg TRACE_CONVERSION(instr); 42787ec681f3Smrg 42797ec681f3Smrg if (!emit_instr(ctx, instr)) { 42807ec681f3Smrg return false; 42817ec681f3Smrg } 42827ec681f3Smrg } 42837ec681f3Smrg return true; 42847ec681f3Smrg} 42857ec681f3Smrg 42867ec681f3Smrgstatic bool 42877ec681f3Smrgemit_cf_list(struct ntd_context *ctx, struct exec_list *list); 42887ec681f3Smrg 42897ec681f3Smrgstatic bool 42907ec681f3Smrgemit_if(struct ntd_context *ctx, struct nir_if *if_stmt) 42917ec681f3Smrg{ 42927ec681f3Smrg assert(nir_src_num_components(if_stmt->condition) == 1); 42937ec681f3Smrg const struct dxil_value *cond = get_src(ctx, &if_stmt->condition, 0, 42947ec681f3Smrg nir_type_bool); 42957ec681f3Smrg if (!cond) 42967ec681f3Smrg return false; 42977ec681f3Smrg 42987ec681f3Smrg /* prepare blocks */ 42997ec681f3Smrg nir_block *then_block = nir_if_first_then_block(if_stmt); 43007ec681f3Smrg assert(nir_if_last_then_block(if_stmt)->successors[0]); 43017ec681f3Smrg assert(!nir_if_last_then_block(if_stmt)->successors[1]); 43027ec681f3Smrg int then_succ = nir_if_last_then_block(if_stmt)->successors[0]->index; 43037ec681f3Smrg 43047ec681f3Smrg nir_block *else_block = NULL; 43057ec681f3Smrg int else_succ = -1; 43067ec681f3Smrg if (!exec_list_is_empty(&if_stmt->else_list)) { 43077ec681f3Smrg else_block = nir_if_first_else_block(if_stmt); 43087ec681f3Smrg assert(nir_if_last_else_block(if_stmt)->successors[0]); 43097ec681f3Smrg assert(!nir_if_last_else_block(if_stmt)->successors[1]); 43107ec681f3Smrg else_succ = nir_if_last_else_block(if_stmt)->successors[0]->index; 43117ec681f3Smrg } 43127ec681f3Smrg 43137ec681f3Smrg if (!emit_cond_branch(ctx, cond, then_block->index, 43147ec681f3Smrg else_block ? else_block->index : then_succ)) 43157ec681f3Smrg return false; 43167ec681f3Smrg 43177ec681f3Smrg /* handle then-block */ 43187ec681f3Smrg if (!emit_cf_list(ctx, &if_stmt->then_list) || 43197ec681f3Smrg (!nir_block_ends_in_jump(nir_if_last_then_block(if_stmt)) && 43207ec681f3Smrg !emit_branch(ctx, then_succ))) 43217ec681f3Smrg return false; 43227ec681f3Smrg 43237ec681f3Smrg if (else_block) { 43247ec681f3Smrg /* handle else-block */ 43257ec681f3Smrg if (!emit_cf_list(ctx, &if_stmt->else_list) || 43267ec681f3Smrg (!nir_block_ends_in_jump(nir_if_last_else_block(if_stmt)) && 43277ec681f3Smrg !emit_branch(ctx, else_succ))) 43287ec681f3Smrg return false; 43297ec681f3Smrg } 43307ec681f3Smrg 43317ec681f3Smrg return true; 43327ec681f3Smrg} 43337ec681f3Smrg 43347ec681f3Smrgstatic bool 43357ec681f3Smrgemit_loop(struct ntd_context *ctx, nir_loop *loop) 43367ec681f3Smrg{ 43377ec681f3Smrg nir_block *first_block = nir_loop_first_block(loop); 43387ec681f3Smrg 43397ec681f3Smrg assert(nir_loop_last_block(loop)->successors[0]); 43407ec681f3Smrg assert(!nir_loop_last_block(loop)->successors[1]); 43417ec681f3Smrg 43427ec681f3Smrg if (!emit_branch(ctx, first_block->index)) 43437ec681f3Smrg return false; 43447ec681f3Smrg 43457ec681f3Smrg if (!emit_cf_list(ctx, &loop->body)) 43467ec681f3Smrg return false; 43477ec681f3Smrg 43487ec681f3Smrg if (!emit_branch(ctx, first_block->index)) 43497ec681f3Smrg return false; 43507ec681f3Smrg 43517ec681f3Smrg return true; 43527ec681f3Smrg} 43537ec681f3Smrg 43547ec681f3Smrgstatic bool 43557ec681f3Smrgemit_cf_list(struct ntd_context *ctx, struct exec_list *list) 43567ec681f3Smrg{ 43577ec681f3Smrg foreach_list_typed(nir_cf_node, node, node, list) { 43587ec681f3Smrg switch (node->type) { 43597ec681f3Smrg case nir_cf_node_block: 43607ec681f3Smrg if (!emit_block(ctx, nir_cf_node_as_block(node))) 43617ec681f3Smrg return false; 43627ec681f3Smrg break; 43637ec681f3Smrg 43647ec681f3Smrg case nir_cf_node_if: 43657ec681f3Smrg if (!emit_if(ctx, nir_cf_node_as_if(node))) 43667ec681f3Smrg return false; 43677ec681f3Smrg break; 43687ec681f3Smrg 43697ec681f3Smrg case nir_cf_node_loop: 43707ec681f3Smrg if (!emit_loop(ctx, nir_cf_node_as_loop(node))) 43717ec681f3Smrg return false; 43727ec681f3Smrg break; 43737ec681f3Smrg 43747ec681f3Smrg default: 43757ec681f3Smrg unreachable("unsupported cf-list node"); 43767ec681f3Smrg break; 43777ec681f3Smrg } 43787ec681f3Smrg } 43797ec681f3Smrg return true; 43807ec681f3Smrg} 43817ec681f3Smrg 43827ec681f3Smrgstatic void 43837ec681f3Smrginsert_sorted_by_binding(struct exec_list *var_list, nir_variable *new_var) 43847ec681f3Smrg{ 43857ec681f3Smrg nir_foreach_variable_in_list(var, var_list) { 43867ec681f3Smrg if (var->data.binding > new_var->data.binding) { 43877ec681f3Smrg exec_node_insert_node_before(&var->node, &new_var->node); 43887ec681f3Smrg return; 43897ec681f3Smrg } 43907ec681f3Smrg } 43917ec681f3Smrg exec_list_push_tail(var_list, &new_var->node); 43927ec681f3Smrg} 43937ec681f3Smrg 43947ec681f3Smrg 43957ec681f3Smrgstatic void 43967ec681f3Smrgsort_uniforms_by_binding_and_remove_structs(nir_shader *s) 43977ec681f3Smrg{ 43987ec681f3Smrg struct exec_list new_list; 43997ec681f3Smrg exec_list_make_empty(&new_list); 44007ec681f3Smrg 44017ec681f3Smrg nir_foreach_variable_with_modes_safe(var, s, nir_var_uniform) { 44027ec681f3Smrg exec_node_remove(&var->node); 44037ec681f3Smrg const struct glsl_type *type = glsl_without_array(var->type); 44047ec681f3Smrg if (!glsl_type_is_struct(type)) 44057ec681f3Smrg insert_sorted_by_binding(&new_list, var); 44067ec681f3Smrg } 44077ec681f3Smrg exec_list_append(&s->variables, &new_list); 44087ec681f3Smrg} 44097ec681f3Smrg 44107ec681f3Smrgstatic void 44117ec681f3Smrgprepare_phi_values(struct ntd_context *ctx) 44127ec681f3Smrg{ 44137ec681f3Smrg /* PHI nodes are difficult to get right when tracking the types: 44147ec681f3Smrg * Since the incoming sources are linked to blocks, we can't bitcast 44157ec681f3Smrg * on the fly while loading. So scan the shader and insert a typed dummy 44167ec681f3Smrg * value for each phi source, and when storing we convert if the incoming 44177ec681f3Smrg * value has a different type then the one expected by the phi node. 44187ec681f3Smrg * We choose int as default, because it supports more bit sizes. 44197ec681f3Smrg */ 44207ec681f3Smrg nir_foreach_function(function, ctx->shader) { 44217ec681f3Smrg if (function->impl) { 44227ec681f3Smrg nir_foreach_block(block, function->impl) { 44237ec681f3Smrg nir_foreach_instr(instr, block) { 44247ec681f3Smrg if (instr->type == nir_instr_type_phi) { 44257ec681f3Smrg nir_phi_instr *ir = nir_instr_as_phi(instr); 44267ec681f3Smrg unsigned bitsize = nir_dest_bit_size(ir->dest); 44277ec681f3Smrg const struct dxil_value *dummy = dxil_module_get_int_const(&ctx->mod, 0, bitsize); 44287ec681f3Smrg nir_foreach_phi_src(src, ir) { 44297ec681f3Smrg for(unsigned int i = 0; i < ir->dest.ssa.num_components; ++i) 44307ec681f3Smrg store_ssa_def(ctx, src->src.ssa, i, dummy); 44317ec681f3Smrg } 44327ec681f3Smrg } 44337ec681f3Smrg } 44347ec681f3Smrg } 44357ec681f3Smrg } 44367ec681f3Smrg } 44377ec681f3Smrg} 44387ec681f3Smrg 44397ec681f3Smrgstatic bool 44407ec681f3Smrgemit_cbvs(struct ntd_context *ctx) 44417ec681f3Smrg{ 44427ec681f3Smrg if (ctx->shader->info.stage == MESA_SHADER_KERNEL || ctx->opts->vulkan_environment) { 44437ec681f3Smrg nir_foreach_variable_with_modes(var, ctx->shader, nir_var_mem_ubo) { 44447ec681f3Smrg if (!emit_ubo_var(ctx, var)) 44457ec681f3Smrg return false; 44467ec681f3Smrg } 44477ec681f3Smrg } else { 44487ec681f3Smrg for (int i = ctx->opts->ubo_binding_offset; i < ctx->shader->info.num_ubos; ++i) { 44497ec681f3Smrg char name[64]; 44507ec681f3Smrg snprintf(name, sizeof(name), "__ubo%d", i); 44517ec681f3Smrg if (!emit_cbv(ctx, i, 0, 16384 /*4096 vec4's*/, 1, name)) 44527ec681f3Smrg return false; 44537ec681f3Smrg } 44547ec681f3Smrg } 44557ec681f3Smrg 44567ec681f3Smrg return true; 44577ec681f3Smrg} 44587ec681f3Smrg 44597ec681f3Smrgstatic bool 44607ec681f3Smrgemit_scratch(struct ntd_context *ctx) 44617ec681f3Smrg{ 44627ec681f3Smrg if (ctx->shader->scratch_size) { 44637ec681f3Smrg /* 44647ec681f3Smrg * We always allocate an u32 array, no matter the actual variable types. 44657ec681f3Smrg * According to the DXIL spec, the minimum load/store granularity is 44667ec681f3Smrg * 32-bit, anything smaller requires using a read-extract/read-write-modify 44677ec681f3Smrg * approach. 44687ec681f3Smrg */ 44697ec681f3Smrg unsigned size = ALIGN_POT(ctx->shader->scratch_size, sizeof(uint32_t)); 44707ec681f3Smrg const struct dxil_type *int32 = dxil_module_get_int_type(&ctx->mod, 32); 44717ec681f3Smrg const struct dxil_value *array_length = dxil_module_get_int32_const(&ctx->mod, size / sizeof(uint32_t)); 44727ec681f3Smrg if (!int32 || !array_length) 44737ec681f3Smrg return false; 44747ec681f3Smrg 44757ec681f3Smrg const struct dxil_type *type = dxil_module_get_array_type( 44767ec681f3Smrg &ctx->mod, int32, size / sizeof(uint32_t)); 44777ec681f3Smrg if (!type) 44787ec681f3Smrg return false; 44797ec681f3Smrg 44807ec681f3Smrg ctx->scratchvars = dxil_emit_alloca(&ctx->mod, type, int32, array_length, 4); 44817ec681f3Smrg if (!ctx->scratchvars) 44827ec681f3Smrg return false; 44837ec681f3Smrg } 44847ec681f3Smrg 44857ec681f3Smrg return true; 44867ec681f3Smrg} 44877ec681f3Smrg 44887ec681f3Smrg/* The validator complains if we don't have ops that reference a global variable. */ 44897ec681f3Smrgstatic bool 44907ec681f3Smrgshader_has_shared_ops(struct nir_shader *s) 44917ec681f3Smrg{ 44927ec681f3Smrg nir_foreach_function(func, s) { 44937ec681f3Smrg if (!func->impl) 44947ec681f3Smrg continue; 44957ec681f3Smrg nir_foreach_block(block, func->impl) { 44967ec681f3Smrg nir_foreach_instr(instr, block) { 44977ec681f3Smrg if (instr->type != nir_instr_type_intrinsic) 44987ec681f3Smrg continue; 44997ec681f3Smrg nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr); 45007ec681f3Smrg switch (intrin->intrinsic) { 45017ec681f3Smrg case nir_intrinsic_load_shared_dxil: 45027ec681f3Smrg case nir_intrinsic_store_shared_dxil: 45037ec681f3Smrg case nir_intrinsic_shared_atomic_add_dxil: 45047ec681f3Smrg case nir_intrinsic_shared_atomic_and_dxil: 45057ec681f3Smrg case nir_intrinsic_shared_atomic_comp_swap_dxil: 45067ec681f3Smrg case nir_intrinsic_shared_atomic_exchange_dxil: 45077ec681f3Smrg case nir_intrinsic_shared_atomic_imax_dxil: 45087ec681f3Smrg case nir_intrinsic_shared_atomic_imin_dxil: 45097ec681f3Smrg case nir_intrinsic_shared_atomic_or_dxil: 45107ec681f3Smrg case nir_intrinsic_shared_atomic_umax_dxil: 45117ec681f3Smrg case nir_intrinsic_shared_atomic_umin_dxil: 45127ec681f3Smrg case nir_intrinsic_shared_atomic_xor_dxil: 45137ec681f3Smrg return true; 45147ec681f3Smrg default: break; 45157ec681f3Smrg } 45167ec681f3Smrg } 45177ec681f3Smrg } 45187ec681f3Smrg } 45197ec681f3Smrg return false; 45207ec681f3Smrg} 45217ec681f3Smrg 45227ec681f3Smrgstatic bool 45237ec681f3Smrgemit_module(struct ntd_context *ctx, const struct nir_to_dxil_options *opts) 45247ec681f3Smrg{ 45257ec681f3Smrg /* The validator forces us to emit resources in a specific order: 45267ec681f3Smrg * CBVs, Samplers, SRVs, UAVs. While we are at it also remove 45277ec681f3Smrg * stale struct uniforms, they are lowered but might not have been removed */ 45287ec681f3Smrg sort_uniforms_by_binding_and_remove_structs(ctx->shader); 45297ec681f3Smrg 45307ec681f3Smrg /* CBVs */ 45317ec681f3Smrg if (!emit_cbvs(ctx)) 45327ec681f3Smrg return false; 45337ec681f3Smrg 45347ec681f3Smrg /* Samplers */ 45357ec681f3Smrg nir_foreach_variable_with_modes(var, ctx->shader, nir_var_uniform) { 45367ec681f3Smrg unsigned count = glsl_type_get_sampler_count(var->type); 45377ec681f3Smrg const struct glsl_type *without_array = glsl_without_array(var->type); 45387ec681f3Smrg if (var->data.mode == nir_var_uniform && glsl_type_is_sampler(without_array) && 45397ec681f3Smrg glsl_get_sampler_result_type(without_array) == GLSL_TYPE_VOID) { 45407ec681f3Smrg if (!emit_sampler(ctx, var, count)) 45417ec681f3Smrg return false; 45427ec681f3Smrg } 45437ec681f3Smrg } 45447ec681f3Smrg 45457ec681f3Smrg /* SRVs */ 45467ec681f3Smrg nir_foreach_variable_with_modes(var, ctx->shader, nir_var_uniform) { 45477ec681f3Smrg unsigned count = glsl_type_get_sampler_count(var->type); 45487ec681f3Smrg const struct glsl_type *without_array = glsl_without_array(var->type); 45497ec681f3Smrg if (var->data.mode == nir_var_uniform && glsl_type_is_sampler(without_array) && 45507ec681f3Smrg glsl_get_sampler_result_type(without_array) != GLSL_TYPE_VOID) { 45517ec681f3Smrg if (!emit_srv(ctx, var, count)) 45527ec681f3Smrg return false; 45537ec681f3Smrg } 45547ec681f3Smrg } 45557ec681f3Smrg /* Handle read-only SSBOs as SRVs */ 45567ec681f3Smrg nir_foreach_variable_with_modes(var, ctx->shader, nir_var_mem_ssbo) { 45577ec681f3Smrg if ((var->data.access & ACCESS_NON_WRITEABLE) != 0) { 45587ec681f3Smrg unsigned count = 1; 45597ec681f3Smrg if (glsl_type_is_array(var->type)) 45607ec681f3Smrg count = glsl_get_length(var->type); 45617ec681f3Smrg if (!emit_srv(ctx, var, count)) 45627ec681f3Smrg return false; 45637ec681f3Smrg } 45647ec681f3Smrg } 45657ec681f3Smrg 45667ec681f3Smrg if (ctx->shader->info.shared_size && shader_has_shared_ops(ctx->shader)) { 45677ec681f3Smrg const struct dxil_type *type; 45687ec681f3Smrg unsigned size; 45697ec681f3Smrg 45707ec681f3Smrg /* 45717ec681f3Smrg * We always allocate an u32 array, no matter the actual variable types. 45727ec681f3Smrg * According to the DXIL spec, the minimum load/store granularity is 45737ec681f3Smrg * 32-bit, anything smaller requires using a read-extract/read-write-modify 45747ec681f3Smrg * approach. Non-atomic 64-bit accesses are allowed, but the 45757ec681f3Smrg * GEP(cast(gvar, u64[] *), offset) and cast(GEP(gvar, offset), u64 *)) 45767ec681f3Smrg * sequences don't seem to be accepted by the DXIL validator when the 45777ec681f3Smrg * pointer is in the groupshared address space, making the 32-bit -> 64-bit 45787ec681f3Smrg * pointer cast impossible. 45797ec681f3Smrg */ 45807ec681f3Smrg size = ALIGN_POT(ctx->shader->info.shared_size, sizeof(uint32_t)); 45817ec681f3Smrg type = dxil_module_get_array_type(&ctx->mod, 45827ec681f3Smrg dxil_module_get_int_type(&ctx->mod, 32), 45837ec681f3Smrg size / sizeof(uint32_t)); 45847ec681f3Smrg ctx->sharedvars = dxil_add_global_ptr_var(&ctx->mod, "shared", type, 45857ec681f3Smrg DXIL_AS_GROUPSHARED, 45867ec681f3Smrg ffs(sizeof(uint64_t)), 45877ec681f3Smrg NULL); 45887ec681f3Smrg } 45897ec681f3Smrg 45907ec681f3Smrg if (!emit_scratch(ctx)) 45917ec681f3Smrg return false; 45927ec681f3Smrg 45937ec681f3Smrg /* UAVs */ 45947ec681f3Smrg if (ctx->shader->info.stage == MESA_SHADER_KERNEL) { 45957ec681f3Smrg if (!emit_globals(ctx, opts->num_kernel_globals)) 45967ec681f3Smrg return false; 45977ec681f3Smrg 45987ec681f3Smrg ctx->consts = _mesa_pointer_hash_table_create(ctx->ralloc_ctx); 45997ec681f3Smrg if (!ctx->consts) 46007ec681f3Smrg return false; 46017ec681f3Smrg if (!emit_global_consts(ctx)) 46027ec681f3Smrg return false; 46037ec681f3Smrg } else { 46047ec681f3Smrg /* Handle read/write SSBOs as UAVs */ 46057ec681f3Smrg nir_foreach_variable_with_modes(var, ctx->shader, nir_var_mem_ssbo) { 46067ec681f3Smrg if ((var->data.access & ACCESS_NON_WRITEABLE) == 0) { 46077ec681f3Smrg unsigned count = 1; 46087ec681f3Smrg if (glsl_type_is_array(var->type)) 46097ec681f3Smrg count = glsl_get_length(var->type); 46107ec681f3Smrg if (!emit_uav(ctx, var->data.binding, var->data.descriptor_set, 46117ec681f3Smrg count, DXIL_COMP_TYPE_INVALID, 46127ec681f3Smrg DXIL_RESOURCE_KIND_RAW_BUFFER, var->name)) 46137ec681f3Smrg return false; 46147ec681f3Smrg 46157ec681f3Smrg } 46167ec681f3Smrg } 46177ec681f3Smrg } 46187ec681f3Smrg 46197ec681f3Smrg nir_foreach_variable_with_modes(var, ctx->shader, nir_var_uniform) { 46207ec681f3Smrg if (var->data.mode == nir_var_uniform && glsl_type_is_image(glsl_without_array(var->type))) { 46217ec681f3Smrg if (!emit_uav_var(ctx, var, glsl_type_get_image_count(var->type))) 46227ec681f3Smrg return false; 46237ec681f3Smrg } 46247ec681f3Smrg } 46257ec681f3Smrg 46267ec681f3Smrg nir_function_impl *entry = nir_shader_get_entrypoint(ctx->shader); 46277ec681f3Smrg nir_metadata_require(entry, nir_metadata_block_index); 46287ec681f3Smrg 46297ec681f3Smrg assert(entry->num_blocks > 0); 46307ec681f3Smrg ctx->mod.basic_block_ids = rzalloc_array(ctx->ralloc_ctx, int, 46317ec681f3Smrg entry->num_blocks); 46327ec681f3Smrg if (!ctx->mod.basic_block_ids) 46337ec681f3Smrg return false; 46347ec681f3Smrg 46357ec681f3Smrg for (int i = 0; i < entry->num_blocks; ++i) 46367ec681f3Smrg ctx->mod.basic_block_ids[i] = -1; 46377ec681f3Smrg ctx->mod.num_basic_block_ids = entry->num_blocks; 46387ec681f3Smrg 46397ec681f3Smrg ctx->defs = rzalloc_array(ctx->ralloc_ctx, struct dxil_def, 46407ec681f3Smrg entry->ssa_alloc); 46417ec681f3Smrg if (!ctx->defs) 46427ec681f3Smrg return false; 46437ec681f3Smrg ctx->num_defs = entry->ssa_alloc; 46447ec681f3Smrg 46457ec681f3Smrg ctx->phis = _mesa_pointer_hash_table_create(ctx->ralloc_ctx); 46467ec681f3Smrg if (!ctx->phis) 46477ec681f3Smrg return false; 46487ec681f3Smrg 46497ec681f3Smrg prepare_phi_values(ctx); 46507ec681f3Smrg 46517ec681f3Smrg if (!emit_cf_list(ctx, &entry->body)) 46527ec681f3Smrg return false; 46537ec681f3Smrg 46547ec681f3Smrg hash_table_foreach(ctx->phis, entry) { 46557ec681f3Smrg fixup_phi(ctx, (nir_phi_instr *)entry->key, 46567ec681f3Smrg (struct phi_block *)entry->data); 46577ec681f3Smrg } 46587ec681f3Smrg 46597ec681f3Smrg if (!dxil_emit_ret_void(&ctx->mod)) 46607ec681f3Smrg return false; 46617ec681f3Smrg 46627ec681f3Smrg if (ctx->shader->info.stage == MESA_SHADER_FRAGMENT) { 46637ec681f3Smrg nir_foreach_variable_with_modes(var, ctx->shader, nir_var_shader_out) { 46647ec681f3Smrg if (var->data.location == FRAG_RESULT_STENCIL) { 46657ec681f3Smrg ctx->mod.feats.stencil_ref = true; 46667ec681f3Smrg } 46677ec681f3Smrg } 46687ec681f3Smrg } 46697ec681f3Smrg 46707ec681f3Smrg if (ctx->mod.feats.native_low_precision) 46717ec681f3Smrg ctx->mod.minor_version = MAX2(ctx->mod.minor_version, 2); 46727ec681f3Smrg 46737ec681f3Smrg return emit_metadata(ctx) && 46747ec681f3Smrg dxil_emit_module(&ctx->mod); 46757ec681f3Smrg} 46767ec681f3Smrg 46777ec681f3Smrgstatic unsigned int 46787ec681f3Smrgget_dxil_shader_kind(struct nir_shader *s) 46797ec681f3Smrg{ 46807ec681f3Smrg switch (s->info.stage) { 46817ec681f3Smrg case MESA_SHADER_VERTEX: 46827ec681f3Smrg return DXIL_VERTEX_SHADER; 46837ec681f3Smrg case MESA_SHADER_GEOMETRY: 46847ec681f3Smrg return DXIL_GEOMETRY_SHADER; 46857ec681f3Smrg case MESA_SHADER_FRAGMENT: 46867ec681f3Smrg return DXIL_PIXEL_SHADER; 46877ec681f3Smrg case MESA_SHADER_KERNEL: 46887ec681f3Smrg case MESA_SHADER_COMPUTE: 46897ec681f3Smrg return DXIL_COMPUTE_SHADER; 46907ec681f3Smrg default: 46917ec681f3Smrg unreachable("unknown shader stage in nir_to_dxil"); 46927ec681f3Smrg return DXIL_COMPUTE_SHADER; 46937ec681f3Smrg } 46947ec681f3Smrg} 46957ec681f3Smrg 46967ec681f3Smrgstatic unsigned 46977ec681f3Smrglower_bit_size_callback(const nir_instr* instr, void *data) 46987ec681f3Smrg{ 46997ec681f3Smrg if (instr->type != nir_instr_type_alu) 47007ec681f3Smrg return 0; 47017ec681f3Smrg const nir_alu_instr *alu = nir_instr_as_alu(instr); 47027ec681f3Smrg 47037ec681f3Smrg if (nir_op_infos[alu->op].is_conversion) 47047ec681f3Smrg return 0; 47057ec681f3Smrg 47067ec681f3Smrg unsigned num_inputs = nir_op_infos[alu->op].num_inputs; 47077ec681f3Smrg const struct nir_to_dxil_options *opts = (const struct nir_to_dxil_options*)data; 47087ec681f3Smrg unsigned min_bit_size = opts->lower_int16 ? 32 : 16; 47097ec681f3Smrg 47107ec681f3Smrg unsigned ret = 0; 47117ec681f3Smrg for (unsigned i = 0; i < num_inputs; i++) { 47127ec681f3Smrg unsigned bit_size = nir_src_bit_size(alu->src[i].src); 47137ec681f3Smrg if (bit_size != 1 && bit_size < min_bit_size) 47147ec681f3Smrg ret = min_bit_size; 47157ec681f3Smrg } 47167ec681f3Smrg 47177ec681f3Smrg return ret; 47187ec681f3Smrg} 47197ec681f3Smrg 47207ec681f3Smrgstatic void 47217ec681f3Smrgoptimize_nir(struct nir_shader *s, const struct nir_to_dxil_options *opts) 47227ec681f3Smrg{ 47237ec681f3Smrg bool progress; 47247ec681f3Smrg do { 47257ec681f3Smrg progress = false; 47267ec681f3Smrg NIR_PASS_V(s, nir_lower_vars_to_ssa); 47277ec681f3Smrg NIR_PASS(progress, s, nir_lower_indirect_derefs, nir_var_function_temp, UINT32_MAX); 47287ec681f3Smrg NIR_PASS(progress, s, nir_lower_alu_to_scalar, NULL, NULL); 47297ec681f3Smrg NIR_PASS(progress, s, nir_copy_prop); 47307ec681f3Smrg NIR_PASS(progress, s, nir_opt_copy_prop_vars); 47317ec681f3Smrg NIR_PASS(progress, s, nir_lower_bit_size, lower_bit_size_callback, (void*)opts); 47327ec681f3Smrg NIR_PASS(progress, s, dxil_nir_lower_8bit_conv); 47337ec681f3Smrg if (opts->lower_int16) 47347ec681f3Smrg NIR_PASS(progress, s, dxil_nir_lower_16bit_conv); 47357ec681f3Smrg NIR_PASS(progress, s, nir_opt_remove_phis); 47367ec681f3Smrg NIR_PASS(progress, s, nir_opt_dce); 47377ec681f3Smrg NIR_PASS(progress, s, nir_opt_if, true); 47387ec681f3Smrg NIR_PASS(progress, s, nir_opt_dead_cf); 47397ec681f3Smrg NIR_PASS(progress, s, nir_opt_cse); 47407ec681f3Smrg NIR_PASS(progress, s, nir_opt_peephole_select, 8, true, true); 47417ec681f3Smrg NIR_PASS(progress, s, nir_opt_algebraic); 47427ec681f3Smrg NIR_PASS(progress, s, dxil_nir_lower_x2b); 47437ec681f3Smrg if (s->options->lower_int64_options) 47447ec681f3Smrg NIR_PASS(progress, s, nir_lower_int64); 47457ec681f3Smrg NIR_PASS(progress, s, nir_lower_alu); 47467ec681f3Smrg NIR_PASS(progress, s, dxil_nir_lower_inot); 47477ec681f3Smrg NIR_PASS(progress, s, nir_opt_constant_folding); 47487ec681f3Smrg NIR_PASS(progress, s, nir_opt_undef); 47497ec681f3Smrg NIR_PASS(progress, s, nir_lower_undef_to_zero); 47507ec681f3Smrg NIR_PASS(progress, s, nir_opt_deref); 47517ec681f3Smrg NIR_PASS(progress, s, dxil_nir_lower_upcast_phis, opts->lower_int16 ? 32 : 16); 47527ec681f3Smrg NIR_PASS(progress, s, nir_lower_64bit_phis); 47537ec681f3Smrg NIR_PASS_V(s, nir_lower_system_values); 47547ec681f3Smrg } while (progress); 47557ec681f3Smrg 47567ec681f3Smrg do { 47577ec681f3Smrg progress = false; 47587ec681f3Smrg NIR_PASS(progress, s, nir_opt_algebraic_late); 47597ec681f3Smrg } while (progress); 47607ec681f3Smrg} 47617ec681f3Smrg 47627ec681f3Smrgstatic 47637ec681f3Smrgvoid dxil_fill_validation_state(struct ntd_context *ctx, 47647ec681f3Smrg struct dxil_validation_state *state) 47657ec681f3Smrg{ 47667ec681f3Smrg state->num_resources = util_dynarray_num_elements(&ctx->resources, struct dxil_resource); 47677ec681f3Smrg state->resources = (struct dxil_resource*)ctx->resources.data; 47687ec681f3Smrg state->state.psv0.max_expected_wave_lane_count = UINT_MAX; 47697ec681f3Smrg state->state.shader_stage = (uint8_t)ctx->mod.shader_kind; 47707ec681f3Smrg state->state.sig_input_elements = (uint8_t)ctx->mod.num_sig_inputs; 47717ec681f3Smrg state->state.sig_output_elements = (uint8_t)ctx->mod.num_sig_outputs; 47727ec681f3Smrg //state->state.sig_patch_const_or_prim_elements = 0; 47737ec681f3Smrg 47747ec681f3Smrg switch (ctx->mod.shader_kind) { 47757ec681f3Smrg case DXIL_VERTEX_SHADER: 47767ec681f3Smrg state->state.psv0.vs.output_position_present = ctx->mod.info.has_out_position; 47777ec681f3Smrg break; 47787ec681f3Smrg case DXIL_PIXEL_SHADER: 47797ec681f3Smrg /* TODO: handle depth outputs */ 47807ec681f3Smrg state->state.psv0.ps.depth_output = ctx->mod.info.has_out_depth; 47817ec681f3Smrg state->state.psv0.ps.sample_frequency = 47827ec681f3Smrg ctx->mod.info.has_per_sample_input; 47837ec681f3Smrg break; 47847ec681f3Smrg case DXIL_COMPUTE_SHADER: 47857ec681f3Smrg break; 47867ec681f3Smrg case DXIL_GEOMETRY_SHADER: 47877ec681f3Smrg state->state.max_vertex_count = ctx->shader->info.gs.vertices_out; 47887ec681f3Smrg state->state.psv0.gs.input_primitive = dxil_get_input_primitive(ctx->shader->info.gs.input_primitive); 47897ec681f3Smrg state->state.psv0.gs.output_toplology = dxil_get_primitive_topology(ctx->shader->info.gs.output_primitive); 47907ec681f3Smrg state->state.psv0.gs.output_stream_mask = ctx->shader->info.gs.active_stream_mask; 47917ec681f3Smrg state->state.psv0.gs.output_position_present = ctx->mod.info.has_out_position; 47927ec681f3Smrg break; 47937ec681f3Smrg default: 47947ec681f3Smrg assert(0 && "Shader type not (yet) supported"); 47957ec681f3Smrg } 47967ec681f3Smrg} 47977ec681f3Smrg 47987ec681f3Smrgstatic nir_variable * 47997ec681f3Smrgadd_sysvalue(struct ntd_context *ctx, 48007ec681f3Smrg uint8_t value, char *name, 48017ec681f3Smrg int driver_location) 48027ec681f3Smrg{ 48037ec681f3Smrg 48047ec681f3Smrg nir_variable *var = rzalloc(ctx->shader, nir_variable); 48057ec681f3Smrg if (!var) 48067ec681f3Smrg return NULL; 48077ec681f3Smrg var->data.driver_location = driver_location; 48087ec681f3Smrg var->data.location = value; 48097ec681f3Smrg var->type = glsl_uint_type(); 48107ec681f3Smrg var->name = name; 48117ec681f3Smrg var->data.mode = nir_var_system_value; 48127ec681f3Smrg var->data.interpolation = INTERP_MODE_FLAT; 48137ec681f3Smrg return var; 48147ec681f3Smrg} 48157ec681f3Smrg 48167ec681f3Smrgstatic bool 48177ec681f3Smrgappend_input_or_sysvalue(struct ntd_context *ctx, 48187ec681f3Smrg int input_loc, int sv_slot, 48197ec681f3Smrg char *name, int driver_location) 48207ec681f3Smrg{ 48217ec681f3Smrg if (input_loc >= 0) { 48227ec681f3Smrg /* Check inputs whether a variable is available the corresponds 48237ec681f3Smrg * to the sysvalue */ 48247ec681f3Smrg nir_foreach_variable_with_modes(var, ctx->shader, nir_var_shader_in) { 48257ec681f3Smrg if (var->data.location == input_loc) { 48267ec681f3Smrg ctx->system_value[sv_slot] = var; 48277ec681f3Smrg return true; 48287ec681f3Smrg } 48297ec681f3Smrg } 48307ec681f3Smrg } 48317ec681f3Smrg 48327ec681f3Smrg ctx->system_value[sv_slot] = add_sysvalue(ctx, sv_slot, name, driver_location); 48337ec681f3Smrg if (!ctx->system_value[sv_slot]) 48347ec681f3Smrg return false; 48357ec681f3Smrg 48367ec681f3Smrg nir_shader_add_variable(ctx->shader, ctx->system_value[sv_slot]); 48377ec681f3Smrg return true; 48387ec681f3Smrg} 48397ec681f3Smrg 48407ec681f3Smrgstruct sysvalue_name { 48417ec681f3Smrg gl_system_value value; 48427ec681f3Smrg int slot; 48437ec681f3Smrg char *name; 48447ec681f3Smrg} possible_sysvalues[] = { 48457ec681f3Smrg {SYSTEM_VALUE_VERTEX_ID_ZERO_BASE, -1, "SV_VertexID"}, 48467ec681f3Smrg {SYSTEM_VALUE_INSTANCE_ID, -1, "SV_InstanceID"}, 48477ec681f3Smrg {SYSTEM_VALUE_FRONT_FACE, VARYING_SLOT_FACE, "SV_IsFrontFace"}, 48487ec681f3Smrg {SYSTEM_VALUE_PRIMITIVE_ID, VARYING_SLOT_PRIMITIVE_ID, "SV_PrimitiveID"}, 48497ec681f3Smrg {SYSTEM_VALUE_SAMPLE_ID, -1, "SV_SampleIndex"}, 48507ec681f3Smrg}; 48517ec681f3Smrg 48527ec681f3Smrgstatic bool 48537ec681f3Smrgallocate_sysvalues(struct ntd_context *ctx) 48547ec681f3Smrg{ 48557ec681f3Smrg unsigned driver_location = 0; 48567ec681f3Smrg nir_foreach_variable_with_modes(var, ctx->shader, nir_var_shader_in) 48577ec681f3Smrg driver_location++; 48587ec681f3Smrg nir_foreach_variable_with_modes(var, ctx->shader, nir_var_system_value) 48597ec681f3Smrg driver_location++; 48607ec681f3Smrg 48617ec681f3Smrg for (unsigned i = 0; i < ARRAY_SIZE(possible_sysvalues); ++i) { 48627ec681f3Smrg struct sysvalue_name *info = &possible_sysvalues[i]; 48637ec681f3Smrg if (BITSET_TEST(ctx->shader->info.system_values_read, info->value)) { 48647ec681f3Smrg if (!append_input_or_sysvalue(ctx, info->slot, 48657ec681f3Smrg info->value, info->name, 48667ec681f3Smrg driver_location++)) 48677ec681f3Smrg return false; 48687ec681f3Smrg } 48697ec681f3Smrg } 48707ec681f3Smrg return true; 48717ec681f3Smrg} 48727ec681f3Smrg 48737ec681f3Smrgbool 48747ec681f3Smrgnir_to_dxil(struct nir_shader *s, const struct nir_to_dxil_options *opts, 48757ec681f3Smrg struct blob *blob) 48767ec681f3Smrg{ 48777ec681f3Smrg assert(opts); 48787ec681f3Smrg bool retval = true; 48797ec681f3Smrg debug_dxil = (int)debug_get_option_debug_dxil(); 48807ec681f3Smrg blob_init(blob); 48817ec681f3Smrg 48827ec681f3Smrg struct ntd_context *ctx = calloc(1, sizeof(*ctx)); 48837ec681f3Smrg if (!ctx) 48847ec681f3Smrg return false; 48857ec681f3Smrg 48867ec681f3Smrg ctx->opts = opts; 48877ec681f3Smrg ctx->shader = s; 48887ec681f3Smrg 48897ec681f3Smrg ctx->ralloc_ctx = ralloc_context(NULL); 48907ec681f3Smrg if (!ctx->ralloc_ctx) { 48917ec681f3Smrg retval = false; 48927ec681f3Smrg goto out; 48937ec681f3Smrg } 48947ec681f3Smrg 48957ec681f3Smrg util_dynarray_init(&ctx->srv_metadata_nodes, ctx->ralloc_ctx); 48967ec681f3Smrg util_dynarray_init(&ctx->uav_metadata_nodes, ctx->ralloc_ctx); 48977ec681f3Smrg util_dynarray_init(&ctx->cbv_metadata_nodes, ctx->ralloc_ctx); 48987ec681f3Smrg util_dynarray_init(&ctx->sampler_metadata_nodes, ctx->ralloc_ctx); 48997ec681f3Smrg util_dynarray_init(&ctx->resources, ctx->ralloc_ctx); 49007ec681f3Smrg dxil_module_init(&ctx->mod, ctx->ralloc_ctx); 49017ec681f3Smrg ctx->mod.shader_kind = get_dxil_shader_kind(s); 49027ec681f3Smrg ctx->mod.major_version = 6; 49037ec681f3Smrg ctx->mod.minor_version = 1; 49047ec681f3Smrg 49057ec681f3Smrg NIR_PASS_V(s, nir_lower_pack); 49067ec681f3Smrg NIR_PASS_V(s, nir_lower_frexp); 49077ec681f3Smrg NIR_PASS_V(s, nir_lower_flrp, 16 | 32 | 64, true); 49087ec681f3Smrg 49097ec681f3Smrg optimize_nir(s, opts); 49107ec681f3Smrg 49117ec681f3Smrg NIR_PASS_V(s, nir_remove_dead_variables, 49127ec681f3Smrg nir_var_function_temp | nir_var_shader_temp, NULL); 49137ec681f3Smrg 49147ec681f3Smrg if (!allocate_sysvalues(ctx)) 49157ec681f3Smrg return false; 49167ec681f3Smrg 49177ec681f3Smrg if (debug_dxil & DXIL_DEBUG_VERBOSE) 49187ec681f3Smrg nir_print_shader(s, stderr); 49197ec681f3Smrg 49207ec681f3Smrg if (!emit_module(ctx, opts)) { 49217ec681f3Smrg debug_printf("D3D12: dxil_container_add_module failed\n"); 49227ec681f3Smrg retval = false; 49237ec681f3Smrg goto out; 49247ec681f3Smrg } 49257ec681f3Smrg 49267ec681f3Smrg if (debug_dxil & DXIL_DEBUG_DUMP_MODULE) { 49277ec681f3Smrg struct dxil_dumper *dumper = dxil_dump_create(); 49287ec681f3Smrg dxil_dump_module(dumper, &ctx->mod); 49297ec681f3Smrg fprintf(stderr, "\n"); 49307ec681f3Smrg dxil_dump_buf_to_file(dumper, stderr); 49317ec681f3Smrg fprintf(stderr, "\n\n"); 49327ec681f3Smrg dxil_dump_free(dumper); 49337ec681f3Smrg } 49347ec681f3Smrg 49357ec681f3Smrg struct dxil_container container; 49367ec681f3Smrg dxil_container_init(&container); 49377ec681f3Smrg if (!dxil_container_add_features(&container, &ctx->mod.feats)) { 49387ec681f3Smrg debug_printf("D3D12: dxil_container_add_features failed\n"); 49397ec681f3Smrg retval = false; 49407ec681f3Smrg goto out; 49417ec681f3Smrg } 49427ec681f3Smrg 49437ec681f3Smrg if (!dxil_container_add_io_signature(&container, 49447ec681f3Smrg DXIL_ISG1, 49457ec681f3Smrg ctx->mod.num_sig_inputs, 49467ec681f3Smrg ctx->mod.inputs)) { 49477ec681f3Smrg debug_printf("D3D12: failed to write input signature\n"); 49487ec681f3Smrg retval = false; 49497ec681f3Smrg goto out; 49507ec681f3Smrg } 49517ec681f3Smrg 49527ec681f3Smrg if (!dxil_container_add_io_signature(&container, 49537ec681f3Smrg DXIL_OSG1, 49547ec681f3Smrg ctx->mod.num_sig_outputs, 49557ec681f3Smrg ctx->mod.outputs)) { 49567ec681f3Smrg debug_printf("D3D12: failed to write output signature\n"); 49577ec681f3Smrg retval = false; 49587ec681f3Smrg goto out; 49597ec681f3Smrg } 49607ec681f3Smrg 49617ec681f3Smrg struct dxil_validation_state validation_state; 49627ec681f3Smrg memset(&validation_state, 0, sizeof(validation_state)); 49637ec681f3Smrg dxil_fill_validation_state(ctx, &validation_state); 49647ec681f3Smrg 49657ec681f3Smrg if (!dxil_container_add_state_validation(&container,&ctx->mod, 49667ec681f3Smrg &validation_state)) { 49677ec681f3Smrg debug_printf("D3D12: failed to write state-validation\n"); 49687ec681f3Smrg retval = false; 49697ec681f3Smrg goto out; 49707ec681f3Smrg } 49717ec681f3Smrg 49727ec681f3Smrg if (!dxil_container_add_module(&container, &ctx->mod)) { 49737ec681f3Smrg debug_printf("D3D12: failed to write module\n"); 49747ec681f3Smrg retval = false; 49757ec681f3Smrg goto out; 49767ec681f3Smrg } 49777ec681f3Smrg 49787ec681f3Smrg if (!dxil_container_write(&container, blob)) { 49797ec681f3Smrg debug_printf("D3D12: dxil_container_write failed\n"); 49807ec681f3Smrg retval = false; 49817ec681f3Smrg goto out; 49827ec681f3Smrg } 49837ec681f3Smrg dxil_container_finish(&container); 49847ec681f3Smrg 49857ec681f3Smrg if (debug_dxil & DXIL_DEBUG_DUMP_BLOB) { 49867ec681f3Smrg static int shader_id = 0; 49877ec681f3Smrg char buffer[64]; 49887ec681f3Smrg snprintf(buffer, sizeof(buffer), "shader_%s_%d.blob", 49897ec681f3Smrg get_shader_kind_str(ctx->mod.shader_kind), shader_id++); 49907ec681f3Smrg debug_printf("Try to write blob to %s\n", buffer); 49917ec681f3Smrg FILE *f = fopen(buffer, "wb"); 49927ec681f3Smrg if (f) { 49937ec681f3Smrg fwrite(blob->data, 1, blob->size, f); 49947ec681f3Smrg fclose(f); 49957ec681f3Smrg } 49967ec681f3Smrg } 49977ec681f3Smrg 49987ec681f3Smrgout: 49997ec681f3Smrg dxil_module_release(&ctx->mod); 50007ec681f3Smrg ralloc_free(ctx->ralloc_ctx); 50017ec681f3Smrg free(ctx); 50027ec681f3Smrg return retval; 50037ec681f3Smrg} 50047ec681f3Smrg 50057ec681f3Smrgenum dxil_sysvalue_type 50067ec681f3Smrgnir_var_to_dxil_sysvalue_type(nir_variable *var, uint64_t other_stage_mask) 50077ec681f3Smrg{ 50087ec681f3Smrg switch (var->data.location) { 50097ec681f3Smrg case VARYING_SLOT_FACE: 50107ec681f3Smrg return DXIL_GENERATED_SYSVALUE; 50117ec681f3Smrg case VARYING_SLOT_POS: 50127ec681f3Smrg case VARYING_SLOT_PRIMITIVE_ID: 50137ec681f3Smrg case VARYING_SLOT_CLIP_DIST0: 50147ec681f3Smrg case VARYING_SLOT_CLIP_DIST1: 50157ec681f3Smrg case VARYING_SLOT_PSIZ: 50167ec681f3Smrg if (!((1ull << var->data.location) & other_stage_mask)) 50177ec681f3Smrg return DXIL_SYSVALUE; 50187ec681f3Smrg FALLTHROUGH; 50197ec681f3Smrg default: 50207ec681f3Smrg return DXIL_NO_SYSVALUE; 50217ec681f3Smrg } 50227ec681f3Smrg} 5023