1636 lines
56 KiB
C++
1636 lines
56 KiB
C++
#include "internal_includes/tokens.h"
|
|
#include "internal_includes/decode.h"
|
|
#include "stdlib.h"
|
|
#include "stdio.h"
|
|
#include "internal_includes/reflect.h"
|
|
#include "internal_includes/debug.h"
|
|
#include "internal_includes/toGLSLOperand.h"
|
|
#include "internal_includes/Shader.h"
|
|
#include "internal_includes/Instruction.h"
|
|
#include "internal_includes/Declaration.h"
|
|
|
|
#define FOURCC(a, b, c, d) ((uint32_t)(uint8_t)(a) | ((uint32_t)(uint8_t)(b) << 8) | ((uint32_t)(uint8_t)(c) << 16) | ((uint32_t)(uint8_t)(d) << 24 ))
|
|
enum { FOURCC_DXBC = FOURCC('D', 'X', 'B', 'C') }; //DirectX byte code
|
|
enum { FOURCC_SHDR = FOURCC('S', 'H', 'D', 'R') }; //Shader model 4 code
|
|
enum { FOURCC_SHEX = FOURCC('S', 'H', 'E', 'X') }; //Shader model 5 code
|
|
enum { FOURCC_RDEF = FOURCC('R', 'D', 'E', 'F') }; //Resource definition (e.g. constant buffers)
|
|
enum { FOURCC_ISGN = FOURCC('I', 'S', 'G', 'N') }; //Input signature
|
|
enum { FOURCC_IFCE = FOURCC('I', 'F', 'C', 'E') }; //Interface (for dynamic linking)
|
|
enum { FOURCC_OSGN = FOURCC('O', 'S', 'G', 'N') }; //Output signature
|
|
enum { FOURCC_PSGN = FOURCC('P', 'C', 'S', 'G') }; //Patch-constant signature
|
|
|
|
enum { FOURCC_ISG1 = FOURCC('I', 'S', 'G', '1') }; //Input signature with Stream and MinPrecision
|
|
enum { FOURCC_OSG1 = FOURCC('O', 'S', 'G', '1') }; //Output signature with Stream and MinPrecision
|
|
enum { FOURCC_OSG5 = FOURCC('O', 'S', 'G', '5') }; //Output signature with Stream
|
|
enum { FOURCC_PSG1 = FOURCC('P', 'S', 'G', '1') }; //Patch constant signature with MinPrecision
|
|
|
|
enum { FOURCC_STAT = FOURCC('S', 'T', 'A', 'T') }; // Chunks that we ignore
|
|
enum { FOURCC_SFI0 = FOURCC('S', 'F', 'I', '0') }; // Chunks that we ignore
|
|
|
|
|
|
typedef struct DXBCContainerHeaderTAG
|
|
{
|
|
unsigned fourcc;
|
|
uint32_t unk[4];
|
|
uint32_t one;
|
|
uint32_t totalSize;
|
|
uint32_t chunkCount;
|
|
} DXBCContainerHeader;
|
|
|
|
typedef struct DXBCChunkHeaderTAG
|
|
{
|
|
unsigned fourcc;
|
|
unsigned size;
|
|
} DXBCChunkHeader;
|
|
|
|
#ifdef _DEBUG
|
|
static uint64_t operandID = 0;
|
|
static uint64_t instructionID = 0;
|
|
#endif
|
|
|
|
void DecodeNameToken(const uint32_t* pui32NameToken, Operand* psOperand)
|
|
{
|
|
psOperand->eSpecialName = DecodeOperandSpecialName(*pui32NameToken);
|
|
switch (psOperand->eSpecialName)
|
|
{
|
|
case NAME_UNDEFINED:
|
|
{
|
|
psOperand->specialName = "undefined";
|
|
break;
|
|
}
|
|
case NAME_POSITION:
|
|
{
|
|
psOperand->specialName = "position";
|
|
break;
|
|
}
|
|
case NAME_CLIP_DISTANCE:
|
|
{
|
|
psOperand->specialName = "clipDistance";
|
|
break;
|
|
}
|
|
case NAME_CULL_DISTANCE:
|
|
{
|
|
psOperand->specialName = "cullDistance";
|
|
break;
|
|
}
|
|
case NAME_RENDER_TARGET_ARRAY_INDEX:
|
|
{
|
|
psOperand->specialName = "renderTargetArrayIndex";
|
|
break;
|
|
}
|
|
case NAME_VIEWPORT_ARRAY_INDEX:
|
|
{
|
|
psOperand->specialName = "viewportArrayIndex";
|
|
break;
|
|
}
|
|
case NAME_VERTEX_ID:
|
|
{
|
|
psOperand->specialName = "vertexID";
|
|
break;
|
|
}
|
|
case NAME_PRIMITIVE_ID:
|
|
{
|
|
psOperand->specialName = "primitiveID";
|
|
break;
|
|
}
|
|
case NAME_INSTANCE_ID:
|
|
{
|
|
psOperand->specialName = "instanceID";
|
|
break;
|
|
}
|
|
case NAME_IS_FRONT_FACE:
|
|
{
|
|
psOperand->specialName = "isFrontFace";
|
|
break;
|
|
}
|
|
case NAME_SAMPLE_INDEX:
|
|
{
|
|
psOperand->specialName = "sampleIndex";
|
|
break;
|
|
}
|
|
//For the quadrilateral domain, there are 6 factors (4 sides, 2 inner).
|
|
case NAME_FINAL_QUAD_U_EQ_0_EDGE_TESSFACTOR:
|
|
case NAME_FINAL_QUAD_V_EQ_0_EDGE_TESSFACTOR:
|
|
case NAME_FINAL_QUAD_U_EQ_1_EDGE_TESSFACTOR:
|
|
case NAME_FINAL_QUAD_V_EQ_1_EDGE_TESSFACTOR:
|
|
case NAME_FINAL_QUAD_U_INSIDE_TESSFACTOR:
|
|
case NAME_FINAL_QUAD_V_INSIDE_TESSFACTOR:
|
|
|
|
//For the triangular domain, there are 4 factors (3 sides, 1 inner)
|
|
case NAME_FINAL_TRI_U_EQ_0_EDGE_TESSFACTOR:
|
|
case NAME_FINAL_TRI_V_EQ_0_EDGE_TESSFACTOR:
|
|
case NAME_FINAL_TRI_W_EQ_0_EDGE_TESSFACTOR:
|
|
case NAME_FINAL_TRI_INSIDE_TESSFACTOR:
|
|
|
|
//For the isoline domain, there are 2 factors (detail and density).
|
|
case NAME_FINAL_LINE_DETAIL_TESSFACTOR:
|
|
case NAME_FINAL_LINE_DENSITY_TESSFACTOR:
|
|
{
|
|
psOperand->specialName = "tessFactor";
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
ASSERT(0);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Find the declaration of the texture described by psTextureOperand and
|
|
// mark it as a shadow type. (e.g. accessed via sampler2DShadow rather than sampler2D)
|
|
static void MarkTextureAsShadow(ShaderInfo* psShaderInfo, std::vector<Declaration> &declarations, const Operand* psTextureOperand)
|
|
{
|
|
ASSERT(psTextureOperand->eType == OPERAND_TYPE_RESOURCE);
|
|
|
|
for (std::vector<Declaration>::iterator psDecl = declarations.begin(); psDecl != declarations.end(); psDecl++)
|
|
{
|
|
if (psDecl->eOpcode == OPCODE_DCL_RESOURCE)
|
|
{
|
|
if (psDecl->asOperands[0].eType == OPERAND_TYPE_RESOURCE &&
|
|
psDecl->asOperands[0].ui32RegisterNumber == psTextureOperand->ui32RegisterNumber)
|
|
{
|
|
psDecl->ui32IsShadowTex = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void MarkTextureSamplerPair(ShaderInfo* psShaderInfo, std::vector<Declaration> & declarations, const Operand* psTextureOperand, const Operand* psSamplerOperand, TextureSamplerPairs& samplers)
|
|
{
|
|
ASSERT(psTextureOperand->eType == OPERAND_TYPE_RESOURCE);
|
|
ASSERT(psSamplerOperand->eType == OPERAND_TYPE_SAMPLER);
|
|
|
|
for (std::vector<Declaration>::iterator psDecl = declarations.begin(); psDecl != declarations.end(); psDecl++)
|
|
{
|
|
if (psDecl->eOpcode == OPCODE_DCL_RESOURCE)
|
|
{
|
|
if (psDecl->asOperands[0].eType == OPERAND_TYPE_RESOURCE &&
|
|
psDecl->asOperands[0].ui32RegisterNumber == psTextureOperand->ui32RegisterNumber)
|
|
{
|
|
// psDecl is the texture resource referenced by psTextureOperand
|
|
|
|
// add psSamplerOperand->ui32RegisterNumber to list of samplers that use this texture
|
|
// set::insert returns a pair of which .second tells whether a new element was actually added
|
|
if (psDecl->samplersUsed.insert(psSamplerOperand->ui32RegisterNumber).second)
|
|
{
|
|
// Record the <texturename>TEX_with_SMP<samplername> string in the TextureSamplerPair array that we return to the client
|
|
std::string combinedname = TextureSamplerName(psShaderInfo, psTextureOperand->ui32RegisterNumber, psSamplerOperand->ui32RegisterNumber, psDecl->ui32IsShadowTex);
|
|
samplers.push_back(combinedname);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
uint32_t DecodeOperand(const uint32_t *pui32Tokens, Operand* psOperand)
|
|
{
|
|
int i;
|
|
uint32_t ui32NumTokens = 1;
|
|
OPERAND_NUM_COMPONENTS eNumComponents;
|
|
|
|
#ifdef _DEBUG
|
|
psOperand->id = operandID++;
|
|
#endif
|
|
|
|
//Some defaults
|
|
psOperand->iWriteMaskEnabled = 1;
|
|
psOperand->iGSInput = 0;
|
|
psOperand->iPSInOut = 0;
|
|
psOperand->aeDataType[0] = SVT_FLOAT;
|
|
psOperand->aeDataType[1] = SVT_FLOAT;
|
|
psOperand->aeDataType[2] = SVT_FLOAT;
|
|
psOperand->aeDataType[3] = SVT_FLOAT;
|
|
|
|
psOperand->iExtended = DecodeIsOperandExtended(*pui32Tokens);
|
|
|
|
|
|
psOperand->eModifier = OPERAND_MODIFIER_NONE;
|
|
psOperand->m_SubOperands[0].reset();
|
|
psOperand->m_SubOperands[1].reset();
|
|
psOperand->m_SubOperands[2].reset();
|
|
|
|
psOperand->eMinPrecision = OPERAND_MIN_PRECISION_DEFAULT;
|
|
|
|
/* Check if this instruction is extended. If it is,
|
|
* we need to print the information first */
|
|
if (psOperand->iExtended)
|
|
{
|
|
/* OperandToken1 is the second token */
|
|
ui32NumTokens++;
|
|
|
|
if (DecodeExtendedOperandType(pui32Tokens[1]) == EXTENDED_OPERAND_MODIFIER)
|
|
{
|
|
psOperand->eModifier = DecodeExtendedOperandModifier(pui32Tokens[1]);
|
|
psOperand->eMinPrecision = (OPERAND_MIN_PRECISION)DecodeOperandMinPrecision(pui32Tokens[1]);
|
|
}
|
|
}
|
|
|
|
psOperand->iIndexDims = DecodeOperandIndexDimension(*pui32Tokens);
|
|
psOperand->eType = DecodeOperandType(*pui32Tokens);
|
|
|
|
psOperand->ui32RegisterNumber = 0;
|
|
|
|
eNumComponents = DecodeOperandNumComponents(*pui32Tokens);
|
|
|
|
if (psOperand->eType == OPERAND_TYPE_INPUT_GS_INSTANCE_ID)
|
|
{
|
|
eNumComponents = OPERAND_1_COMPONENT;
|
|
psOperand->aeDataType[0] = SVT_UINT;
|
|
}
|
|
|
|
switch (eNumComponents)
|
|
{
|
|
case OPERAND_1_COMPONENT:
|
|
{
|
|
psOperand->iNumComponents = 1;
|
|
break;
|
|
}
|
|
case OPERAND_4_COMPONENT:
|
|
{
|
|
psOperand->iNumComponents = 4;
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
psOperand->iNumComponents = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (psOperand->iWriteMaskEnabled &&
|
|
psOperand->iNumComponents == 4)
|
|
{
|
|
psOperand->eSelMode = DecodeOperand4CompSelMode(*pui32Tokens);
|
|
|
|
if (psOperand->eSelMode == OPERAND_4_COMPONENT_MASK_MODE)
|
|
{
|
|
psOperand->ui32CompMask = DecodeOperand4CompMask(*pui32Tokens);
|
|
}
|
|
else if (psOperand->eSelMode == OPERAND_4_COMPONENT_SWIZZLE_MODE)
|
|
{
|
|
psOperand->ui32Swizzle = DecodeOperand4CompSwizzle(*pui32Tokens);
|
|
|
|
if (psOperand->ui32Swizzle != NO_SWIZZLE)
|
|
{
|
|
psOperand->aui32Swizzle[0] = DecodeOperand4CompSwizzleSource(*pui32Tokens, 0);
|
|
psOperand->aui32Swizzle[1] = DecodeOperand4CompSwizzleSource(*pui32Tokens, 1);
|
|
psOperand->aui32Swizzle[2] = DecodeOperand4CompSwizzleSource(*pui32Tokens, 2);
|
|
psOperand->aui32Swizzle[3] = DecodeOperand4CompSwizzleSource(*pui32Tokens, 3);
|
|
}
|
|
else
|
|
{
|
|
psOperand->aui32Swizzle[0] = OPERAND_4_COMPONENT_X;
|
|
psOperand->aui32Swizzle[1] = OPERAND_4_COMPONENT_Y;
|
|
psOperand->aui32Swizzle[2] = OPERAND_4_COMPONENT_Z;
|
|
psOperand->aui32Swizzle[3] = OPERAND_4_COMPONENT_W;
|
|
}
|
|
}
|
|
else if (psOperand->eSelMode == OPERAND_4_COMPONENT_SELECT_1_MODE)
|
|
{
|
|
psOperand->aui32Swizzle[0] = DecodeOperand4CompSel1(*pui32Tokens);
|
|
}
|
|
}
|
|
|
|
if (psOperand->eType == OPERAND_TYPE_IMMEDIATE32)
|
|
{
|
|
for (i = 0; i < psOperand->iNumComponents; ++i)
|
|
{
|
|
psOperand->afImmediates[i] = *((float*)(&pui32Tokens[ui32NumTokens]));
|
|
ui32NumTokens++;
|
|
}
|
|
}
|
|
else if (psOperand->eType == OPERAND_TYPE_IMMEDIATE64)
|
|
{
|
|
for (i = 0; i < psOperand->iNumComponents; ++i)
|
|
{
|
|
psOperand->adImmediates[i] = *((double*)(&pui32Tokens[ui32NumTokens]));
|
|
ui32NumTokens += 2;
|
|
}
|
|
}
|
|
|
|
// Used only for Metal
|
|
if (psOperand->eType == OPERAND_TYPE_OUTPUT_DEPTH_GREATER_EQUAL || psOperand->eType == OPERAND_TYPE_OUTPUT_DEPTH_LESS_EQUAL || psOperand->eType == OPERAND_TYPE_OUTPUT_DEPTH)
|
|
{
|
|
psOperand->ui32RegisterNumber = 0;
|
|
psOperand->ui32CompMask = 1;
|
|
}
|
|
|
|
for (i = 0; i < psOperand->iIndexDims; ++i)
|
|
{
|
|
OPERAND_INDEX_REPRESENTATION eRep = DecodeOperandIndexRepresentation(i , *pui32Tokens);
|
|
|
|
psOperand->eIndexRep[i] = eRep;
|
|
|
|
psOperand->aui32ArraySizes[i] = 0;
|
|
psOperand->ui32RegisterNumber = 0;
|
|
|
|
switch (eRep)
|
|
{
|
|
case OPERAND_INDEX_IMMEDIATE32:
|
|
{
|
|
psOperand->ui32RegisterNumber = *(pui32Tokens + ui32NumTokens);
|
|
psOperand->aui32ArraySizes[i] = psOperand->ui32RegisterNumber;
|
|
break;
|
|
}
|
|
case OPERAND_INDEX_RELATIVE:
|
|
{
|
|
psOperand->m_SubOperands[i].reset(new Operand());
|
|
DecodeOperand(pui32Tokens + ui32NumTokens, psOperand->m_SubOperands[i].get());
|
|
|
|
ui32NumTokens++;
|
|
break;
|
|
}
|
|
case OPERAND_INDEX_IMMEDIATE32_PLUS_RELATIVE:
|
|
{
|
|
psOperand->ui32RegisterNumber = *(pui32Tokens + ui32NumTokens);
|
|
psOperand->aui32ArraySizes[i] = psOperand->ui32RegisterNumber;
|
|
|
|
ui32NumTokens++;
|
|
|
|
psOperand->m_SubOperands[i].reset(new Operand());
|
|
DecodeOperand(pui32Tokens + ui32NumTokens, psOperand->m_SubOperands[i].get());
|
|
|
|
ui32NumTokens++;
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
ASSERT(0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Indices should be ints
|
|
switch (eRep)
|
|
{
|
|
case OPERAND_INDEX_IMMEDIATE32:
|
|
case OPERAND_INDEX_RELATIVE:
|
|
case OPERAND_INDEX_IMMEDIATE32_PLUS_RELATIVE:
|
|
{
|
|
int j = 0;
|
|
for (; j < psOperand->iNumComponents; j++)
|
|
{
|
|
psOperand->aeDataType[j] = SVT_INT;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
ui32NumTokens++;
|
|
}
|
|
|
|
psOperand->specialName = "";
|
|
|
|
return ui32NumTokens;
|
|
}
|
|
|
|
const uint32_t* DecodeDeclaration(Shader* psShader, const uint32_t* pui32Token, Declaration* psDecl, ShaderPhase *psPhase)
|
|
{
|
|
uint32_t ui32TokenLength = DecodeInstructionLength(*pui32Token);
|
|
const uint32_t bExtended = DecodeIsOpcodeExtended(*pui32Token);
|
|
const OPCODE_TYPE eOpcode = DecodeOpcodeType(*pui32Token);
|
|
uint32_t ui32OperandOffset = 1;
|
|
|
|
if (eOpcode < NUM_OPCODES && eOpcode >= 0)
|
|
{
|
|
psShader->aiOpcodeUsed[eOpcode] = 1;
|
|
}
|
|
|
|
psDecl->eOpcode = eOpcode;
|
|
|
|
psDecl->ui32IsShadowTex = 0;
|
|
|
|
if (bExtended)
|
|
{
|
|
ui32OperandOffset = 2;
|
|
}
|
|
|
|
switch (eOpcode)
|
|
{
|
|
case OPCODE_DCL_RESOURCE: // DCL* opcodes have
|
|
{
|
|
psDecl->value.eResourceDimension = DecodeResourceDimension(*pui32Token);
|
|
psDecl->ui32NumOperands = 1;
|
|
DecodeOperand(pui32Token + ui32OperandOffset, &psDecl->asOperands[0]);
|
|
break;
|
|
}
|
|
case OPCODE_DCL_CONSTANT_BUFFER: // custom operand formats.
|
|
{
|
|
psDecl->ui32NumOperands = 1;
|
|
DecodeOperand(pui32Token + ui32OperandOffset, &psDecl->asOperands[0]);
|
|
break;
|
|
}
|
|
case OPCODE_DCL_SAMPLER:
|
|
{
|
|
psDecl->ui32NumOperands = 1;
|
|
psDecl->value.eSamplerMode = DecodeSamplerMode(*pui32Token);
|
|
|
|
DecodeOperand(pui32Token + ui32OperandOffset, &psDecl->asOperands[0]);
|
|
break;
|
|
}
|
|
case OPCODE_DCL_INDEX_RANGE:
|
|
{
|
|
int regSpace = 0;
|
|
psDecl->ui32NumOperands = 1;
|
|
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psDecl->asOperands[0]);
|
|
psDecl->value.ui32IndexRange = pui32Token[ui32OperandOffset];
|
|
|
|
regSpace = psDecl->asOperands[0].GetRegisterSpace(psShader->eShaderType, psPhase->ePhase);
|
|
if (psDecl->asOperands[0].eType == OPERAND_TYPE_INPUT)
|
|
{
|
|
uint32_t i;
|
|
const uint32_t indexRange = psDecl->value.ui32IndexRange;
|
|
const uint32_t reg = psDecl->asOperands[0].ui32RegisterNumber;
|
|
|
|
psShader->aIndexedInput[regSpace][reg] = indexRange;
|
|
psShader->aIndexedInputParents[regSpace][reg] = reg;
|
|
|
|
//-1 means don't declare this input because it falls in
|
|
//the range of an already declared array.
|
|
for (i = reg + 1; i < reg + indexRange; ++i)
|
|
{
|
|
psShader->aIndexedInput[regSpace][i] = -1;
|
|
psShader->aIndexedInputParents[regSpace][i] = reg;
|
|
}
|
|
}
|
|
|
|
if (psDecl->asOperands[0].eType == OPERAND_TYPE_OUTPUT)
|
|
{
|
|
psShader->aIndexedOutput[regSpace][psDecl->asOperands[0].ui32RegisterNumber] = true;
|
|
}
|
|
break;
|
|
}
|
|
case OPCODE_DCL_GS_OUTPUT_PRIMITIVE_TOPOLOGY:
|
|
{
|
|
psDecl->value.eOutputPrimitiveTopology = DecodeGSOutputPrimitiveTopology(*pui32Token);
|
|
break;
|
|
}
|
|
case OPCODE_DCL_GS_INPUT_PRIMITIVE:
|
|
{
|
|
psDecl->value.eInputPrimitive = DecodeGSInputPrimitive(*pui32Token);
|
|
break;
|
|
}
|
|
case OPCODE_DCL_MAX_OUTPUT_VERTEX_COUNT:
|
|
{
|
|
psDecl->value.ui32MaxOutputVertexCount = pui32Token[1];
|
|
break;
|
|
}
|
|
case OPCODE_DCL_TESS_PARTITIONING:
|
|
{
|
|
psDecl->value.eTessPartitioning = DecodeTessPartitioning(*pui32Token);
|
|
break;
|
|
}
|
|
case OPCODE_DCL_TESS_DOMAIN:
|
|
{
|
|
psDecl->value.eTessDomain = DecodeTessDomain(*pui32Token);
|
|
break;
|
|
}
|
|
case OPCODE_DCL_TESS_OUTPUT_PRIMITIVE:
|
|
{
|
|
psDecl->value.eTessOutPrim = DecodeTessOutPrim(*pui32Token);
|
|
break;
|
|
}
|
|
case OPCODE_DCL_THREAD_GROUP:
|
|
{
|
|
psDecl->value.aui32WorkGroupSize[0] = pui32Token[1];
|
|
psDecl->value.aui32WorkGroupSize[1] = pui32Token[2];
|
|
psDecl->value.aui32WorkGroupSize[2] = pui32Token[3];
|
|
break;
|
|
}
|
|
case OPCODE_DCL_INPUT:
|
|
{
|
|
psDecl->ui32NumOperands = 1;
|
|
DecodeOperand(pui32Token + ui32OperandOffset, &psDecl->asOperands[0]);
|
|
break;
|
|
}
|
|
case OPCODE_DCL_INPUT_SIV:
|
|
{
|
|
psDecl->ui32NumOperands = 1;
|
|
DecodeOperand(pui32Token + ui32OperandOffset, &psDecl->asOperands[0]);
|
|
if (psShader->eShaderType == PIXEL_SHADER)
|
|
{
|
|
psDecl->value.eInterpolation = DecodeInterpolationMode(*pui32Token);
|
|
}
|
|
break;
|
|
}
|
|
case OPCODE_DCL_INPUT_PS:
|
|
{
|
|
psDecl->ui32NumOperands = 1;
|
|
psDecl->value.eInterpolation = DecodeInterpolationMode(*pui32Token);
|
|
Operand* psOperand = &psDecl->asOperands[0];
|
|
DecodeOperand(pui32Token + ui32OperandOffset, psOperand);
|
|
|
|
ShaderInfo::InOutSignature *psSig = NULL;
|
|
psShader->sInfo.GetInputSignatureFromRegister(psOperand->ui32RegisterNumber, psOperand->ui32CompMask, (const ShaderInfo::InOutSignature**)&psSig);
|
|
|
|
/* UNITY_FRAMEBUFFER_FETCH_AVAILABLE
|
|
special case mapping for inout color.
|
|
|
|
In the fragment shader, setting inout <type> var : SV_Target would result to
|
|
compiler error, unless SV_Target is defined to COLOR semantic for compatibility
|
|
reasons. Unfortunately, we still need to have a clear distinction between
|
|
vertex shader COLOR output and SV_Target, so the following workaround abuses
|
|
the fact that semantic names are case insensitive and preprocessor macros
|
|
are not. The resulting HLSL bytecode has semantics in case preserving form,
|
|
helps code generator to do extra work required for framebuffer fetch
|
|
|
|
See also HLSLSupport.cginc
|
|
*/
|
|
if (psSig->eSystemValueType == NAME_UNDEFINED &&
|
|
psSig->semanticName.size() == 5 && !strncmp(psSig->semanticName.c_str(), "CoLoR", 5))
|
|
{
|
|
// Rename into something more readable, matches output
|
|
psSig->semanticName.replace(0, 9, "SV_Target");
|
|
psOperand->iPSInOut = 1;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case OPCODE_DCL_INPUT_SGV:
|
|
case OPCODE_DCL_INPUT_PS_SGV:
|
|
{
|
|
psDecl->ui32NumOperands = 1;
|
|
DecodeOperand(pui32Token + ui32OperandOffset, &psDecl->asOperands[0]);
|
|
DecodeNameToken(pui32Token + 3, &psDecl->asOperands[0]);
|
|
break;
|
|
}
|
|
case OPCODE_DCL_INPUT_PS_SIV:
|
|
{
|
|
psDecl->ui32NumOperands = 1;
|
|
psDecl->value.eInterpolation = DecodeInterpolationMode(*pui32Token);
|
|
DecodeOperand(pui32Token + ui32OperandOffset, &psDecl->asOperands[0]);
|
|
DecodeNameToken(pui32Token + 3, &psDecl->asOperands[0]);
|
|
break;
|
|
}
|
|
case OPCODE_DCL_OUTPUT:
|
|
{
|
|
psDecl->ui32NumOperands = 1;
|
|
DecodeOperand(pui32Token + ui32OperandOffset, &psDecl->asOperands[0]);
|
|
break;
|
|
}
|
|
case OPCODE_DCL_OUTPUT_SGV:
|
|
{
|
|
break;
|
|
}
|
|
case OPCODE_DCL_OUTPUT_SIV:
|
|
{
|
|
psDecl->ui32NumOperands = 1;
|
|
DecodeOperand(pui32Token + ui32OperandOffset, &psDecl->asOperands[0]);
|
|
DecodeNameToken(pui32Token + 3, &psDecl->asOperands[0]);
|
|
break;
|
|
}
|
|
case OPCODE_DCL_TEMPS:
|
|
{
|
|
psDecl->value.ui32NumTemps = *(pui32Token + ui32OperandOffset);
|
|
break;
|
|
}
|
|
case OPCODE_DCL_INDEXABLE_TEMP:
|
|
{
|
|
psDecl->sIdxTemp.ui32RegIndex = *(pui32Token + ui32OperandOffset);
|
|
psDecl->sIdxTemp.ui32RegCount = *(pui32Token + ui32OperandOffset + 1);
|
|
psDecl->sIdxTemp.ui32RegComponentSize = *(pui32Token + ui32OperandOffset + 2);
|
|
break;
|
|
}
|
|
case OPCODE_DCL_GLOBAL_FLAGS:
|
|
{
|
|
psDecl->value.ui32GlobalFlags = DecodeGlobalFlags(*pui32Token);
|
|
break;
|
|
}
|
|
case OPCODE_DCL_INTERFACE:
|
|
{
|
|
uint32_t func = 0, numClassesImplementingThisInterface, arrayLen, interfaceID;
|
|
interfaceID = pui32Token[ui32OperandOffset];
|
|
ui32OperandOffset++;
|
|
psDecl->ui32TableLength = pui32Token[ui32OperandOffset];
|
|
ui32OperandOffset++;
|
|
|
|
numClassesImplementingThisInterface = DecodeInterfaceTableLength(*(pui32Token + ui32OperandOffset));
|
|
arrayLen = DecodeInterfaceArrayLength(*(pui32Token + ui32OperandOffset));
|
|
|
|
ui32OperandOffset++;
|
|
|
|
psDecl->value.iface.ui32InterfaceID = interfaceID;
|
|
psDecl->value.iface.ui32NumFuncTables = numClassesImplementingThisInterface;
|
|
psDecl->value.iface.ui32ArraySize = arrayLen;
|
|
|
|
psShader->funcPointer[interfaceID].ui32NumBodiesPerTable = psDecl->ui32TableLength;
|
|
|
|
for (; func < numClassesImplementingThisInterface; ++func)
|
|
{
|
|
uint32_t ui32FuncTable = *(pui32Token + ui32OperandOffset);
|
|
psShader->aui32FuncTableToFuncPointer[ui32FuncTable] = interfaceID;
|
|
|
|
psShader->funcPointer[interfaceID].aui32FuncTables[func] = ui32FuncTable;
|
|
ui32OperandOffset++;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case OPCODE_DCL_FUNCTION_BODY:
|
|
{
|
|
psDecl->ui32NumOperands = 1;
|
|
DecodeOperand(pui32Token + ui32OperandOffset, &psDecl->asOperands[0]);
|
|
break;
|
|
}
|
|
case OPCODE_DCL_FUNCTION_TABLE:
|
|
{
|
|
uint32_t ui32Func;
|
|
const uint32_t ui32FuncTableID = pui32Token[ui32OperandOffset++];
|
|
const uint32_t ui32NumFuncsInTable = pui32Token[ui32OperandOffset++];
|
|
|
|
for (ui32Func = 0; ui32Func < ui32NumFuncsInTable; ++ui32Func)
|
|
{
|
|
const uint32_t ui32FuncBodyID = pui32Token[ui32OperandOffset++];
|
|
|
|
psShader->aui32FuncBodyToFuncTable[ui32FuncBodyID] = ui32FuncTableID;
|
|
|
|
psShader->funcTable[ui32FuncTableID].aui32FuncBodies[ui32Func] = ui32FuncBodyID;
|
|
}
|
|
|
|
// OpcodeToken0 is followed by a DWORD that represents the function table
|
|
// identifier and another DWORD (TableLength) that gives the number of
|
|
// functions in the table.
|
|
//
|
|
// This is followed by TableLength DWORDs which are function body indices.
|
|
//
|
|
|
|
break;
|
|
}
|
|
case OPCODE_DCL_INPUT_CONTROL_POINT_COUNT:
|
|
{
|
|
psDecl->value.ui32MaxOutputVertexCount = DecodeOutputControlPointCount(*pui32Token);
|
|
break;
|
|
}
|
|
case OPCODE_HS_DECLS:
|
|
{
|
|
break;
|
|
}
|
|
case OPCODE_DCL_OUTPUT_CONTROL_POINT_COUNT:
|
|
{
|
|
psDecl->value.ui32MaxOutputVertexCount = DecodeOutputControlPointCount(*pui32Token);
|
|
break;
|
|
}
|
|
case OPCODE_HS_JOIN_PHASE:
|
|
case OPCODE_HS_FORK_PHASE:
|
|
case OPCODE_HS_CONTROL_POINT_PHASE:
|
|
{
|
|
break;
|
|
}
|
|
case OPCODE_DCL_HS_FORK_PHASE_INSTANCE_COUNT:
|
|
case OPCODE_DCL_HS_JOIN_PHASE_INSTANCE_COUNT:
|
|
{
|
|
psDecl->value.ui32HullPhaseInstanceCount = pui32Token[1];
|
|
psPhase->ui32InstanceCount = psDecl->value.ui32HullPhaseInstanceCount;
|
|
break;
|
|
}
|
|
case OPCODE_CUSTOMDATA:
|
|
{
|
|
ui32TokenLength = pui32Token[1];
|
|
{
|
|
// int iTupleSrc = 0, iTupleDest = 0;
|
|
//const uint32_t ui32ConstCount = pui32Token[1] - 2;
|
|
//const uint32_t ui32TupleCount = (ui32ConstCount / 4);
|
|
|
|
const uint32_t ui32NumVec4 = (ui32TokenLength - 2) / 4;
|
|
|
|
ICBVec4 const *pVec4Array = (ICBVec4 const *)(void*)(pui32Token + 2);
|
|
|
|
/* must be a multiple of 4 */
|
|
ASSERT(((ui32TokenLength - 2) % 4) == 0);
|
|
|
|
psDecl->asImmediateConstBuffer.assign(pVec4Array, pVec4Array + ui32NumVec4);
|
|
|
|
psDecl->ui32NumOperands = ui32NumVec4;
|
|
}
|
|
break;
|
|
}
|
|
case OPCODE_DCL_HS_MAX_TESSFACTOR:
|
|
{
|
|
psDecl->value.fMaxTessFactor = *((float*)&pui32Token[1]);
|
|
break;
|
|
}
|
|
case OPCODE_DCL_UNORDERED_ACCESS_VIEW_TYPED:
|
|
{
|
|
psDecl->ui32NumOperands = 2;
|
|
psDecl->value.eResourceDimension = DecodeResourceDimension(*pui32Token);
|
|
psDecl->sUAV.ui32GloballyCoherentAccess = DecodeAccessCoherencyFlags(*pui32Token);
|
|
psDecl->sUAV.bCounter = 0;
|
|
psDecl->ui32BufferStride = 4;
|
|
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psDecl->asOperands[0]);
|
|
psDecl->sUAV.Type = DecodeResourceReturnType(0, pui32Token[ui32OperandOffset]);
|
|
break;
|
|
}
|
|
case OPCODE_DCL_UNORDERED_ACCESS_VIEW_RAW:
|
|
{
|
|
psDecl->ui32NumOperands = 1;
|
|
psDecl->sUAV.ui32GloballyCoherentAccess = DecodeAccessCoherencyFlags(*pui32Token);
|
|
psDecl->sUAV.bCounter = 0;
|
|
psDecl->ui32BufferStride = 4;
|
|
DecodeOperand(pui32Token + ui32OperandOffset, &psDecl->asOperands[0]);
|
|
//This should be a RTYPE_UAV_RWBYTEADDRESS buffer. It is memory backed by
|
|
//a shader storage buffer whose is unknown at compile time.
|
|
break;
|
|
}
|
|
case OPCODE_DCL_UNORDERED_ACCESS_VIEW_STRUCTURED:
|
|
{
|
|
const ResourceBinding* psBinding = NULL;
|
|
const ConstantBuffer* psBuffer = NULL;
|
|
|
|
psDecl->ui32NumOperands = 1;
|
|
psDecl->sUAV.ui32GloballyCoherentAccess = DecodeAccessCoherencyFlags(*pui32Token);
|
|
psDecl->sUAV.bCounter = 0;
|
|
DecodeOperand(pui32Token + ui32OperandOffset, &psDecl->asOperands[0]);
|
|
|
|
psShader->sInfo.GetResourceFromBindingPoint(RGROUP_UAV, psDecl->asOperands[0].ui32RegisterNumber, &psBinding);
|
|
psShader->sInfo.GetConstantBufferFromBindingPoint(RGROUP_UAV, psBinding->ui32BindPoint, &psBuffer);
|
|
psDecl->ui32BufferStride = psBuffer->ui32TotalSizeInBytes;
|
|
|
|
switch (psBinding->eType)
|
|
{
|
|
case RTYPE_UAV_RWSTRUCTURED_WITH_COUNTER:
|
|
case RTYPE_UAV_APPEND_STRUCTURED:
|
|
case RTYPE_UAV_CONSUME_STRUCTURED:
|
|
psDecl->sUAV.bCounter = 1;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case OPCODE_DCL_RESOURCE_STRUCTURED:
|
|
{
|
|
const ResourceBinding* psBinding = NULL;
|
|
const ConstantBuffer* psBuffer = NULL;
|
|
psDecl->ui32NumOperands = 1;
|
|
DecodeOperand(pui32Token + ui32OperandOffset, &psDecl->asOperands[0]);
|
|
|
|
psShader->sInfo.GetResourceFromBindingPoint(RGROUP_TEXTURE, psDecl->asOperands[0].ui32RegisterNumber, &psBinding);
|
|
psShader->sInfo.GetConstantBufferFromBindingPoint(RGROUP_TEXTURE, psBinding->ui32BindPoint, &psBuffer);
|
|
psDecl->ui32BufferStride = psBuffer->ui32TotalSizeInBytes;
|
|
break;
|
|
}
|
|
case OPCODE_DCL_RESOURCE_RAW:
|
|
{
|
|
psDecl->ui32NumOperands = 1;
|
|
psDecl->ui32BufferStride = 4;
|
|
DecodeOperand(pui32Token + ui32OperandOffset, &psDecl->asOperands[0]);
|
|
break;
|
|
}
|
|
case OPCODE_DCL_THREAD_GROUP_SHARED_MEMORY_STRUCTURED:
|
|
{
|
|
psDecl->ui32NumOperands = 1;
|
|
psDecl->sUAV.ui32GloballyCoherentAccess = 0;
|
|
|
|
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psDecl->asOperands[0]);
|
|
|
|
psDecl->sTGSM.ui32Stride = pui32Token[ui32OperandOffset++];
|
|
psDecl->sTGSM.ui32Count = pui32Token[ui32OperandOffset++];
|
|
break;
|
|
}
|
|
case OPCODE_DCL_THREAD_GROUP_SHARED_MEMORY_RAW:
|
|
{
|
|
psDecl->ui32NumOperands = 1;
|
|
psDecl->sUAV.ui32GloballyCoherentAccess = 0;
|
|
|
|
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psDecl->asOperands[0]);
|
|
|
|
psDecl->sTGSM.ui32Stride = 4;
|
|
psDecl->sTGSM.ui32Count = pui32Token[ui32OperandOffset++];
|
|
break;
|
|
}
|
|
case OPCODE_DCL_STREAM:
|
|
{
|
|
psDecl->ui32NumOperands = 1;
|
|
DecodeOperand(pui32Token + ui32OperandOffset, &psDecl->asOperands[0]);
|
|
break;
|
|
}
|
|
case OPCODE_DCL_GS_INSTANCE_COUNT:
|
|
{
|
|
psDecl->ui32NumOperands = 0;
|
|
psDecl->value.ui32GSInstanceCount = pui32Token[1];
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
//Reached end of declarations
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return pui32Token + ui32TokenLength;
|
|
}
|
|
|
|
const uint32_t* DecodeInstruction(const uint32_t* pui32Token, Instruction* psInst, Shader* psShader, ShaderPhase *psPhase)
|
|
{
|
|
uint32_t ui32TokenLength = DecodeInstructionLength(*pui32Token);
|
|
const uint32_t bExtended = DecodeIsOpcodeExtended(*pui32Token);
|
|
const OPCODE_TYPE eOpcode = DecodeOpcodeType(*pui32Token);
|
|
uint32_t ui32OperandOffset = 1;
|
|
|
|
#ifdef _DEBUG
|
|
psInst->id = instructionID++;
|
|
#endif
|
|
|
|
psInst->eOpcode = eOpcode;
|
|
|
|
psInst->bSaturate = DecodeInstructionSaturate(*pui32Token);
|
|
psInst->ui32PreciseMask = DecodeInstructionPreciseMask(*pui32Token);
|
|
|
|
psInst->bAddressOffset = 0;
|
|
|
|
psInst->ui32FirstSrc = 1;
|
|
|
|
psInst->iCausedSplit = 0;
|
|
|
|
if (bExtended)
|
|
{
|
|
do
|
|
{
|
|
const uint32_t ui32ExtOpcodeToken = pui32Token[ui32OperandOffset];
|
|
const EXTENDED_OPCODE_TYPE eExtType = DecodeExtendedOpcodeType(ui32ExtOpcodeToken);
|
|
|
|
if (eExtType == EXTENDED_OPCODE_SAMPLE_CONTROLS)
|
|
{
|
|
struct {int i4 : 4;} sU;
|
|
struct {int i4 : 4;} sV;
|
|
struct {int i4 : 4;} sW;
|
|
|
|
psInst->bAddressOffset = 1;
|
|
|
|
sU.i4 = DecodeImmediateAddressOffset(
|
|
IMMEDIATE_ADDRESS_OFFSET_U, ui32ExtOpcodeToken);
|
|
sV.i4 = DecodeImmediateAddressOffset(
|
|
IMMEDIATE_ADDRESS_OFFSET_V, ui32ExtOpcodeToken);
|
|
sW.i4 = DecodeImmediateAddressOffset(
|
|
IMMEDIATE_ADDRESS_OFFSET_W, ui32ExtOpcodeToken);
|
|
|
|
psInst->iUAddrOffset = sU.i4;
|
|
psInst->iVAddrOffset = sV.i4;
|
|
psInst->iWAddrOffset = sW.i4;
|
|
}
|
|
else if (eExtType == EXTENDED_OPCODE_RESOURCE_RETURN_TYPE)
|
|
{
|
|
psInst->xType = DecodeExtendedResourceReturnType(0, ui32ExtOpcodeToken);
|
|
psInst->yType = DecodeExtendedResourceReturnType(1, ui32ExtOpcodeToken);
|
|
psInst->zType = DecodeExtendedResourceReturnType(2, ui32ExtOpcodeToken);
|
|
psInst->wType = DecodeExtendedResourceReturnType(3, ui32ExtOpcodeToken);
|
|
}
|
|
else if (eExtType == EXTENDED_OPCODE_RESOURCE_DIM)
|
|
{
|
|
psInst->eResDim = DecodeExtendedResourceDimension(ui32ExtOpcodeToken);
|
|
}
|
|
|
|
ui32OperandOffset++;
|
|
}
|
|
while (DecodeIsOpcodeExtended(pui32Token[ui32OperandOffset - 1]));
|
|
}
|
|
|
|
if (eOpcode < NUM_OPCODES && eOpcode >= 0)
|
|
{
|
|
psShader->aiOpcodeUsed[eOpcode] = 1;
|
|
}
|
|
|
|
switch (eOpcode)
|
|
{
|
|
//no operands
|
|
case OPCODE_CUT:
|
|
case OPCODE_EMIT:
|
|
case OPCODE_EMITTHENCUT:
|
|
case OPCODE_RET:
|
|
case OPCODE_LOOP:
|
|
case OPCODE_ENDLOOP:
|
|
case OPCODE_BREAK:
|
|
case OPCODE_ELSE:
|
|
case OPCODE_ENDIF:
|
|
case OPCODE_CONTINUE:
|
|
case OPCODE_DEFAULT:
|
|
case OPCODE_ENDSWITCH:
|
|
case OPCODE_NOP:
|
|
case OPCODE_HS_CONTROL_POINT_PHASE:
|
|
case OPCODE_HS_FORK_PHASE:
|
|
case OPCODE_HS_JOIN_PHASE:
|
|
{
|
|
psInst->ui32NumOperands = 0;
|
|
psInst->ui32FirstSrc = 0;
|
|
break;
|
|
}
|
|
case OPCODE_DCL_HS_FORK_PHASE_INSTANCE_COUNT:
|
|
case OPCODE_DCL_HS_JOIN_PHASE_INSTANCE_COUNT:
|
|
{
|
|
psInst->ui32NumOperands = 0;
|
|
psInst->ui32FirstSrc = 0;
|
|
break;
|
|
}
|
|
case OPCODE_SYNC:
|
|
{
|
|
psInst->ui32NumOperands = 0;
|
|
psInst->ui32FirstSrc = 0;
|
|
psInst->ui32SyncFlags = DecodeSyncFlags(*pui32Token);
|
|
break;
|
|
}
|
|
|
|
//1 operand
|
|
case OPCODE_EMIT_STREAM:
|
|
case OPCODE_CUT_STREAM:
|
|
case OPCODE_EMITTHENCUT_STREAM:
|
|
case OPCODE_CASE:
|
|
case OPCODE_SWITCH:
|
|
case OPCODE_LABEL:
|
|
{
|
|
psInst->ui32NumOperands = 1;
|
|
psInst->ui32FirstSrc = 0;
|
|
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psInst->asOperands[0]);
|
|
break;
|
|
}
|
|
|
|
case OPCODE_INTERFACE_CALL:
|
|
{
|
|
psInst->ui32NumOperands = 1;
|
|
psInst->ui32FirstSrc = 0;
|
|
psInst->ui32FuncIndexWithinInterface = pui32Token[ui32OperandOffset];
|
|
ui32OperandOffset++;
|
|
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psInst->asOperands[0]);
|
|
|
|
break;
|
|
}
|
|
|
|
/* Floating point instruction decodes */
|
|
|
|
//Instructions with two operands go here
|
|
case OPCODE_MOV:
|
|
{
|
|
psInst->ui32NumOperands = 2;
|
|
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psInst->asOperands[0]);
|
|
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psInst->asOperands[1]);
|
|
break;
|
|
}
|
|
case OPCODE_LOG:
|
|
case OPCODE_RSQ:
|
|
case OPCODE_EXP:
|
|
case OPCODE_SQRT:
|
|
case OPCODE_ROUND_PI:
|
|
case OPCODE_ROUND_NI:
|
|
case OPCODE_ROUND_Z:
|
|
case OPCODE_ROUND_NE:
|
|
case OPCODE_FRC:
|
|
case OPCODE_FTOU:
|
|
case OPCODE_FTOI:
|
|
case OPCODE_UTOF:
|
|
case OPCODE_ITOF:
|
|
case OPCODE_INEG:
|
|
case OPCODE_IMM_ATOMIC_ALLOC:
|
|
case OPCODE_IMM_ATOMIC_CONSUME:
|
|
case OPCODE_DMOV:
|
|
case OPCODE_DTOF:
|
|
case OPCODE_FTOD:
|
|
case OPCODE_DRCP:
|
|
case OPCODE_COUNTBITS:
|
|
case OPCODE_FIRSTBIT_HI:
|
|
case OPCODE_FIRSTBIT_LO:
|
|
case OPCODE_FIRSTBIT_SHI:
|
|
case OPCODE_BFREV:
|
|
case OPCODE_F32TOF16:
|
|
case OPCODE_F16TOF32:
|
|
case OPCODE_RCP:
|
|
case OPCODE_DERIV_RTX:
|
|
case OPCODE_DERIV_RTY:
|
|
case OPCODE_DERIV_RTX_COARSE:
|
|
case OPCODE_DERIV_RTX_FINE:
|
|
case OPCODE_DERIV_RTY_COARSE:
|
|
case OPCODE_DERIV_RTY_FINE:
|
|
case OPCODE_NOT:
|
|
case OPCODE_BUFINFO:
|
|
{
|
|
psInst->ui32NumOperands = 2;
|
|
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psInst->asOperands[0]);
|
|
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psInst->asOperands[1]);
|
|
break;
|
|
}
|
|
|
|
//Instructions with three operands go here
|
|
case OPCODE_SINCOS:
|
|
{
|
|
psInst->ui32FirstSrc = 2;
|
|
//Intentional fall-through
|
|
}
|
|
case OPCODE_IMIN:
|
|
case OPCODE_UMIN:
|
|
case OPCODE_UMAX:
|
|
case OPCODE_MIN:
|
|
case OPCODE_IMAX:
|
|
case OPCODE_MAX:
|
|
case OPCODE_MUL:
|
|
case OPCODE_DIV:
|
|
case OPCODE_ADD:
|
|
case OPCODE_DP2:
|
|
case OPCODE_DP3:
|
|
case OPCODE_DP4:
|
|
case OPCODE_NE:
|
|
case OPCODE_OR:
|
|
case OPCODE_XOR:
|
|
case OPCODE_LT:
|
|
case OPCODE_IEQ:
|
|
case OPCODE_IADD:
|
|
case OPCODE_AND:
|
|
case OPCODE_GE:
|
|
case OPCODE_IGE:
|
|
case OPCODE_EQ:
|
|
case OPCODE_USHR:
|
|
case OPCODE_ISHL:
|
|
case OPCODE_ISHR:
|
|
case OPCODE_LD:
|
|
case OPCODE_ILT:
|
|
case OPCODE_INE:
|
|
case OPCODE_UGE:
|
|
case OPCODE_ULT:
|
|
case OPCODE_ATOMIC_AND:
|
|
case OPCODE_ATOMIC_IADD:
|
|
case OPCODE_ATOMIC_OR:
|
|
case OPCODE_ATOMIC_XOR:
|
|
case OPCODE_ATOMIC_IMAX:
|
|
case OPCODE_ATOMIC_IMIN:
|
|
case OPCODE_ATOMIC_UMAX:
|
|
case OPCODE_ATOMIC_UMIN:
|
|
case OPCODE_DADD:
|
|
case OPCODE_DMAX:
|
|
case OPCODE_DMIN:
|
|
case OPCODE_DMUL:
|
|
case OPCODE_DEQ:
|
|
case OPCODE_DGE:
|
|
case OPCODE_DLT:
|
|
case OPCODE_DNE:
|
|
case OPCODE_DDIV:
|
|
{
|
|
psInst->ui32NumOperands = 3;
|
|
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psInst->asOperands[0]);
|
|
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psInst->asOperands[1]);
|
|
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psInst->asOperands[2]);
|
|
break;
|
|
}
|
|
//Instructions with four operands go here
|
|
case OPCODE_MAD:
|
|
case OPCODE_MOVC:
|
|
case OPCODE_IMAD:
|
|
case OPCODE_UDIV:
|
|
case OPCODE_LOD:
|
|
case OPCODE_SAMPLE:
|
|
case OPCODE_GATHER4:
|
|
case OPCODE_LD_MS:
|
|
case OPCODE_UBFE:
|
|
case OPCODE_IBFE:
|
|
case OPCODE_ATOMIC_CMP_STORE:
|
|
case OPCODE_IMM_ATOMIC_IADD:
|
|
case OPCODE_IMM_ATOMIC_AND:
|
|
case OPCODE_IMM_ATOMIC_OR:
|
|
case OPCODE_IMM_ATOMIC_XOR:
|
|
case OPCODE_IMM_ATOMIC_EXCH:
|
|
case OPCODE_IMM_ATOMIC_IMAX:
|
|
case OPCODE_IMM_ATOMIC_IMIN:
|
|
case OPCODE_IMM_ATOMIC_UMAX:
|
|
case OPCODE_IMM_ATOMIC_UMIN:
|
|
case OPCODE_DMOVC:
|
|
case OPCODE_DFMA:
|
|
case OPCODE_IMUL:
|
|
{
|
|
psInst->ui32NumOperands = 4;
|
|
|
|
if (eOpcode == OPCODE_IMUL || eOpcode == OPCODE_UDIV)
|
|
{
|
|
psInst->ui32FirstSrc = 2;
|
|
}
|
|
|
|
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psInst->asOperands[0]);
|
|
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psInst->asOperands[1]);
|
|
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psInst->asOperands[2]);
|
|
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psInst->asOperands[3]);
|
|
break;
|
|
}
|
|
case OPCODE_GATHER4_PO:
|
|
case OPCODE_SAMPLE_L:
|
|
case OPCODE_BFI:
|
|
case OPCODE_SWAPC:
|
|
case OPCODE_IMM_ATOMIC_CMP_EXCH:
|
|
{
|
|
psInst->ui32NumOperands = 5;
|
|
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psInst->asOperands[0]);
|
|
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psInst->asOperands[1]);
|
|
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psInst->asOperands[2]);
|
|
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psInst->asOperands[3]);
|
|
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psInst->asOperands[4]);
|
|
break;
|
|
}
|
|
case OPCODE_GATHER4_C:
|
|
case OPCODE_SAMPLE_C:
|
|
case OPCODE_SAMPLE_C_LZ:
|
|
case OPCODE_SAMPLE_B:
|
|
{
|
|
psInst->ui32NumOperands = 5;
|
|
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psInst->asOperands[0]);
|
|
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psInst->asOperands[1]);
|
|
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psInst->asOperands[2]);
|
|
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psInst->asOperands[3]);
|
|
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psInst->asOperands[4]);
|
|
|
|
/* sample_b is not a shadow sampler, others need flagging */
|
|
if (eOpcode != OPCODE_SAMPLE_B)
|
|
{
|
|
MarkTextureAsShadow(&psShader->sInfo, psPhase->psDecl, &psInst->asOperands[2]);
|
|
}
|
|
|
|
break;
|
|
}
|
|
case OPCODE_GATHER4_PO_C:
|
|
case OPCODE_SAMPLE_D:
|
|
{
|
|
psInst->ui32NumOperands = 6;
|
|
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psInst->asOperands[0]);
|
|
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psInst->asOperands[1]);
|
|
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psInst->asOperands[2]);
|
|
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psInst->asOperands[3]);
|
|
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psInst->asOperands[4]);
|
|
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psInst->asOperands[5]);
|
|
|
|
/* sample_d is not a shadow sampler, others need flagging */
|
|
if (eOpcode != OPCODE_SAMPLE_D)
|
|
{
|
|
MarkTextureAsShadow(&psShader->sInfo,
|
|
psPhase->psDecl,
|
|
&psInst->asOperands[2]);
|
|
}
|
|
break;
|
|
}
|
|
case OPCODE_IF:
|
|
case OPCODE_BREAKC:
|
|
case OPCODE_CONTINUEC:
|
|
case OPCODE_RETC:
|
|
case OPCODE_DISCARD:
|
|
{
|
|
psInst->eBooleanTestType = DecodeInstrTestBool(*pui32Token);
|
|
psInst->ui32NumOperands = 1;
|
|
psInst->ui32FirstSrc = 0; // no destination registers
|
|
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psInst->asOperands[0]);
|
|
break;
|
|
}
|
|
case OPCODE_CALLC:
|
|
{
|
|
psInst->eBooleanTestType = DecodeInstrTestBool(*pui32Token);
|
|
psInst->ui32NumOperands = 2;
|
|
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psInst->asOperands[0]);
|
|
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psInst->asOperands[1]);
|
|
break;
|
|
}
|
|
case OPCODE_CUSTOMDATA:
|
|
{
|
|
psInst->ui32NumOperands = 0;
|
|
ui32TokenLength = pui32Token[1];
|
|
break;
|
|
}
|
|
case OPCODE_EVAL_CENTROID:
|
|
{
|
|
psInst->ui32NumOperands = 2;
|
|
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psInst->asOperands[0]);
|
|
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psInst->asOperands[1]);
|
|
break;
|
|
}
|
|
case OPCODE_EVAL_SAMPLE_INDEX:
|
|
case OPCODE_EVAL_SNAPPED:
|
|
case OPCODE_STORE_UAV_TYPED:
|
|
case OPCODE_LD_UAV_TYPED:
|
|
case OPCODE_LD_RAW:
|
|
case OPCODE_STORE_RAW:
|
|
{
|
|
psInst->ui32NumOperands = 3;
|
|
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psInst->asOperands[0]);
|
|
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psInst->asOperands[1]);
|
|
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psInst->asOperands[2]);
|
|
break;
|
|
}
|
|
case OPCODE_STORE_STRUCTURED:
|
|
case OPCODE_LD_STRUCTURED:
|
|
{
|
|
psInst->ui32NumOperands = 4;
|
|
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psInst->asOperands[0]);
|
|
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psInst->asOperands[1]);
|
|
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psInst->asOperands[2]);
|
|
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psInst->asOperands[3]);
|
|
break;
|
|
}
|
|
case OPCODE_RESINFO:
|
|
{
|
|
psInst->ui32NumOperands = 3;
|
|
|
|
psInst->eResInfoReturnType = DecodeResInfoReturnType(pui32Token[0]);
|
|
|
|
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psInst->asOperands[0]);
|
|
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psInst->asOperands[1]);
|
|
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psInst->asOperands[2]);
|
|
break;
|
|
}
|
|
case OPCODE_SAMPLE_INFO:
|
|
{
|
|
psInst->ui32NumOperands = 2;
|
|
|
|
psInst->eResInfoReturnType = DecodeResInfoReturnType(pui32Token[0]);
|
|
|
|
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psInst->asOperands[0]);
|
|
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psInst->asOperands[1]);
|
|
break;
|
|
}
|
|
case OPCODE_MSAD:
|
|
default:
|
|
{
|
|
ASSERT(0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// For opcodes that sample textures, mark which samplers are used by each texture
|
|
{
|
|
uint32_t ui32TextureRegisterNumber = 0;
|
|
uint32_t ui32SamplerRegisterNumber = 0;
|
|
uint32_t bTextureSampleInstruction = 0;
|
|
switch (eOpcode)
|
|
{
|
|
case OPCODE_GATHER4:
|
|
// dest, coords, tex, sampler
|
|
ui32TextureRegisterNumber = 2;
|
|
ui32SamplerRegisterNumber = 3;
|
|
bTextureSampleInstruction = 1;
|
|
break;
|
|
case OPCODE_GATHER4_PO:
|
|
//dest, coords, offset, tex, sampler
|
|
ui32TextureRegisterNumber = 3;
|
|
ui32SamplerRegisterNumber = 4;
|
|
bTextureSampleInstruction = 1;
|
|
break;
|
|
case OPCODE_GATHER4_C:
|
|
//dest, coords, tex, sampler srcReferenceValue
|
|
ui32TextureRegisterNumber = 2;
|
|
ui32SamplerRegisterNumber = 3;
|
|
bTextureSampleInstruction = 1;
|
|
break;
|
|
case OPCODE_GATHER4_PO_C:
|
|
//dest, coords, offset, tex, sampler, srcReferenceValue
|
|
ui32TextureRegisterNumber = 3;
|
|
ui32SamplerRegisterNumber = 4;
|
|
bTextureSampleInstruction = 1;
|
|
break;
|
|
case OPCODE_SAMPLE:
|
|
case OPCODE_SAMPLE_L:
|
|
case OPCODE_SAMPLE_C:
|
|
case OPCODE_SAMPLE_C_LZ:
|
|
case OPCODE_SAMPLE_B:
|
|
case OPCODE_SAMPLE_D:
|
|
// dest, coords, tex, sampler [, reference]
|
|
ui32TextureRegisterNumber = 2;
|
|
ui32SamplerRegisterNumber = 3;
|
|
bTextureSampleInstruction = 1;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (bTextureSampleInstruction)
|
|
{
|
|
MarkTextureSamplerPair(&psShader->sInfo,
|
|
psPhase->psDecl,
|
|
&psInst->asOperands[ui32TextureRegisterNumber],
|
|
&psInst->asOperands[ui32SamplerRegisterNumber],
|
|
psShader->textureSamplers);
|
|
}
|
|
}
|
|
|
|
return pui32Token + ui32TokenLength;
|
|
}
|
|
|
|
const uint32_t* DecodeShaderPhase(const uint32_t* pui32Tokens,
|
|
Shader* psShader,
|
|
const SHADER_PHASE_TYPE ePhaseType,
|
|
ShaderPhase *psPhase)
|
|
{
|
|
const uint32_t* pui32CurrentToken = pui32Tokens;
|
|
const uint32_t ui32ShaderLength = psShader->ui32ShaderLength;
|
|
|
|
psPhase->ePhase = ePhaseType;
|
|
//Using ui32ShaderLength as the declaration and instruction count
|
|
//will allocate more than enough memory. Avoids having to
|
|
//traverse the entire shader just to get the real counts.
|
|
|
|
psPhase->psDecl.clear();
|
|
psPhase->psDecl.reserve(ui32ShaderLength);
|
|
|
|
while (1) //Keep going until we reach the first non-declaration token, or the end of the shader.
|
|
{
|
|
psPhase->psDecl.push_back(Declaration());
|
|
const uint32_t* pui32Result = DecodeDeclaration(psShader, pui32CurrentToken, &psPhase->psDecl[psPhase->psDecl.size() - 1], psPhase);
|
|
|
|
if (pui32Result)
|
|
{
|
|
pui32CurrentToken = pui32Result;
|
|
|
|
if (pui32CurrentToken >= (psShader->pui32FirstToken + ui32ShaderLength))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
psPhase->psDecl.pop_back(); // Remove the last one, it wasn't needed after all
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
//Instructions
|
|
psPhase->psInst.clear();
|
|
psPhase->psInst.reserve(ui32ShaderLength);
|
|
|
|
while (pui32CurrentToken < (psShader->pui32FirstToken + ui32ShaderLength))
|
|
{
|
|
psPhase->psInst.push_back(Instruction());
|
|
const uint32_t* nextInstr = DecodeInstruction(pui32CurrentToken, &psPhase->psInst[psPhase->psInst.size() - 1], psShader, psPhase);
|
|
|
|
#ifdef _DEBUG
|
|
if (nextInstr == pui32CurrentToken)
|
|
{
|
|
ASSERT(0);
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
if (psPhase->psInst[psPhase->psInst.size() - 1].eOpcode == OPCODE_HS_FORK_PHASE || psPhase->psInst[psPhase->psInst.size() - 1].eOpcode == OPCODE_HS_JOIN_PHASE)
|
|
{
|
|
psPhase->psInst.pop_back();
|
|
return pui32CurrentToken;
|
|
}
|
|
pui32CurrentToken = nextInstr;
|
|
}
|
|
|
|
return pui32CurrentToken;
|
|
}
|
|
|
|
const void AllocateHullPhaseArrays(const uint32_t* pui32Tokens,
|
|
Shader* psShader)
|
|
{
|
|
const uint32_t* pui32CurrentToken = pui32Tokens;
|
|
const uint32_t ui32ShaderLength = psShader->ui32ShaderLength;
|
|
uint32_t ui32PhaseCount = 2; // Always the main phase and the HS global declarations
|
|
uint32_t i;
|
|
|
|
while (1) //Keep going until we reach the first non-declaration token, or the end of the shader.
|
|
{
|
|
uint32_t ui32TokenLength = DecodeInstructionLength(*pui32CurrentToken);
|
|
const OPCODE_TYPE eOpcode = DecodeOpcodeType(*pui32CurrentToken);
|
|
|
|
if (eOpcode == OPCODE_CUSTOMDATA)
|
|
{
|
|
ui32TokenLength = pui32CurrentToken[1];
|
|
}
|
|
|
|
pui32CurrentToken = pui32CurrentToken + ui32TokenLength;
|
|
|
|
switch (eOpcode)
|
|
{
|
|
case OPCODE_HS_CONTROL_POINT_PHASE:
|
|
case OPCODE_HS_JOIN_PHASE:
|
|
case OPCODE_HS_FORK_PHASE:
|
|
ui32PhaseCount++;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (pui32CurrentToken >= (psShader->pui32FirstToken + ui32ShaderLength))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
psShader->asPhases.clear();
|
|
psShader->asPhases.resize(ui32PhaseCount);
|
|
for (i = 0; i < ui32PhaseCount; i++)
|
|
psShader->asPhases[i].ui32InstanceCount = 1;
|
|
}
|
|
|
|
const uint32_t* DecodeHullShader(const uint32_t* pui32Tokens, Shader* psShader)
|
|
{
|
|
const uint32_t* pui32CurrentToken = pui32Tokens;
|
|
const uint32_t ui32ShaderLength = psShader->ui32ShaderLength;
|
|
ShaderPhase *psPhase;
|
|
|
|
AllocateHullPhaseArrays(pui32Tokens, psShader);
|
|
|
|
// Index 1 is HS_GLOBAL_DECL
|
|
psShader->asPhases[1].psInst.clear();
|
|
psShader->asPhases[1].psDecl.clear();
|
|
psShader->asPhases[1].ePhase = HS_GLOBAL_DECL_PHASE;
|
|
psShader->asPhases[1].ui32InstanceCount = 1;
|
|
|
|
// The next phase to parse in.
|
|
psPhase = &psShader->asPhases[2];
|
|
|
|
//Keep going until we have done all phases or the end of the shader.
|
|
while (1)
|
|
{
|
|
Declaration newDecl;
|
|
const uint32_t* pui32Result = DecodeDeclaration(psShader, pui32CurrentToken, &newDecl, psPhase);
|
|
|
|
if (pui32Result)
|
|
{
|
|
pui32CurrentToken = pui32Result;
|
|
|
|
if (newDecl.eOpcode == OPCODE_HS_CONTROL_POINT_PHASE)
|
|
{
|
|
pui32CurrentToken = DecodeShaderPhase(pui32CurrentToken, psShader, HS_CTRL_POINT_PHASE, psPhase);
|
|
psPhase++;
|
|
}
|
|
else if (newDecl.eOpcode == OPCODE_HS_FORK_PHASE)
|
|
{
|
|
pui32CurrentToken = DecodeShaderPhase(pui32CurrentToken, psShader, HS_FORK_PHASE, psPhase++);
|
|
}
|
|
else if (newDecl.eOpcode == OPCODE_HS_JOIN_PHASE)
|
|
{
|
|
pui32CurrentToken = DecodeShaderPhase(pui32CurrentToken, psShader, HS_JOIN_PHASE, psPhase++);
|
|
}
|
|
else
|
|
{
|
|
psShader->asPhases[1].psDecl.push_back(newDecl);
|
|
}
|
|
|
|
if (pui32CurrentToken >= (psShader->pui32FirstToken + ui32ShaderLength))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
return pui32CurrentToken;
|
|
}
|
|
|
|
void Decode(const uint32_t* pui32Tokens, Shader* psShader)
|
|
{
|
|
const uint32_t* pui32CurrentToken = pui32Tokens;
|
|
const uint32_t ui32ShaderLength = pui32Tokens[1];
|
|
|
|
psShader->ui32MajorVersion = DecodeProgramMajorVersion(*pui32CurrentToken);
|
|
psShader->ui32MinorVersion = DecodeProgramMinorVersion(*pui32CurrentToken);
|
|
psShader->eShaderType = DecodeShaderType(*pui32CurrentToken);
|
|
|
|
pui32CurrentToken++;//Move to shader length
|
|
psShader->ui32ShaderLength = ui32ShaderLength;
|
|
pui32CurrentToken++;//Move to after shader length (usually a declaration)
|
|
|
|
psShader->pui32FirstToken = pui32Tokens;
|
|
|
|
if (psShader->eShaderType == HULL_SHADER)
|
|
{
|
|
// DecodeHullShader will allocate psShader->asPhases array.
|
|
pui32CurrentToken = DecodeHullShader(pui32CurrentToken, psShader);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
psShader->asPhases.clear();
|
|
psShader->asPhases.resize(1);
|
|
}
|
|
|
|
// Phase 0 is always the main phase
|
|
psShader->asPhases[0].ui32InstanceCount = 1;
|
|
|
|
DecodeShaderPhase(pui32CurrentToken, psShader, MAIN_PHASE, &psShader->asPhases[0]);
|
|
}
|
|
|
|
Shader* DecodeDXBC(uint32_t* data, uint32_t decodeFlags)
|
|
{
|
|
Shader* psShader;
|
|
DXBCContainerHeader* header = (DXBCContainerHeader*)data;
|
|
uint32_t i;
|
|
uint32_t chunkCount;
|
|
uint32_t* chunkOffsets;
|
|
ReflectionChunks refChunks;
|
|
uint32_t* shaderChunk = 0;
|
|
|
|
if (header->fourcc != FOURCC_DXBC)
|
|
{
|
|
ASSERT(0 && "Invalid shader type (DX9 shaders no longer supported)!");
|
|
}
|
|
|
|
refChunks.pui32Inputs = NULL;
|
|
refChunks.pui32Interfaces = NULL;
|
|
refChunks.pui32Outputs = NULL;
|
|
refChunks.pui32Resources = NULL;
|
|
refChunks.pui32Inputs11 = NULL;
|
|
refChunks.pui32Outputs11 = NULL;
|
|
refChunks.pui32OutputsWithStreams = NULL;
|
|
refChunks.pui32PatchConstants = NULL;
|
|
refChunks.pui32PatchConstants11 = NULL;
|
|
|
|
chunkOffsets = (uint32_t*)(header + 1);
|
|
|
|
chunkCount = header->chunkCount;
|
|
|
|
for (i = 0; i < chunkCount; ++i)
|
|
{
|
|
uint32_t offset = chunkOffsets[i];
|
|
|
|
DXBCChunkHeader* chunk = (DXBCChunkHeader*)((char*)data + offset);
|
|
|
|
switch (chunk->fourcc)
|
|
{
|
|
case FOURCC_ISGN:
|
|
{
|
|
refChunks.pui32Inputs = (uint32_t*)(chunk + 1);
|
|
break;
|
|
}
|
|
case FOURCC_ISG1:
|
|
{
|
|
refChunks.pui32Inputs11 = (uint32_t*)(chunk + 1);
|
|
break;
|
|
}
|
|
case FOURCC_RDEF:
|
|
{
|
|
refChunks.pui32Resources = (uint32_t*)(chunk + 1);
|
|
break;
|
|
}
|
|
case FOURCC_IFCE:
|
|
{
|
|
refChunks.pui32Interfaces = (uint32_t*)(chunk + 1);
|
|
break;
|
|
}
|
|
case FOURCC_OSGN:
|
|
{
|
|
refChunks.pui32Outputs = (uint32_t*)(chunk + 1);
|
|
break;
|
|
}
|
|
case FOURCC_OSG1:
|
|
{
|
|
refChunks.pui32Outputs11 = (uint32_t*)(chunk + 1);
|
|
break;
|
|
}
|
|
case FOURCC_OSG5:
|
|
{
|
|
refChunks.pui32OutputsWithStreams = (uint32_t*)(chunk + 1);
|
|
break;
|
|
}
|
|
case FOURCC_SHDR:
|
|
case FOURCC_SHEX:
|
|
{
|
|
shaderChunk = (uint32_t*)(chunk + 1);
|
|
break;
|
|
}
|
|
case FOURCC_PSGN:
|
|
{
|
|
refChunks.pui32PatchConstants = (uint32_t*)(chunk + 1);
|
|
break;
|
|
}
|
|
case FOURCC_PSG1:
|
|
{
|
|
refChunks.pui32PatchConstants11 = (uint32_t*)(chunk + 1);
|
|
break;
|
|
}
|
|
case FOURCC_STAT:
|
|
case FOURCC_SFI0:
|
|
{
|
|
break; // Ignored
|
|
}
|
|
default:
|
|
{
|
|
// ASSERT(0); // Uncomment this to hunt for unknown chunks later on.
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (shaderChunk)
|
|
{
|
|
uint32_t ui32MajorVersion;
|
|
uint32_t ui32MinorVersion;
|
|
|
|
psShader = new Shader();
|
|
|
|
ui32MajorVersion = DecodeProgramMajorVersion(*shaderChunk);
|
|
ui32MinorVersion = DecodeProgramMinorVersion(*shaderChunk);
|
|
|
|
LoadShaderInfo(ui32MajorVersion,
|
|
ui32MinorVersion,
|
|
&refChunks,
|
|
&psShader->sInfo, decodeFlags);
|
|
|
|
Decode(shaderChunk, psShader);
|
|
|
|
return psShader;
|
|
}
|
|
|
|
return 0;
|
|
}
|