Update vertex shader compilation to version 2.x

- Added define for max temporary register count
- Added define for max instruction counts
- Updated address register accesses to use 'mova' instruction
- Updated shader versions to '2.x'
- Updated shader instruction truncation logic to use max instruction define
- Updated register usage arrays to use max temporary register define
- Updated register usage logic to make use of 'NumTemps' vertex shader caps
This commit is contained in:
revel8n 2018-08-09 05:11:43 -05:00
parent aebfde5df5
commit 9e0e367d15
No known key found for this signature in database
GPG Key ID: 7FC46D430508269D
1 changed files with 32 additions and 13 deletions

View File

@ -63,6 +63,13 @@
#define VSH_XBOX_MAX_INSTRUCTION_COUNT 136 // The maximum Xbox shader instruction count #define VSH_XBOX_MAX_INSTRUCTION_COUNT 136 // The maximum Xbox shader instruction count
#define VSH_MAX_INTERMEDIATE_COUNT 1024 // The maximum number of intermediate format slots #define VSH_MAX_INTERMEDIATE_COUNT 1024 // The maximum number of intermediate format slots
#define VSH_MAX_TEMPORARY_REGISTERS 32
#define VSH_VS11_MAX_INSTRUCTION_COUNT 128
#define VSH_VS2X_MAX_INSTRUCTION_COUNT 256
#define VSH_VS30_MAX_INSTRUCTION_COUNT 512
#define VSH_MAX_INSTRUCTION_COUNT VSH_VS2X_MAX_INSTRUCTION_COUNT
#define X_D3DVSD_MASK_TESSUV 0x10000000 #define X_D3DVSD_MASK_TESSUV 0x10000000
#define X_D3DVSD_MASK_SKIP 0x10000000 // Skips (normally) dwords #define X_D3DVSD_MASK_SKIP 0x10000000 // Skips (normally) dwords
#define X_D3DVSD_MASK_SKIPBYTES 0x08000000 // Skips bytes (no, really?!) #define X_D3DVSD_MASK_SKIPBYTES 0x08000000 // Skips bytes (no, really?!)
@ -447,7 +454,7 @@ static const char* MAC_OpCode[] =
"max", "max",
"slt", "slt",
"sge", "sge",
"mov", // really "arl" Dxbx note : Alias for 'mov a0.x' "mova", // really "arl" Dxbx note : Alias for 'mov a0.x'
"???", "???",
"???" "???"
}; };
@ -827,7 +834,7 @@ static void VshWriteShader(VSH_XBOX_SHADER *pShader,
#ifdef CXBX_USE_VS30 #ifdef CXBX_USE_VS30
DisassemblyPos += sprintf(pDisassembly + DisassemblyPos, "vs.3.0\n"); DisassemblyPos += sprintf(pDisassembly + DisassemblyPos, "vs.3.0\n");
#else #else
DisassemblyPos += sprintf(pDisassembly + DisassemblyPos, "vs.1.1\n"); DisassemblyPos += sprintf(pDisassembly + DisassemblyPos, "vs.2.x\n");
#endif #endif
break; break;
case VERSION_XVS: case VERSION_XVS:
@ -887,14 +894,14 @@ static void VshWriteShader(VSH_XBOX_SHADER *pShader,
} }
i++; i++;
} while (i < 16); } while (i < RegVUsage.size());
} }
for (int i = 0; i < pShader->IntermediateCount && (i < 128 || !Truncate); i++) for (int i = 0; i < pShader->IntermediateCount && (i < VSH_MAX_INSTRUCTION_COUNT || !Truncate); i++)
{ {
VSH_INTERMEDIATE_FORMAT *pIntermediate = &pShader->Intermediate[i]; VSH_INTERMEDIATE_FORMAT *pIntermediate = &pShader->Intermediate[i];
if(i == 128) if(i == VSH_MAX_INSTRUCTION_COUNT)
{ {
DisassemblyPos += sprintf(pDisassembly + DisassemblyPos, "; -- Passing the truncation limit --\n"); DisassemblyPos += sprintf(pDisassembly + DisassemblyPos, "; -- Passing the truncation limit --\n");
} }
@ -1473,7 +1480,13 @@ static boolean VshConvertShader(VSH_XBOX_SHADER *pShader,
bool *pDeclaredRegisters bool *pDeclaredRegisters
) )
{ {
boolean RUsage[13] = { FALSE }; using namespace XTL;
extern XTL::D3DCAPS g_D3DCaps;
const DWORD temporaryCount = g_D3DCaps.VS20Caps.NumTemps;
boolean RUsage[VSH_MAX_TEMPORARY_REGISTERS] = { FALSE };
// TODO: What about state shaders and such? // TODO: What about state shaders and such?
pShader->ShaderHeader.Version = VERSION_VS; pShader->ShaderHeader.Version = VERSION_VS;
@ -1618,8 +1631,10 @@ static boolean VshConvertShader(VSH_XBOX_SHADER *pShader,
// attempt to find unused register... // attempt to find unused register...
int outRegister = -1; int outRegister = -1;
for (int j = 11; j >= 0; --j) for (int j = temporaryCount - 1; j >= 0; --j)
{ {
if (j == 12) continue;
if(!RUsage[j]) if(!RUsage[j])
{ {
outRegister = j; outRegister = j;
@ -1700,10 +1715,10 @@ static boolean VshConvertShader(VSH_XBOX_SHADER *pShader,
} }
} }
int16 R12Replacement = -1; int16 R12Replacement = -1;
if(RUsage[12]) if(temporaryCount <= 12 && RUsage[12])
{ {
// Sigh, they absolutely had to use r12, didn't they? // Sigh, they absolutely had to use r12, didn't they?
for (int i = 11; i >= 0; i--) for (int i = temporaryCount - 1; i >= 0; i--)
{ {
if(!RUsage[i]) if(!RUsage[i])
{ {
@ -2432,6 +2447,8 @@ 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
( (
@ -2444,6 +2461,8 @@ extern HRESULT XTL::EmuRecompileVshFunction
DWORD DeclarationSize DWORD DeclarationSize
) )
{ {
const DWORD temporaryCount = g_D3DCaps.VS20Caps.NumTemps;
VSH_SHADER_HEADER *pShaderHeader = (VSH_SHADER_HEADER*)pFunction; VSH_SHADER_HEADER *pShaderHeader = (VSH_SHADER_HEADER*)pFunction;
DWORD *pToken; DWORD *pToken;
boolean EOI = false; boolean EOI = false;
@ -2454,12 +2473,12 @@ extern HRESULT XTL::EmuRecompileVshFunction
// Build an array of registers that are declared // Build an array of registers that are declared
// This is used to remove instructions that haven't been declared // This is used to remove instructions that haven't been declared
// as they cause CreateVertexShader to fail // as they cause CreateVertexShader to fail
bool declaredRegisters[13] = { false }; bool declaredRegisters[VSH_MAX_TEMPORARY_REGISTERS] = { false };
DWORD* pDeclToken = pRecompiledDeclaration; DWORD* pDeclToken = pRecompiledDeclaration;
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 > 12) { if (regNum >= temporaryCount /*12*/) {
// Lego Star Wars hits this // Lego Star Wars hits this
LOG_TEST_CASE("RegNum > 12"); LOG_TEST_CASE("RegNum > 12");
pDeclToken++; pDeclToken++;
@ -2538,12 +2557,12 @@ extern HRESULT XTL::EmuRecompileVshFunction
DbgVshPrintf("-----------------------\n"); DbgVshPrintf("-----------------------\n");
// HACK: Azurik. Prevent Direct3D from trying to assemble this. // HACK: Azurik. Prevent Direct3D from trying to assemble this.
if(!strcmp(pShaderDisassembly, "vs.1.1\n")) if(!strcmp(pShaderDisassembly, "vs.2.x\n"))
{ {
EmuWarning("Replacing empty vertex shader with fallback"); EmuWarning("Replacing empty vertex shader with fallback");
static const char dummy[] = static const char dummy[] =
"vs.1.1\n" "vs.2.x\n"
"dp4 oPos.x, v0, c96\n" "dp4 oPos.x, v0, c96\n"
"dp4 oPos.y, v0, c97\n" "dp4 oPos.y, v0, c97\n"
"dp4 oPos.z, v0, c98\n" "dp4 oPos.z, v0, c98\n"