Read registers not present in vertex buffers from SetVertexData4f registers

This commit is contained in:
Luke Usher 2019-07-24 14:39:58 +01:00
parent 8d8e256697
commit 5bfb98c312
1 changed files with 42 additions and 40 deletions

View File

@ -486,8 +486,8 @@ static const char* OReg_Name[] =
"a0.x" "a0.x"
}; };
std::array<bool, 16> RegVDeclIsUsed; std::array<bool, 16> RegVIsPresentInDeclaration;
std::array<int, 16> RegVDeclUsageOverride; std::array<bool, 16> RegVIsUsedByShader;
/* TODO : map non-FVF Xbox vertex shader handle to CxbxVertexShader (a struct containing a host Xbox vertex shader handle and the original members) /* TODO : map non-FVF Xbox vertex shader handle to CxbxVertexShader (a struct containing a host Xbox vertex shader handle and the original members)
std::unordered_map<DWORD, CxbxVertexShader> g_CxbxVertexShaders; std::unordered_map<DWORD, CxbxVertexShader> g_CxbxVertexShaders;
@ -870,6 +870,8 @@ XTL::D3DDECLUSAGE Xb2PCRegisterType
return PCRegisterType; return PCRegisterType;
} }
extern XTL::D3DCAPS g_D3DCaps;
static void VshWriteShader(VSH_XBOX_SHADER *pShader, static void VshWriteShader(VSH_XBOX_SHADER *pShader,
std::stringstream& pDisassembly, std::stringstream& pDisassembly,
XTL::D3DVERTEXELEMENT *pRecompiled, XTL::D3DVERTEXELEMENT *pRecompiled,
@ -898,18 +900,28 @@ static void VshWriteShader(VSH_XBOX_SHADER *pShader,
} }
if (Truncate) { if (Truncate) {
std::stringstream moveConstantsToTemporaries;
pDisassembly << "; Input usage declarations --\n"; pDisassembly << "; Input usage declarations --\n";
unsigned i = 0; unsigned i = 0;
do { do {
if (RegVDeclIsUsed[i]) { if (RegVIsUsedByShader[i]) {
if (!RegVIsPresentInDeclaration[i]) {
// Log test case and skip
// Any registers hitting this critera were already replaced with constant/temporary reads
// To correctly use the values given in SetVertexData4f.
// We need to move these constant values to temporaries so they can be used as input alongside other constants!
// We count down from the highest available on the host because Xbox titles don't use values that high, and we read from c192 because Xbox uses 192 constants
static int temporaryRegisterBase = g_D3DCaps.VS20Caps.NumTemps - 13;
moveConstantsToTemporaries << "mov r" << (temporaryRegisterBase + i) << ", c" << (193 + i) << "\n";
LOG_TEST_CASE("Shader uses undeclared Vertex Input Registers");
i++;
continue;
}
BYTE PCUsageIndex = 0; BYTE PCUsageIndex = 0;
DWORD usage = Xb2PCRegisterType(i, PCUsageIndex); DWORD usage = Xb2PCRegisterType(i, PCUsageIndex);
// If an override exists, use it
if (RegVDeclUsageOverride[i] >= 0) {
usage = RegVDeclUsageOverride[i];
}
std::stringstream dclStream; std::stringstream dclStream;
switch (usage) { switch (usage) {
case XTL::D3DDECLUSAGE_POSITION: case XTL::D3DDECLUSAGE_POSITION:
@ -946,7 +958,9 @@ static void VshWriteShader(VSH_XBOX_SHADER *pShader,
} }
i++; i++;
} while (i < RegVDeclIsUsed.size()); } while (i < RegVIsUsedByShader.size());
pDisassembly << moveConstantsToTemporaries.str();
} }
for (int i = 0; i < pShader->IntermediateCount && (i < VSH_MAX_INSTRUCTION_COUNT || !Truncate); i++) for (int i = 0; i < pShader->IntermediateCount && (i < VSH_MAX_INSTRUCTION_COUNT || !Truncate); i++)
@ -1525,8 +1539,6 @@ static boolean VshConvertShader(VSH_XBOX_SHADER *pShader,
{ {
using namespace XTL; using namespace XTL;
extern XTL::D3DCAPS g_D3DCaps;
const DWORD temporaryCount = g_D3DCaps.VS20Caps.NumTemps; const DWORD temporaryCount = g_D3DCaps.VS20Caps.NumTemps;
boolean RUsage[VSH_MAX_TEMPORARY_REGISTERS] = { FALSE }; boolean RUsage[VSH_MAX_TEMPORARY_REGISTERS] = { FALSE };
@ -1626,7 +1638,16 @@ static boolean VshConvertShader(VSH_XBOX_SHADER *pShader,
} }
if (pIntermediate->Parameters[j].Parameter.ParameterType == PARAM_V) { if (pIntermediate->Parameters[j].Parameter.ParameterType == PARAM_V) {
RegVDeclIsUsed[pIntermediate->Parameters[j].Parameter.Address] = TRUE; RegVIsUsedByShader[pIntermediate->Parameters[j].Parameter.Address] = TRUE;
if (!RegVIsPresentInDeclaration[pIntermediate->Parameters[j].Parameter.Address]) {
// This vertex register was not declared and therefore is not present within the Vertex Data object
// We read from tempories instead, that are set based on constants, in-turn, set by SetVertexData4f
// We count down from the highest available on the host because Xbox titles don't use values that high, and we read from c192 because Xbox uses 192 constants
static int temporaryRegisterBase = g_D3DCaps.VS20Caps.NumTemps - 13;
pIntermediate->Parameters[j].Parameter.ParameterType = PARAM_R;
pIntermediate->Parameters[j].Parameter.Address += temporaryRegisterBase;
}
} }
} }
} }
@ -2014,18 +2035,17 @@ static void VshConvertToken_STREAMDATA_REG(
{ {
using namespace XTL; using namespace XTL;
extern XTL::D3DCAPS g_D3DCaps;
XTL::DWORD VertexRegister = VshGetVertexRegister(*pToken); XTL::DWORD VertexRegister = VshGetVertexRegister(*pToken);
XTL::BYTE HostVertexRegister;
XTL::BOOL NeedPatching = FALSE; XTL::BOOL NeedPatching = FALSE;
XTL::BYTE Index; XTL::BYTE Index;
DbgVshPrintf("\t\tD3DVSD_REG("); DbgVshPrintf("\t\tD3DVSD_REG(");
BYTE XboxVertexRegister = Xb2PCRegisterType(VertexRegister, Index); BYTE HostVertexRegisterType = Xb2PCRegisterType(VertexRegister, Index);
HostVertexRegister = XboxVertexRegister;
DbgVshPrintf(", "); DbgVshPrintf(", ");
// Add this regiseter to the list of declared registers
RegVIsPresentInDeclaration[VertexRegister] = true;
XTL::DWORD XboxVertexElementDataType = (*pToken & X_D3DVSD_DATATYPEMASK) >> X_D3DVSD_DATATYPESHIFT; XTL::DWORD XboxVertexElementDataType = (*pToken & X_D3DVSD_DATATYPEMASK) >> X_D3DVSD_DATATYPESHIFT;
XTL::BYTE HostVertexElementDataType = 0; XTL::BYTE HostVertexElementDataType = 0;
XTL::WORD HostVertexElementByteSize = 0; XTL::WORD HostVertexElementByteSize = 0;
@ -2041,32 +2061,21 @@ static void VshConvertToken_STREAMDATA_REG(
DbgVshPrintf("D3DVSDT_FLOAT2"); DbgVshPrintf("D3DVSDT_FLOAT2");
HostVertexElementDataType = D3DDECLTYPE_FLOAT2; HostVertexElementDataType = D3DDECLTYPE_FLOAT2;
HostVertexElementByteSize = 2 * sizeof(FLOAT); HostVertexElementByteSize = 2 * sizeof(FLOAT);
//HostVertexRegister = D3DDECLUSAGE_TEXCOORD;
break; break;
case X_D3DVSDT_FLOAT3: // 0x32: case X_D3DVSDT_FLOAT3: // 0x32:
DbgVshPrintf("D3DVSDT_FLOAT3"); DbgVshPrintf("D3DVSDT_FLOAT3");
HostVertexElementDataType = D3DDECLTYPE_FLOAT3; HostVertexElementDataType = D3DDECLTYPE_FLOAT3;
HostVertexElementByteSize = 3 * sizeof(FLOAT); HostVertexElementByteSize = 3 * sizeof(FLOAT);
/*
if (pPatchData->pCurrentVertexShaderStreamInfo->DeclPosition) {
pPatchData->pCurrentVertexShaderStreamInfo->DeclPosition = true;
HostVertexRegister = D3DDECLUSAGE_POSITION;
} else {
HostVertexRegister = D3DDECLUSAGE_NORMAL;
} */
break; break;
case X_D3DVSDT_FLOAT4: // 0x42: case X_D3DVSDT_FLOAT4: // 0x42:
DbgVshPrintf("D3DVSDT_FLOAT4"); DbgVshPrintf("D3DVSDT_FLOAT4");
HostVertexElementDataType = D3DDECLTYPE_FLOAT4; HostVertexElementDataType = D3DDECLTYPE_FLOAT4;
HostVertexElementByteSize = 4 * sizeof(FLOAT); HostVertexElementByteSize = 4 * sizeof(FLOAT);
//HostVertexRegister = D3DDECLUSAGE_COLOR;
break; break;
case X_D3DVSDT_D3DCOLOR: // 0x40: case X_D3DVSDT_D3DCOLOR: // 0x40:
DbgVshPrintf("D3DVSDT_D3DCOLOR"); DbgVshPrintf("D3DVSDT_D3DCOLOR");
HostVertexElementDataType = D3DDECLTYPE_D3DCOLOR; HostVertexElementDataType = D3DDECLTYPE_D3DCOLOR;
HostVertexElementByteSize = 1 * sizeof(D3DCOLOR); HostVertexElementByteSize = 1 * sizeof(D3DCOLOR);
//HostVertexRegister = D3DDECLUSAGE_COLOR;
break; break;
case X_D3DVSDT_SHORT2: // 0x25: case X_D3DVSDT_SHORT2: // 0x25:
DbgVshPrintf("D3DVSDT_SHORT2"); DbgVshPrintf("D3DVSDT_SHORT2");
@ -2241,14 +2250,9 @@ static void VshConvertToken_STREAMDATA_REG(
pRecompiled->Offset = pPatchData->pCurrentVertexShaderStreamInfo->HostVertexStride; pRecompiled->Offset = pPatchData->pCurrentVertexShaderStreamInfo->HostVertexStride;
pRecompiled->Type = HostVertexElementDataType; pRecompiled->Type = HostVertexElementDataType;
pRecompiled->Method = D3DDECLMETHOD_DEFAULT; pRecompiled->Method = D3DDECLMETHOD_DEFAULT;
pRecompiled->Usage = HostVertexRegister; pRecompiled->Usage = HostVertexRegisterType;
pRecompiled->UsageIndex = Index; pRecompiled->UsageIndex = Index;
// If the xbox and host register number and usage differ, store an override!
if (XboxVertexRegister != HostVertexRegister) {
RegVDeclUsageOverride[XboxVertexRegister] = HostVertexRegister;
}
pRecompiled++; pRecompiled++;
pPatchData->pCurrentVertexShaderStreamInfo->HostVertexStride += HostVertexElementByteSize; pPatchData->pCurrentVertexShaderStreamInfo->HostVertexStride += HostVertexElementByteSize;
@ -2332,7 +2336,7 @@ DWORD XTL::EmuRecompileVshDeclaration
CxbxVertexShaderInfo *pVertexShaderInfo CxbxVertexShaderInfo *pVertexShaderInfo
) )
{ {
RegVDeclUsageOverride.fill(-1); RegVIsPresentInDeclaration.fill(false);
// First of all some info: // First of all some info:
// We have to figure out which flags are set and then // We have to figure out which flags are set and then
@ -2382,8 +2386,6 @@ DWORD XTL::EmuRecompileVshDeclaration
return D3D_OK; return D3D_OK;
} }
extern XTL::D3DCAPS g_D3DCaps;
// recompile xbox vertex shader function // recompile xbox vertex shader function
extern HRESULT XTL::EmuRecompileVshFunction extern HRESULT XTL::EmuRecompileVshFunction
( (
@ -2413,9 +2415,9 @@ extern HRESULT XTL::EmuRecompileVshFunction
DWORD* pDeclEnd = (DWORD*)((BYTE*)pDeclToken + DeclarationSize); DWORD* pDeclEnd = (DWORD*)((BYTE*)pDeclToken + DeclarationSize);
do { do {
DWORD regNum = *pDeclToken & X_D3DVSD_VERTEXREGMASK; DWORD regNum = *pDeclToken & X_D3DVSD_VERTEXREGMASK;
if (regNum >= temporaryCount /*12*/) { if (regNum >= temporaryCount /*12 for D3D8, D3D9 value depends on host GPU */) {
// Lego Star Wars hits this // Lego Star Wars hits this
LOG_TEST_CASE("RegNum > 12"); LOG_TEST_CASE("RegNum > NumTemps");
pDeclToken++; pDeclToken++;
continue; continue;
} }
@ -2458,7 +2460,7 @@ extern HRESULT XTL::EmuRecompileVshFunction
if(SUCCEEDED(hRet)) if(SUCCEEDED(hRet))
{ {
RegVDeclIsUsed.fill(false); RegVIsUsedByShader.fill(false);
for (pToken = (DWORD*)((uint8_t*)pFunction + sizeof(VSH_SHADER_HEADER)); !EOI; pToken += VSH_INSTRUCTION_SIZE) for (pToken = (DWORD*)((uint8_t*)pFunction + sizeof(VSH_SHADER_HEADER)); !EOI; pToken += VSH_INSTRUCTION_SIZE)
{ {