Skip to content

Commit

Permalink
Fix bugs in resinfo opcode parsing.
Browse files Browse the repository at this point in the history
Numerous problems with the previous version, this rewrites it completely using the BinaryCompiler flags as much as possible.
This uses temporary registers defined at the top, to hold the return values, because this instruction GetDimension does not have a return value, only parameters.
Those parameters are then assigned to what the output was defined to be.

Should handle the swizzle properly. Not 100% sure, it's fairly gnarly.
Definitely handles both float and uint variants, and should generate a non-compiling error for cases that don't work, instead of generating bad code.

Also added some code to the BinaryCompiler, copied from the newest version on Git, to handle the resinfo flags that were not previously decoded.
  • Loading branch information
bo3b committed Jan 13, 2015
1 parent b692c6b commit 821cf81
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 10 deletions.
16 changes: 14 additions & 2 deletions BinaryDecompiler/decode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -935,7 +935,6 @@ const uint32_t* DeocdeInstruction(const uint32_t* pui32Token, Instruction* psIns
case OPCODE_DLT:
case OPCODE_DNE:
case OPCODE_DDIV:
case OPCODE_RESINFO:
case OPCODE_XOR:
case OPCODE_SAMPLE_POS: // bo3b: added for WatchDogs
{
Expand Down Expand Up @@ -1075,7 +1074,20 @@ const uint32_t* DeocdeInstruction(const uint32_t* pui32Token, Instruction* psIns
ui32OperandOffset += DecodeOperand(pui32Token+ui32OperandOffset, &psInst->asOperands[3]);
break;
}
case OPCODE_MSAD:
// Added to decode ResInfo variants.
// TODO: update to newest version of CrossCompiler.
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_MSAD:
default:
{
ASSERT(0);
Expand Down
2 changes: 2 additions & 0 deletions BinaryDecompiler/internal_includes/structs.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ struct Instruction
uint32_t bSaturate;
uint32_t ui32FuncIndexWithinInterface;

RESINFO_RETURN_TYPE eResInfoReturnType; // added for ResInfo parse

int bAddressOffset;
int iUAddrOffset;
int iVAddrOffset;
Expand Down
15 changes: 15 additions & 0 deletions BinaryDecompiler/internal_includes/tokens.h
Original file line number Diff line number Diff line change
Expand Up @@ -746,6 +746,21 @@ static uint32_t DecodeAccessCoherencyFlags(uint32_t ui32Token)
return ui32Token & 0x00010000;
}


// From newer version of James-Jones CrossCompiler- needed to decode ResInfo.

typedef enum RESINFO_RETURN_TYPE
{
RESINFO_INSTRUCTION_RETURN_FLOAT = 0,
RESINFO_INSTRUCTION_RETURN_RCPFLOAT = 1,
RESINFO_INSTRUCTION_RETURN_UINT = 2
} RESINFO_RETURN_TYPE;

static RESINFO_RETURN_TYPE DecodeResInfoReturnType(uint32_t ui32Token)
{
return (RESINFO_RETURN_TYPE)((ui32Token & 0x00001800) >> 11);
}

#include "tokensDX9.h"

#endif
119 changes: 111 additions & 8 deletions HLSLDecompiler/DecompileHLSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2761,7 +2761,7 @@ class Decompiler
mOutput.pop_back();
mOutput.push_back(';');
mOutput.push_back('\n');
const char *helperDecl = " uint4 bitmask, src0, src1, dst0;\n";
const char *helperDecl = " uint4 bitmask, src0, src1, uiDest;\n float4 fDest;\n\n";
mOutput.insert(mOutput.end(), helperDecl, helperDecl + strlen(helperDecl));
}
else if (!strncmp(statement, "dcl_", 4))
Expand Down Expand Up @@ -4058,16 +4058,119 @@ class Decompiler
appendOutput(buffer);
break;

// The GetDimensions can also see a 4 parameter version in the immediate case.
// resinfo[_uint|_rcpFloat] dest[.mask], srcMipLevel.select_component, srcResource[.swizzle]
// In different variants based on input texture, becomes:
// void Object.GetDimensions(UINT MipLevel, typeX Width, typeX Height, typeX Elements, typeX Depth, typeX NumberOfLevels, typeX NumberOfSamples);
//
// We only see the immediate version l(0) in use, like:
//
// resinfo_indexable(texture2d)(uint, uint, uint, uint)_uint r2.zw, l(0), t5.zwxy
// Becomes 2 param version: SectorAtlasTexture_UINT_TextureObject.GetDimensions(r2.z, r2.w);
//
// resinfo_indexable(texture2dms)(float, float, float, float)_uint r0.xy, l(0), t0.xyzw
// Becomes 3 param version: DepthVPSampler_TextureObject.GetDimensions(r0.x, r0.y, bitmask.x);
//
// resinfo_indexable(texture2darray)(float, float, float, float) r0.xy, l(0), t0.xyzw
//
// So, we'll only handle that immediate for now, and generate syntax errors if we see any other variant.
// We don't want to knowingly generate code that compiles, but has errors. Includes _rcpFloat as unknown.
//
// This also added new ResInfo parsing that was not in our older BinaryCompiler.
case OPCODE_RESINFO:
{
remapTarget(op1);
applySwizzle(".x", fixImm(op2, instr->asOperands[1]), true);
if (instr->asOperands[1].eType == OPERAND_TYPE_IMMEDIATE32)
strcpy(op2, "bitmask.x");
int textureId;
sscanf_s(op3, "t%d.", &textureId);
sprintf(buffer, " %s.GetDimensions(%s, %s, %s);\n", mTextureNames[textureId].c_str(), ci(GetSuffix(op1, 0)).c_str(), ci(GetSuffix(op1, 1)).c_str(), ci(op2).c_str());
appendOutput(buffer);

bool unknownVariant = true;
Operand output = instr->asOperands[0];
Operand constZero = instr->asOperands[1];
Operand texture = instr->asOperands[2];
RESINFO_RETURN_TYPE returnType = instr->eResInfoReturnType;
int texReg = texture.ui32RegisterNumber;
ResourceBinding *bindInfo;

// We only presently handle the float and _uint return types, and the const 0 mode.
// And the texture2d and textures2dms types. That's all we've seen so far.
if ((constZero.eType == OPERAND_TYPE_IMMEDIATE32) && (constZero.afImmediates[0] == 0)
&& (returnType == RESINFO_INSTRUCTION_RETURN_UINT || returnType == RESINFO_INSTRUCTION_RETURN_FLOAT)
&& GetResourceFromBindingPoint(RTYPE_TEXTURE, texReg, shader->sInfo, &bindInfo)
&& texture.eType == OPERAND_TYPE_RESOURCE)
{
//string out1, out2, out3;

// return results into uint variables forces compiler to generate _uint variant.
//if (returnType == RESINFO_INSTRUCTION_RETURN_UINT)
//{
// out1 = "dst0.x";
// out2 = "dst0.y";
// out3 = "dst0.w";
//}
//else
//{
// out1 = ci(GetSuffix(op1, 0));
// out2 = ci(GetSuffix(op1, 1));
// out3 = "fDst0.x";
//}

if (bindInfo->eDimension == REFLECT_RESOURCE_DIMENSION_TEXTURE2D)
{
if (returnType == RESINFO_INSTRUCTION_RETURN_UINT)
sprintf(buffer, " %s.GetDimensions(0, uiDest.x, uiDest.y, uiDest.z);\n", bindInfo->Name.c_str());
else
sprintf(buffer, " %s.GetDimensions(0, fDest.x, fDest.y, fDest.z);\n", bindInfo->Name.c_str());
appendOutput(buffer);
unknownVariant = false;
}
else if (bindInfo->eDimension == REFLECT_RESOURCE_DIMENSION_TEXTURE2DMS)
{
if (returnType == RESINFO_INSTRUCTION_RETURN_UINT)
sprintf(buffer, " %s.GetDimensions(uiDest.x, uiDest.y, uiDest.z);\n", bindInfo->Name.c_str());
else
sprintf(buffer, " %s.GetDimensions(fDest.x, fDest.y, fDest.z);\n", bindInfo->Name.c_str());
appendOutput(buffer);
unknownVariant = false;
}
else if (bindInfo->eDimension == REFLECT_RESOURCE_DIMENSION_TEXTURE2DARRAY)
{
if (returnType == RESINFO_INSTRUCTION_RETURN_UINT)
sprintf(buffer, " %s.GetDimensions(0, uiDest.x, uiDest.y, uiDest.z, uiDest.w);\n", bindInfo->Name.c_str());
else
sprintf(buffer, " %s.GetDimensions(0, fDest.x, fDest.y, fDest.z, fDest.w);\n", bindInfo->Name.c_str());
appendOutput(buffer);
unknownVariant = false;
}

// For the output, we saw a r3.xyzw which makes no sense for this instruction.
// Not sure this is fully correct, but the goal here is to apply the swizzle from the op3, which is the texture
// register, as the pieces that are valid to copy to the op1 output.
// The op3 texture swizzle can determine which components to use, and what order.
// The op1 output determines which ones are valid for output.
if (returnType == RESINFO_INSTRUCTION_RETURN_UINT)
{
char dest[opcodeSize] = "uiDest.xyzw";
applySwizzle(op3, dest);
applySwizzle(op1, dest);
sprintf(buffer, " %s = %s;\n", op1, dest);
appendOutput(buffer);
}
else
{
char dest[opcodeSize] = "fDest.xyzw";
applySwizzle(op3, dest);
applySwizzle(op1, dest);
sprintf(buffer, " %s = %s;\n", op1, dest);
appendOutput(buffer);
}
}
if (unknownVariant)
{
string line = string(c + pos);
line = line.substr(0, line.find('\n'));
sprintf(buffer, " Unknown use of GetDimensions for _resinfo: %s\n", line.c_str());
appendOutput(buffer);

logDecompileError("Unknown _resinfo variant: " + line);
}
break;
}

Expand Down

0 comments on commit 821cf81

Please sign in to comment.