diff options
Diffstat (limited to '3rdparty/bgfx/src/shader_dx9bc.cpp')
-rw-r--r-- | 3rdparty/bgfx/src/shader_dx9bc.cpp | 748 |
1 files changed, 748 insertions, 0 deletions
diff --git a/3rdparty/bgfx/src/shader_dx9bc.cpp b/3rdparty/bgfx/src/shader_dx9bc.cpp new file mode 100644 index 00000000000..bfbf4f6ee98 --- /dev/null +++ b/3rdparty/bgfx/src/shader_dx9bc.cpp @@ -0,0 +1,748 @@ +/* + * Copyright 2011-2015 Branimir Karadzic. All rights reserved. + * License: http://www.opensource.org/licenses/BSD-2-Clause + */ + +#include "bgfx_p.h" +#include "shader_dx9bc.h" + +BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG_GCC("-Wunused-parameter"); +BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG("-Wunneeded-internal-declaration"); + +namespace bgfx +{ + struct Dx9bcOpcodeInfo + { + uint8_t numOperands; + uint8_t numValues; + }; + + static const Dx9bcOpcodeInfo s_dx9bcOpcodeInfo[] = + { + { 0, 0 }, // NOP + { 2, 0 }, // MOV + { 3, 0 }, // ADD + { 1, 0 }, // SUB + { 4, 0 }, // MAD + { 3, 0 }, // MUL + { 2, 0 }, // RCP + { 2, 0 }, // RSQ + { 3, 0 }, // DP3 + { 3, 0 }, // DP4 + { 3, 0 }, // MIN + { 3, 0 }, // MAX + { 3, 0 }, // SLT + { 3, 0 }, // SGE + { 2, 0 }, // EXP + { 2, 0 }, // LOG + { 1, 0 }, // LIT + { 1, 0 }, // DST + { 4, 0 }, // LRP + { 2, 0 }, // FRC + { 1, 0 }, // M4X4 + { 1, 0 }, // M4X3 + { 1, 0 }, // M3X4 + { 1, 0 }, // M3X3 + { 1, 0 }, // M3X2 + { 0, 0 }, // CALL + { 0, 0 }, // CALLNZ + { 0, 0 }, // LOOP + { 0, 0 }, // RET + { 0, 0 }, // ENDLOOP + { 0, 0 }, // LABEL + { 1, 1 }, // DCL + { 3, 0 }, // POW + { 1, 0 }, // CRS + { 1, 0 }, // SGN + { 1, 0 }, // ABS + { 2, 0 }, // NRM + { 4, 0 }, // SINCOS + { 1, 0 }, // REP + { 0, 0 }, // ENDREP + { 1, 0 }, // IF + { 2, 0 }, // IFC + { 0, 0 }, // ELSE + { 0, 0 }, // ENDIF + { 0, 0 }, // BREAK + { 2, 0 }, // BREAKC + { 2, 0 }, // MOVA + { 1, 4 }, // DEFB + { 1, 4 }, // DEFI + { 0, 0 }, // 0 + { 0, 0 }, // 1 + { 0, 0 }, // 2 + { 0, 0 }, // 3 + { 0, 0 }, // 4 + { 0, 0 }, // 5 + { 0, 0 }, // 6 + { 0, 0 }, // 7 + { 0, 0 }, // 8 + { 0, 0 }, // 9 + { 0, 0 }, // 10 + { 0, 0 }, // 11 + { 0, 0 }, // 12 + { 0, 0 }, // 13 + { 0, 0 }, // 14 + { 1, 0 }, // TEXCOORD + { 1, 0 }, // TEXKILL + { 3, 0 }, // TEX + { 1, 0 }, // TEXBEM + { 1, 0 }, // TEXBEM1 + { 1, 0 }, // TEXREG2AR + { 1, 0 }, // TEXREG2GB + { 1, 0 }, // TEXM3X2PAD + { 1, 0 }, // TEXM3X2TEX + { 1, 0 }, // TEXM3X3PAD + { 1, 0 }, // TEXM3X3TEX + { 1, 0 }, // TEXM3X3DIFF + { 1, 0 }, // TEXM3X3SPEC + { 1, 0 }, // TEXM3X3VSPEC + { 2, 0 }, // EXPP + { 2, 0 }, // LOGP + { 4, 0 }, // CND + { 1, 4 }, // DEF + { 1, 0 }, // TEXREG2RGB + { 1, 0 }, // TEXDP3TEX + { 1, 0 }, // TEXM3X2DEPTH + { 1, 0 }, // TEXDP3 + { 1, 0 }, // TEXM3X3 + { 1, 0 }, // TEXDEPTH + { 4, 0 }, // CMP + { 1, 0 }, // BEM + { 4, 0 }, // DP2ADD + { 2, 0 }, // DSX + { 2, 0 }, // DSY + { 5, 0 }, // TEXLDD + { 1, 0 }, // SETP + { 3, 0 }, // TEXLDL + { 0, 0 }, // BREAKP + }; + BX_STATIC_ASSERT(BX_COUNTOF(s_dx9bcOpcodeInfo) == Dx9bcOpcode::Count); + + static const char* s_dx9bcOpcode[] = + { + "nop", + "mov", + "add", + "sub", + "mad", + "mul", + "rcp", + "rsq", + "dp3", + "dp4", + "min", + "max", + "slt", + "sge", + "exp", + "log", + "lit", + "dst", + "lrp", + "frc", + "m4x4", + "m4x3", + "m3x4", + "m3x3", + "m3x2", + "call", + "callnz", + "loop", + "ret", + "endloop", + "label", + "dcl", + "pow", + "crs", + "sgn", + "abs", + "nrm", + "sincos", + "rep", + "endrep", + "if", + "ifc", + "else", + "endif", + "break", + "breakc", + "mova", + "defb", + "defi", + + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + + "texcoord", + "texkill", + "tex", + "texbem", + "texbem1", + "texreg2ar", + "texreg2gb", + "texm3x2pad", + "texm3x2tex", + "texm3x3pad", + "texm3x3tex", + "texm3x3diff", + "texm3x3spec", + "texm3x3vspec", + "expp", + "logp", + "cnd", + "def", + "texreg2rgb", + "texdp3tex", + "texm3x2depth", + "texdp3", + "texm3x3", + "texdepth", + "cmp", + "bem", + "dp2add", + "dsx", + "dsy", + "texldd", + "setp", + "texldl", + "breakp", + }; + BX_STATIC_ASSERT(BX_COUNTOF(s_dx9bcOpcode) == Dx9bcOpcode::Count); + + const char* getName(Dx9bcOpcode::Enum _opcode) + { + BX_CHECK(_opcode < Dx9bcOpcode::Count, "Unknown opcode id %d (%x).", _opcode, _opcode); + return s_dx9bcOpcode[_opcode]; + } + + static const char* s_dx9bcOperandType[] = + { + "r", // Temporary Register File + "v", // Input Register File + "c", // Constant Register File + "t", // Texture Register File (PS) + "oPos", // Rasterizer Register File + "oD", // Attribute Output Register File + "oT", // Texture Coordinate Output Register File + "output", // Output register file for VS3.0+ + "i", // Constant Integer Vector Register File + "oColor", // Color Output Register File + "oDepth", // Depth Output Register File + "s", // Sampler State Register File + "c", // Constant Register File 2048 - 4095 + "c", // Constant Register File 4096 - 6143 + "c", // Constant Register File 6144 - 8191 + "b", // Constant Boolean register file + "aL", // Loop counter register file + "tempfloat16", // 16-bit float temp register file + "misctype", // Miscellaneous (single) registers. + "label", // Label + "p", // Predicate register + }; + BX_STATIC_ASSERT(BX_COUNTOF(s_dx9bcOperandType) == Dx9bcOperandType::Count); + + static const char* s_dx9bcDeclUsage[] = + { + "position", + "blendweight", + "blendindices", + "normal", + "psize", + "texcoord", + "tangent", + "binormal", + "tessfactor", + "positiont", + "color", + "fog", + "depth", + "sample", + }; + BX_STATIC_ASSERT(BX_COUNTOF(s_dx9bcDeclUsage) == Dx9bcDeclUsage::Count); + + int32_t read(bx::ReaderI* _reader, Dx9bcSubOperand& _subOperand) + { + int32_t size = 0; + + uint32_t token; + size += bx::read(_reader, token); + + _subOperand.type = Dx9bcOperandType::Enum( ( (token & UINT32_C(0x70000000) ) >> 28) + | ( (token & UINT32_C(0x00001800) ) >> 8) ); + _subOperand.regIndex = (token & UINT32_C(0x000007ff) ); + _subOperand.swizzleBits = uint8_t( (token & UINT32_C(0x00ff0000) ) >> 16); + + return size; + } + + int32_t write(bx::WriterI* _writer, const Dx9bcSubOperand& _subOperand) + { + int32_t size = 0; + + uint32_t token = 0; + token |= (_subOperand.type << 28) & UINT32_C(0x70000000); + token |= (_subOperand.type << 8) & UINT32_C(0x00001800); + token |= _subOperand.regIndex & UINT32_C(0x000007ff); + token |= (_subOperand.swizzleBits << 16) & UINT32_C(0x00ff0000); + size += bx::write(_writer, token); + + return size; + } + + int32_t read(bx::ReaderI* _reader, Dx9bcOperand& _operand) + { + int32_t size = 0; + + uint32_t token; + size += bx::read(_reader, token); + + _operand.type = Dx9bcOperandType::Enum( ( (token & UINT32_C(0x70000000) ) >> 28) + | ( (token & UINT32_C(0x00001800) ) >> 8) ); + _operand.regIndex = (token & UINT32_C(0x000007ff) ); + _operand.addrMode = Dx9bcOperandAddrMode::Enum( (token & UINT32_C(0x00002000) ) >> 13); + + if (_operand.destination) + { + // Destination Parameter Token + // https://msdn.microsoft.com/en-us/library/ff552738.aspx + + _operand.writeMask = uint8_t( (token & UINT32_C(0x000f0000) ) >> 16); + _operand.saturate = 0 != (token & UINT32_C(0x00100000) ); + _operand.partialPrecision = 0 != (token & UINT32_C(0x00200000) ); + _operand.centroid = 0 != (token & UINT32_C(0x00400000) ); + } + else + { + // Source Parameter Token + // https://msdn.microsoft.com/en-us/library/ff569716%28v=vs.85%29.aspx + + _operand.writeMask = 0; + _operand.saturate = false; + _operand.partialPrecision = false; + _operand.centroid = false; + _operand.swizzleBits = uint8_t( (token & UINT32_C(0x00ff0000) ) >> 16); + } + + if (Dx9bcOperandAddrMode::Relative == _operand.addrMode) + { + size += read(_reader, _operand.subOperand); + } + + return size; + } + + int32_t write(bx::WriterI* _writer, const Dx9bcOperand& _operand) + { + int32_t size = 0; + + uint32_t token = 0; + token |= (_operand.type << 28) & UINT32_C(0x70000000); + token |= (_operand.type << 8) & UINT32_C(0x00001800); + token |= _operand.regIndex & UINT32_C(0x000007ff); + token |= (_operand.addrMode << 13) & UINT32_C(0x00002000); + size += bx::write(_writer, token); + + if (Dx9bcOperandAddrMode::Relative == _operand.addrMode) + { + size += write(_writer, _operand.subOperand); + } + + return size; + } + + int32_t read(bx::ReaderI* _reader, Dx9bcInstruction& _instruction) + { + int32_t size = 0; + + uint32_t token; + size += bx::read(_reader, token); + + _instruction.opcode = Dx9bcOpcode::Enum( (token & UINT32_C(0x0000ffff) ) ); + + if (Dx9bcOpcode::Comment == _instruction.opcode) + { + _instruction.specific = 0; + _instruction.length = uint16_t( (token & UINT32_C(0x7fff0000) ) >> 16) + 1; + _instruction.predicated = false; + _instruction.coissue = false; + } + else + { + _instruction.specific = uint8_t( (token & UINT32_C(0x00ff0000) ) >> 16); + _instruction.length = uint8_t( (token & UINT32_C(0x0f000000) ) >> 24) + 1; + _instruction.predicated = 0 != (token & UINT32_C(0x10000000) ); + _instruction.coissue = 0 != (token & UINT32_C(0x40000000) ); + } + + if (Dx9bcOpcode::Count <= _instruction.opcode) + { + if (Dx9bcOpcode::Comment == _instruction.opcode) + { + for (int32_t ii = 0, num = _instruction.length-1; ii < num; ++ii) + { + uint32_t tmp; + size += bx::read(_reader, tmp); + } + } + + return size; + } + + uint32_t currOp = 0; + + const Dx9bcOpcodeInfo& info = s_dx9bcOpcodeInfo[bx::uint32_min(_instruction.opcode, Dx9bcOpcode::Count)]; + _instruction.numOperands = info.numOperands; + _instruction.numValues = info.numValues; + + switch (_instruction.opcode) + { + case Dx9bcOpcode::SINCOS: + if (5 > _instruction.length) + { + _instruction.numOperands = 2; + } + break; + + default: + break; + }; + +//BX_TRACE("%d (%d), %d, %d, 0x%08x" +// , _instruction.opcode +// , bx::uint32_min(_instruction.opcode, Dx9bcOpcode::Count) +// , _instruction.length +// , _instruction.numOperands +// , token +// ); + + const bool valuesBeforeOpcode = false + || Dx9bcOpcode::DCL == _instruction.opcode + ; + + if (valuesBeforeOpcode + && 0 < info.numValues) + { + size += read(_reader, _instruction.value, info.numValues*sizeof(uint32_t) ); + } + + _instruction.operand[0].destination = true; + + switch (_instruction.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 (!valuesBeforeOpcode + && 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) + , _instruction.numOperands + , info.numValues + ); + break; + } + + return size; + } + + int32_t write(bx::WriterI* _writer, const Dx9bcInstruction& _instruction) + { + int32_t size = 0; + + uint32_t token = 0; + token |= _instruction.opcode & UINT32_C(0x0000ffff); + token |= (_instruction.specific << 16) & UINT32_C(0x00ff0000); + token |= ( (_instruction.length - 1) << 24) & UINT32_C(0x0f000000); + size += bx::write(_writer, token); + + uint32_t currOp = 0; + switch (_instruction.numOperands) + { + case 6: size += write(_writer, _instruction.operand[currOp++]); + case 5: size += write(_writer, _instruction.operand[currOp++]); + case 4: size += write(_writer, _instruction.operand[currOp++]); + case 3: size += write(_writer, _instruction.operand[currOp++]); + case 2: size += write(_writer, _instruction.operand[currOp++]); + case 1: size += write(_writer, _instruction.operand[currOp++]); + case 0: + break; + } + + return 0; + } + + int32_t toString(char* _out, int32_t _size, const Dx9bcInstruction& _instruction) + { + int32_t size = 0; + + if (Dx9bcOpcode::Comment == _instruction.opcode + || Dx9bcOpcode::Phase == _instruction.opcode) + { + size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size) + , "// %x" + , _instruction.opcode + ); + return size; + } + + size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size) + , "%2d %s" + , _instruction.opcode + , getName(_instruction.opcode) + ); + + switch (_instruction.opcode) + { + case Dx9bcOpcode::DCL: + size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size) + , "_%s%d (%d, %d, %d, %d)" + , s_dx9bcDeclUsage[_instruction.value[0] & UINT32_C(0x0000000f)] + , (_instruction.value[0] & UINT32_C(0x000f0000) )>>16 + , (_instruction.value[0] & UINT32_C(0x08000000) )>>27 // ? + , (_instruction.value[0] & UINT32_C(0x10000000) )>>28 // texture2d + , (_instruction.value[0] & UINT32_C(0x20000000) )>>29 // textureCube + , (_instruction.value[0] & UINT32_C(0x40000000) )>>30 // texture3d + ); + break; + + default: + break; + } + + for (uint32_t ii = 0; ii < _instruction.numOperands; ++ii) + { + const Dx9bcOperand& operand = _instruction.operand[ii]; + size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size) + , "%s%s%d" + , 0 == ii ? " " : ", " + , s_dx9bcOperandType[operand.type] + , operand.regIndex + ); + + if (operand.destination) + { + if (0xf > operand.writeMask + && 0 < operand.writeMask) + { + size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size) + , ".%s%s%s%s" + , 0 == (operand.writeMask & 1) ? "" : "x" + , 0 == (operand.writeMask & 2) ? "" : "y" + , 0 == (operand.writeMask & 4) ? "" : "z" + , 0 == (operand.writeMask & 8) ? "" : "w" + ); + } + } + else + { + if (Dx9bcOperandAddrMode::Relative == operand.addrMode) + { + const bool array = true; + + size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size) + , "[" + ); + + size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size) + , "%s%d" + , s_dx9bcOperandType[operand.subOperand.type] + , operand.subOperand.regIndex + ); + + size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size) + , "%s" + , array ? "]" : "" + ); + } + + if (0xe4 != operand.swizzleBits) + { + size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size) + , ".%c%c%c%c" + , "xyzw"[(operand.swizzleBits )&0x3] + , "xyzw"[(operand.swizzleBits>>2)&0x3] + , "xyzw"[(operand.swizzleBits>>4)&0x3] + , "xyzw"[(operand.swizzleBits>>6)&0x3] + ); + } + } + } + + switch (_instruction.opcode) + { + case Dx9bcOpcode::DEF: + for (uint32_t jj = 0; jj < _instruction.numValues; ++jj) + { + union { int32_t i; float f; } cast = { _instruction.value[jj] }; + size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size) + , "%s%f%s" + , 0 == jj ? " (" : ", " + , cast.f + , uint32_t(_instruction.numValues-1) == jj ? ")" : "" + ); + } + break; + + case Dx9bcOpcode::DEFI: + for (uint32_t jj = 0; jj < _instruction.numValues; ++jj) + { + size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size) + , "%s%d%s" + , 0 == jj ? " (" : ", " + , _instruction.value[jj] + , uint32_t(_instruction.numValues-1) == jj ? ")" : "" + ); + } + break; + + default: + break; + } + + return size; + } + + int32_t read(bx::ReaderSeekerI* _reader, Dx9bcShader& _shader) + { + int32_t size = 0; + int64_t offset = bx::seek(_reader); + + for (;;) + { + Dx9bcInstruction instruction; + int32_t length = read(_reader, instruction); + size += length; + + if (Dx9bcOpcode::Count > instruction.opcode) + { + char temp[512]; + toString(temp, 512, instruction); + + BX_CHECK(length/4 == instruction.length + , "%s\nread %d, expected %d" + , temp + , length/4 + , instruction.length + ); + } + else + { + if (Dx9bcOpcode::End == instruction.opcode) + { + size -= length; + break; + } + } + } + + bx::seek(_reader, offset, bx::Whence::Begin); + + _shader.byteCode.resize(size); + bx::read(_reader, _shader.byteCode.data(), size); + + return size; + } + + int32_t write(bx::WriterI* _writer, const Dx9bcShader& _shader) + { + BX_UNUSED(_writer, _shader); + return 0; + } + + int32_t read(bx::ReaderSeekerI* _reader, Dx9bc& _bc) + { + int32_t size = 0; + + size += bx::read(_reader, _bc.version); + + bool pixelShader = (0xffff0000 == (_bc.version & 0xffff0000) ); + uint32_t versionMajor = (_bc.version>>8)&0xff; + uint32_t versionMinor = _bc.version&0xff; + BX_UNUSED(pixelShader, versionMajor, versionMinor); + BX_TRACE("%s shader %d.%d" + , pixelShader ? "pixel" : "vertex" + , versionMajor + , versionMinor + ); + + size += read(_reader, _bc.shader); + + return size; + } + + int32_t write(bx::WriterSeekerI* _writer, const Dx9bc& _dxbc) + { + BX_UNUSED(_writer, _dxbc); + return 0; + } + + void parse(const Dx9bcShader& _src, Dx9bcParseFn _fn, void* _userData) + { + bx::MemoryReader reader(_src.byteCode.data(), uint32_t(_src.byteCode.size() ) ); + +//BX_TRACE("parse %d", _src.byteCode.size()); + + for (uint32_t token = 0, numTokens = uint32_t(_src.byteCode.size() / sizeof(uint32_t) ); token < numTokens;) + { + Dx9bcInstruction 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(token * sizeof(uint32_t), instruction, _userData); + + token += instruction.length; + } + } + + void filter(Dx9bcShader& _dst, const Dx9bcShader& _src, Dx9bcFilterFn _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;) + { + Dx9bcInstruction 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 |