756 lines
19 KiB
C++
756 lines
19 KiB
C++
/*
|
|
* Copyright 2011-2021 Branimir Karadzic. All rights reserved.
|
|
* License: https://github.com/bkaradzic/bgfx#license-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_ASSERT(_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, bx::Error* _err)
|
|
{
|
|
int32_t size = 0;
|
|
|
|
uint32_t token;
|
|
size += bx::read(_reader, token, _err);
|
|
|
|
_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, bx::Error* _err)
|
|
{
|
|
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, _err);
|
|
|
|
return size;
|
|
}
|
|
|
|
int32_t read(bx::ReaderI* _reader, Dx9bcOperand& _operand, bx::Error* _err)
|
|
{
|
|
int32_t size = 0;
|
|
|
|
uint32_t token;
|
|
size += bx::read(_reader, token, _err);
|
|
|
|
_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, _err);
|
|
}
|
|
|
|
return size;
|
|
}
|
|
|
|
int32_t write(bx::WriterI* _writer, const Dx9bcOperand& _operand, bx::Error* _err)
|
|
{
|
|
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, _err);
|
|
|
|
if (Dx9bcOperandAddrMode::Relative == _operand.addrMode)
|
|
{
|
|
size += write(_writer, _operand.subOperand, _err);
|
|
}
|
|
|
|
return size;
|
|
}
|
|
|
|
int32_t read(bx::ReaderI* _reader, Dx9bcInstruction& _instruction, bx::Error* _err)
|
|
{
|
|
int32_t size = 0;
|
|
|
|
uint32_t token;
|
|
size += bx::read(_reader, token, _err);
|
|
|
|
_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, _err);
|
|
}
|
|
}
|
|
|
|
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), _err);
|
|
}
|
|
|
|
_instruction.operand[0].destination = true;
|
|
|
|
switch (_instruction.numOperands)
|
|
{
|
|
case 6: size += read(_reader, _instruction.operand[currOp++], _err); BX_FALLTHROUGH;
|
|
case 5: size += read(_reader, _instruction.operand[currOp++], _err); BX_FALLTHROUGH;
|
|
case 4: size += read(_reader, _instruction.operand[currOp++], _err); BX_FALLTHROUGH;
|
|
case 3: size += read(_reader, _instruction.operand[currOp++], _err); BX_FALLTHROUGH;
|
|
case 2: size += read(_reader, _instruction.operand[currOp++], _err); BX_FALLTHROUGH;
|
|
case 1: size += read(_reader, _instruction.operand[currOp++], _err); BX_FALLTHROUGH;
|
|
case 0:
|
|
if (!valuesBeforeOpcode
|
|
&& 0 < info.numValues)
|
|
{
|
|
size += read(_reader, _instruction.value, info.numValues*sizeof(uint32_t), _err);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
BX_ASSERT(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, bx::Error* _err)
|
|
{
|
|
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, _err);
|
|
|
|
uint32_t currOp = 0;
|
|
switch (_instruction.numOperands)
|
|
{
|
|
case 6: size += write(_writer, _instruction.operand[currOp++], _err); BX_FALLTHROUGH;
|
|
case 5: size += write(_writer, _instruction.operand[currOp++], _err); BX_FALLTHROUGH;
|
|
case 4: size += write(_writer, _instruction.operand[currOp++], _err); BX_FALLTHROUGH;
|
|
case 3: size += write(_writer, _instruction.operand[currOp++], _err); BX_FALLTHROUGH;
|
|
case 2: size += write(_writer, _instruction.operand[currOp++], _err); BX_FALLTHROUGH;
|
|
case 1: size += write(_writer, _instruction.operand[currOp++], _err); BX_FALLTHROUGH;
|
|
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, bx::Error* _err)
|
|
{
|
|
int32_t size = 0;
|
|
int64_t offset = bx::seek(_reader);
|
|
|
|
for (;;)
|
|
{
|
|
Dx9bcInstruction instruction;
|
|
int32_t length = read(_reader, instruction, _err);
|
|
size += length;
|
|
|
|
if (Dx9bcOpcode::Count > instruction.opcode)
|
|
{
|
|
char temp[512];
|
|
toString(temp, 512, instruction);
|
|
|
|
BX_ASSERT(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, _err);
|
|
|
|
return size;
|
|
}
|
|
|
|
int32_t write(bx::WriterI* _writer, const Dx9bcShader& _shader, bx::Error* _err)
|
|
{
|
|
BX_UNUSED(_writer, _shader, _err);
|
|
return 0;
|
|
}
|
|
|
|
int32_t read(bx::ReaderSeekerI* _reader, Dx9bc& _bc, bx::Error* _err)
|
|
{
|
|
int32_t size = 0;
|
|
|
|
size += bx::read(_reader, _bc.version, _err);
|
|
|
|
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, _err);
|
|
|
|
return size;
|
|
}
|
|
|
|
int32_t write(bx::WriterSeekerI* _writer, const Dx9bc& _dxbc, bx::Error* _err)
|
|
{
|
|
BX_UNUSED(_writer, _dxbc, _err);
|
|
return 0;
|
|
}
|
|
|
|
void parse(const Dx9bcShader& _src, Dx9bcParseFn _fn, void* _userData, bx::Error* _err)
|
|
{
|
|
BX_ERROR_SCOPE(_err);
|
|
|
|
bx::MemoryReader reader(_src.byteCode.data(), uint32_t(_src.byteCode.size() ) );
|
|
|
|
bx::Error err;
|
|
|
|
for (uint32_t token = 0, numTokens = uint32_t(_src.byteCode.size() / sizeof(uint32_t) ); token < numTokens;)
|
|
{
|
|
Dx9bcInstruction instruction;
|
|
uint32_t size = read(&reader, instruction, _err);
|
|
BX_ASSERT(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(Dx9bcShader& _dst, const Dx9bcShader& _src, Dx9bcFilterFn _fn, void* _userData, bx::Error* _err)
|
|
{
|
|
BX_ERROR_SCOPE(_err);
|
|
|
|
bx::MemoryReader reader(_src.byteCode.data(), uint32_t(_src.byteCode.size() ) );
|
|
|
|
bx::MemoryBlock mb(g_allocator);
|
|
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, _err);
|
|
BX_ASSERT(size/4 == instruction.length, "read %d, expected %d", size/4, instruction.length); BX_UNUSED(size);
|
|
|
|
_fn(instruction, _userData);
|
|
|
|
write(&writer, instruction, _err);
|
|
|
|
token += instruction.length;
|
|
}
|
|
|
|
uint8_t* data = (uint8_t*)mb.more();
|
|
uint32_t size = uint32_t(bx::getSize(&writer) );
|
|
_dst.byteCode.reserve(size);
|
|
bx::memCopy(_dst.byteCode.data(), data, size);
|
|
}
|
|
|
|
} // namespace bgfx
|