diff options
Diffstat (limited to '3rdparty/bgfx/src/shader_dxbc.cpp')
-rw-r--r-- | 3rdparty/bgfx/src/shader_dxbc.cpp | 1924 |
1 files changed, 1924 insertions, 0 deletions
diff --git a/3rdparty/bgfx/src/shader_dxbc.cpp b/3rdparty/bgfx/src/shader_dxbc.cpp new file mode 100644 index 00000000000..34e50c14424 --- /dev/null +++ b/3rdparty/bgfx/src/shader_dxbc.cpp @@ -0,0 +1,1924 @@ +/* + * Copyright 2011-2015 Branimir Karadzic. All rights reserved. + * License: http://www.opensource.org/licenses/BSD-2-Clause + */ + +#include "bgfx_p.h" +#include "shader_dxbc.h" + +namespace bgfx +{ + struct DxbcOpcodeInfo + { + uint8_t numOperands; + uint8_t numValues; + }; + + static const DxbcOpcodeInfo s_dxbcOpcodeInfo[] = + { + { 3, 0 }, // ADD + { 3, 0 }, // AND + { 0, 0 }, // BREAK + { 1, 0 }, // BREAKC + { 0, 0 }, // CALL + { 0, 0 }, // CALLC + { 1, 0 }, // CASE + { 0, 0 }, // CONTINUE + { 1, 0 }, // CONTINUEC + { 0, 0 }, // CUT + { 0, 0 }, // DEFAULT + { 2, 0 }, // DERIV_RTX + { 2, 0 }, // DERIV_RTY + { 1, 0 }, // DISCARD + { 3, 0 }, // DIV + { 3, 0 }, // DP2 + { 3, 0 }, // DP3 + { 3, 0 }, // DP4 + { 0, 0 }, // ELSE + { 0, 0 }, // EMIT + { 0, 0 }, // EMITTHENCUT + { 0, 0 }, // ENDIF + { 0, 0 }, // ENDLOOP + { 0, 0 }, // ENDSWITCH + { 3, 0 }, // EQ + { 2, 0 }, // EXP + { 2, 0 }, // FRC + { 2, 0 }, // FTOI + { 2, 0 }, // FTOU + { 3, 0 }, // GE + { 3, 0 }, // IADD + { 1, 0 }, // IF + { 3, 0 }, // IEQ + { 3, 0 }, // IGE + { 3, 0 }, // ILT + { 4, 0 }, // IMAD + { 3, 0 }, // IMAX + { 3, 0 }, // IMIN + { 4, 0 }, // IMUL + { 3, 0 }, // INE + { 2, 0 }, // INEG + { 3, 0 }, // ISHL + { 3, 0 }, // ISHR + { 2, 0 }, // ITOF + { 0, 0 }, // LABEL + { 3, 0 }, // LD + { 4, 0 }, // LD_MS + { 2, 0 }, // LOG + { 0, 0 }, // LOOP + { 3, 0 }, // LT + { 4, 0 }, // MAD + { 3, 0 }, // MIN + { 3, 0 }, // MAX + { 0, 1 }, // CUSTOMDATA + { 2, 0 }, // MOV + { 4, 0 }, // MOVC + { 3, 0 }, // MUL + { 3, 0 }, // NE + { 0, 0 }, // NOP + { 2, 0 }, // NOT + { 3, 0 }, // OR + { 3, 0 }, // RESINFO + { 0, 0 }, // RET + { 1, 0 }, // RETC + { 2, 0 }, // ROUND_NE + { 2, 0 }, // ROUND_NI + { 2, 0 }, // ROUND_PI + { 2, 0 }, // ROUND_Z + { 2, 0 }, // RSQ + { 4, 0 }, // SAMPLE + { 5, 0 }, // SAMPLE_C + { 5, 0 }, // SAMPLE_C_LZ + { 5, 0 }, // SAMPLE_L + { 6, 0 }, // SAMPLE_D + { 5, 0 }, // SAMPLE_B + { 2, 0 }, // SQRT + { 1, 0 }, // SWITCH + { 3, 0 }, // SINCOS + { 3, 0 }, // UDIV + { 3, 0 }, // ULT + { 3, 0 }, // UGE + { 4, 0 }, // UMUL + { 4, 0 }, // UMAD + { 3, 0 }, // UMAX + { 3, 0 }, // UMIN + { 3, 0 }, // USHR + { 2, 0 }, // UTOF + { 3, 0 }, // XOR + { 1, 1 }, // DCL_RESOURCE + { 1, 0 }, // DCL_CONSTANT_BUFFER + { 1, 0 }, // DCL_SAMPLER + { 1, 1 }, // DCL_INDEX_RANGE + { 1, 0 }, // DCL_GS_OUTPUT_PRIMITIVE_TOPOLOGY + { 1, 0 }, // DCL_GS_INPUT_PRIMITIVE + { 0, 1 }, // DCL_MAX_OUTPUT_VERTEX_COUNT + { 1, 0 }, // DCL_INPUT + { 1, 1 }, // DCL_INPUT_SGV + { 1, 0 }, // DCL_INPUT_SIV + { 1, 0 }, // DCL_INPUT_PS + { 1, 1 }, // DCL_INPUT_PS_SGV + { 1, 1 }, // DCL_INPUT_PS_SIV + { 1, 0 }, // DCL_OUTPUT + { 1, 0 }, // DCL_OUTPUT_SGV + { 1, 1 }, // DCL_OUTPUT_SIV + { 0, 1 }, // DCL_TEMPS + { 0, 3 }, // DCL_INDEXABLE_TEMP + { 0, 0 }, // DCL_GLOBAL_FLAGS + + { 0, 0 }, // InstrD3D10 + { 4, 0 }, // LOD + { 4, 0 }, // GATHER4 + { 0, 0 }, // SAMPLE_POS + { 0, 0 }, // SAMPLE_INFO + + { 0, 0 }, // InstrD3D10_1 + { 0, 0 }, // HS_DECLS + { 0, 0 }, // HS_CONTROL_POINT_PHASE + { 0, 0 }, // HS_FORK_PHASE + { 0, 0 }, // HS_JOIN_PHASE + { 0, 0 }, // EMIT_STREAM + { 0, 0 }, // CUT_STREAM + { 1, 0 }, // EMITTHENCUT_STREAM + { 1, 0 }, // INTERFACE_CALL + { 0, 0 }, // BUFINFO + { 2, 0 }, // DERIV_RTX_COARSE + { 2, 0 }, // DERIV_RTX_FINE + { 2, 0 }, // DERIV_RTY_COARSE + { 2, 0 }, // DERIV_RTY_FINE + { 5, 0 }, // GATHER4_C + { 5, 0 }, // GATHER4_PO + { 0, 0 }, // GATHER4_PO_C + { 0, 0 }, // RCP + { 0, 0 }, // F32TOF16 + { 0, 0 }, // F16TOF32 + { 0, 0 }, // UADDC + { 0, 0 }, // USUBB + { 0, 0 }, // COUNTBITS + { 0, 0 }, // FIRSTBIT_HI + { 0, 0 }, // FIRSTBIT_LO + { 0, 0 }, // FIRSTBIT_SHI + { 0, 0 }, // UBFE + { 0, 0 }, // IBFE + { 5, 0 }, // BFI + { 0, 0 }, // BFREV + { 5, 0 }, // SWAPC + { 0, 0 }, // DCL_STREAM + { 1, 0 }, // DCL_FUNCTION_BODY + { 0, 0 }, // DCL_FUNCTION_TABLE + { 0, 0 }, // DCL_INTERFACE + { 0, 0 }, // DCL_INPUT_CONTROL_POINT_COUNT + { 0, 0 }, // DCL_OUTPUT_CONTROL_POINT_COUNT + { 0, 0 }, // DCL_TESS_DOMAIN + { 0, 0 }, // DCL_TESS_PARTITIONING + { 0, 0 }, // DCL_TESS_OUTPUT_PRIMITIVE + { 0, 0 }, // DCL_HS_MAX_TESSFACTOR + { 0, 0 }, // DCL_HS_FORK_PHASE_INSTANCE_COUNT + { 0, 0 }, // DCL_HS_JOIN_PHASE_INSTANCE_COUNT + { 0, 3 }, // DCL_THREAD_GROUP + { 1, 1 }, // DCL_UNORDERED_ACCESS_VIEW_TYPED + { 1, 0 }, // DCL_UNORDERED_ACCESS_VIEW_RAW + { 1, 1 }, // DCL_UNORDERED_ACCESS_VIEW_STRUCTURED + { 1, 1 }, // DCL_THREAD_GROUP_SHARED_MEMORY_RAW + { 1, 2 }, // DCL_THREAD_GROUP_SHARED_MEMORY_STRUCTURED + { 1, 0 }, // DCL_RESOURCE_RAW + { 1, 1 }, // DCL_RESOURCE_STRUCTURED + { 3, 0 }, // LD_UAV_TYPED + { 3, 0 }, // STORE_UAV_TYPED + { 3, 0 }, // LD_RAW + { 3, 0 }, // STORE_RAW + { 4, 0 }, // LD_STRUCTURED + { 4, 0 }, // STORE_STRUCTURED + { 3, 0 }, // ATOMIC_AND + { 3, 0 }, // ATOMIC_OR + { 3, 0 }, // ATOMIC_XOR + { 3, 0 }, // ATOMIC_CMP_STORE + { 3, 0 }, // ATOMIC_IADD + { 3, 0 }, // ATOMIC_IMAX + { 3, 0 }, // ATOMIC_IMIN + { 3, 0 }, // ATOMIC_UMAX + { 3, 0 }, // ATOMIC_UMIN + { 2, 0 }, // IMM_ATOMIC_ALLOC + { 2, 0 }, // IMM_ATOMIC_CONSUME + { 0, 0 }, // IMM_ATOMIC_IADD + { 0, 0 }, // IMM_ATOMIC_AND + { 0, 0 }, // IMM_ATOMIC_OR + { 0, 0 }, // IMM_ATOMIC_XOR + { 0, 0 }, // IMM_ATOMIC_EXCH + { 0, 0 }, // IMM_ATOMIC_CMP_EXCH + { 0, 0 }, // IMM_ATOMIC_IMAX + { 0, 0 }, // IMM_ATOMIC_IMIN + { 0, 0 }, // IMM_ATOMIC_UMAX + { 0, 0 }, // IMM_ATOMIC_UMIN + { 0, 0 }, // SYNC + { 3, 0 }, // DADD + { 3, 0 }, // DMAX + { 3, 0 }, // DMIN + { 3, 0 }, // DMUL + { 3, 0 }, // DEQ + { 3, 0 }, // DGE + { 3, 0 }, // DLT + { 3, 0 }, // DNE + { 2, 0 }, // DMOV + { 4, 0 }, // DMOVC + { 0, 0 }, // DTOF + { 0, 0 }, // FTOD + { 3, 0 }, // EVAL_SNAPPED + { 3, 0 }, // EVAL_SAMPLE_INDEX + { 2, 0 }, // EVAL_CENTROID + { 0, 1 }, // DCL_GS_INSTANCE_COUNT + { 0, 0 }, // ABORT + { 0, 0 }, // DEBUG_BREAK + + { 0, 0 }, // InstrD3D11 + { 0, 0 }, // DDIV + { 0, 0 }, // DFMA + { 0, 0 }, // DRCP + { 0, 0 }, // MSAD + { 0, 0 }, // DTOI + { 0, 0 }, // DTOU + { 0, 0 }, // ITOD + { 0, 0 }, // UTOD + }; + BX_STATIC_ASSERT(BX_COUNTOF(s_dxbcOpcodeInfo) == DxbcOpcode::Count); + + static const char* s_dxbcOpcode[] = + { + "add", + "and", + "break", + "breakc", + "call", + "callc", + "case", + "continue", + "continuec", + "cut", + "default", + "deriv_rtx", + "deriv_rty", + "discard", + "div", + "dp2", + "dp3", + "dp4", + "else", + "emit", + "emitthencut", + "endif", + "endloop", + "endswitch", + "eq", + "exp", + "frc", + "ftoi", + "ftou", + "ge", + "iadd", + "if", + "ieq", + "ige", + "ilt", + "imad", + "imax", + "imin", + "imul", + "ine", + "ineg", + "ishl", + "ishr", + "itof", + "label", + "ld", + "ld_ms", + "log", + "loop", + "lt", + "mad", + "min", + "max", + "customdata", + "mov", + "movc", + "mul", + "ne", + "nop", + "not", + "or", + "resinfo", + "ret", + "retc", + "round_ne", + "round_ni", + "round_pi", + "round_z", + "rsq", + "sample", + "sample_c", + "sample_c_lz", + "sample_l", + "sample_d", + "sample_b", + "sqrt", + "switch", + "sincos", + "udiv", + "ult", + "uge", + "umul", + "umad", + "umax", + "umin", + "ushr", + "utof", + "xor", + "dcl_resource", + "dcl_constantbuffer", + "dcl_sampler", + "dcl_index_range", + "dcl_gs_output_primitive_topology", + "dcl_gs_input_primitive", + "dcl_max_output_vertex_count", + "dcl_input", + "dcl_input_sgv", + "dcl_input_siv", + "dcl_input_ps", + "dcl_input_ps_sgv", + "dcl_input_ps_siv", + "dcl_output", + "dcl_output_sgv", + "dcl_output_siv", + "dcl_temps", + "dcl_indexable_temp", + "dcl_global_flags", + + NULL, + "lod", + "gather4", + "sample_pos", + "sample_info", + + NULL, + "hs_decls", + "hs_control_point_phase", + "hs_fork_phase", + "hs_join_phase", + "emit_stream", + "cut_stream", + "emitthencut_stream", + "interface_call", + "bufinfo", + "deriv_rtx_coarse", + "deriv_rtx_fine", + "deriv_rty_coarse", + "deriv_rty_fine", + "gather4_c", + "gather4_po", + "gather4_po_c", + "rcp", + "f32tof16", + "f16tof32", + "uaddc", + "usubb", + "countbits", + "firstbit_hi", + "firstbit_lo", + "firstbit_shi", + "ubfe", + "ibfe", + "bfi", + "bfrev", + "swapc", + "dcl_stream", + "dcl_function_body", + "dcl_function_table", + "dcl_interface", + "dcl_input_control_point_count", + "dcl_output_control_point_count", + "dcl_tess_domain", + "dcl_tess_partitioning", + "dcl_tess_output_primitive", + "dcl_hs_max_tessfactor", + "dcl_hs_fork_phase_instance_count", + "dcl_hs_join_phase_instance_count", + "dcl_thread_group", + "dcl_unordered_access_view_typed", + "dcl_unordered_access_view_raw", + "dcl_unordered_access_view_structured", + "dcl_thread_group_shared_memory_raw", + "dcl_thread_group_shared_memory_structured", + "dcl_resource_raw", + "dcl_resource_structured", + "ld_uav_typed", + "store_uav_typed", + "ld_raw", + "store_raw", + "ld_structured", + "store_structured", + "atomic_and", + "atomic_or", + "atomic_xor", + "atomic_cmp_store", + "atomic_iadd", + "atomic_imax", + "atomic_imin", + "atomic_umax", + "atomic_umin", + "imm_atomic_alloc", + "imm_atomic_consume", + "imm_atomic_iadd", + "imm_atomic_and", + "imm_atomic_or", + "imm_atomic_xor", + "imm_atomic_exch", + "imm_atomic_cmp_exch", + "imm_atomic_imax", + "imm_atomic_imin", + "imm_atomic_umax", + "imm_atomic_umin", + "sync", + "dadd", + "dmax", + "dmin", + "dmul", + "deq", + "dge", + "dlt", + "dne", + "dmov", + "dmovc", + "dtof", + "ftod", + "eval_snapped", + "eval_sample_index", + "eval_centroid", + "dcl_gs_instance_count", + "abort", + "debug_break", + + NULL, + "ddiv", + "dfma", + "drcp", + "msad", + "dtoi", + "dtou", + "itod", + "utod", + }; + BX_STATIC_ASSERT(BX_COUNTOF(s_dxbcOpcode) == DxbcOpcode::Count); + + const char* getName(DxbcOpcode::Enum _opcode) + { + BX_CHECK(_opcode < DxbcOpcode::Count, "Unknown opcode id %d.", _opcode); + return s_dxbcOpcode[_opcode]; + } + + static const char* s_dxbcSrvType[] = + { + "", // Unknown + "Buffer", // Buffer + "Texture1D", // Texture1D + "Texture2D", // Texture2D + "Texture2DMS", // Texture2DMS + "Texture3D", // Texture3D + "TextureCube", // TextureCube + "Texture1DArray", // Texture1DArray + "Texture2DArray", // Texture2DArray + "Texture2DMSArray", // Texture2DMSArray + "TextureCubearray", // TextureCubearray + "RawBuffer", // RawBuffer + "StructuredBuffer", // StructuredBuffer + }; + BX_STATIC_ASSERT(BX_COUNTOF(s_dxbcSrvType) == DxbcResourceDim::Count); + + const char* s_dxbcInterpolationName[] = + { + "", + "constant", + "linear", + "linear centroid", + "linear noperspective", + "linear noperspective centroid", + "linear sample", + "linear noperspective sample", + }; + BX_STATIC_ASSERT(BX_COUNTOF(s_dxbcInterpolationName) == DxbcInterpolation::Count); + + // mesa/src/gallium/state_trackers/d3d1x/d3d1xshader/defs/shortfiles.txt + static const char* s_dxbcOperandType[] = + { + "r", // Temp + "v", // Input + "o", // Output + "x", // TempArray + "l", // Imm32 + "d", // Imm64 + "s", // Sampler + "t", // Resource + "cb", // ConstantBuffer + "icb", // ImmConstantBuffer + "label", // Label + "vPrim", // PrimitiveID + "oDepth", // OutputDepth + "null", // Null + "rasterizer", // Rasterizer + "oMask", // CoverageMask + "stream", // Stream + "function_body", // FunctionBody + "function_table", // FunctionTable + "interface", // Interface + "function_input", // FunctionInput + "function_output", // FunctionOutput + "vOutputControlPointID", // OutputControlPointId + "vForkInstanceID", // InputForkInstanceId + "vJoinInstanceID", // InputJoinInstanceId + "vicp", // InputControlPoint + "vocp", // OutputControlPoint + "vpc", // InputPatchConstant + "vDomain", // InputDomainPoint + "this", // ThisPointer + "u", // UnorderedAccessView + "g", // ThreadGroupSharedMemory + "vThreadID", // InputThreadId + "vThreadGrouID", // InputThreadGroupId + "vThreadIDInGroup", // InputThreadIdInGroup + "vCoverage", // InputCoverageMask + "vThreadIDInGroupFlattened", // InputThreadIdInGroupFlattened + "vGSInstanceID", // InputGsInstanceId + "oDepthGE", // OutputDepthGreaterEqual + "oDepthLE", // OutputDepthLessEqual + "vCycleCounter", // CycleCounter + }; + BX_STATIC_ASSERT(BX_COUNTOF(s_dxbcOperandType) == DxbcOperandType::Count); + +#define DXBC_MAX_NAME_STRING 512 + + int32_t readString(bx::ReaderSeekerI* _reader, int64_t _offset, char* _out, uint32_t _max = DXBC_MAX_NAME_STRING) + { + int64_t oldOffset = bx::seek(_reader); + bx::seek(_reader, _offset, bx::Whence::Begin); + + int32_t size = 0; + + for (uint32_t ii = 0; ii < _max-1; ++ii) + { + char ch; + size += bx::read(_reader, ch); + *_out++ = ch; + + if ('\0' == ch) + { + break; + } + } + *_out = '\0'; + + bx::seek(_reader, oldOffset, bx::Whence::Begin); + + return size; + } + + inline uint32_t dxbcMixF(uint32_t _b, uint32_t _c, uint32_t _d) + { + const uint32_t tmp0 = bx::uint32_xor(_c, _d); + const uint32_t tmp1 = bx::uint32_and(_b, tmp0); + const uint32_t result = bx::uint32_xor(_d, tmp1); + + return result; + } + + inline uint32_t dxbcMixG(uint32_t _b, uint32_t _c, uint32_t _d) + { + return dxbcMixF(_d, _b, _c); + } + + inline uint32_t dxbcMixH(uint32_t _b, uint32_t _c, uint32_t _d) + { + const uint32_t tmp0 = bx::uint32_xor(_b, _c); + const uint32_t result = bx::uint32_xor(_d, tmp0); + + return result; + } + + inline uint32_t dxbcMixI(uint32_t _b, uint32_t _c, uint32_t _d) + { + const uint32_t tmp0 = bx::uint32_orc(_b, _d); + const uint32_t result = bx::uint32_xor(_c, tmp0); + + return result; + } + + void dxbcHashBlock(const uint32_t* data, uint32_t* hash) + { + const uint32_t d0 = data[ 0]; + const uint32_t d1 = data[ 1]; + const uint32_t d2 = data[ 2]; + const uint32_t d3 = data[ 3]; + const uint32_t d4 = data[ 4]; + const uint32_t d5 = data[ 5]; + const uint32_t d6 = data[ 6]; + const uint32_t d7 = data[ 7]; + const uint32_t d8 = data[ 8]; + const uint32_t d9 = data[ 9]; + const uint32_t d10 = data[10]; + const uint32_t d11 = data[11]; + const uint32_t d12 = data[12]; + const uint32_t d13 = data[13]; + const uint32_t d14 = data[14]; + const uint32_t d15 = data[15]; + + uint32_t aa = hash[0]; + uint32_t bb = hash[1]; + uint32_t cc = hash[2]; + uint32_t dd = hash[3]; + + aa = bb + bx::uint32_rol(aa + dxbcMixF(bb, cc, dd) + d0 + 0xd76aa478, 7); + dd = aa + bx::uint32_rol(dd + dxbcMixF(aa, bb, cc) + d1 + 0xe8c7b756, 12); + cc = dd + bx::uint32_ror(cc + dxbcMixF(dd, aa, bb) + d2 + 0x242070db, 15); + bb = cc + bx::uint32_ror(bb + dxbcMixF(cc, dd, aa) + d3 + 0xc1bdceee, 10); + aa = bb + bx::uint32_rol(aa + dxbcMixF(bb, cc, dd) + d4 + 0xf57c0faf, 7); + dd = aa + bx::uint32_rol(dd + dxbcMixF(aa, bb, cc) + d5 + 0x4787c62a, 12); + cc = dd + bx::uint32_ror(cc + dxbcMixF(dd, aa, bb) + d6 + 0xa8304613, 15); + bb = cc + bx::uint32_ror(bb + dxbcMixF(cc, dd, aa) + d7 + 0xfd469501, 10); + aa = bb + bx::uint32_rol(aa + dxbcMixF(bb, cc, dd) + d8 + 0x698098d8, 7); + dd = aa + bx::uint32_rol(dd + dxbcMixF(aa, bb, cc) + d9 + 0x8b44f7af, 12); + cc = dd + bx::uint32_ror(cc + dxbcMixF(dd, aa, bb) + d10 + 0xffff5bb1, 15); + bb = cc + bx::uint32_ror(bb + dxbcMixF(cc, dd, aa) + d11 + 0x895cd7be, 10); + aa = bb + bx::uint32_rol(aa + dxbcMixF(bb, cc, dd) + d12 + 0x6b901122, 7); + dd = aa + bx::uint32_rol(dd + dxbcMixF(aa, bb, cc) + d13 + 0xfd987193, 12); + cc = dd + bx::uint32_ror(cc + dxbcMixF(dd, aa, bb) + d14 + 0xa679438e, 15); + bb = cc + bx::uint32_ror(bb + dxbcMixF(cc, dd, aa) + d15 + 0x49b40821, 10); + + aa = bb + bx::uint32_rol(aa + dxbcMixG(bb, cc, dd) + d1 + 0xf61e2562, 5); + dd = aa + bx::uint32_rol(dd + dxbcMixG(aa, bb, cc) + d6 + 0xc040b340, 9); + cc = dd + bx::uint32_rol(cc + dxbcMixG(dd, aa, bb) + d11 + 0x265e5a51, 14); + bb = cc + bx::uint32_ror(bb + dxbcMixG(cc, dd, aa) + d0 + 0xe9b6c7aa, 12); + aa = bb + bx::uint32_rol(aa + dxbcMixG(bb, cc, dd) + d5 + 0xd62f105d, 5); + dd = aa + bx::uint32_rol(dd + dxbcMixG(aa, bb, cc) + d10 + 0x02441453, 9); + cc = dd + bx::uint32_rol(cc + dxbcMixG(dd, aa, bb) + d15 + 0xd8a1e681, 14); + bb = cc + bx::uint32_ror(bb + dxbcMixG(cc, dd, aa) + d4 + 0xe7d3fbc8, 12); + aa = bb + bx::uint32_rol(aa + dxbcMixG(bb, cc, dd) + d9 + 0x21e1cde6, 5); + dd = aa + bx::uint32_rol(dd + dxbcMixG(aa, bb, cc) + d14 + 0xc33707d6, 9); + cc = dd + bx::uint32_rol(cc + dxbcMixG(dd, aa, bb) + d3 + 0xf4d50d87, 14); + bb = cc + bx::uint32_ror(bb + dxbcMixG(cc, dd, aa) + d8 + 0x455a14ed, 12); + aa = bb + bx::uint32_rol(aa + dxbcMixG(bb, cc, dd) + d13 + 0xa9e3e905, 5); + dd = aa + bx::uint32_rol(dd + dxbcMixG(aa, bb, cc) + d2 + 0xfcefa3f8, 9); + cc = dd + bx::uint32_rol(cc + dxbcMixG(dd, aa, bb) + d7 + 0x676f02d9, 14); + bb = cc + bx::uint32_ror(bb + dxbcMixG(cc, dd, aa) + d12 + 0x8d2a4c8a, 12); + + aa = bb + bx::uint32_rol(aa + dxbcMixH(bb, cc, dd) + d5 + 0xfffa3942, 4); + dd = aa + bx::uint32_rol(dd + dxbcMixH(aa, bb, cc) + d8 + 0x8771f681, 11); + cc = dd + bx::uint32_rol(cc + dxbcMixH(dd, aa, bb) + d11 + 0x6d9d6122, 16); + bb = cc + bx::uint32_ror(bb + dxbcMixH(cc, dd, aa) + d14 + 0xfde5380c, 9); + aa = bb + bx::uint32_rol(aa + dxbcMixH(bb, cc, dd) + d1 + 0xa4beea44, 4); + dd = aa + bx::uint32_rol(dd + dxbcMixH(aa, bb, cc) + d4 + 0x4bdecfa9, 11); + cc = dd + bx::uint32_rol(cc + dxbcMixH(dd, aa, bb) + d7 + 0xf6bb4b60, 16); + bb = cc + bx::uint32_ror(bb + dxbcMixH(cc, dd, aa) + d10 + 0xbebfbc70, 9); + aa = bb + bx::uint32_rol(aa + dxbcMixH(bb, cc, dd) + d13 + 0x289b7ec6, 4); + dd = aa + bx::uint32_rol(dd + dxbcMixH(aa, bb, cc) + d0 + 0xeaa127fa, 11); + cc = dd + bx::uint32_rol(cc + dxbcMixH(dd, aa, bb) + d3 + 0xd4ef3085, 16); + bb = cc + bx::uint32_ror(bb + dxbcMixH(cc, dd, aa) + d6 + 0x04881d05, 9); + aa = bb + bx::uint32_rol(aa + dxbcMixH(bb, cc, dd) + d9 + 0xd9d4d039, 4); + dd = aa + bx::uint32_rol(dd + dxbcMixH(aa, bb, cc) + d12 + 0xe6db99e5, 11); + cc = dd + bx::uint32_rol(cc + dxbcMixH(dd, aa, bb) + d15 + 0x1fa27cf8, 16); + bb = cc + bx::uint32_ror(bb + dxbcMixH(cc, dd, aa) + d2 + 0xc4ac5665, 9); + + aa = bb + bx::uint32_rol(aa + dxbcMixI(bb, cc, dd) + d0 + 0xf4292244, 6); + dd = aa + bx::uint32_rol(dd + dxbcMixI(aa, bb, cc) + d7 + 0x432aff97, 10); + cc = dd + bx::uint32_rol(cc + dxbcMixI(dd, aa, bb) + d14 + 0xab9423a7, 15); + bb = cc + bx::uint32_ror(bb + dxbcMixI(cc, dd, aa) + d5 + 0xfc93a039, 11); + aa = bb + bx::uint32_rol(aa + dxbcMixI(bb, cc, dd) + d12 + 0x655b59c3, 6); + dd = aa + bx::uint32_rol(dd + dxbcMixI(aa, bb, cc) + d3 + 0x8f0ccc92, 10); + cc = dd + bx::uint32_rol(cc + dxbcMixI(dd, aa, bb) + d10 + 0xffeff47d, 15); + bb = cc + bx::uint32_ror(bb + dxbcMixI(cc, dd, aa) + d1 + 0x85845dd1, 11); + aa = bb + bx::uint32_rol(aa + dxbcMixI(bb, cc, dd) + d8 + 0x6fa87e4f, 6); + dd = aa + bx::uint32_rol(dd + dxbcMixI(aa, bb, cc) + d15 + 0xfe2ce6e0, 10); + cc = dd + bx::uint32_rol(cc + dxbcMixI(dd, aa, bb) + d6 + 0xa3014314, 15); + bb = cc + bx::uint32_ror(bb + dxbcMixI(cc, dd, aa) + d13 + 0x4e0811a1, 11); + aa = bb + bx::uint32_rol(aa + dxbcMixI(bb, cc, dd) + d4 + 0xf7537e82, 6); + dd = aa + bx::uint32_rol(dd + dxbcMixI(aa, bb, cc) + d11 + 0xbd3af235, 10); + cc = dd + bx::uint32_rol(cc + dxbcMixI(dd, aa, bb) + d2 + 0x2ad7d2bb, 15); + bb = cc + bx::uint32_ror(bb + dxbcMixI(cc, dd, aa) + d9 + 0xeb86d391, 11); + + hash[0] += aa; + hash[1] += bb; + hash[2] += cc; + hash[3] += dd; + } + + // dxbc hash function is slightly modified version of MD5 hash. + // https://tools.ietf.org/html/rfc1321 + // http://www.efgh.com/software/md5.txt + // + // Assumption is that data pointer, size are both 4-byte aligned, + // and little endian. + // + void dxbcHash(const void* _data, uint32_t _size, void* _digest) + { + uint32_t hash[4] = + { + 0x67452301, + 0xefcdab89, + 0x98badcfe, + 0x10325476, + }; + + const uint32_t* data = (const uint32_t*)_data; + for (uint32_t ii = 0, num = _size/64; ii < num; ++ii) + { + dxbcHashBlock(data, hash); + data += 16; + } + + uint32_t last[16]; + memset(last, 0, sizeof(last) ); + + const uint32_t remaining = _size & 0x3f; + + if (remaining >= 56) + { + memcpy(&last[0], data, remaining); + last[remaining/4] = 0x80; + dxbcHashBlock(last, hash); + + memset(&last[1], 0, 56); + } + else + { + memcpy(&last[1], data, remaining); + last[1 + remaining/4] = 0x80; + } + + last[ 0] = _size * 8; + last[15] = _size * 2 + 1; + dxbcHashBlock(last, hash); + + memcpy(_digest, hash, 16); + } + + int32_t read(bx::ReaderI* _reader, DxbcSubOperand& _subOperand) + { + uint32_t token; + int32_t size = 0; + + // 0 1 2 3 + // 76543210765432107654321076543210 + // e222111000nnttttttttssssssssmmoo + // ^^ ^ ^ ^ ^ ^ ^ ^-- number of operands + // || | | | | | +---- operand mode + // || | | | | +------------ operand mode bits + // || | | | +-------------------- type + // || | | +---------------------- number of addressing modes + // || | +------------------------- addressing mode 0 + // || +---------------------------- addressing mode 1 + // |+------------------------------- addressing mode 2 + // +-------------------------------- extended + + size += bx::read(_reader, token); + _subOperand.type = DxbcOperandType::Enum( (token & UINT32_C(0x000ff000) ) >> 12); + _subOperand.numAddrModes = uint8_t( (token & UINT32_C(0x00300000) ) >> 20); + _subOperand.addrMode = uint8_t( (token & UINT32_C(0x01c00000) ) >> 22); + _subOperand.mode = DxbcOperandMode::Enum( (token & UINT32_C(0x0000000c) ) >> 2); + _subOperand.modeBits = uint8_t( (token & UINT32_C(0x00000ff0) ) >> 4) & "\x0f\xff\x03\x00"[_subOperand.mode]; + _subOperand.num = uint8_t( (token & UINT32_C(0x00000003) ) ); + + switch (_subOperand.addrMode) + { + case DxbcOperandAddrMode::Imm32: + size += bx::read(_reader, _subOperand.regIndex); + break; + + case DxbcOperandAddrMode::Reg: + { + DxbcSubOperand subOperand; + size += read(_reader, subOperand); + } + break; + + case DxbcOperandAddrMode::RegImm32: + { + size += bx::read(_reader, _subOperand.regIndex); + + DxbcSubOperand subOperand; + size += read(_reader, subOperand); + } + break; + + case DxbcOperandAddrMode::RegImm64: + { + size += bx::read(_reader, _subOperand.regIndex); + size += bx::read(_reader, _subOperand.regIndex); + + DxbcSubOperand subOperand; + size += read(_reader, subOperand); + } + break; + + default: + BX_CHECK(false, "sub operand addressing mode %d", _subOperand.addrMode); + break; + } + + return size; + } + + int32_t write(bx::WriterI* _writer, const DxbcSubOperand& _subOperand) + { + int32_t size = 0; + + uint32_t token = 0; + token |= (_subOperand.type << 12) & UINT32_C(0x000ff000); + token |= (_subOperand.numAddrModes << 20) & UINT32_C(0x00300000); + token |= (_subOperand.addrMode << 22) & UINT32_C(0x01c00000); + token |= (_subOperand.mode << 2) & UINT32_C(0x0000000c); + token |= (_subOperand.modeBits << 4) & UINT32_C(0x00000ff0); + token |= _subOperand.num & UINT32_C(0x00000003); + size += bx::write(_writer, token); + + switch (_subOperand.addrMode) + { + case DxbcOperandAddrMode::Imm32: + size += bx::write(_writer, _subOperand.regIndex); + break; + + case DxbcOperandAddrMode::Reg: + { + DxbcSubOperand subOperand; + size += write(_writer, subOperand); + } + break; + + case DxbcOperandAddrMode::RegImm32: + { + size += bx::write(_writer, _subOperand.regIndex); + + DxbcSubOperand subOperand; + size += write(_writer, subOperand); + } + break; + + case DxbcOperandAddrMode::RegImm64: + { + size += bx::write(_writer, _subOperand.regIndex); + size += bx::write(_writer, _subOperand.regIndex); + + DxbcSubOperand subOperand; + size += write(_writer, subOperand); + } + break; + + default: + BX_CHECK(false, "sub operand addressing mode %d", _subOperand.addrMode); + break; + } + + return size; + } + + int32_t read(bx::ReaderI* _reader, DxbcOperand& _operand) + { + int32_t size = 0; + + uint32_t token; + size += bx::read(_reader, token); + + // 0 1 2 3 + // 76543210765432107654321076543210 + // e222111000nnttttttttssssssssmmoo + // ^^ ^ ^ ^ ^ ^ ^ ^-- number of operands + // || | | | | | +---- operand mode + // || | | | | +------------ operand mode bits + // || | | | +-------------------- type + // || | | +---------------------- number of addressing modes + // || | +------------------------- addressing mode 0 + // || +---------------------------- addressing mode 1 + // |+------------------------------- addressing mode 2 + // +-------------------------------- extended + + _operand.extended = 0 != (token & UINT32_C(0x80000000) ); + _operand.numAddrModes = uint8_t( (token & UINT32_C(0x00300000) ) >> 20); + _operand.addrMode[0] = uint8_t( (token & UINT32_C(0x01c00000) ) >> 22); + _operand.addrMode[1] = uint8_t( (token & UINT32_C(0x0e000000) ) >> 25); + _operand.addrMode[2] = uint8_t( (token & UINT32_C(0x70000000) ) >> 28); + _operand.type = DxbcOperandType::Enum( (token & UINT32_C(0x000ff000) ) >> 12); + _operand.mode = DxbcOperandMode::Enum( (token & UINT32_C(0x0000000c) ) >> 2); + _operand.modeBits = uint8_t( (token & UINT32_C(0x00000ff0) ) >> 4) & "\x0f\xff\x03\x00"[_operand.mode]; + _operand.num = uint8_t( (token & UINT32_C(0x00000003) ) ); + + if (_operand.extended) + { + size += bx::read(_reader, _operand.extBits); + } + + switch (_operand.type) + { + case DxbcOperandType::Imm32: + _operand.num = 2 == _operand.num ? 4 : _operand.num; + for (uint32_t ii = 0; ii < _operand.num; ++ii) + { + size += bx::read(_reader, _operand.un.imm32[ii]); + } + break; + + case DxbcOperandType::Imm64: + _operand.num = 2 == _operand.num ? 4 : _operand.num; + for (uint32_t ii = 0; ii < _operand.num; ++ii) + { + size += bx::read(_reader, _operand.un.imm64[ii]); + } + break; + + default: + break; + } + + for (uint32_t ii = 0; ii < _operand.numAddrModes; ++ii) + { + switch (_operand.addrMode[ii]) + { + case DxbcOperandAddrMode::Imm32: + size += bx::read(_reader, _operand.regIndex[ii]); + break; + + case DxbcOperandAddrMode::Reg: + size += read(_reader, _operand.subOperand[ii]); + break; + + case DxbcOperandAddrMode::RegImm32: + size += bx::read(_reader, _operand.regIndex[ii]); + size += read(_reader, _operand.subOperand[ii]); + break; + + default: + BX_CHECK(false, "operand %d addressing mode %d", ii, _operand.addrMode[ii]); + break; + } + } + + return size; + } + + int32_t write(bx::WriterI* _writer, const DxbcOperand& _operand) + { + int32_t size = 0; + + uint32_t token = 0; + token |= _operand.extended ? UINT32_C(0x80000000) : 0; + token |= (_operand.numAddrModes << 20) & UINT32_C(0x00300000); + token |= (_operand.addrMode[0] << 22) & UINT32_C(0x01c00000); + token |= (_operand.addrMode[1] << 25) & UINT32_C(0x0e000000); + token |= (_operand.addrMode[2] << 28) & UINT32_C(0x70000000); + token |= (_operand.type << 12) & UINT32_C(0x000ff000); + token |= (_operand.mode << 2) & UINT32_C(0x0000000c); + + token |= (4 == _operand.num ? 2 : _operand.num) & UINT32_C(0x00000003); + token |= ( (_operand.modeBits & "\x0f\xff\x03\x00"[_operand.mode]) << 4) & UINT32_C(0x00000ff0); + + size += bx::write(_writer, token); + + if (_operand.extended) + { + size += bx::write(_writer, _operand.extBits); + } + + switch (_operand.type) + { + case DxbcOperandType::Imm32: + for (uint32_t ii = 0; ii < _operand.num; ++ii) + { + size += bx::write(_writer, _operand.un.imm32[ii]); + } + break; + + case DxbcOperandType::Imm64: + for (uint32_t ii = 0; ii < _operand.num; ++ii) + { + size += bx::write(_writer, _operand.un.imm64[ii]); + } + break; + + default: + break; + } + + for (uint32_t ii = 0; ii < _operand.numAddrModes; ++ii) + { + switch (_operand.addrMode[ii]) + { + case DxbcOperandAddrMode::Imm32: + size += bx::write(_writer, _operand.regIndex[ii]); + break; + + case DxbcOperandAddrMode::Reg: + size += write(_writer, _operand.subOperand[ii]); + break; + + case DxbcOperandAddrMode::RegImm32: + size += bx::write(_writer, _operand.regIndex[ii]); + size += write(_writer, _operand.subOperand[ii]); + break; + + default: + BX_CHECK(false, "operand %d addressing mode %d", ii, _operand.addrMode[ii]); + break; + } + } + + return size; + } + + int32_t read(bx::ReaderI* _reader, DxbcInstruction& _instruction) + { + uint32_t size = 0; + + uint32_t token; + size += bx::read(_reader, token); + + // 0 1 2 3 + // 76543210765432107654321076543210 + // elllllll.............ooooooooooo + // ^^ ^----------- opcode + // |+------------------------------- length + // +-------------------------------- extended + + _instruction.opcode = DxbcOpcode::Enum( (token & UINT32_C(0x000007ff) ) ); + _instruction.length = uint8_t( (token & UINT32_C(0x7f000000) ) >> 24); + bool extended = 0 != (token & UINT32_C(0x80000000) ); + + _instruction.srv = DxbcResourceDim::Unknown; + _instruction.samples = 0; + + _instruction.shadow = false; + _instruction.mono = false; + + _instruction.allowRefactoring = false; + _instruction.fp64 = false; + _instruction.earlyDepth = false; + _instruction.enableBuffers = false; + _instruction.skipOptimization = false; + _instruction.enableMinPrecision = false; + _instruction.enableDoubleExtensions = false; + _instruction.enableShaderExtensions = false; + + _instruction.threadsInGroup = false; + _instruction.sharedMemory = false; + _instruction.uavGroup = false; + _instruction.uavGlobal = false; + + _instruction.saturate = false; + _instruction.testNZ = false; + _instruction.retType = DxbcResourceReturnType::Unused; + + switch (_instruction.opcode) + { + case DxbcOpcode::CUSTOMDATA: + { +// uint32_t dataClass; + size += bx::read(_reader, _instruction.length); + for (uint32_t ii = 0, num = (_instruction.length-2)/4; ii < num; ++ii) + { + char temp[16]; + size += bx::read(_reader, temp, 16); + } + + } + return size; + + case DxbcOpcode::DCL_CONSTANT_BUFFER: + // 0 1 2 3 + // 76543210765432107654321076543210 + // ........ a........... + // ^------------ Allow refactoring + + _instruction.allowRefactoring = 0 != (token & UINT32_C(0x00000800) ); + break; + + case DxbcOpcode::DCL_GLOBAL_FLAGS: + // 0 1 2 3 + // 76543210765432107654321076543210 + // ........ sxmoudfa........... + // ^^^^^^^^------------ Allow refactoring + // ||||||+------------- FP64 + // |||||+-------------- Force early depth/stencil + // ||||+--------------- Enable raw and structured buffers + // |||+---------------- Skip optimizations + // ||+----------------- Enable minimum precision + // |+------------------ Enable double extension + // +------------------- Enable shader extension + + _instruction.allowRefactoring = 0 != (token & UINT32_C(0x00000800) ); + _instruction.fp64 = 0 != (token & UINT32_C(0x00001000) ); + _instruction.earlyDepth = 0 != (token & UINT32_C(0x00002000) ); + _instruction.enableBuffers = 0 != (token & UINT32_C(0x00004000) ); + _instruction.skipOptimization = 0 != (token & UINT32_C(0x00008000) ); + _instruction.enableMinPrecision = 0 != (token & UINT32_C(0x00010000) ); + _instruction.enableDoubleExtensions = 0 != (token & UINT32_C(0x00020000) ); + _instruction.enableShaderExtensions = 0 != (token & UINT32_C(0x00040000) ); + break; + + case DxbcOpcode::DCL_INPUT_PS: + // 0 1 2 3 + // 76543210765432107654321076543210 + // ........ iiiii........... + // ^---------------- Interploation + + _instruction.interpolation = DxbcInterpolation::Enum( (token & UINT32_C(0x0000f800) ) >> 11); + break; + + case DxbcOpcode::DCL_RESOURCE: + // 0 1 2 3 + // 76543210765432107654321076543210 + // ........ sssssssrrrrr........... + // ^ ^---------------- SRV + // +----------------------- MSAA samples + + _instruction.srv = DxbcResourceDim::Enum( (token & UINT32_C(0x0000f800) ) >> 11); + _instruction.samples = uint8_t( (token & UINT32_C(0x007f0000) ) >> 16); + break; + + case DxbcOpcode::DCL_SAMPLER: + // 0 1 2 3 + // 76543210765432107654321076543210 + // ........ ms........... + // ^^------------ Shadow sampler + // +------------- Mono + + _instruction.shadow = 0 != (token & UINT32_C(0x00000800) ); + _instruction.mono = 0 != (token & UINT32_C(0x00001000) ); + break; + + case DxbcOpcode::SYNC: + // 0 1 2 3 + // 76543210765432107654321076543210 + // ........ gust........... + // ^^^^------------ Threads in group + // ||+------------- Shared memory + // |+-------------- UAV group + // +--------------- UAV global + + _instruction.threadsInGroup = 0 != (token & UINT32_C(0x00000800) ); + _instruction.sharedMemory = 0 != (token & UINT32_C(0x00001000) ); + _instruction.uavGroup = 0 != (token & UINT32_C(0x00002000) ); + _instruction.uavGlobal = 0 != (token & UINT32_C(0x00004000) ); + break; + + default: + // 0 1 2 3 + // 76543210765432107654321076543210 + // ........ ppppn stt........... + // ^ ^ ^^------------- Resource info return type + // | | +-------------- Saturate + // | +------------------- Test not zero + // +----------------------- Precise mask + + _instruction.retType = DxbcResourceReturnType::Enum( (token & UINT32_C(0x00001800) ) >> 11); + _instruction.saturate = 0 != (token & UINT32_C(0x00002000) ); + _instruction.testNZ = 0 != (token & UINT32_C(0x00040000) ); +// _instruction.precise = uint8_t( (token & UINT32_C(0x00780000) ) >> 19); + break; + } + + _instruction.extended[0] = DxbcInstruction::ExtendedType::Count; + for (uint32_t ii = 0; extended; ++ii) + { + // 0 1 2 3 + // 76543210765432107654321076543210 + // e..........................ttttt + // ^ ^ + // | +----- type + // +-------------------------------- extended + + uint32_t extBits; + size += bx::read(_reader, extBits); + extended = 0 != (extBits & UINT32_C(0x80000000) ); + _instruction.extended[ii] = DxbcInstruction::ExtendedType::Enum(extBits & UINT32_C(0x0000001f) ); + _instruction.extended[ii+1] = DxbcInstruction::ExtendedType::Count; + + switch (_instruction.extended[ii]) + { + case DxbcInstruction::ExtendedType::SampleControls: + // 0 1 2 3 + // 76543210765432107654321076543210 + // . zzzzyyyyxxxx ..... + // ^ ^ ^ + // | | +------------- x + // | +----------------- y + // +--------------------- z + + _instruction.sampleOffsets[0] = uint8_t( (extBits & UINT32_C(0x00001e00) ) >> 9); + _instruction.sampleOffsets[1] = uint8_t( (extBits & UINT32_C(0x0001e000) ) >> 13); + _instruction.sampleOffsets[2] = uint8_t( (extBits & UINT32_C(0x001e0000) ) >> 17); + break; + + case DxbcInstruction::ExtendedType::ResourceDim: + // 0 1 2 3 + // 76543210765432107654321076543210 + // . ..... + // + + _instruction.resourceTarget = uint8_t( (extBits & UINT32_C(0x000003e0) ) >> 6); + _instruction.resourceStride = uint8_t( (extBits & UINT32_C(0x0000f800) ) >> 11); + break; + + case DxbcInstruction::ExtendedType::ResourceReturnType: + // 0 1 2 3 + // 76543210765432107654321076543210 + // . 3333222211110000..... + // ^ ^ ^ + // | | +------------- x + // | +----------------- y + // +--------------------- z + + _instruction.resourceReturnTypes[0] = DxbcResourceReturnType::Enum( (extBits & UINT32_C(0x000001e0) ) >> 6); + _instruction.resourceReturnTypes[1] = DxbcResourceReturnType::Enum( (extBits & UINT32_C(0x00001e00) ) >> 9); + _instruction.resourceReturnTypes[2] = DxbcResourceReturnType::Enum( (extBits & UINT32_C(0x0001e000) ) >> 13); + _instruction.resourceReturnTypes[3] = DxbcResourceReturnType::Enum( (extBits & UINT32_C(0x001e0000) ) >> 17); + break; + + default: + break; + } + } + + switch (_instruction.opcode) + { + case DxbcOpcode::DCL_FUNCTION_TABLE: + { + uint32_t tableId; + size += read(_reader, tableId); + + uint32_t num; + size += read(_reader, num); + + for (uint32_t ii = 0; ii < num; ++ii) + { + uint32_t bodyId; + size += read(_reader, bodyId); + } + } + break; + + case DxbcOpcode::DCL_INTERFACE: + { + uint32_t interfaceId; + size += read(_reader, interfaceId); + + uint32_t num; + size += read(_reader, num); + + BX_CHECK(false, "not implemented."); + } + break; + + default: + break; + }; + + uint32_t currOp = 0; + + const DxbcOpcodeInfo& info = s_dxbcOpcodeInfo[_instruction.opcode]; + _instruction.numOperands = info.numOperands; + switch (info.numOperands) + { + case 6: size += read(_reader, _instruction.operand[currOp++]); + case 5: size += read(_reader, _instruction.operand[currOp++]); + case 4: size += read(_reader, _instruction.operand[currOp++]); + case 3: size += read(_reader, _instruction.operand[currOp++]); + case 2: size += read(_reader, _instruction.operand[currOp++]); + case 1: size += read(_reader, _instruction.operand[currOp++]); + case 0: + if (0 < info.numValues) + { + size += read(_reader, _instruction.value, info.numValues*sizeof(uint32_t) ); + } + break; + + default: + BX_CHECK(false, "Instruction %s with invalid number of operands %d (numValues %d)." + , getName(_instruction.opcode) + , info.numOperands + , info.numValues + ); + break; + } + + return size; + } + + int32_t write(bx::WriterI* _writer, const DxbcInstruction& _instruction) + { + uint32_t token = 0; + token |= (_instruction.opcode ) & UINT32_C(0x000007ff); + token |= (_instruction.length << 24) & UINT32_C(0x7f000000); + + token |= DxbcInstruction::ExtendedType::Count != _instruction.extended[0] + ? UINT32_C(0x80000000) + : 0 + ; + + switch (_instruction.opcode) + { +// case DxbcOpcode::CUSTOMDATA: +// return size; + + case DxbcOpcode::DCL_CONSTANT_BUFFER: + token |= _instruction.allowRefactoring ? UINT32_C(0x00000800) : 0; + break; + + case DxbcOpcode::DCL_GLOBAL_FLAGS: + token |= _instruction.allowRefactoring ? UINT32_C(0x00000800) : 0; + token |= _instruction.fp64 ? UINT32_C(0x00001000) : 0; + token |= _instruction.earlyDepth ? UINT32_C(0x00002000) : 0; + token |= _instruction.enableBuffers ? UINT32_C(0x00004000) : 0; + token |= _instruction.skipOptimization ? UINT32_C(0x00008000) : 0; + token |= _instruction.enableMinPrecision ? UINT32_C(0x00010000) : 0; + token |= _instruction.enableDoubleExtensions ? UINT32_C(0x00020000) : 0; + token |= _instruction.enableShaderExtensions ? UINT32_C(0x00040000) : 0; + break; + + case DxbcOpcode::DCL_INPUT_PS: + token |= (_instruction.interpolation << 11) & UINT32_C(0x0000f800); + break; + + case DxbcOpcode::DCL_RESOURCE: + token |= (_instruction.srv << 11) & UINT32_C(0x0000f800); + token |= (_instruction.samples << 16) & UINT32_C(0x007f0000); + break; + + case DxbcOpcode::DCL_SAMPLER: + token |= _instruction.shadow ? (0x00000800) : 0; + token |= _instruction.mono ? (0x00001000) : 0; + break; + + case DxbcOpcode::SYNC: + token |= _instruction.threadsInGroup ? UINT32_C(0x00000800) : 0; + token |= _instruction.sharedMemory ? UINT32_C(0x00001000) : 0; + token |= _instruction.uavGroup ? UINT32_C(0x00002000) : 0; + token |= _instruction.uavGlobal ? UINT32_C(0x00004000) : 0; + break; + + default: + token |= (_instruction.retType << 11) & UINT32_C(0x00001800); + token |= _instruction.saturate ? UINT32_C(0x00002000) : 0; + token |= _instruction.testNZ ? UINT32_C(0x00040000) : 0; +// _instruction.precise = uint8_t( (token & UINT32_C(0x00780000) ) >> 19); + break; + } + + uint32_t size =0; + size += bx::write(_writer, token); +; + for (uint32_t ii = 0; _instruction.extended[ii] != DxbcInstruction::ExtendedType::Count; ++ii) + { + // 0 1 2 3 + // 76543210765432107654321076543210 + // e..........................ttttt + // ^ ^ + // | +----- type + // +-------------------------------- extended + + token = _instruction.extended[ii+1] == DxbcInstruction::ExtendedType::Count + ? 0 + : UINT32_C(0x80000000) + ; + token |= uint8_t(_instruction.extended[ii]); + + switch (_instruction.extended[ii]) + { + case DxbcInstruction::ExtendedType::SampleControls: + // 0 1 2 3 + // 76543210765432107654321076543210 + // . zzzzyyyyxxxx ..... + // ^ ^ ^ + // | | +------------- x + // | +----------------- y + // +--------------------- z + + token |= (uint32_t(_instruction.sampleOffsets[0]) << 9) & UINT32_C(0x00001e00); + token |= (uint32_t(_instruction.sampleOffsets[1]) << 13) & UINT32_C(0x0001e000); + token |= (uint32_t(_instruction.sampleOffsets[2]) << 17) & UINT32_C(0x001e0000); + break; + + case DxbcInstruction::ExtendedType::ResourceDim: + // 0 1 2 3 + // 76543210765432107654321076543210 + // . ..... + // + + token |= (uint32_t(_instruction.resourceTarget << 6) & UINT32_C(0x000003e0) ); + token |= (uint32_t(_instruction.resourceStride << 11) & UINT32_C(0x0000f800) ); + break; + + case DxbcInstruction::ExtendedType::ResourceReturnType: + // 0 1 2 3 + // 76543210765432107654321076543210 + // . 3333222211110000..... + // ^ ^ ^ + // | | +------------- x + // | +----------------- y + // +--------------------- z + + token |= (uint32_t(_instruction.resourceReturnTypes[0]) << 6) & UINT32_C(0x000001e0); + token |= (uint32_t(_instruction.resourceReturnTypes[1]) << 9) & UINT32_C(0x00001e00); + token |= (uint32_t(_instruction.resourceReturnTypes[2]) << 13) & UINT32_C(0x0001e000); + token |= (uint32_t(_instruction.resourceReturnTypes[3]) << 17) & UINT32_C(0x001e0000); + break; + + default: + break; + } + + size += bx::write(_writer, token); + } + + for (uint32_t ii = 0; ii < _instruction.numOperands; ++ii) + { + size += write(_writer, _instruction.operand[ii]); + } + + const DxbcOpcodeInfo& info = s_dxbcOpcodeInfo[_instruction.opcode]; + if (0 < info.numValues) + { + size += bx::write(_writer, _instruction.value, info.numValues*sizeof(uint32_t) ); + } + + return size; + } + + int32_t toString(char* _out, int32_t _size, const DxbcInstruction& _instruction) + { + int32_t size = 0; + + size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size) + , "%s%s%s" + , getName(_instruction.opcode) + , _instruction.saturate ? "_sat" : "" + , _instruction.testNZ ? "_nz" : "" + ); + + if (DxbcResourceDim::Unknown != _instruction.srv) + { + size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size) + , " %s<%x>" + , s_dxbcSrvType[_instruction.srv] + , _instruction.value[0] + ); + } + else if (0 < s_dxbcOpcodeInfo[_instruction.opcode].numValues) + { + size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size) + , " %d" + , _instruction.value[0] + ); + } + + for (uint32_t ii = 0; ii < _instruction.numOperands; ++ii) + { + const DxbcOperand& operand = _instruction.operand[ii]; + + const bool array = false + || 1 < operand.numAddrModes + || DxbcOperandAddrMode::Imm32 != operand.addrMode[0] + ; + + size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size) + , "%s%s%s" + , 0 == ii ? " " : ", " + , operand.extended ? "*" : "" + , s_dxbcOperandType[operand.type] + ); + + switch (operand.type) + { + case DxbcOperandType::Imm32: + case DxbcOperandType::Imm64: + for (uint32_t jj = 0; jj < operand.num; ++jj) + { + union { uint32_t i; float f; } cast = { operand.un.imm32[jj] }; + size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size) + , "%s%f" + , 0 == jj ? "(" : ", " + , cast.f + ); + } + + size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size) + , ")" + ); + break; + + default: + break; + } + + const uint32_t first = DxbcOperandAddrMode::RegImm32 == operand.addrMode[0] ? 0 : 1; + if (0 == first) + { + size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size) + , "[" + ); + } + else + { + size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size) + , "%d%s" + , operand.regIndex[0] + , array ? "[" : "" + ); + } + + for (uint32_t jj = first; jj < operand.numAddrModes; ++jj) + { + switch (operand.addrMode[jj]) + { + case DxbcOperandAddrMode::Imm32: + size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size) + , "%d" + , operand.regIndex[jj] + ); + break; + + case DxbcOperandAddrMode::Reg: + size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size) + , "%s%d" + , s_dxbcOperandType[operand.subOperand[jj].type] + , operand.regIndex[jj] + ); + break; + + case DxbcOperandAddrMode::RegImm32: + size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size) + , "%d + %s%d" + , operand.regIndex[jj] + , s_dxbcOperandType[operand.subOperand[jj].type] + , operand.regIndex[jj] + ); + break; + + default: + break; + } + } + + size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size) + , "%s" + , array ? "]" : "" + ); + + switch (operand.mode) + { + case DxbcOperandMode::Mask: + if (0xf > operand.modeBits + && 0 < operand.modeBits) + { + size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size) + , ".%s%s%s%s" + , 0 == (operand.modeBits & 1) ? "" : "x" + , 0 == (operand.modeBits & 2) ? "" : "y" + , 0 == (operand.modeBits & 4) ? "" : "z" + , 0 == (operand.modeBits & 8) ? "" : "w" + ); + } + break; + + case DxbcOperandMode::Swizzle: + if (0xe4 != operand.modeBits) + { + size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size) + , ".%c%c%c%c" + , "xyzw"[(operand.modeBits )&0x3] + , "xyzw"[(operand.modeBits>>2)&0x3] + , "xyzw"[(operand.modeBits>>4)&0x3] + , "xyzw"[(operand.modeBits>>6)&0x3] + ); + } + break; + + case DxbcOperandMode::Scalar: + size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size) + , ".%c" + , "xyzw"[operand.modeBits] + ); + break; + + default: + break; + } + + } + + return size; + } + + int32_t read(bx::ReaderSeekerI* _reader, DxbcSignature& _signature) + { + int32_t size = 0; + + int64_t offset = bx::seek(_reader); + + uint32_t num; + size += bx::read(_reader, num); + size += bx::read(_reader, _signature.key); + + for (uint32_t ii = 0; ii < num; ++ii) + { + DxbcSignature::Element element; + + uint32_t nameOffset; + size += bx::read(_reader, nameOffset); + + char name[DXBC_MAX_NAME_STRING]; + readString(_reader, offset + nameOffset, name); + element.name = name; + + size += bx::read(_reader, element.semanticIndex); + size += bx::read(_reader, element.valueType); + size += bx::read(_reader, element.componentType); + size += bx::read(_reader, element.registerIndex); + size += bx::read(_reader, element.mask); + size += bx::read(_reader, element.readWriteMask); + size += bx::read(_reader, element.stream); + + // padding + uint8_t padding; + size += bx::read(_reader, padding); + + _signature.elements.push_back(element); + } + + return size; + } + + int32_t write(bx::WriterI* _writer, const DxbcSignature& _signature) + { + int32_t size = 0; + + const uint32_t num = uint32_t(_signature.elements.size() ); + size += bx::write(_writer, num); + size += bx::write(_writer, _signature.key); + + typedef stl::unordered_map<stl::string, uint32_t> NameOffsetMap; + NameOffsetMap nom; + + const uint8_t pad = 0; + uint32_t nameOffset = num * 24 + 8; + for (uint32_t ii = 0; ii < num; ++ii) + { + const DxbcSignature::Element& element = _signature.elements[ii]; + + NameOffsetMap::iterator it = nom.find(element.name); + if (it == nom.end() ) + { + nom.insert(stl::make_pair(element.name, nameOffset) ); + size += bx::write(_writer, nameOffset); + nameOffset += uint32_t(element.name.size() + 1); + } + else + { + size += bx::write(_writer, it->second); + } + + size += bx::write(_writer, element.semanticIndex); + size += bx::write(_writer, element.valueType); + size += bx::write(_writer, element.componentType); + size += bx::write(_writer, element.registerIndex); + size += bx::write(_writer, element.mask); + size += bx::write(_writer, element.readWriteMask); + size += bx::write(_writer, element.stream); + size += bx::write(_writer, pad); + + } + + uint32_t len = 0; + for (uint32_t ii = 0; ii < num; ++ii) + { + const DxbcSignature::Element& element = _signature.elements[ii]; + NameOffsetMap::iterator it = nom.find(element.name); + if (it != nom.end() ) + { + nom.erase(it); + size += bx::write(_writer, element.name.c_str(), uint32_t(element.name.size() + 1) ); + len += uint32_t(element.name.size() + 1); + } + } + + // align 4 bytes + size += bx::writeRep(_writer, 0xab, (len+3)/4*4 - len); + + return size; + } + + int32_t read(bx::ReaderSeekerI* _reader, DxbcShader& _shader) + { + int32_t size = 0; + + size += bx::read(_reader, _shader.version); + + uint32_t bcLength; + size += bx::read(_reader, bcLength); + + uint32_t len = (bcLength-2)*sizeof(uint32_t); + _shader.byteCode.resize(len); + size += bx::read(_reader, _shader.byteCode.data(), len); + + return size; + } + + int32_t write(bx::WriterI* _writer, const DxbcShader& _shader) + { + const uint32_t len = uint32_t(_shader.byteCode.size() ); + const uint32_t bcLength = len / sizeof(uint32_t) + 2; + + int32_t size = 0; + size += bx::write(_writer, _shader.version); + size += bx::write(_writer, bcLength); + size += bx::write(_writer, _shader.byteCode.data(), len); + + return size; + } + +#define DXBC_CHUNK_HEADER BX_MAKEFOURCC('D', 'X', 'B', 'C') +#define DXBC_CHUNK_SHADER BX_MAKEFOURCC('S', 'H', 'D', 'R') +#define DXBC_CHUNK_SHADER_EX BX_MAKEFOURCC('S', 'H', 'E', 'X') + +#define DXBC_CHUNK_INPUT_SIGNATURE BX_MAKEFOURCC('I', 'S', 'G', 'N') +#define DXBC_CHUNK_OUTPUT_SIGNATURE BX_MAKEFOURCC('O', 'S', 'G', 'N') + + int32_t read(bx::ReaderSeekerI* _reader, DxbcContext& _dxbc) + { + int32_t size = 0; + size += bx::read(_reader, _dxbc.header); + _dxbc.shader.shex = false; + + for (uint32_t ii = 0; ii < _dxbc.header.numChunks; ++ii) + { + bx::seek(_reader, sizeof(DxbcContext::Header) + ii*sizeof(uint32_t), bx::Whence::Begin); + + uint32_t chunkOffset; + size += bx::read(_reader, chunkOffset); + + bx::seek(_reader, chunkOffset, bx::Whence::Begin); + + uint32_t fourcc; + size += bx::read(_reader, fourcc); + + uint32_t chunkSize; + size += bx::read(_reader, chunkSize); + + switch (fourcc) + { + case DXBC_CHUNK_SHADER_EX: + _dxbc.shader.shex = true; + // fallthrough + + case DXBC_CHUNK_SHADER: + size += read(_reader, _dxbc.shader); + break; + + case BX_MAKEFOURCC('I', 'S', 'G', '1'): + case DXBC_CHUNK_INPUT_SIGNATURE: + size += read(_reader, _dxbc.inputSignature); + break; + + case BX_MAKEFOURCC('O', 'S', 'G', '1'): + case BX_MAKEFOURCC('O', 'S', 'G', '5'): + case DXBC_CHUNK_OUTPUT_SIGNATURE: + size += read(_reader, _dxbc.outputSignature); + break; + + case BX_MAKEFOURCC('R', 'D', 'E', 'F'): + case BX_MAKEFOURCC('I', 'F', 'C', 'E'): + case BX_MAKEFOURCC('P', 'C', 'S', 'G'): + case BX_MAKEFOURCC('S', 'T', 'A', 'T'): + case BX_MAKEFOURCC('S', 'F', 'I', '0'): + case BX_MAKEFOURCC('P', 'S', 'O', '1'): + case BX_MAKEFOURCC('P', 'S', 'O', '2'): + size += chunkSize; + break; + + default: + size += chunkSize; + BX_CHECK(false, "UNKNOWN FOURCC %c%c%c%c %d" + , ( (char*)&fourcc)[0] + , ( (char*)&fourcc)[1] + , ( (char*)&fourcc)[2] + , ( (char*)&fourcc)[3] + , size + ); + break; + } + } + + return size; + } + + int32_t write(bx::WriterSeekerI* _writer, const DxbcContext& _dxbc) + { + int32_t size = 0; + + int64_t dxbcOffset = bx::seek(_writer); + size += bx::write(_writer, DXBC_CHUNK_HEADER); + + size += bx::writeRep(_writer, 0, 16); + + size += bx::write(_writer, UINT32_C(1) ); + + int64_t sizeOffset = bx::seek(_writer); + size += bx::writeRep(_writer, 0, 4); + + uint32_t numChunks = 3; + size += bx::write(_writer, numChunks); + + int64_t chunksOffsets = bx::seek(_writer); + size += bx::writeRep(_writer, 0, numChunks*sizeof(uint32_t) ); + + uint32_t chunkOffset[3]; + uint32_t chunkSize[3]; + + chunkOffset[0] = uint32_t(bx::seek(_writer) - dxbcOffset); + size += write(_writer, DXBC_CHUNK_INPUT_SIGNATURE); + size += write(_writer, UINT32_C(0) ); + chunkSize[0] = write(_writer, _dxbc.inputSignature); + + chunkOffset[1] = uint32_t(bx::seek(_writer) - dxbcOffset); + size += write(_writer, DXBC_CHUNK_OUTPUT_SIGNATURE); + size += write(_writer, UINT32_C(0) ); + chunkSize[1] = write(_writer, _dxbc.outputSignature); + + chunkOffset[2] = uint32_t(bx::seek(_writer) - dxbcOffset); + size += write(_writer, _dxbc.shader.shex ? DXBC_CHUNK_SHADER_EX : DXBC_CHUNK_SHADER); + size += write(_writer, UINT32_C(0) ); + chunkSize[2] = write(_writer, _dxbc.shader); + + size += 0 + + chunkSize[0] + + chunkSize[1] + + chunkSize[2] + ; + + int64_t eof = bx::seek(_writer); + + bx::seek(_writer, sizeOffset, bx::Whence::Begin); + bx::write(_writer, size); + + bx::seek(_writer, chunksOffsets, bx::Whence::Begin); + bx::write(_writer, chunkOffset, sizeof(chunkOffset) ); + + for (uint32_t ii = 0; ii < BX_COUNTOF(chunkOffset); ++ii) + { + bx::seek(_writer, chunkOffset[ii]+4, bx::Whence::Begin); + bx::write(_writer, chunkSize[ii]); + } + + bx::seek(_writer, eof, bx::Whence::Begin); + + return size; + } + + void parse(const DxbcShader& _src, DxbcParseFn _fn, void* _userData) + { + bx::MemoryReader reader(_src.byteCode.data(), uint32_t(_src.byteCode.size() ) ); + + for (uint32_t token = 0, numTokens = uint32_t(_src.byteCode.size() / sizeof(uint32_t) ); token < numTokens;) + { + DxbcInstruction instruction; + uint32_t size = read(&reader, instruction); + BX_CHECK(size/4 == instruction.length, "read %d, expected %d", size/4, instruction.length); BX_UNUSED(size); + + bool cont = _fn(token * sizeof(uint32_t), instruction, _userData); + if (!cont) + { + return; + } + + token += instruction.length; + } + } + + void filter(DxbcShader& _dst, const DxbcShader& _src, DxbcFilterFn _fn, void* _userData) + { + bx::MemoryReader reader(_src.byteCode.data(), uint32_t(_src.byteCode.size() ) ); + + bx::CrtAllocator r; + bx::MemoryBlock mb(&r); + bx::MemoryWriter writer(&mb); + + for (uint32_t token = 0, numTokens = uint32_t(_src.byteCode.size() / sizeof(uint32_t) ); token < numTokens;) + { + DxbcInstruction instruction; + uint32_t size = read(&reader, instruction); + BX_CHECK(size/4 == instruction.length, "read %d, expected %d", size/4, instruction.length); BX_UNUSED(size); + + _fn(instruction, _userData); + + write(&writer, instruction); + + token += instruction.length; + } + + uint8_t* data = (uint8_t*)mb.more(); + uint32_t size = uint32_t(bx::getSize(&writer) ); + _dst.byteCode.reserve(size); + memcpy(_dst.byteCode.data(), data, size); + } + +} // namespace bgfx |