/* * Copyright 2002-2003 Jason Edmeades * Copyright 2002-2003 Raphael Junqueira * Copyright 2004 Christian Costa * Copyright 2005 Oliver Stieber * Copyright 2006 Ivan Gyurdiev * Copyright 2007-2008, 2013 Stefan Dösinger for CodeWeavers * Copyright 2009-2011 Henri Verbeet for CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include "vkd3d_shader_private.h" #include #include static const char * const shader_opcode_names[] = { [VKD3DSIH_ABS ] = "abs", [VKD3DSIH_ACOS ] = "acos", [VKD3DSIH_ADD ] = "add", [VKD3DSIH_AND ] = "and", [VKD3DSIH_ASIN ] = "asin", [VKD3DSIH_ATAN ] = "atan", [VKD3DSIH_ATOMIC_AND ] = "atomic_and", [VKD3DSIH_ATOMIC_CMP_STORE ] = "atomic_cmp_store", [VKD3DSIH_ATOMIC_IADD ] = "atomic_iadd", [VKD3DSIH_ATOMIC_IMAX ] = "atomic_imax", [VKD3DSIH_ATOMIC_IMIN ] = "atomic_imin", [VKD3DSIH_ATOMIC_OR ] = "atomic_or", [VKD3DSIH_ATOMIC_UMAX ] = "atomic_umax", [VKD3DSIH_ATOMIC_UMIN ] = "atomic_umin", [VKD3DSIH_ATOMIC_XOR ] = "atomic_xor", [VKD3DSIH_BEM ] = "bem", [VKD3DSIH_BFI ] = "bfi", [VKD3DSIH_BFREV ] = "bfrev", [VKD3DSIH_BRANCH ] = "branch", [VKD3DSIH_BREAK ] = "break", [VKD3DSIH_BREAKC ] = "breakc", [VKD3DSIH_BREAKP ] = "breakp", [VKD3DSIH_BUFINFO ] = "bufinfo", [VKD3DSIH_CALL ] = "call", [VKD3DSIH_CALLNZ ] = "callnz", [VKD3DSIH_CASE ] = "case", [VKD3DSIH_CHECK_ACCESS_FULLY_MAPPED ] = "check_access_fully_mapped", [VKD3DSIH_CMP ] = "cmp", [VKD3DSIH_CND ] = "cnd", [VKD3DSIH_CONTINUE ] = "continue", [VKD3DSIH_CONTINUEP ] = "continuec", [VKD3DSIH_COUNTBITS ] = "countbits", [VKD3DSIH_CRS ] = "crs", [VKD3DSIH_CUT ] = "cut", [VKD3DSIH_CUT_STREAM ] = "cut_stream", [VKD3DSIH_DADD ] = "dadd", [VKD3DSIH_DCL ] = "dcl", [VKD3DSIH_DCL_CONSTANT_BUFFER ] = "dcl_constantBuffer", [VKD3DSIH_DCL_FUNCTION_BODY ] = "dcl_function_body", [VKD3DSIH_DCL_FUNCTION_TABLE ] = "dcl_function_table", [VKD3DSIH_DCL_GLOBAL_FLAGS ] = "dcl_globalFlags", [VKD3DSIH_DCL_GS_INSTANCES ] = "dcl_gs_instances", [VKD3DSIH_DCL_HS_FORK_PHASE_INSTANCE_COUNT] = "dcl_hs_fork_phase_instance_count", [VKD3DSIH_DCL_HS_JOIN_PHASE_INSTANCE_COUNT] = "dcl_hs_join_phase_instance_count", [VKD3DSIH_DCL_HS_MAX_TESSFACTOR ] = "dcl_hs_max_tessfactor", [VKD3DSIH_DCL_IMMEDIATE_CONSTANT_BUFFER ] = "dcl_immediateConstantBuffer", [VKD3DSIH_DCL_INDEX_RANGE ] = "dcl_index_range", [VKD3DSIH_DCL_INDEXABLE_TEMP ] = "dcl_indexableTemp", [VKD3DSIH_DCL_INPUT ] = "dcl_input", [VKD3DSIH_DCL_INPUT_CONTROL_POINT_COUNT ] = "dcl_input_control_point_count", [VKD3DSIH_DCL_INPUT_PRIMITIVE ] = "dcl_inputPrimitive", [VKD3DSIH_DCL_INPUT_PS ] = "dcl_input_ps", [VKD3DSIH_DCL_INPUT_PS_SGV ] = "dcl_input_ps_sgv", [VKD3DSIH_DCL_INPUT_PS_SIV ] = "dcl_input_ps_siv", [VKD3DSIH_DCL_INPUT_SGV ] = "dcl_input_sgv", [VKD3DSIH_DCL_INPUT_SIV ] = "dcl_input_siv", [VKD3DSIH_DCL_INTERFACE ] = "dcl_interface", [VKD3DSIH_DCL_OUTPUT ] = "dcl_output", [VKD3DSIH_DCL_OUTPUT_CONTROL_POINT_COUNT ] = "dcl_output_control_point_count", [VKD3DSIH_DCL_OUTPUT_SIV ] = "dcl_output_siv", [VKD3DSIH_DCL_OUTPUT_TOPOLOGY ] = "dcl_outputTopology", [VKD3DSIH_DCL_RESOURCE_RAW ] = "dcl_resource_raw", [VKD3DSIH_DCL_RESOURCE_STRUCTURED ] = "dcl_resource_structured", [VKD3DSIH_DCL_SAMPLER ] = "dcl_sampler", [VKD3DSIH_DCL_STREAM ] = "dcl_stream", [VKD3DSIH_DCL_TEMPS ] = "dcl_temps", [VKD3DSIH_DCL_TESSELLATOR_DOMAIN ] = "dcl_tessellator_domain", [VKD3DSIH_DCL_TESSELLATOR_OUTPUT_PRIMITIVE] = "dcl_tessellator_output_primitive", [VKD3DSIH_DCL_TESSELLATOR_PARTITIONING ] = "dcl_tessellator_partitioning", [VKD3DSIH_DCL_TGSM_RAW ] = "dcl_tgsm_raw", [VKD3DSIH_DCL_TGSM_STRUCTURED ] = "dcl_tgsm_structured", [VKD3DSIH_DCL_THREAD_GROUP ] = "dcl_thread_group", [VKD3DSIH_DCL_UAV_RAW ] = "dcl_uav_raw", [VKD3DSIH_DCL_UAV_STRUCTURED ] = "dcl_uav_structured", [VKD3DSIH_DCL_UAV_TYPED ] = "dcl_uav_typed", [VKD3DSIH_DCL_VERTICES_OUT ] = "dcl_maxOutputVertexCount", [VKD3DSIH_DDIV ] = "ddiv", [VKD3DSIH_DEF ] = "def", [VKD3DSIH_DEFAULT ] = "default", [VKD3DSIH_DEFB ] = "defb", [VKD3DSIH_DEFI ] = "defi", [VKD3DSIH_DEQO ] = "deq", [VKD3DSIH_DFMA ] = "dfma", [VKD3DSIH_DGEO ] = "dge", [VKD3DSIH_DISCARD ] = "discard", [VKD3DSIH_DIV ] = "div", [VKD3DSIH_DLT ] = "dlt", [VKD3DSIH_DMAX ] = "dmax", [VKD3DSIH_DMIN ] = "dmin", [VKD3DSIH_DMOV ] = "dmov", [VKD3DSIH_DMOVC ] = "dmovc", [VKD3DSIH_DMUL ] = "dmul", [VKD3DSIH_DNE ] = "dne", [VKD3DSIH_DP2 ] = "dp2", [VKD3DSIH_DP2ADD ] = "dp2add", [VKD3DSIH_DP3 ] = "dp3", [VKD3DSIH_DP4 ] = "dp4", [VKD3DSIH_DRCP ] = "drcp", [VKD3DSIH_DST ] = "dst", [VKD3DSIH_DSX ] = "dsx", [VKD3DSIH_DSX_COARSE ] = "deriv_rtx_coarse", [VKD3DSIH_DSX_FINE ] = "deriv_rtx_fine", [VKD3DSIH_DSY ] = "dsy", [VKD3DSIH_DSY_COARSE ] = "deriv_rty_coarse", [VKD3DSIH_DSY_FINE ] = "deriv_rty_fine", [VKD3DSIH_DTOF ] = "dtof", [VKD3DSIH_DTOI ] = "dtoi", [VKD3DSIH_DTOU ] = "dtou", [VKD3DSIH_ELSE ] = "else", [VKD3DSIH_EMIT ] = "emit", [VKD3DSIH_EMIT_STREAM ] = "emit_stream", [VKD3DSIH_ENDIF ] = "endif", [VKD3DSIH_ENDLOOP ] = "endloop", [VKD3DSIH_ENDREP ] = "endrep", [VKD3DSIH_ENDSWITCH ] = "endswitch", [VKD3DSIH_EQO ] = "eq", [VKD3DSIH_EQU ] = "eq_unord", [VKD3DSIH_EVAL_CENTROID ] = "eval_centroid", [VKD3DSIH_EVAL_SAMPLE_INDEX ] = "eval_sample_index", [VKD3DSIH_EXP ] = "exp", [VKD3DSIH_EXPP ] = "expp", [VKD3DSIH_F16TOF32 ] = "f16tof32", [VKD3DSIH_F32TOF16 ] = "f32tof16", [VKD3DSIH_FCALL ] = "fcall", [VKD3DSIH_FIRSTBIT_HI ] = "firstbit_hi", [VKD3DSIH_FIRSTBIT_LO ] = "firstbit_lo", [VKD3DSIH_FIRSTBIT_SHI ] = "firstbit_shi", [VKD3DSIH_FRC ] = "frc", [VKD3DSIH_FREM ] = "frem", [VKD3DSIH_FTOD ] = "ftod", [VKD3DSIH_FTOI ] = "ftoi", [VKD3DSIH_FTOU ] = "ftou", [VKD3DSIH_GATHER4 ] = "gather4", [VKD3DSIH_GATHER4_C ] = "gather4_c", [VKD3DSIH_GATHER4_C_S ] = "gather4_c_s", [VKD3DSIH_GATHER4_PO ] = "gather4_po", [VKD3DSIH_GATHER4_PO_C ] = "gather4_po_c", [VKD3DSIH_GATHER4_PO_C_S ] = "gather4_po_c_s", [VKD3DSIH_GATHER4_PO_S ] = "gather4_po_s", [VKD3DSIH_GATHER4_S ] = "gather4_s", [VKD3DSIH_GEO ] = "ge", [VKD3DSIH_GEU ] = "ge_unord", [VKD3DSIH_HCOS ] = "hcos", [VKD3DSIH_HS_CONTROL_POINT_PHASE ] = "hs_control_point_phase", [VKD3DSIH_HS_DECLS ] = "hs_decls", [VKD3DSIH_HS_FORK_PHASE ] = "hs_fork_phase", [VKD3DSIH_HS_JOIN_PHASE ] = "hs_join_phase", [VKD3DSIH_HSIN ] = "hsin", [VKD3DSIH_HTAN ] = "htan", [VKD3DSIH_IADD ] = "iadd", [VKD3DSIH_IBFE ] = "ibfe", [VKD3DSIH_IDIV ] = "idiv", [VKD3DSIH_IEQ ] = "ieq", [VKD3DSIH_IF ] = "if", [VKD3DSIH_IFC ] = "ifc", [VKD3DSIH_IGE ] = "ige", [VKD3DSIH_ILT ] = "ilt", [VKD3DSIH_IMAD ] = "imad", [VKD3DSIH_IMAX ] = "imax", [VKD3DSIH_IMIN ] = "imin", [VKD3DSIH_IMM_ATOMIC_ALLOC ] = "imm_atomic_alloc", [VKD3DSIH_IMM_ATOMIC_AND ] = "imm_atomic_and", [VKD3DSIH_IMM_ATOMIC_CMP_EXCH ] = "imm_atomic_cmp_exch", [VKD3DSIH_IMM_ATOMIC_CONSUME ] = "imm_atomic_consume", [VKD3DSIH_IMM_ATOMIC_EXCH ] = "imm_atomic_exch", [VKD3DSIH_IMM_ATOMIC_IADD ] = "imm_atomic_iadd", [VKD3DSIH_IMM_ATOMIC_IMAX ] = "imm_atomic_imax", [VKD3DSIH_IMM_ATOMIC_IMIN ] = "imm_atomic_imin", [VKD3DSIH_IMM_ATOMIC_OR ] = "imm_atomic_or", [VKD3DSIH_IMM_ATOMIC_UMAX ] = "imm_atomic_umax", [VKD3DSIH_IMM_ATOMIC_UMIN ] = "imm_atomic_umin", [VKD3DSIH_IMM_ATOMIC_XOR ] = "imm_atomic_xor", [VKD3DSIH_IMUL ] = "imul", [VKD3DSIH_INE ] = "ine", [VKD3DSIH_INEG ] = "ineg", [VKD3DSIH_ISFINITE ] = "isfinite", [VKD3DSIH_ISHL ] = "ishl", [VKD3DSIH_ISHR ] = "ishr", [VKD3DSIH_ISINF ] = "isinf", [VKD3DSIH_ISNAN ] = "isnan", [VKD3DSIH_ITOD ] = "itod", [VKD3DSIH_ITOF ] = "itof", [VKD3DSIH_ITOI ] = "itoi", [VKD3DSIH_LABEL ] = "label", [VKD3DSIH_LD ] = "ld", [VKD3DSIH_LD2DMS ] = "ld2dms", [VKD3DSIH_LD2DMS_S ] = "ld2dms_s", [VKD3DSIH_LD_RAW ] = "ld_raw", [VKD3DSIH_LD_RAW_S ] = "ld_raw_s", [VKD3DSIH_LD_S ] = "ld_s", [VKD3DSIH_LD_STRUCTURED ] = "ld_structured", [VKD3DSIH_LD_STRUCTURED_S ] = "ld_structured_s", [VKD3DSIH_LD_UAV_TYPED ] = "ld_uav_typed", [VKD3DSIH_LD_UAV_TYPED_S ] = "ld_uav_typed_s", [VKD3DSIH_LIT ] = "lit", [VKD3DSIH_LOD ] = "lod", [VKD3DSIH_LOG ] = "log", [VKD3DSIH_LOGP ] = "logp", [VKD3DSIH_LOOP ] = "loop", [VKD3DSIH_LRP ] = "lrp", [VKD3DSIH_LTO ] = "lt", [VKD3DSIH_LTU ] = "lt_unord", [VKD3DSIH_M3x2 ] = "m3x2", [VKD3DSIH_M3x3 ] = "m3x3", [VKD3DSIH_M3x4 ] = "m3x4", [VKD3DSIH_M4x3 ] = "m4x3", [VKD3DSIH_M4x4 ] = "m4x4", [VKD3DSIH_MAD ] = "mad", [VKD3DSIH_MAX ] = "max", [VKD3DSIH_MIN ] = "min", [VKD3DSIH_MOV ] = "mov", [VKD3DSIH_MOVA ] = "mova", [VKD3DSIH_MOVC ] = "movc", [VKD3DSIH_MSAD ] = "msad", [VKD3DSIH_MUL ] = "mul", [VKD3DSIH_NEO ] = "ne_ord", [VKD3DSIH_NEU ] = "ne", [VKD3DSIH_NOP ] = "nop", [VKD3DSIH_NOT ] = "not", [VKD3DSIH_NRM ] = "nrm", [VKD3DSIH_OR ] = "or", [VKD3DSIH_ORD ] = "ord", [VKD3DSIH_PHASE ] = "phase", [VKD3DSIH_PHI ] = "phi", [VKD3DSIH_POW ] = "pow", [VKD3DSIH_RCP ] = "rcp", [VKD3DSIH_REP ] = "rep", [VKD3DSIH_RESINFO ] = "resinfo", [VKD3DSIH_RET ] = "ret", [VKD3DSIH_RETP ] = "retp", [VKD3DSIH_ROUND_NE ] = "round_ne", [VKD3DSIH_ROUND_NI ] = "round_ni", [VKD3DSIH_ROUND_PI ] = "round_pi", [VKD3DSIH_ROUND_Z ] = "round_z", [VKD3DSIH_RSQ ] = "rsq", [VKD3DSIH_SAMPLE ] = "sample", [VKD3DSIH_SAMPLE_B ] = "sample_b", [VKD3DSIH_SAMPLE_B_CL_S ] = "sample_b_cl_s", [VKD3DSIH_SAMPLE_C ] = "sample_c", [VKD3DSIH_SAMPLE_C_CL_S ] = "sample_c_cl_s", [VKD3DSIH_SAMPLE_C_LZ ] = "sample_c_lz", [VKD3DSIH_SAMPLE_C_LZ_S ] = "sample_c_lz_s", [VKD3DSIH_SAMPLE_CL_S ] = "sample_cl_s", [VKD3DSIH_SAMPLE_GRAD ] = "sample_d", [VKD3DSIH_SAMPLE_GRAD_CL_S ] = "sample_d_cl_s", [VKD3DSIH_SAMPLE_INFO ] = "sample_info", [VKD3DSIH_SAMPLE_LOD ] = "sample_l", [VKD3DSIH_SAMPLE_LOD_S ] = "sample_l_s", [VKD3DSIH_SAMPLE_POS ] = "sample_pos", [VKD3DSIH_SETP ] = "setp", [VKD3DSIH_SGE ] = "sge", [VKD3DSIH_SGN ] = "sgn", [VKD3DSIH_SINCOS ] = "sincos", [VKD3DSIH_SLT ] = "slt", [VKD3DSIH_SQRT ] = "sqrt", [VKD3DSIH_STORE_RAW ] = "store_raw", [VKD3DSIH_STORE_STRUCTURED ] = "store_structured", [VKD3DSIH_STORE_UAV_TYPED ] = "store_uav_typed", [VKD3DSIH_SUB ] = "sub", [VKD3DSIH_SWAPC ] = "swapc", [VKD3DSIH_SWITCH ] = "switch", [VKD3DSIH_SWITCH_MONOLITHIC ] = "switch", [VKD3DSIH_SYNC ] = "sync", [VKD3DSIH_TAN ] = "tan", [VKD3DSIH_TEX ] = "texld", [VKD3DSIH_TEXBEM ] = "texbem", [VKD3DSIH_TEXBEML ] = "texbeml", [VKD3DSIH_TEXCOORD ] = "texcrd", [VKD3DSIH_TEXDEPTH ] = "texdepth", [VKD3DSIH_TEXDP3 ] = "texdp3", [VKD3DSIH_TEXDP3TEX ] = "texdp3tex", [VKD3DSIH_TEXKILL ] = "texkill", [VKD3DSIH_TEXLDD ] = "texldd", [VKD3DSIH_TEXLDL ] = "texldl", [VKD3DSIH_TEXM3x2DEPTH ] = "texm3x2depth", [VKD3DSIH_TEXM3x2PAD ] = "texm3x2pad", [VKD3DSIH_TEXM3x2TEX ] = "texm3x2tex", [VKD3DSIH_TEXM3x3 ] = "texm3x3", [VKD3DSIH_TEXM3x3DIFF ] = "texm3x3diff", [VKD3DSIH_TEXM3x3PAD ] = "texm3x3pad", [VKD3DSIH_TEXM3x3SPEC ] = "texm3x3spec", [VKD3DSIH_TEXM3x3TEX ] = "texm3x3tex", [VKD3DSIH_TEXM3x3VSPEC ] = "texm3x3vspec", [VKD3DSIH_TEXREG2AR ] = "texreg2ar", [VKD3DSIH_TEXREG2GB ] = "texreg2gb", [VKD3DSIH_TEXREG2RGB ] = "texreg2rgb", [VKD3DSIH_UBFE ] = "ubfe", [VKD3DSIH_UDIV ] = "udiv", [VKD3DSIH_UGE ] = "uge", [VKD3DSIH_ULT ] = "ult", [VKD3DSIH_UMAX ] = "umax", [VKD3DSIH_UMIN ] = "umin", [VKD3DSIH_UMUL ] = "umul", [VKD3DSIH_UNO ] = "uno", [VKD3DSIH_USHR ] = "ushr", [VKD3DSIH_UTOD ] = "utod", [VKD3DSIH_UTOF ] = "utof", [VKD3DSIH_UTOU ] = "utou", [VKD3DSIH_XOR ] = "xor", }; static const struct { enum vkd3d_shader_input_sysval_semantic sysval_semantic; const char *sysval_name; } shader_input_sysval_semantic_names[] = { {VKD3D_SIV_POSITION, "position"}, {VKD3D_SIV_CLIP_DISTANCE, "clip_distance"}, {VKD3D_SIV_CULL_DISTANCE, "cull_distance"}, {VKD3D_SIV_RENDER_TARGET_ARRAY_INDEX, "render_target_array_index"}, {VKD3D_SIV_VIEWPORT_ARRAY_INDEX, "viewport_array_index"}, {VKD3D_SIV_VERTEX_ID, "vertex_id"}, {VKD3D_SIV_INSTANCE_ID, "instance_id"}, {VKD3D_SIV_PRIMITIVE_ID, "primitive_id"}, {VKD3D_SIV_IS_FRONT_FACE, "is_front_face"}, {VKD3D_SIV_SAMPLE_INDEX, "sample_index"}, {VKD3D_SIV_QUAD_U0_TESS_FACTOR, "finalQuadUeq0EdgeTessFactor"}, {VKD3D_SIV_QUAD_V0_TESS_FACTOR, "finalQuadVeq0EdgeTessFactor"}, {VKD3D_SIV_QUAD_U1_TESS_FACTOR, "finalQuadUeq1EdgeTessFactor"}, {VKD3D_SIV_QUAD_V1_TESS_FACTOR, "finalQuadVeq1EdgeTessFactor"}, {VKD3D_SIV_QUAD_U_INNER_TESS_FACTOR, "finalQuadUInsideTessFactor"}, {VKD3D_SIV_QUAD_V_INNER_TESS_FACTOR, "finalQuadVInsideTessFactor"}, {VKD3D_SIV_TRIANGLE_U_TESS_FACTOR, "finalTriUeq0EdgeTessFactor"}, {VKD3D_SIV_TRIANGLE_V_TESS_FACTOR, "finalTriVeq0EdgeTessFactor"}, {VKD3D_SIV_TRIANGLE_W_TESS_FACTOR, "finalTriWeq0EdgeTessFactor"}, {VKD3D_SIV_TRIANGLE_INNER_TESS_FACTOR, "finalTriInsideTessFactor"}, {VKD3D_SIV_LINE_DETAIL_TESS_FACTOR, "finalLineDetailTessFactor"}, {VKD3D_SIV_LINE_DENSITY_TESS_FACTOR, "finalLineDensityTessFactor"}, }; struct vkd3d_d3d_asm_colours { const char *reset; const char *error; const char *literal; const char *modifier; const char *opcode; const char *reg; const char *swizzle; const char *version; const char *write_mask; const char *label; }; struct vkd3d_d3d_asm_compiler { struct vkd3d_string_buffer buffer; struct vkd3d_shader_version shader_version; struct vkd3d_d3d_asm_colours colours; enum vsir_asm_flags flags; const struct vkd3d_shader_instruction *current; }; static int VKD3D_PRINTF_FUNC(2, 3) shader_addline(struct vkd3d_string_buffer *buffer, const char *format, ...) { va_list args; int ret; va_start(args, format); ret = vkd3d_string_buffer_vprintf(buffer, format, args); va_end(args); return ret; } /* Convert floating point offset relative to a register file to an absolute * offset for float constants. */ static unsigned int shader_get_float_offset(enum vkd3d_shader_register_type register_type, UINT register_idx) { switch (register_type) { case VKD3DSPR_CONST: return register_idx; case VKD3DSPR_CONST2: return 2048 + register_idx; case VKD3DSPR_CONST3: return 4096 + register_idx; case VKD3DSPR_CONST4: return 6144 + register_idx; default: FIXME("Unsupported register type: %u.\n", register_type); return register_idx; } } static void shader_dump_global_flags(struct vkd3d_d3d_asm_compiler *compiler, enum vkd3d_shader_global_flags global_flags) { unsigned int i; static const struct { enum vkd3d_shader_global_flags flag; const char *name; } global_flag_info[] = { {VKD3DSGF_REFACTORING_ALLOWED, "refactoringAllowed"}, {VKD3DSGF_FORCE_EARLY_DEPTH_STENCIL, "forceEarlyDepthStencil"}, {VKD3DSGF_ENABLE_RAW_AND_STRUCTURED_BUFFERS, "enableRawAndStructuredBuffers"}, {VKD3DSGF_ENABLE_MINIMUM_PRECISION, "enableMinimumPrecision"}, {VKD3DSGF_SKIP_OPTIMIZATION, "skipOptimization"}, {VKD3DSGF_ENABLE_DOUBLE_PRECISION_FLOAT_OPS, "enableDoublePrecisionFloatOps"}, {VKD3DSGF_ENABLE_11_1_DOUBLE_EXTENSIONS, "enable11_1DoubleExtensions"}, }; for (i = 0; i < ARRAY_SIZE(global_flag_info); ++i) { if (global_flags & global_flag_info[i].flag) { vkd3d_string_buffer_printf(&compiler->buffer, "%s", global_flag_info[i].name); global_flags &= ~global_flag_info[i].flag; if (global_flags) vkd3d_string_buffer_printf(&compiler->buffer, " | "); } } if (global_flags) vkd3d_string_buffer_printf(&compiler->buffer, "unknown_flags(%#"PRIx64")", (uint64_t)global_flags); } static void shader_dump_sync_flags(struct vkd3d_d3d_asm_compiler *compiler, uint32_t sync_flags) { if (sync_flags & VKD3DSSF_GLOBAL_UAV) { vkd3d_string_buffer_printf(&compiler->buffer, "_uglobal"); sync_flags &= ~VKD3DSSF_GLOBAL_UAV; } if (sync_flags & VKD3DSSF_THREAD_GROUP_UAV) { vkd3d_string_buffer_printf(&compiler->buffer, "_ugroup"); sync_flags &= ~VKD3DSSF_THREAD_GROUP_UAV; } if (sync_flags & VKD3DSSF_GROUP_SHARED_MEMORY) { vkd3d_string_buffer_printf(&compiler->buffer, "_g"); sync_flags &= ~VKD3DSSF_GROUP_SHARED_MEMORY; } if (sync_flags & VKD3DSSF_THREAD_GROUP) { vkd3d_string_buffer_printf(&compiler->buffer, "_t"); sync_flags &= ~VKD3DSSF_THREAD_GROUP; } if (sync_flags) vkd3d_string_buffer_printf(&compiler->buffer, "_unknown_flags(%#x)", sync_flags); } static void shader_dump_precise_flags(struct vkd3d_d3d_asm_compiler *compiler, uint32_t flags) { if (!(flags & VKD3DSI_PRECISE_XYZW)) return; vkd3d_string_buffer_printf(&compiler->buffer, " [precise"); if (flags != VKD3DSI_PRECISE_XYZW) { vkd3d_string_buffer_printf(&compiler->buffer, "(%s%s%s%s)", flags & VKD3DSI_PRECISE_X ? "x" : "", flags & VKD3DSI_PRECISE_Y ? "y" : "", flags & VKD3DSI_PRECISE_Z ? "z" : "", flags & VKD3DSI_PRECISE_W ? "w" : ""); } vkd3d_string_buffer_printf(&compiler->buffer, "]"); } static void shader_dump_uav_flags(struct vkd3d_d3d_asm_compiler *compiler, uint32_t uav_flags) { if (uav_flags & VKD3DSUF_GLOBALLY_COHERENT) { vkd3d_string_buffer_printf(&compiler->buffer, "_glc"); uav_flags &= ~VKD3DSUF_GLOBALLY_COHERENT; } if (uav_flags & VKD3DSUF_ORDER_PRESERVING_COUNTER) { vkd3d_string_buffer_printf(&compiler->buffer, "_opc"); uav_flags &= ~VKD3DSUF_ORDER_PRESERVING_COUNTER; } if (uav_flags & VKD3DSUF_RASTERISER_ORDERED_VIEW) { vkd3d_string_buffer_printf(&compiler->buffer, "_rov"); uav_flags &= ~VKD3DSUF_RASTERISER_ORDERED_VIEW; } if (uav_flags) vkd3d_string_buffer_printf(&compiler->buffer, "_unknown_flags(%#x)", uav_flags); } static void shader_dump_tessellator_domain(struct vkd3d_d3d_asm_compiler *compiler, enum vkd3d_tessellator_domain domain) { struct vkd3d_string_buffer *buffer = &compiler->buffer; shader_addline(buffer, "domain_"); switch (domain) { case VKD3D_TESSELLATOR_DOMAIN_LINE: shader_addline(buffer, "isoline"); break; case VKD3D_TESSELLATOR_DOMAIN_TRIANGLE: shader_addline(buffer, "tri"); break; case VKD3D_TESSELLATOR_DOMAIN_QUAD: shader_addline(buffer, "quad"); break; default: shader_addline(buffer, "unknown_tessellator_domain(%#x)", domain); break; } } static void shader_dump_tessellator_output_primitive(struct vkd3d_d3d_asm_compiler *compiler, enum vkd3d_shader_tessellator_output_primitive output_primitive) { struct vkd3d_string_buffer *buffer = &compiler->buffer; shader_addline(buffer, "output_"); switch (output_primitive) { case VKD3D_SHADER_TESSELLATOR_OUTPUT_POINT: shader_addline(buffer, "point"); break; case VKD3D_SHADER_TESSELLATOR_OUTPUT_LINE: shader_addline(buffer, "line"); break; case VKD3D_SHADER_TESSELLATOR_OUTPUT_TRIANGLE_CW: shader_addline(buffer, "triangle_cw"); break; case VKD3D_SHADER_TESSELLATOR_OUTPUT_TRIANGLE_CCW: shader_addline(buffer, "triangle_ccw"); break; default: shader_addline(buffer, "unknown_tessellator_output_primitive(%#x)", output_primitive); break; } } static void shader_dump_tessellator_partitioning(struct vkd3d_d3d_asm_compiler *compiler, enum vkd3d_shader_tessellator_partitioning partitioning) { struct vkd3d_string_buffer *buffer = &compiler->buffer; shader_addline(buffer, "partitioning_"); switch (partitioning) { case VKD3D_SHADER_TESSELLATOR_PARTITIONING_INTEGER: shader_addline(buffer, "integer"); break; case VKD3D_SHADER_TESSELLATOR_PARTITIONING_POW2: shader_addline(buffer, "pow2"); break; case VKD3D_SHADER_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD: shader_addline(buffer, "fractional_odd"); break; case VKD3D_SHADER_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN: shader_addline(buffer, "fractional_even"); break; default: shader_addline(buffer, "unknown_tessellator_partitioning(%#x)", partitioning); break; } } static void shader_dump_shader_input_sysval_semantic(struct vkd3d_d3d_asm_compiler *compiler, enum vkd3d_shader_input_sysval_semantic semantic) { unsigned int i; for (i = 0; i < ARRAY_SIZE(shader_input_sysval_semantic_names); ++i) { if (shader_input_sysval_semantic_names[i].sysval_semantic == semantic) { vkd3d_string_buffer_printf(&compiler->buffer, "%s", shader_input_sysval_semantic_names[i].sysval_name); return; } } vkd3d_string_buffer_printf(&compiler->buffer, "unknown_shader_input_sysval_semantic(%#x)", semantic); } static void shader_dump_resource_type(struct vkd3d_d3d_asm_compiler *compiler, enum vkd3d_shader_resource_type type) { static const char *const resource_type_names[] = { [VKD3D_SHADER_RESOURCE_NONE ] = "none", [VKD3D_SHADER_RESOURCE_BUFFER ] = "buffer", [VKD3D_SHADER_RESOURCE_TEXTURE_1D ] = "texture1d", [VKD3D_SHADER_RESOURCE_TEXTURE_2D ] = "texture2d", [VKD3D_SHADER_RESOURCE_TEXTURE_2DMS ] = "texture2dms", [VKD3D_SHADER_RESOURCE_TEXTURE_3D ] = "texture3d", [VKD3D_SHADER_RESOURCE_TEXTURE_CUBE ] = "texturecube", [VKD3D_SHADER_RESOURCE_TEXTURE_1DARRAY ] = "texture1darray", [VKD3D_SHADER_RESOURCE_TEXTURE_2DARRAY ] = "texture2darray", [VKD3D_SHADER_RESOURCE_TEXTURE_2DMSARRAY] = "texture2dmsarray", [VKD3D_SHADER_RESOURCE_TEXTURE_CUBEARRAY] = "texturecubearray", }; if (type < ARRAY_SIZE(resource_type_names)) vkd3d_string_buffer_printf(&compiler->buffer, "%s", resource_type_names[type]); else vkd3d_string_buffer_printf(&compiler->buffer, "unknown"); } static void shader_dump_data_type(struct vkd3d_d3d_asm_compiler *compiler, enum vkd3d_data_type type) { static const char *const data_type_names[] = { [VKD3D_DATA_FLOAT ] = "float", [VKD3D_DATA_INT ] = "int", [VKD3D_DATA_RESOURCE ] = "resource", [VKD3D_DATA_SAMPLER ] = "sampler", [VKD3D_DATA_UAV ] = "uav", [VKD3D_DATA_UINT ] = "uint", [VKD3D_DATA_UNORM ] = "unorm", [VKD3D_DATA_SNORM ] = "snorm", [VKD3D_DATA_OPAQUE ] = "opaque", [VKD3D_DATA_MIXED ] = "mixed", [VKD3D_DATA_DOUBLE ] = "double", [VKD3D_DATA_CONTINUED] = "", [VKD3D_DATA_UNUSED ] = "", [VKD3D_DATA_UINT8 ] = "uint8", [VKD3D_DATA_UINT64 ] = "uint64", [VKD3D_DATA_BOOL ] = "bool", [VKD3D_DATA_UINT16 ] = "uint16", [VKD3D_DATA_HALF ] = "half", }; const char *name; if (type < ARRAY_SIZE(data_type_names)) name = data_type_names[type]; else name = ""; vkd3d_string_buffer_printf(&compiler->buffer, "%s", name); } static void shader_dump_resource_data_type(struct vkd3d_d3d_asm_compiler *compiler, const enum vkd3d_data_type *type) { int i; vkd3d_string_buffer_printf(&compiler->buffer, "("); for (i = 0; i < 4; i++) { vkd3d_string_buffer_printf(&compiler->buffer, "%s", i == 0 ? "" : ","); shader_dump_data_type(compiler, type[i]); } vkd3d_string_buffer_printf(&compiler->buffer, ")"); } static void shader_dump_decl_usage(struct vkd3d_d3d_asm_compiler *compiler, const struct vkd3d_shader_semantic *semantic, uint32_t flags) { struct vkd3d_string_buffer *buffer = &compiler->buffer; if (semantic->resource.reg.reg.type == VKD3DSPR_COMBINED_SAMPLER) { switch (semantic->resource_type) { case VKD3D_SHADER_RESOURCE_TEXTURE_2D: shader_addline(buffer, "_2d"); break; case VKD3D_SHADER_RESOURCE_TEXTURE_3D: shader_addline(buffer, "_volume"); break; case VKD3D_SHADER_RESOURCE_TEXTURE_CUBE: shader_addline(buffer, "_cube"); break; default: shader_addline(buffer, "_unknown_resource_type(%#x)", semantic->resource_type); break; } } else if (semantic->resource.reg.reg.type == VKD3DSPR_RESOURCE || semantic->resource.reg.reg.type == VKD3DSPR_UAV) { if (semantic->resource.reg.reg.type == VKD3DSPR_RESOURCE) shader_addline(buffer, "_resource"); shader_addline(buffer, "_"); shader_dump_resource_type(compiler, semantic->resource_type); if (semantic->resource_type == VKD3D_SHADER_RESOURCE_TEXTURE_2DMS || semantic->resource_type == VKD3D_SHADER_RESOURCE_TEXTURE_2DMSARRAY) { shader_addline(buffer, "(%u)", semantic->sample_count); } if (semantic->resource.reg.reg.type == VKD3DSPR_UAV) shader_dump_uav_flags(compiler, flags); shader_addline(buffer, " "); shader_dump_resource_data_type(compiler, semantic->resource_data_type); } else { /* Pixel shaders 3.0 don't have usage semantics. */ if (!vkd3d_shader_ver_ge(&compiler->shader_version, 3, 0) && compiler->shader_version.type == VKD3D_SHADER_TYPE_PIXEL) return; else shader_addline(buffer, "_"); switch (semantic->usage) { case VKD3D_DECL_USAGE_POSITION: shader_addline(buffer, "position%u", semantic->usage_idx); break; case VKD3D_DECL_USAGE_BLEND_INDICES: shader_addline(buffer, "blend"); break; case VKD3D_DECL_USAGE_BLEND_WEIGHT: shader_addline(buffer, "weight"); break; case VKD3D_DECL_USAGE_NORMAL: shader_addline(buffer, "normal%u", semantic->usage_idx); break; case VKD3D_DECL_USAGE_PSIZE: shader_addline(buffer, "psize"); break; case VKD3D_DECL_USAGE_COLOR: if (!semantic->usage_idx) shader_addline(buffer, "color"); else shader_addline(buffer, "specular%u", (semantic->usage_idx - 1)); break; case VKD3D_DECL_USAGE_TEXCOORD: shader_addline(buffer, "texcoord%u", semantic->usage_idx); break; case VKD3D_DECL_USAGE_TANGENT: shader_addline(buffer, "tangent"); break; case VKD3D_DECL_USAGE_BINORMAL: shader_addline(buffer, "binormal"); break; case VKD3D_DECL_USAGE_TESS_FACTOR: shader_addline(buffer, "tessfactor"); break; case VKD3D_DECL_USAGE_POSITIONT: shader_addline(buffer, "positionT%u", semantic->usage_idx); break; case VKD3D_DECL_USAGE_FOG: shader_addline(buffer, "fog"); break; case VKD3D_DECL_USAGE_DEPTH: shader_addline(buffer, "depth"); break; case VKD3D_DECL_USAGE_SAMPLE: shader_addline(buffer, "sample"); break; default: shader_addline(buffer, "", semantic->usage); FIXME("Unrecognised semantic usage %#x.\n", semantic->usage); } } } static void shader_dump_src_param(struct vkd3d_d3d_asm_compiler *compiler, const struct vkd3d_shader_src_param *param); static void shader_print_float_literal(struct vkd3d_d3d_asm_compiler *compiler, const char *prefix, float f, const char *suffix) { const char *sign = ""; if (isfinite(f) && signbit(f)) { sign = "-"; f = -f; } vkd3d_string_buffer_printf(&compiler->buffer, "%s%s%s", prefix, sign, compiler->colours.literal); vkd3d_string_buffer_print_f32(&compiler->buffer, f); vkd3d_string_buffer_printf(&compiler->buffer, "%s%s", compiler->colours.reset, suffix); } static void shader_print_double_literal(struct vkd3d_d3d_asm_compiler *compiler, const char *prefix, double d, const char *suffix) { const char *sign = ""; if (isfinite(d) && signbit(d)) { sign = "-"; d = -d; } vkd3d_string_buffer_printf(&compiler->buffer, "%s%s%s", prefix, sign, compiler->colours.literal); vkd3d_string_buffer_print_f64(&compiler->buffer, d); vkd3d_string_buffer_printf(&compiler->buffer, "l%s%s", compiler->colours.reset, suffix); } static void shader_print_int_literal(struct vkd3d_d3d_asm_compiler *compiler, const char *prefix, int i, const char *suffix) { if (i < 0) vkd3d_string_buffer_printf(&compiler->buffer, "%s-%s%d%s%s", prefix, compiler->colours.literal, -i, compiler->colours.reset, suffix); else vkd3d_string_buffer_printf(&compiler->buffer, "%s%s%d%s%s", prefix, compiler->colours.literal, i, compiler->colours.reset, suffix); } static void shader_print_uint_literal(struct vkd3d_d3d_asm_compiler *compiler, const char *prefix, unsigned int i, const char *suffix) { vkd3d_string_buffer_printf(&compiler->buffer, "%s%s%u%s%s", prefix, compiler->colours.literal, i, compiler->colours.reset, suffix); } static void shader_print_uint64_literal(struct vkd3d_d3d_asm_compiler *compiler, const char *prefix, uint64_t i, const char *suffix) { vkd3d_string_buffer_printf(&compiler->buffer, "%s%s%"PRIu64"%s%s", prefix, compiler->colours.literal, i, compiler->colours.reset, suffix); } static void shader_print_hex_literal(struct vkd3d_d3d_asm_compiler *compiler, const char *prefix, unsigned int i, const char *suffix) { vkd3d_string_buffer_printf(&compiler->buffer, "%s%s0x%08x%s%s", prefix, compiler->colours.literal, i, compiler->colours.reset, suffix); } static void shader_print_bool_literal(struct vkd3d_d3d_asm_compiler *compiler, const char *prefix, unsigned int b, const char *suffix) { vkd3d_string_buffer_printf(&compiler->buffer, "%s%s%s%s%s", prefix, compiler->colours.literal, b ? "true" : "false", compiler->colours.reset, suffix); } static void shader_print_untyped_literal(struct vkd3d_d3d_asm_compiler *compiler, const char *prefix, uint32_t u, const char *suffix) { union { uint32_t u; float f; } value; unsigned int exponent = (u >> 23) & 0xff; value.u = u; if (exponent != 0 && exponent != 0xff) return shader_print_float_literal(compiler, prefix, value.f, suffix); if (u <= 10000) return shader_print_uint_literal(compiler, prefix, value.u, suffix); return shader_print_hex_literal(compiler, prefix, value.u, suffix); } static void shader_print_subscript(struct vkd3d_d3d_asm_compiler *compiler, unsigned int offset, const struct vkd3d_shader_src_param *rel_addr) { vkd3d_string_buffer_printf(&compiler->buffer, "["); if (rel_addr) { shader_dump_src_param(compiler, rel_addr); vkd3d_string_buffer_printf(&compiler->buffer, " + "); } shader_print_uint_literal(compiler, "", offset, "]"); } static void shader_print_subscript_range(struct vkd3d_d3d_asm_compiler *compiler, unsigned int offset_first, unsigned int offset_last) { shader_print_uint_literal(compiler, "[", offset_first, ":"); if (offset_last != ~0u) shader_print_uint_literal(compiler, "", offset_last, "]"); else vkd3d_string_buffer_printf(&compiler->buffer, "*]"); } static void shader_dump_register(struct vkd3d_d3d_asm_compiler *compiler, const struct vkd3d_shader_register *reg, bool is_declaration) { struct vkd3d_string_buffer *buffer = &compiler->buffer; unsigned int offset = reg->idx[0].offset; bool is_descriptor = false; static const char * const rastout_reg_names[] = {"oPos", "oFog", "oPts"}; static const char * const misctype_reg_names[] = {"vPos", "vFace"}; shader_addline(buffer, "%s", reg->type == VKD3DSPR_LABEL ? compiler->colours.label : compiler->colours.reg); switch (reg->type) { case VKD3DSPR_TEMP: shader_addline(buffer, "r"); break; case VKD3DSPR_INPUT: shader_addline(buffer, "v"); break; case VKD3DSPR_CONST: case VKD3DSPR_CONST2: case VKD3DSPR_CONST3: case VKD3DSPR_CONST4: shader_addline(buffer, "c"); offset = shader_get_float_offset(reg->type, offset); break; case VKD3DSPR_TEXTURE: /* vs: case VKD3DSPR_ADDR */ vkd3d_string_buffer_printf(buffer, "%c", compiler->shader_version.type == VKD3D_SHADER_TYPE_PIXEL ? 't' : 'a'); break; case VKD3DSPR_RASTOUT: shader_addline(buffer, "%s", rastout_reg_names[offset]); break; case VKD3DSPR_COLOROUT: shader_addline(buffer, "oC"); break; case VKD3DSPR_DEPTHOUT: shader_addline(buffer, "oDepth"); break; case VKD3DSPR_DEPTHOUTGE: shader_addline(buffer, "oDepthGE"); break; case VKD3DSPR_DEPTHOUTLE: shader_addline(buffer, "oDepthLE"); break; case VKD3DSPR_ATTROUT: shader_addline(buffer, "oD"); break; case VKD3DSPR_TEXCRDOUT: /* Vertex shaders >= 3.0 use general purpose output registers * (VKD3DSPR_OUTPUT), which can include an address token. */ if (vkd3d_shader_ver_ge(&compiler->shader_version, 3, 0)) shader_addline(buffer, "o"); else shader_addline(buffer, "oT"); break; case VKD3DSPR_CONSTINT: shader_addline(buffer, "i"); break; case VKD3DSPR_CONSTBOOL: shader_addline(buffer, "b"); break; case VKD3DSPR_LABEL: shader_addline(buffer, "l"); break; case VKD3DSPR_LOOP: shader_addline(buffer, "aL"); break; case VKD3DSPR_COMBINED_SAMPLER: case VKD3DSPR_SAMPLER: shader_addline(buffer, "s"); is_descriptor = true; break; case VKD3DSPR_MISCTYPE: if (offset > 1) { FIXME("Unhandled misctype register %u.\n", offset); shader_addline(buffer, "", offset); } else { shader_addline(buffer, "%s", misctype_reg_names[offset]); } break; case VKD3DSPR_PREDICATE: shader_addline(buffer, "p"); break; case VKD3DSPR_IMMCONST: shader_addline(buffer, "l"); break; case VKD3DSPR_IMMCONST64: shader_addline(buffer, "d"); break; case VKD3DSPR_CONSTBUFFER: shader_addline(buffer, "cb"); is_descriptor = true; break; case VKD3DSPR_IMMCONSTBUFFER: shader_addline(buffer, "icb"); break; case VKD3DSPR_PRIMID: shader_addline(buffer, "primID"); break; case VKD3DSPR_NULL: shader_addline(buffer, "null"); break; case VKD3DSPR_RASTERIZER: shader_addline(buffer, "rasterizer"); break; case VKD3DSPR_RESOURCE: shader_addline(buffer, "t"); is_descriptor = true; break; case VKD3DSPR_UAV: shader_addline(buffer, "u"); is_descriptor = true; break; case VKD3DSPR_OUTPOINTID: shader_addline(buffer, "vOutputControlPointID"); break; case VKD3DSPR_FORKINSTID: shader_addline(buffer, "vForkInstanceId"); break; case VKD3DSPR_JOININSTID: shader_addline(buffer, "vJoinInstanceId"); break; case VKD3DSPR_INCONTROLPOINT: shader_addline(buffer, "vicp"); break; case VKD3DSPR_OUTCONTROLPOINT: shader_addline(buffer, "vocp"); break; case VKD3DSPR_PATCHCONST: shader_addline(buffer, "vpc"); break; case VKD3DSPR_TESSCOORD: shader_addline(buffer, "vDomainLocation"); break; case VKD3DSPR_GROUPSHAREDMEM: shader_addline(buffer, "g"); break; case VKD3DSPR_THREADID: shader_addline(buffer, "vThreadID"); break; case VKD3DSPR_THREADGROUPID: shader_addline(buffer, "vThreadGroupID"); break; case VKD3DSPR_LOCALTHREADID: shader_addline(buffer, "vThreadIDInGroup"); break; case VKD3DSPR_LOCALTHREADINDEX: shader_addline(buffer, "vThreadIDInGroupFlattened"); break; case VKD3DSPR_IDXTEMP: shader_addline(buffer, "x"); break; case VKD3DSPR_STREAM: shader_addline(buffer, "m"); break; case VKD3DSPR_FUNCTIONBODY: shader_addline(buffer, "fb"); break; case VKD3DSPR_FUNCTIONPOINTER: shader_addline(buffer, "fp"); break; case VKD3DSPR_COVERAGE: shader_addline(buffer, "vCoverage"); break; case VKD3DSPR_SAMPLEMASK: shader_addline(buffer, "oMask"); break; case VKD3DSPR_GSINSTID: shader_addline(buffer, "vGSInstanceID"); break; case VKD3DSPR_OUTSTENCILREF: shader_addline(buffer, "oStencilRef"); break; case VKD3DSPR_UNDEF: shader_addline(buffer, "undef"); break; case VKD3DSPR_SSA: shader_addline(buffer, "sr"); break; default: shader_addline(buffer, "", reg->type); break; } if (reg->type == VKD3DSPR_IMMCONST) { bool untyped = false; switch (compiler->current->handler_idx) { case VKD3DSIH_MOV: case VKD3DSIH_MOVC: untyped = true; break; default: break; } shader_addline(buffer, "%s(", compiler->colours.reset); switch (reg->dimension) { case VSIR_DIMENSION_SCALAR: switch (reg->data_type) { case VKD3D_DATA_FLOAT: if (untyped) shader_print_untyped_literal(compiler, "", reg->u.immconst_u32[0], ""); else shader_print_float_literal(compiler, "", reg->u.immconst_f32[0], ""); break; case VKD3D_DATA_INT: shader_print_int_literal(compiler, "", reg->u.immconst_u32[0], ""); break; case VKD3D_DATA_RESOURCE: case VKD3D_DATA_SAMPLER: case VKD3D_DATA_UINT: shader_print_uint_literal(compiler, "", reg->u.immconst_u32[0], ""); break; default: shader_addline(buffer, "", reg->data_type); break; } break; case VSIR_DIMENSION_VEC4: switch (reg->data_type) { case VKD3D_DATA_FLOAT: if (untyped) { shader_print_untyped_literal(compiler, "", reg->u.immconst_u32[0], ""); shader_print_untyped_literal(compiler, ", ", reg->u.immconst_u32[1], ""); shader_print_untyped_literal(compiler, ", ", reg->u.immconst_u32[2], ""); shader_print_untyped_literal(compiler, ", ", reg->u.immconst_u32[3], ""); } else { shader_print_float_literal(compiler, "", reg->u.immconst_f32[0], ""); shader_print_float_literal(compiler, ", ", reg->u.immconst_f32[1], ""); shader_print_float_literal(compiler, ", ", reg->u.immconst_f32[2], ""); shader_print_float_literal(compiler, ", ", reg->u.immconst_f32[3], ""); } break; case VKD3D_DATA_INT: shader_print_int_literal(compiler, "", reg->u.immconst_u32[0], ""); shader_print_int_literal(compiler, ", ", reg->u.immconst_u32[1], ""); shader_print_int_literal(compiler, ", ", reg->u.immconst_u32[2], ""); shader_print_int_literal(compiler, ", ", reg->u.immconst_u32[3], ""); break; case VKD3D_DATA_RESOURCE: case VKD3D_DATA_SAMPLER: case VKD3D_DATA_UINT: shader_print_uint_literal(compiler, "", reg->u.immconst_u32[0], ""); shader_print_uint_literal(compiler, ", ", reg->u.immconst_u32[1], ""); shader_print_uint_literal(compiler, ", ", reg->u.immconst_u32[2], ""); shader_print_uint_literal(compiler, ", ", reg->u.immconst_u32[3], ""); break; default: shader_addline(buffer, "", reg->data_type); break; } break; default: shader_addline(buffer, "", reg->dimension); break; } shader_addline(buffer, ")"); } else if (reg->type == VKD3DSPR_IMMCONST64) { shader_addline(buffer, "%s(", compiler->colours.reset); /* A double2 vector is treated as a float4 vector in enum vsir_dimension. */ if (reg->dimension == VSIR_DIMENSION_SCALAR || reg->dimension == VSIR_DIMENSION_VEC4) { if (reg->data_type == VKD3D_DATA_DOUBLE) { shader_print_double_literal(compiler, "", reg->u.immconst_f64[0], ""); if (reg->dimension == VSIR_DIMENSION_VEC4) shader_print_double_literal(compiler, ", ", reg->u.immconst_f64[1], ""); } else if (reg->data_type == VKD3D_DATA_UINT64) { shader_print_uint64_literal(compiler, "", reg->u.immconst_u64[0], ""); if (reg->dimension == VSIR_DIMENSION_VEC4) shader_print_uint64_literal(compiler, "", reg->u.immconst_u64[1], ""); } else { shader_addline(buffer, "", reg->data_type); } } else { shader_addline(buffer, "", reg->dimension); } shader_addline(buffer, ")"); } else if (reg->type != VKD3DSPR_RASTOUT && reg->type != VKD3DSPR_MISCTYPE && reg->type != VKD3DSPR_NULL && reg->type != VKD3DSPR_DEPTHOUT) { if (offset != ~0u) { bool is_sm_5_1 = vkd3d_shader_ver_ge(&compiler->shader_version, 5, 1); if (reg->idx[0].rel_addr || reg->type == VKD3DSPR_IMMCONSTBUFFER || reg->type == VKD3DSPR_INCONTROLPOINT || (reg->type == VKD3DSPR_INPUT && (compiler->shader_version.type == VKD3D_SHADER_TYPE_GEOMETRY || compiler->shader_version.type == VKD3D_SHADER_TYPE_HULL))) { vkd3d_string_buffer_printf(buffer, "%s", compiler->colours.reset); shader_print_subscript(compiler, offset, reg->idx[0].rel_addr); } else { vkd3d_string_buffer_printf(buffer, "%u%s", offset, compiler->colours.reset); } /* For sm 5.1 descriptor declarations we need to print the register range instead of * a single register index. */ if (is_descriptor && is_declaration && is_sm_5_1) { shader_print_subscript_range(compiler, reg->idx[1].offset, reg->idx[2].offset); } else if (reg->type != VKD3DSPR_SSA) { /* For descriptors in sm < 5.1 we move the reg->idx values up one slot * to normalise with 5.1. * Here we should ignore it if it's a descriptor in sm < 5.1. */ if (reg->idx[1].offset != ~0u && (!is_descriptor || is_sm_5_1)) shader_print_subscript(compiler, reg->idx[1].offset, reg->idx[1].rel_addr); if (reg->idx[2].offset != ~0u) shader_print_subscript(compiler, reg->idx[2].offset, reg->idx[2].rel_addr); } } else { shader_addline(buffer, "%s", compiler->colours.reset); } if (reg->type == VKD3DSPR_FUNCTIONPOINTER) shader_print_subscript(compiler, reg->u.fp_body_idx, NULL); } else { shader_addline(buffer, "%s", compiler->colours.reset); } } static void shader_print_precision(struct vkd3d_d3d_asm_compiler *compiler, const struct vkd3d_shader_register *reg) { struct vkd3d_string_buffer *buffer = &compiler->buffer; const char *precision; if (reg->precision == VKD3D_SHADER_REGISTER_PRECISION_DEFAULT) return; switch (reg->precision) { case VKD3D_SHADER_REGISTER_PRECISION_MIN_FLOAT_16: precision = "min16f"; break; case VKD3D_SHADER_REGISTER_PRECISION_MIN_FLOAT_10: precision = "min2_8f"; break; case VKD3D_SHADER_REGISTER_PRECISION_MIN_INT_16: precision = "min16i"; break; case VKD3D_SHADER_REGISTER_PRECISION_MIN_UINT_16: precision = "min16u"; break; default: vkd3d_string_buffer_printf(buffer, " {%s%s}", compiler->colours.error, reg->precision, compiler->colours.reset); return; } vkd3d_string_buffer_printf(buffer, " {%s%s%s}", compiler->colours.modifier, precision, compiler->colours.reset); } static void shader_print_non_uniform(struct vkd3d_d3d_asm_compiler *compiler, const struct vkd3d_shader_register *reg) { if (reg->non_uniform) vkd3d_string_buffer_printf(&compiler->buffer, " {%snonuniform%s}", compiler->colours.modifier, compiler->colours.reset); } static void shader_dump_reg_type(struct vkd3d_d3d_asm_compiler *compiler, const struct vkd3d_shader_register *reg) { static const char *dimensions[] = { [VSIR_DIMENSION_NONE] = "", [VSIR_DIMENSION_SCALAR] = "s:", [VSIR_DIMENSION_VEC4] = "v4:", }; struct vkd3d_string_buffer *buffer = &compiler->buffer; const char *dimension; if (!(compiler->flags & VSIR_ASM_FLAG_DUMP_TYPES)) return; if (reg->data_type == VKD3D_DATA_UNUSED) return; if (reg->dimension < ARRAY_SIZE(dimensions)) dimension = dimensions[reg->dimension]; else dimension = "??"; shader_addline(buffer, " <%s", dimension); shader_dump_data_type(compiler, reg->data_type); shader_addline(buffer, ">"); } static void shader_print_write_mask(struct vkd3d_d3d_asm_compiler *compiler, const char *prefix, uint32_t mask, const char *suffix) { unsigned int i = 0; char buffer[5]; if (mask == 0) { vkd3d_string_buffer_printf(&compiler->buffer, "%s%s", prefix, suffix); return; } if (mask & VKD3DSP_WRITEMASK_0) buffer[i++] = 'x'; if (mask & VKD3DSP_WRITEMASK_1) buffer[i++] = 'y'; if (mask & VKD3DSP_WRITEMASK_2) buffer[i++] = 'z'; if (mask & VKD3DSP_WRITEMASK_3) buffer[i++] = 'w'; buffer[i++] = '\0'; vkd3d_string_buffer_printf(&compiler->buffer, "%s.%s%s%s%s", prefix, compiler->colours.write_mask, buffer, compiler->colours.reset, suffix); } static void shader_dump_dst_param(struct vkd3d_d3d_asm_compiler *compiler, const struct vkd3d_shader_dst_param *param, bool is_declaration) { uint32_t write_mask = param->write_mask; shader_dump_register(compiler, ¶m->reg, is_declaration); if (write_mask && param->reg.dimension == VSIR_DIMENSION_VEC4) { if (data_type_is_64_bit(param->reg.data_type)) write_mask = vsir_write_mask_32_from_64(write_mask); shader_print_write_mask(compiler, "", write_mask, ""); } shader_print_precision(compiler, ¶m->reg); shader_print_non_uniform(compiler, ¶m->reg); shader_dump_reg_type(compiler, ¶m->reg); } static void shader_dump_src_param(struct vkd3d_d3d_asm_compiler *compiler, const struct vkd3d_shader_src_param *param) { enum vkd3d_shader_src_modifier src_modifier = param->modifiers; struct vkd3d_string_buffer *buffer = &compiler->buffer; uint32_t swizzle = param->swizzle; if (src_modifier == VKD3DSPSM_NEG || src_modifier == VKD3DSPSM_BIASNEG || src_modifier == VKD3DSPSM_SIGNNEG || src_modifier == VKD3DSPSM_X2NEG || src_modifier == VKD3DSPSM_ABSNEG) shader_addline(buffer, "-"); else if (src_modifier == VKD3DSPSM_COMP) shader_addline(buffer, "1-"); else if (src_modifier == VKD3DSPSM_NOT) shader_addline(buffer, "!"); if (src_modifier == VKD3DSPSM_ABS || src_modifier == VKD3DSPSM_ABSNEG) shader_addline(buffer, "|"); shader_dump_register(compiler, ¶m->reg, false); switch (src_modifier) { case VKD3DSPSM_NONE: break; case VKD3DSPSM_NEG: break; case VKD3DSPSM_NOT: break; case VKD3DSPSM_BIAS: shader_addline(buffer, "_bias"); break; case VKD3DSPSM_BIASNEG: shader_addline(buffer, "_bias"); break; case VKD3DSPSM_SIGN: shader_addline(buffer, "_bx2"); break; case VKD3DSPSM_SIGNNEG: shader_addline(buffer, "_bx2"); break; case VKD3DSPSM_COMP: break; case VKD3DSPSM_X2: shader_addline(buffer, "_x2"); break; case VKD3DSPSM_X2NEG: shader_addline(buffer, "_x2"); break; case VKD3DSPSM_DZ: shader_addline(buffer, "_dz"); break; case VKD3DSPSM_DW: shader_addline(buffer, "_dw"); break; case VKD3DSPSM_ABSNEG: case VKD3DSPSM_ABS: /* handled later */ break; default: shader_addline(buffer, "_unknown_modifier(%#x)", src_modifier); } if (param->reg.type != VKD3DSPR_IMMCONST && param->reg.type != VKD3DSPR_IMMCONST64 && param->reg.dimension == VSIR_DIMENSION_VEC4) { static const char swizzle_chars[] = "xyzw"; unsigned int swizzle_x, swizzle_y, swizzle_z, swizzle_w; if (data_type_is_64_bit(param->reg.data_type)) swizzle = vsir_swizzle_32_from_64(swizzle); swizzle_x = vsir_swizzle_get_component(swizzle, 0); swizzle_y = vsir_swizzle_get_component(swizzle, 1); swizzle_z = vsir_swizzle_get_component(swizzle, 2); swizzle_w = vsir_swizzle_get_component(swizzle, 3); if (swizzle_x == swizzle_y && swizzle_x == swizzle_z && swizzle_x == swizzle_w) { shader_addline(buffer, ".%s%c%s", compiler->colours.swizzle, swizzle_chars[swizzle_x], compiler->colours.reset); } else { shader_addline(buffer, ".%s%c%c%c%c%s", compiler->colours.swizzle, swizzle_chars[swizzle_x], swizzle_chars[swizzle_y], swizzle_chars[swizzle_z], swizzle_chars[swizzle_w], compiler->colours.reset); } } if (src_modifier == VKD3DSPSM_ABS || src_modifier == VKD3DSPSM_ABSNEG) shader_addline(buffer, "|"); shader_print_precision(compiler, ¶m->reg); shader_print_non_uniform(compiler, ¶m->reg); shader_dump_reg_type(compiler, ¶m->reg); } static void shader_dump_ins_modifiers(struct vkd3d_d3d_asm_compiler *compiler, const struct vkd3d_shader_dst_param *dst) { struct vkd3d_string_buffer *buffer = &compiler->buffer; uint32_t mmask = dst->modifiers; switch (dst->shift) { case 0: break; case 13: shader_addline(buffer, "_d8"); break; case 14: shader_addline(buffer, "_d4"); break; case 15: shader_addline(buffer, "_d2"); break; case 1: shader_addline(buffer, "_x2"); break; case 2: shader_addline(buffer, "_x4"); break; case 3: shader_addline(buffer, "_x8"); break; default: shader_addline(buffer, "_unhandled_shift(%d)", dst->shift); break; } if (mmask & VKD3DSPDM_SATURATE) shader_addline(buffer, "_sat"); if (mmask & VKD3DSPDM_PARTIALPRECISION) shader_addline(buffer, "_pp"); if (mmask & VKD3DSPDM_MSAMPCENTROID) shader_addline(buffer, "_centroid"); mmask &= ~VKD3DSPDM_MASK; if (mmask) FIXME("Unrecognised modifier %#x.\n", mmask); } static void shader_dump_primitive_type(struct vkd3d_d3d_asm_compiler *compiler, const struct vkd3d_shader_primitive_type *primitive_type) { struct vkd3d_string_buffer *buffer = &compiler->buffer; switch (primitive_type->type) { case VKD3D_PT_UNDEFINED: shader_addline(buffer, "undefined"); break; case VKD3D_PT_POINTLIST: shader_addline(buffer, "pointlist"); break; case VKD3D_PT_LINELIST: shader_addline(buffer, "linelist"); break; case VKD3D_PT_LINESTRIP: shader_addline(buffer, "linestrip"); break; case VKD3D_PT_TRIANGLELIST: shader_addline(buffer, "trianglelist"); break; case VKD3D_PT_TRIANGLESTRIP: shader_addline(buffer, "trianglestrip"); break; case VKD3D_PT_TRIANGLEFAN: shader_addline(buffer, "trianglefan"); break; case VKD3D_PT_LINELIST_ADJ: shader_addline(buffer, "linelist_adj"); break; case VKD3D_PT_LINESTRIP_ADJ: shader_addline(buffer, "linestrip_adj"); break; case VKD3D_PT_TRIANGLELIST_ADJ: shader_addline(buffer, "trianglelist_adj"); break; case VKD3D_PT_TRIANGLESTRIP_ADJ: shader_addline(buffer, "trianglestrip_adj"); break; case VKD3D_PT_PATCH: shader_addline(buffer, "patch%u", primitive_type->patch_vertex_count); break; default: shader_addline(buffer, "", primitive_type->type); break; } } static void shader_dump_interpolation_mode(struct vkd3d_d3d_asm_compiler *compiler, enum vkd3d_shader_interpolation_mode interpolation_mode) { struct vkd3d_string_buffer *buffer = &compiler->buffer; switch (interpolation_mode) { case VKD3DSIM_CONSTANT: shader_addline(buffer, "constant"); break; case VKD3DSIM_LINEAR: shader_addline(buffer, "linear"); break; case VKD3DSIM_LINEAR_CENTROID: shader_addline(buffer, "linear centroid"); break; case VKD3DSIM_LINEAR_NOPERSPECTIVE: shader_addline(buffer, "linear noperspective"); break; case VKD3DSIM_LINEAR_SAMPLE: shader_addline(buffer, "linear sample"); break; case VKD3DSIM_LINEAR_NOPERSPECTIVE_CENTROID: shader_addline(buffer, "linear noperspective centroid"); break; case VKD3DSIM_LINEAR_NOPERSPECTIVE_SAMPLE: shader_addline(buffer, "linear noperspective sample"); break; default: shader_addline(buffer, "", interpolation_mode); break; } } const char *shader_get_type_prefix(enum vkd3d_shader_type type) { switch (type) { case VKD3D_SHADER_TYPE_VERTEX: return "vs"; case VKD3D_SHADER_TYPE_HULL: return "hs"; case VKD3D_SHADER_TYPE_DOMAIN: return "ds"; case VKD3D_SHADER_TYPE_GEOMETRY: return "gs"; case VKD3D_SHADER_TYPE_PIXEL: return "ps"; case VKD3D_SHADER_TYPE_COMPUTE: return "cs"; case VKD3D_SHADER_TYPE_EFFECT: return "fx"; case VKD3D_SHADER_TYPE_TEXTURE: return "tx"; case VKD3D_SHADER_TYPE_LIBRARY: return "lib"; default: FIXME("Unhandled shader type %#x.\n", type); return "unknown"; } } static void shader_dump_instruction_flags(struct vkd3d_d3d_asm_compiler *compiler, const struct vkd3d_shader_instruction *ins) { struct vkd3d_string_buffer *buffer = &compiler->buffer; switch (ins->handler_idx) { case VKD3DSIH_BREAKP: case VKD3DSIH_CONTINUEP: case VKD3DSIH_DISCARD: case VKD3DSIH_IF: case VKD3DSIH_RETP: switch (ins->flags) { case VKD3D_SHADER_CONDITIONAL_OP_NZ: shader_addline(buffer, "_nz"); break; case VKD3D_SHADER_CONDITIONAL_OP_Z: shader_addline(buffer, "_z"); break; default: shader_addline(buffer, "_unrecognized(%#x)", ins->flags); break; } break; case VKD3DSIH_IFC: case VKD3DSIH_BREAKC: switch (ins->flags) { case VKD3D_SHADER_REL_OP_GT: shader_addline(buffer, "_gt"); break; case VKD3D_SHADER_REL_OP_EQ: shader_addline(buffer, "_eq"); break; case VKD3D_SHADER_REL_OP_GE: shader_addline(buffer, "_ge"); break; case VKD3D_SHADER_REL_OP_LT: shader_addline(buffer, "_lt"); break; case VKD3D_SHADER_REL_OP_NE: shader_addline(buffer, "_ne"); break; case VKD3D_SHADER_REL_OP_LE: shader_addline(buffer, "_le"); break; default: shader_addline(buffer, "_(%u)", ins->flags); } break; case VKD3DSIH_RESINFO: switch (ins->flags) { case VKD3DSI_NONE: break; case VKD3DSI_RESINFO_RCP_FLOAT: shader_addline(buffer, "_rcpFloat"); break; case VKD3DSI_RESINFO_UINT: shader_addline(buffer, "_uint"); break; default: shader_addline(buffer, "_unrecognized(%#x)", ins->flags); } break; case VKD3DSIH_SAMPLE_INFO: switch (ins->flags) { case VKD3DSI_NONE: break; case VKD3DSI_SAMPLE_INFO_UINT: shader_addline(buffer, "_uint"); break; default: shader_addline(buffer, "_unrecognized(%#x)", ins->flags); } break; case VKD3DSIH_SYNC: shader_dump_sync_flags(compiler, ins->flags); break; case VKD3DSIH_TEX: if (vkd3d_shader_ver_ge(&compiler->shader_version, 2, 0) && (ins->flags & VKD3DSI_TEXLD_PROJECT)) shader_addline(buffer, "p"); break; case VKD3DSIH_ISHL: case VKD3DSIH_ISHR: case VKD3DSIH_USHR: if (ins->flags & VKD3DSI_SHIFT_UNMASKED) shader_addline(buffer, "_unmasked"); /* fall through */ default: shader_dump_precise_flags(compiler, ins->flags); break; } } static void shader_dump_register_space(struct vkd3d_d3d_asm_compiler *compiler, unsigned int register_space) { if (vkd3d_shader_ver_ge(&compiler->shader_version, 5, 1)) shader_print_uint_literal(compiler, ", space=", register_space, ""); } static void shader_print_opcode(struct vkd3d_d3d_asm_compiler *compiler, enum vkd3d_shader_opcode opcode) { vkd3d_string_buffer_printf(&compiler->buffer, "%s%s%s", compiler->colours.opcode, shader_opcode_names[opcode], compiler->colours.reset); } static void shader_dump_icb(struct vkd3d_d3d_asm_compiler *compiler, const struct vkd3d_shader_immediate_constant_buffer *icb) { struct vkd3d_string_buffer *buffer = &compiler->buffer; unsigned int i, j; vkd3d_string_buffer_printf(buffer, " {\n"); if (icb->component_count == 1) { for (i = 0; i < icb->element_count; ) { for (j = 0; i < icb->element_count && j < 4; ++i, ++j) shader_print_hex_literal(compiler, !j ? " " : ", ", icb->data[i], ""); vkd3d_string_buffer_printf(buffer, "\n"); } } else { assert(icb->component_count == VKD3D_VEC4_SIZE); for (i = 0; i < icb->element_count; ++i) { shader_print_hex_literal(compiler, " {", icb->data[4 * i + 0], ""); shader_print_hex_literal(compiler, ", ", icb->data[4 * i + 1], ""); shader_print_hex_literal(compiler, ", ", icb->data[4 * i + 2], ""); shader_print_hex_literal(compiler, ", ", icb->data[4 * i + 3], "},\n"); } } shader_addline(buffer, "}"); } static void shader_dump_instruction(struct vkd3d_d3d_asm_compiler *compiler, const struct vkd3d_shader_instruction *ins) { struct vkd3d_string_buffer *buffer = &compiler->buffer; unsigned int i; compiler->current = ins; if (ins->predicate) { vkd3d_string_buffer_printf(buffer, "("); shader_dump_src_param(compiler, ins->predicate); vkd3d_string_buffer_printf(buffer, ") "); } /* PixWin marks instructions with the coissue flag with a '+' */ if (ins->coissue) vkd3d_string_buffer_printf(buffer, "+"); shader_print_opcode(compiler, ins->handler_idx); switch (ins->handler_idx) { case VKD3DSIH_DCL: case VKD3DSIH_DCL_UAV_TYPED: vkd3d_string_buffer_printf(buffer, "%s", compiler->colours.opcode); shader_dump_decl_usage(compiler, &ins->declaration.semantic, ins->flags); shader_dump_ins_modifiers(compiler, &ins->declaration.semantic.resource.reg); vkd3d_string_buffer_printf(buffer, "%s ", compiler->colours.reset); shader_dump_register(compiler, &ins->declaration.semantic.resource.reg.reg, true); shader_dump_register_space(compiler, ins->declaration.semantic.resource.range.space); break; case VKD3DSIH_DCL_CONSTANT_BUFFER: vkd3d_string_buffer_printf(buffer, " "); shader_dump_register(compiler, &ins->declaration.cb.src.reg, true); if (vkd3d_shader_ver_ge(&compiler->shader_version, 6, 0)) shader_print_subscript(compiler, ins->declaration.cb.size, NULL); else if (vkd3d_shader_ver_ge(&compiler->shader_version, 5, 1)) shader_print_subscript(compiler, ins->declaration.cb.size / VKD3D_VEC4_SIZE / sizeof(float), NULL); shader_addline(buffer, ", %s", ins->flags & VKD3DSI_INDEXED_DYNAMIC ? "dynamicIndexed" : "immediateIndexed"); shader_dump_register_space(compiler, ins->declaration.cb.range.space); break; case VKD3DSIH_DCL_FUNCTION_BODY: vkd3d_string_buffer_printf(buffer, " fb%u", ins->declaration.index); break; case VKD3DSIH_DCL_FUNCTION_TABLE: vkd3d_string_buffer_printf(buffer, " ft%u = {...}", ins->declaration.index); break; case VKD3DSIH_DCL_GLOBAL_FLAGS: vkd3d_string_buffer_printf(buffer, " "); shader_dump_global_flags(compiler, ins->declaration.global_flags); break; case VKD3DSIH_DCL_HS_MAX_TESSFACTOR: shader_print_float_literal(compiler, " ", ins->declaration.max_tessellation_factor, ""); break; case VKD3DSIH_DCL_IMMEDIATE_CONSTANT_BUFFER: shader_dump_icb(compiler, ins->declaration.icb); break; case VKD3DSIH_DCL_INDEX_RANGE: vkd3d_string_buffer_printf(buffer, " "); shader_dump_dst_param(compiler, &ins->declaration.index_range.dst, true); shader_print_uint_literal(compiler, " ", ins->declaration.index_range.register_count, ""); break; case VKD3DSIH_DCL_INDEXABLE_TEMP: vkd3d_string_buffer_printf(buffer, " %sx%u%s", compiler->colours.reg, ins->declaration.indexable_temp.register_idx, compiler->colours.reset); shader_print_subscript(compiler, ins->declaration.indexable_temp.register_size, NULL); shader_print_uint_literal(compiler, ", ", ins->declaration.indexable_temp.component_count, ""); if (ins->declaration.indexable_temp.alignment) shader_print_uint_literal(compiler, ", align ", ins->declaration.indexable_temp.alignment, ""); if (ins->declaration.indexable_temp.initialiser) shader_dump_icb(compiler, ins->declaration.indexable_temp.initialiser); break; case VKD3DSIH_DCL_INPUT_PS: vkd3d_string_buffer_printf(buffer, " "); shader_dump_interpolation_mode(compiler, ins->flags); shader_addline(buffer, " "); shader_dump_dst_param(compiler, &ins->declaration.dst, true); break; case VKD3DSIH_DCL_INPUT_PS_SGV: case VKD3DSIH_DCL_INPUT_SGV: case VKD3DSIH_DCL_INPUT_SIV: case VKD3DSIH_DCL_OUTPUT_SIV: vkd3d_string_buffer_printf(buffer, " "); shader_dump_dst_param(compiler, &ins->declaration.register_semantic.reg, true); shader_addline(buffer, ", "); shader_dump_shader_input_sysval_semantic(compiler, ins->declaration.register_semantic.sysval_semantic); break; case VKD3DSIH_DCL_INPUT_PS_SIV: vkd3d_string_buffer_printf(buffer, " "); shader_dump_interpolation_mode(compiler, ins->flags); shader_addline(buffer, " "); shader_dump_dst_param(compiler, &ins->declaration.register_semantic.reg, true); shader_addline(buffer, ", "); shader_dump_shader_input_sysval_semantic(compiler, ins->declaration.register_semantic.sysval_semantic); break; case VKD3DSIH_DCL_INPUT: case VKD3DSIH_DCL_OUTPUT: vkd3d_string_buffer_printf(buffer, " "); shader_dump_dst_param(compiler, &ins->declaration.dst, true); break; case VKD3DSIH_DCL_INPUT_PRIMITIVE: case VKD3DSIH_DCL_OUTPUT_TOPOLOGY: vkd3d_string_buffer_printf(buffer, " "); shader_dump_primitive_type(compiler, &ins->declaration.primitive_type); break; case VKD3DSIH_DCL_INTERFACE: vkd3d_string_buffer_printf(buffer, " fp%u", ins->declaration.fp.index); shader_print_subscript(compiler, ins->declaration.fp.array_size, NULL); shader_print_subscript(compiler, ins->declaration.fp.body_count, NULL); vkd3d_string_buffer_printf(buffer, " = {...}"); break; case VKD3DSIH_DCL_RESOURCE_RAW: vkd3d_string_buffer_printf(buffer, " "); shader_dump_dst_param(compiler, &ins->declaration.raw_resource.resource.reg, true); shader_dump_register_space(compiler, ins->declaration.raw_resource.resource.range.space); break; case VKD3DSIH_DCL_RESOURCE_STRUCTURED: vkd3d_string_buffer_printf(buffer, " "); shader_dump_dst_param(compiler, &ins->declaration.structured_resource.resource.reg, true); shader_print_uint_literal(compiler, ", ", ins->declaration.structured_resource.byte_stride, ""); shader_dump_register_space(compiler, ins->declaration.structured_resource.resource.range.space); break; case VKD3DSIH_DCL_SAMPLER: vkd3d_string_buffer_printf(buffer, " "); shader_dump_register(compiler, &ins->declaration.sampler.src.reg, true); if (ins->flags == VKD3DSI_SAMPLER_COMPARISON_MODE) shader_addline(buffer, ", comparisonMode"); shader_dump_register_space(compiler, ins->declaration.sampler.range.space); break; case VKD3DSIH_DCL_TEMPS: case VKD3DSIH_DCL_GS_INSTANCES: case VKD3DSIH_DCL_HS_FORK_PHASE_INSTANCE_COUNT: case VKD3DSIH_DCL_HS_JOIN_PHASE_INSTANCE_COUNT: case VKD3DSIH_DCL_INPUT_CONTROL_POINT_COUNT: case VKD3DSIH_DCL_OUTPUT_CONTROL_POINT_COUNT: case VKD3DSIH_DCL_VERTICES_OUT: shader_print_uint_literal(compiler, " ", ins->declaration.count, ""); break; case VKD3DSIH_DCL_TESSELLATOR_DOMAIN: vkd3d_string_buffer_printf(buffer, " "); shader_dump_tessellator_domain(compiler, ins->declaration.tessellator_domain); break; case VKD3DSIH_DCL_TESSELLATOR_OUTPUT_PRIMITIVE: vkd3d_string_buffer_printf(buffer, " "); shader_dump_tessellator_output_primitive(compiler, ins->declaration.tessellator_output_primitive); break; case VKD3DSIH_DCL_TESSELLATOR_PARTITIONING: vkd3d_string_buffer_printf(buffer, " "); shader_dump_tessellator_partitioning(compiler, ins->declaration.tessellator_partitioning); break; case VKD3DSIH_DCL_TGSM_RAW: vkd3d_string_buffer_printf(buffer, " "); shader_dump_dst_param(compiler, &ins->declaration.tgsm_raw.reg, true); shader_print_uint_literal(compiler, ", ", ins->declaration.tgsm_raw.byte_count, ""); break; case VKD3DSIH_DCL_TGSM_STRUCTURED: vkd3d_string_buffer_printf(buffer, " "); shader_dump_dst_param(compiler, &ins->declaration.tgsm_structured.reg, true); shader_print_uint_literal(compiler, ", ", ins->declaration.tgsm_structured.byte_stride, ""); shader_print_uint_literal(compiler, ", ", ins->declaration.tgsm_structured.structure_count, ""); break; case VKD3DSIH_DCL_THREAD_GROUP: shader_print_uint_literal(compiler, " ", ins->declaration.thread_group_size.x, ""); shader_print_uint_literal(compiler, ", ", ins->declaration.thread_group_size.y, ""); shader_print_uint_literal(compiler, ", ", ins->declaration.thread_group_size.z, ""); break; case VKD3DSIH_DCL_UAV_RAW: shader_dump_uav_flags(compiler, ins->flags); shader_addline(buffer, " "); shader_dump_dst_param(compiler, &ins->declaration.raw_resource.resource.reg, true); shader_dump_register_space(compiler, ins->declaration.raw_resource.resource.range.space); break; case VKD3DSIH_DCL_UAV_STRUCTURED: shader_dump_uav_flags(compiler, ins->flags); shader_addline(buffer, " "); shader_dump_dst_param(compiler, &ins->declaration.structured_resource.resource.reg, true); shader_print_uint_literal(compiler, ", ", ins->declaration.structured_resource.byte_stride, ""); shader_dump_register_space(compiler, ins->declaration.structured_resource.resource.range.space); break; case VKD3DSIH_DEF: vkd3d_string_buffer_printf(buffer, " %sc%u%s", compiler->colours.reg, shader_get_float_offset(ins->dst[0].reg.type, ins->dst[0].reg.idx[0].offset), compiler->colours.reset); shader_print_float_literal(compiler, " = ", ins->src[0].reg.u.immconst_f32[0], ""); shader_print_float_literal(compiler, ", ", ins->src[0].reg.u.immconst_f32[1], ""); shader_print_float_literal(compiler, ", ", ins->src[0].reg.u.immconst_f32[2], ""); shader_print_float_literal(compiler, ", ", ins->src[0].reg.u.immconst_f32[3], ""); break; case VKD3DSIH_DEFI: vkd3d_string_buffer_printf(buffer, " %si%u%s", compiler->colours.reg, ins->dst[0].reg.idx[0].offset, compiler->colours.reset); shader_print_int_literal(compiler, " = ", ins->src[0].reg.u.immconst_u32[0], ""); shader_print_int_literal(compiler, ", ", ins->src[0].reg.u.immconst_u32[1], ""); shader_print_int_literal(compiler, ", ", ins->src[0].reg.u.immconst_u32[2], ""); shader_print_int_literal(compiler, ", ", ins->src[0].reg.u.immconst_u32[3], ""); break; case VKD3DSIH_DEFB: vkd3d_string_buffer_printf(buffer, " %sb%u%s", compiler->colours.reg, ins->dst[0].reg.idx[0].offset, compiler->colours.reset); shader_print_bool_literal(compiler, " = ", ins->src[0].reg.u.immconst_u32[0], ""); break; default: shader_dump_instruction_flags(compiler, ins); if (ins->resource_type != VKD3D_SHADER_RESOURCE_NONE) { shader_addline(buffer, "_indexable("); if (ins->raw) vkd3d_string_buffer_printf(buffer, "raw_"); if (ins->structured) vkd3d_string_buffer_printf(buffer, "structured_"); shader_dump_resource_type(compiler, ins->resource_type); if (ins->resource_stride) shader_print_uint_literal(compiler, ", stride=", ins->resource_stride, ""); shader_addline(buffer, ")"); } if (vkd3d_shader_instruction_has_texel_offset(ins)) { shader_print_int_literal(compiler, "(", ins->texel_offset.u, ""); shader_print_int_literal(compiler, ",", ins->texel_offset.v, ""); shader_print_int_literal(compiler, ",", ins->texel_offset.w, ")"); } if (ins->resource_data_type[0] != VKD3D_DATA_FLOAT || ins->resource_data_type[1] != VKD3D_DATA_FLOAT || ins->resource_data_type[2] != VKD3D_DATA_FLOAT || ins->resource_data_type[3] != VKD3D_DATA_FLOAT) shader_dump_resource_data_type(compiler, ins->resource_data_type); for (i = 0; i < ins->dst_count; ++i) { shader_dump_ins_modifiers(compiler, &ins->dst[i]); shader_addline(buffer, !i ? " " : ", "); shader_dump_dst_param(compiler, &ins->dst[i], false); } /* Other source tokens */ for (i = ins->dst_count; i < (ins->dst_count + ins->src_count); ++i) { shader_addline(buffer, !i ? " " : ", "); shader_dump_src_param(compiler, &ins->src[i - ins->dst_count]); } break; } shader_addline(buffer, "\n"); } static const char *get_sysval_semantic_name(enum vkd3d_shader_sysval_semantic semantic) { switch (semantic) { case VKD3D_SHADER_SV_NONE: return "NONE"; case VKD3D_SHADER_SV_POSITION: return "POS"; case VKD3D_SHADER_SV_CLIP_DISTANCE: return "CLIPDST"; case VKD3D_SHADER_SV_CULL_DISTANCE: return "CULLDST"; case VKD3D_SHADER_SV_RENDER_TARGET_ARRAY_INDEX: return "RTINDEX"; case VKD3D_SHADER_SV_VIEWPORT_ARRAY_INDEX: return "VPINDEX"; case VKD3D_SHADER_SV_VERTEX_ID: return "VERTID"; case VKD3D_SHADER_SV_PRIMITIVE_ID: return "PRIMID"; case VKD3D_SHADER_SV_INSTANCE_ID: return "INSTID"; case VKD3D_SHADER_SV_IS_FRONT_FACE: return "FFACE"; case VKD3D_SHADER_SV_SAMPLE_INDEX: return "SAMPLE"; case VKD3D_SHADER_SV_TESS_FACTOR_QUADEDGE: return "QUADEDGE"; case VKD3D_SHADER_SV_TESS_FACTOR_QUADINT: return "QUADINT"; case VKD3D_SHADER_SV_TESS_FACTOR_TRIEDGE: return "TRIEDGE"; case VKD3D_SHADER_SV_TESS_FACTOR_TRIINT: return "TRIINT"; case VKD3D_SHADER_SV_TESS_FACTOR_LINEDET: return "LINEDET"; case VKD3D_SHADER_SV_TESS_FACTOR_LINEDEN: return "LINEDEN"; case VKD3D_SHADER_SV_TARGET: return "TARGET"; case VKD3D_SHADER_SV_DEPTH: return "DEPTH"; case VKD3D_SHADER_SV_COVERAGE: return "COVERAGE"; case VKD3D_SHADER_SV_DEPTH_GREATER_EQUAL: return "DEPTHGE"; case VKD3D_SHADER_SV_DEPTH_LESS_EQUAL: return "DEPTHLE"; case VKD3D_SHADER_SV_STENCIL_REF: return "STENCILREF"; default: return "??"; } } static const char *get_component_type_name(enum vkd3d_shader_component_type type) { switch (type) { case VKD3D_SHADER_COMPONENT_VOID: return "void"; case VKD3D_SHADER_COMPONENT_UINT: return "uint"; case VKD3D_SHADER_COMPONENT_INT: return "int"; case VKD3D_SHADER_COMPONENT_FLOAT: return "float"; case VKD3D_SHADER_COMPONENT_BOOL: return "bool"; case VKD3D_SHADER_COMPONENT_DOUBLE: return "double"; case VKD3D_SHADER_COMPONENT_UINT64: return "uint64"; default: return "??"; } } static const char *get_minimum_precision_name(enum vkd3d_shader_minimum_precision prec) { switch (prec) { case VKD3D_SHADER_MINIMUM_PRECISION_NONE: return "NONE"; case VKD3D_SHADER_MINIMUM_PRECISION_FLOAT_16: return "FLOAT_16"; case VKD3D_SHADER_MINIMUM_PRECISION_FIXED_8_2: return "FIXED_8_2"; case VKD3D_SHADER_MINIMUM_PRECISION_INT_16: return "INT_16"; case VKD3D_SHADER_MINIMUM_PRECISION_UINT_16: return "UINT_16"; default: return "??"; } } static const char *get_semantic_register_name(enum vkd3d_shader_sysval_semantic semantic) { switch (semantic) { case VKD3D_SHADER_SV_DEPTH: return "oDepth"; case VKD3D_SHADER_SV_DEPTH_GREATER_EQUAL: return "oDepthGE"; case VKD3D_SHADER_SV_DEPTH_LESS_EQUAL: return "oDepthLE"; /* SV_Coverage has name vCoverage when used as an input, * but it doens't appear in the signature in that case. */ case VKD3D_SHADER_SV_COVERAGE: return "oMask"; case VKD3D_SHADER_SV_STENCIL_REF: return "oStencilRef"; default: return "??"; } } static enum vkd3d_result dump_signature(struct vkd3d_d3d_asm_compiler *compiler, const char *name, const char *register_name, const struct shader_signature *signature) { struct vkd3d_string_buffer *buffer = &compiler->buffer; unsigned int i; if (signature->element_count == 0) return VKD3D_OK; vkd3d_string_buffer_printf(buffer, "%s%s%s\n", compiler->colours.opcode, name, compiler->colours.reset); for (i = 0; i < signature->element_count; ++i) { struct signature_element *element = &signature->elements[i]; vkd3d_string_buffer_printf(buffer, "%s.param%s %s", compiler->colours.opcode, compiler->colours.reset, element->semantic_name); if (element->semantic_index != 0) vkd3d_string_buffer_printf(buffer, "%u", element->semantic_index); if (element->register_index != -1) { shader_print_write_mask(compiler, "", element->mask, ""); vkd3d_string_buffer_printf(buffer, ", %s%s%d%s", compiler->colours.reg, register_name, element->register_index, compiler->colours.reset); shader_print_write_mask(compiler, "", element->used_mask, ""); } else { vkd3d_string_buffer_printf(buffer, ", %s%s%s", compiler->colours.reg, get_semantic_register_name(element->sysval_semantic), compiler->colours.reset); } if (!element->component_type && !element->sysval_semantic && !element->min_precision && !element->stream_index) goto done; vkd3d_string_buffer_printf(buffer, ", %s", get_component_type_name(element->component_type)); if (!element->sysval_semantic && !element->min_precision && !element->stream_index) goto done; vkd3d_string_buffer_printf(buffer, ", %s", get_sysval_semantic_name(element->sysval_semantic)); if (!element->min_precision && !element->stream_index) goto done; vkd3d_string_buffer_printf(buffer, ", %s", get_minimum_precision_name(element->min_precision)); if (!element->stream_index) goto done; vkd3d_string_buffer_printf(buffer, ", m%u", element->stream_index); done: vkd3d_string_buffer_printf(buffer, "\n"); } return VKD3D_OK; } static enum vkd3d_result dump_signatures(struct vkd3d_d3d_asm_compiler *compiler, const struct vsir_program *program) { enum vkd3d_result ret; if ((ret = dump_signature(compiler, ".input", program->shader_version.type == VKD3D_SHADER_TYPE_DOMAIN ? "vicp" : "v", &program->input_signature)) < 0) return ret; if ((ret = dump_signature(compiler, ".output", "o", &program->output_signature)) < 0) return ret; if ((ret = dump_signature(compiler, ".patch_constant", program->shader_version.type == VKD3D_SHADER_TYPE_DOMAIN ? "vpc" : "o", &program->patch_constant_signature)) < 0) return ret; vkd3d_string_buffer_printf(&compiler->buffer, "%s.text%s\n", compiler->colours.opcode, compiler->colours.reset); return VKD3D_OK; } enum vkd3d_result d3d_asm_compile(const struct vsir_program *program, const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_code *out, enum vsir_asm_flags flags) { const struct vkd3d_shader_version *shader_version = &program->shader_version; enum vkd3d_shader_compile_option_formatting_flags formatting; struct vkd3d_d3d_asm_compiler compiler = { .flags = flags, }; enum vkd3d_result result = VKD3D_OK; struct vkd3d_string_buffer *buffer; unsigned int indent, i, j; const char *indent_str; static const struct vkd3d_d3d_asm_colours no_colours = { .reset = "", .error = "", .literal = "", .modifier = "", .opcode = "", .reg = "", .swizzle = "", .version = "", .write_mask = "", .label = "", }; static const struct vkd3d_d3d_asm_colours colours = { .reset = "\x1b[m", .error = "\x1b[97;41m", .literal = "\x1b[95m", .modifier = "\x1b[36m", .opcode = "\x1b[96;1m", .reg = "\x1b[96m", .swizzle = "\x1b[93m", .version = "\x1b[36m", .write_mask = "\x1b[93m", .label = "\x1b[91m", }; formatting = VKD3D_SHADER_COMPILE_OPTION_FORMATTING_INDENT | VKD3D_SHADER_COMPILE_OPTION_FORMATTING_HEADER; if (compile_info) { for (i = 0; i < compile_info->option_count; ++i) { const struct vkd3d_shader_compile_option *option = &compile_info->options[i]; if (option->name == VKD3D_SHADER_COMPILE_OPTION_FORMATTING) formatting = option->value; } } if (formatting & VKD3D_SHADER_COMPILE_OPTION_FORMATTING_COLOUR) compiler.colours = colours; else compiler.colours = no_colours; if (formatting & VKD3D_SHADER_COMPILE_OPTION_FORMATTING_INDENT) indent_str = " "; else indent_str = ""; buffer = &compiler.buffer; vkd3d_string_buffer_init(buffer); compiler.shader_version = *shader_version; shader_version = &compiler.shader_version; vkd3d_string_buffer_printf(buffer, "%s%s_%u_%u%s\n", compiler.colours.version, shader_get_type_prefix(shader_version->type), shader_version->major, shader_version->minor, compiler.colours.reset); /* The signatures we emit only make sense for DXBC shaders. D3DBC * doesn't even have an explicit concept of signature. */ if (formatting & VKD3D_SHADER_COMPILE_OPTION_FORMATTING_IO_SIGNATURES && shader_version->major >= 4) { if ((result = dump_signatures(&compiler, program)) < 0) { vkd3d_string_buffer_cleanup(buffer); return result; } } indent = 0; for (i = 0; i < program->instructions.count; ++i) { struct vkd3d_shader_instruction *ins = &program->instructions.elements[i]; switch (ins->handler_idx) { case VKD3DSIH_ELSE: case VKD3DSIH_ENDIF: case VKD3DSIH_ENDLOOP: case VKD3DSIH_ENDSWITCH: if (indent) --indent; break; case VKD3DSIH_LABEL: indent = 0; break; default: break; } for (j = 0; j < indent; ++j) { vkd3d_string_buffer_printf(buffer, "%s", indent_str); } shader_dump_instruction(&compiler, ins); switch (ins->handler_idx) { case VKD3DSIH_ELSE: case VKD3DSIH_IF: case VKD3DSIH_IFC: case VKD3DSIH_LOOP: case VKD3DSIH_SWITCH: case VKD3DSIH_LABEL: ++indent; break; default: break; } } vkd3d_shader_code_from_string_buffer(out, buffer); return result; } void vkd3d_shader_trace(const struct vsir_program *program) { const char *p, *q, *end; struct vkd3d_shader_code code; if (d3d_asm_compile(program, NULL, &code, VSIR_ASM_FLAG_DUMP_TYPES) != VKD3D_OK) return; end = (const char *)code.code + code.size; for (p = code.code; p < end; p = q) { if (!(q = memchr(p, '\n', end - p))) q = end; else ++q; TRACE(" %.*s", (int)(q - p), p); } vkd3d_shader_free_shader_code(&code); }