From b5cec3e8fc0a723c88adb5225880ab9794505c0d Mon Sep 17 00:00:00 2001 From: Luke Usher Date: Wed, 24 Jul 2019 11:52:19 +0100 Subject: [PATCH 01/15] Cleanup Register Usage detection + Remove incorrect Xbox->PC mappings (From D3D8to9) --- src/core/hle/D3D8/XbVertexShader.cpp | 223 ++++++++++++--------------- 1 file changed, 96 insertions(+), 127 deletions(-) diff --git a/src/core/hle/D3D8/XbVertexShader.cpp b/src/core/hle/D3D8/XbVertexShader.cpp index f0e89eb16..994748e97 100644 --- a/src/core/hle/D3D8/XbVertexShader.cpp +++ b/src/core/hle/D3D8/XbVertexShader.cpp @@ -486,8 +486,8 @@ static const char* OReg_Name[] = "a0.x" }; -std::array RegVUsage; -std::array RegVDeclUsage; +std::array RegVDeclIsUsed; +std::array RegVDeclUsageOverride; /* 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 g_CxbxVertexShaders; @@ -790,28 +790,85 @@ static void VshWriteParameter(VSH_IMD_PARAMETER *pParameter, } -// From D3D8to9 -static const BYTE DeclAddressUsages[][2] = -{ - { XTL::D3DDECLUSAGE_POSITION, 0 }, - { XTL::D3DDECLUSAGE_BLENDWEIGHT, 0 }, - { XTL::D3DDECLUSAGE_BLENDINDICES, 0 }, - { XTL::D3DDECLUSAGE_NORMAL, 0 }, - { XTL::D3DDECLUSAGE_PSIZE, 0 }, - { XTL::D3DDECLUSAGE_COLOR, 0 }, - { XTL::D3DDECLUSAGE_COLOR, 1 }, - { XTL::D3DDECLUSAGE_TEXCOORD, 0 }, - { XTL::D3DDECLUSAGE_TEXCOORD, 1 }, - { XTL::D3DDECLUSAGE_TEXCOORD, 2 }, - { XTL::D3DDECLUSAGE_TEXCOORD, 3 }, - { XTL::D3DDECLUSAGE_TEXCOORD, 4 }, - { XTL::D3DDECLUSAGE_TEXCOORD, 5 }, - { XTL::D3DDECLUSAGE_TEXCOORD, 6 }, - { XTL::D3DDECLUSAGE_TEXCOORD, 7 }, - { XTL::D3DDECLUSAGE_POSITION, 1 }, - { XTL::D3DDECLUSAGE_NORMAL, 1 } -}; +#define D3DDECLUSAGE_UNSUPPORTED ((D3DDECLUSAGE)-1) +XTL::D3DDECLUSAGE Xb2PCRegisterType +( + DWORD VertexRegister, + BYTE& PCUsageIndex +) +{ + using namespace XTL; + + D3DDECLUSAGE PCRegisterType; + PCUsageIndex = 0; + + switch (VertexRegister) + { + case X_D3DVSDE_VERTEX: // -1 + DbgVshPrintf("D3DVSDE_VERTEX /* xbox ext. */"); + PCRegisterType = D3DDECLUSAGE_UNSUPPORTED; + break; + case X_D3DVSDE_POSITION: // 0 + DbgVshPrintf("D3DVSDE_POSITION"); + PCRegisterType = D3DDECLUSAGE_POSITION; + break; + case X_D3DVSDE_BLENDWEIGHT: // 1 + DbgVshPrintf("D3DVSDE_BLENDWEIGHT"); + PCRegisterType = D3DDECLUSAGE_BLENDWEIGHT; + break; + case X_D3DVSDE_NORMAL: // 2 + DbgVshPrintf("D3DVSDE_NORMAL"); + PCRegisterType = D3DDECLUSAGE_NORMAL; + break; + case X_D3DVSDE_DIFFUSE: // 3 + DbgVshPrintf("D3DVSDE_DIFFUSE"); + PCRegisterType = D3DDECLUSAGE_COLOR; PCUsageIndex = 0; + break; + case X_D3DVSDE_SPECULAR: // 4 + DbgVshPrintf("D3DVSDE_SPECULAR"); + PCRegisterType = D3DDECLUSAGE_COLOR; PCUsageIndex = 1; + break; + case X_D3DVSDE_FOG: // 5 + DbgVshPrintf("D3DVSDE_FOG"); + PCRegisterType = D3DDECLUSAGE_FOG; + break; + case X_D3DVSDE_POINTSIZE: // 6 + DbgVshPrintf("D3DVDSE_POINTSIZE"); + PCRegisterType = D3DDECLUSAGE_PSIZE; + break; + case X_D3DVSDE_BACKDIFFUSE: // 7 + DbgVshPrintf("D3DVSDE_BACKDIFFUSE /* xbox ext. */"); + PCRegisterType = D3DDECLUSAGE_COLOR; PCUsageIndex = 2; + break; + case X_D3DVSDE_BACKSPECULAR: // 8 + DbgVshPrintf("D3DVSDE_BACKSPECULAR /* xbox ext. */"); + PCRegisterType = D3DDECLUSAGE_COLOR; PCUsageIndex = 3; + break; + case X_D3DVSDE_TEXCOORD0: // 9 + DbgVshPrintf("D3DVSDE_TEXCOORD0"); + PCRegisterType = D3DDECLUSAGE_TEXCOORD; PCUsageIndex = 0; + break; + case X_D3DVSDE_TEXCOORD1: // 10 + DbgVshPrintf("D3DVSDE_TEXCOORD1"); + PCRegisterType = D3DDECLUSAGE_TEXCOORD; PCUsageIndex = 1; + break; + case X_D3DVSDE_TEXCOORD2: // 11 + DbgVshPrintf("D3DVSDE_TEXCOORD2"); + PCRegisterType = D3DDECLUSAGE_TEXCOORD; PCUsageIndex = 2; + break; + case X_D3DVSDE_TEXCOORD3: // 12 + DbgVshPrintf("D3DVSDE_TEXCOORD3"); + PCRegisterType = D3DDECLUSAGE_TEXCOORD; PCUsageIndex = 3; + break; + default: + DbgVshPrintf("%d /* unknown register */", VertexRegister); + PCRegisterType = D3DDECLUSAGE_UNSUPPORTED; + break; + } + + return PCRegisterType; +} static void VshWriteShader(VSH_XBOX_SHADER *pShader, std::stringstream& pDisassembly, @@ -844,13 +901,13 @@ static void VshWriteShader(VSH_XBOX_SHADER *pShader, pDisassembly << "; Input usage declarations --\n"; unsigned i = 0; do { - if (RegVUsage[i]) { - DWORD PCUsageIndex = DeclAddressUsages[i][1]; - DWORD usage = DeclAddressUsages[i][0]; + if (RegVDeclIsUsed[i]) { + BYTE PCUsageIndex = 0; + DWORD usage = Xb2PCRegisterType(i, PCUsageIndex); // If an override exists, use it - if (RegVDeclUsage[i] >= 0) { - usage = RegVDeclUsage[i]; + if (RegVDeclUsageOverride[i] >= 0) { + usage = RegVDeclUsageOverride[i]; } std::stringstream dclStream; @@ -889,7 +946,7 @@ static void VshWriteShader(VSH_XBOX_SHADER *pShader, } i++; - } while (i < RegVUsage.size()); + } while (i < RegVDeclIsUsed.size()); } for (int i = 0; i < pShader->IntermediateCount && (i < VSH_MAX_INSTRUCTION_COUNT || !Truncate); i++) @@ -1569,7 +1626,7 @@ static boolean VshConvertShader(VSH_XBOX_SHADER *pShader, } if (pIntermediate->Parameters[j].Parameter.ParameterType == PARAM_V) { - RegVUsage[pIntermediate->Parameters[j].Parameter.Address] = TRUE; + RegVDeclIsUsed[pIntermediate->Parameters[j].Parameter.Address] = TRUE; } } } @@ -1773,93 +1830,6 @@ static DWORD VshGetDeclarationCount(DWORD *pDeclaration) return Pos + 1; } -#define D3DDECLUSAGE_UNSUPPORTED ((D3DDECLUSAGE)-1) - -XTL::D3DDECLUSAGE Xb2PCRegisterType -( - DWORD VertexRegister, - boolean IsFixedFunction, - BYTE& PCUsageIndex -) -{ - using namespace XTL; - - D3DDECLUSAGE PCRegisterType; - PCUsageIndex = 0; - - if (!IsFixedFunction) { - DbgVshPrintf("%d", VertexRegister); - PCUsageIndex = DeclAddressUsages[VertexRegister][1]; - return (D3DDECLUSAGE)DeclAddressUsages[VertexRegister][0]; - } - - switch (VertexRegister) - { - case X_D3DVSDE_VERTEX: // -1 - DbgVshPrintf("D3DVSDE_VERTEX /* xbox ext. */"); - PCRegisterType = D3DDECLUSAGE_UNSUPPORTED; - break; - case X_D3DVSDE_POSITION: // 0 - DbgVshPrintf("D3DVSDE_POSITION"); - PCRegisterType = D3DDECLUSAGE_POSITION; - break; - case X_D3DVSDE_BLENDWEIGHT: // 1 - DbgVshPrintf("D3DVSDE_BLENDWEIGHT"); - PCRegisterType = D3DDECLUSAGE_BLENDWEIGHT; - break; - case X_D3DVSDE_NORMAL: // 2 - DbgVshPrintf("D3DVSDE_NORMAL"); - PCRegisterType = D3DDECLUSAGE_NORMAL; - break; - case X_D3DVSDE_DIFFUSE: // 3 - DbgVshPrintf("D3DVSDE_DIFFUSE"); - PCRegisterType = D3DDECLUSAGE_COLOR; PCUsageIndex = 0; - break; - case X_D3DVSDE_SPECULAR: // 4 - DbgVshPrintf("D3DVSDE_SPECULAR"); - PCRegisterType = D3DDECLUSAGE_COLOR; PCUsageIndex = 1; - break; - case X_D3DVSDE_FOG: // 5 - DbgVshPrintf("D3DVSDE_FOG"); - PCRegisterType = D3DDECLUSAGE_FOG; - break; - case X_D3DVSDE_POINTSIZE: // 6 - DbgVshPrintf("D3DVDSE_POINTSIZE"); - PCRegisterType = D3DDECLUSAGE_PSIZE; - break; - case X_D3DVSDE_BACKDIFFUSE: // 7 - DbgVshPrintf("D3DVSDE_BACKDIFFUSE /* xbox ext. */"); - PCRegisterType = D3DDECLUSAGE_COLOR; PCUsageIndex = 2; - break; - case X_D3DVSDE_BACKSPECULAR: // 8 - DbgVshPrintf("D3DVSDE_BACKSPECULAR /* xbox ext. */"); - PCRegisterType = D3DDECLUSAGE_COLOR; PCUsageIndex = 3; - break; - case X_D3DVSDE_TEXCOORD0: // 9 - DbgVshPrintf("D3DVSDE_TEXCOORD0"); - PCRegisterType = D3DDECLUSAGE_TEXCOORD; PCUsageIndex = 0; - break; - case X_D3DVSDE_TEXCOORD1: // 10 - DbgVshPrintf("D3DVSDE_TEXCOORD1"); - PCRegisterType = D3DDECLUSAGE_TEXCOORD; PCUsageIndex = 1; - break; - case X_D3DVSDE_TEXCOORD2: // 11 - DbgVshPrintf("D3DVSDE_TEXCOORD2"); - PCRegisterType = D3DDECLUSAGE_TEXCOORD; PCUsageIndex = 2; - break; - case X_D3DVSDE_TEXCOORD3: // 12 - DbgVshPrintf("D3DVSDE_TEXCOORD3"); - PCRegisterType = D3DDECLUSAGE_TEXCOORD; PCUsageIndex = 3; - break; - default: - DbgVshPrintf("%d /* unknown register */", VertexRegister); - PCRegisterType = D3DDECLUSAGE_UNSUPPORTED; - break; - } - - return PCRegisterType; -} - static inline DWORD VshGetTokenType(DWORD Token) { return (Token & X_D3DVSD_TOKENTYPEMASK) >> X_D3DVSD_TOKENTYPESHIFT; @@ -1921,19 +1891,18 @@ static void VshConvertToken_TESSELATOR( using namespace XTL; BYTE Index; - // TODO: Investigate why Xb2PCRegisterType is only used for fixed function vertex shaders if(*pToken & X_D3DVSD_MASK_TESSUV) { XTL::DWORD VertexRegister = VshGetVertexRegister(*pToken); XTL::DWORD NewVertexRegister = VertexRegister; DbgVshPrintf("\tD3DVSD_TESSUV("); - NewVertexRegister = Xb2PCRegisterType(VertexRegister, IsFixedFunction, Index); + NewVertexRegister = Xb2PCRegisterType(VertexRegister, Index); DbgVshPrintf("),\n"); // TODO : Expand on the setting of this TESSUV register element : pRecompiled->Usage = D3DDECLUSAGE(NewVertexRegister); - pRecompiled->UsageIndex = Xb2PCRegisterType(NewVertexRegister, IsFixedFunction, Index); // TODO : Get Index from Xb2PCRegisterType + pRecompiled->UsageIndex =Index; } // D3DVSD_TESSNORMAL else @@ -1945,18 +1914,18 @@ static void VshConvertToken_TESSELATOR( XTL::DWORD NewVertexRegisterOut = VertexRegisterOut; DbgVshPrintf("\tD3DVSD_TESSNORMAL("); - NewVertexRegisterIn = Xb2PCRegisterType(VertexRegisterIn, IsFixedFunction, Index); + NewVertexRegisterIn = Xb2PCRegisterType(VertexRegisterIn, Index); DbgVshPrintf(", "); // TODO : Expand on the setting of this TESSNORMAL input register element : pRecompiled->Usage = D3DDECLUSAGE(NewVertexRegisterIn); pRecompiled->UsageIndex = 0; // TODO : Get Index from Xb2PCRegisterType - NewVertexRegisterOut = Xb2PCRegisterType(VertexRegisterOut, IsFixedFunction, Index); + NewVertexRegisterOut = Xb2PCRegisterType(VertexRegisterOut, Index); DbgVshPrintf("),\n"); // TODO : Expand on the setting of this TESSNORMAL output register element : pRecompiled++; pRecompiled->Usage = D3DDECLUSAGE(NewVertexRegisterOut); - pRecompiled->UsageIndex = 0; // TODO : Get Index from Xb2PCRegisterType + pRecompiled->UsageIndex = Index; // TODO : Get Index from Xb2PCRegisterType } } @@ -2053,7 +2022,7 @@ static void VshConvertToken_STREAMDATA_REG( XTL::BYTE Index; DbgVshPrintf("\t\tD3DVSD_REG("); - BYTE XboxVertexRegister = Xb2PCRegisterType(VertexRegister, IsFixedFunction, Index); + BYTE XboxVertexRegister = Xb2PCRegisterType(VertexRegister, Index); HostVertexRegister = XboxVertexRegister; DbgVshPrintf(", "); @@ -2277,7 +2246,7 @@ static void VshConvertToken_STREAMDATA_REG( // If the xbox and host register number and usage differ, store an override! if (XboxVertexRegister != HostVertexRegister) { - RegVDeclUsage[XboxVertexRegister] = HostVertexRegister; + RegVDeclUsageOverride[XboxVertexRegister] = HostVertexRegister; } pRecompiled++; @@ -2363,7 +2332,7 @@ DWORD XTL::EmuRecompileVshDeclaration CxbxVertexShaderInfo *pVertexShaderInfo ) { - RegVDeclUsage.fill(-1); + RegVDeclUsageOverride.fill(-1); // First of all some info: // We have to figure out which flags are set and then @@ -2489,7 +2458,7 @@ extern HRESULT XTL::EmuRecompileVshFunction if(SUCCEEDED(hRet)) { - RegVUsage.fill(false); + RegVDeclIsUsed.fill(false); for (pToken = (DWORD*)((uint8_t*)pFunction + sizeof(VSH_SHADER_HEADER)); !EOI; pToken += VSH_INSTRUCTION_SIZE) { From 8d8e25669797550c7b3035f9a09077a74513feb7 Mon Sep 17 00:00:00 2001 From: Luke Usher Date: Wed, 24 Jul 2019 12:00:32 +0100 Subject: [PATCH 02/15] Update SetVertexData4f to write it's input to shader constants --- src/core/hle/D3D8/Direct3D9/Direct3D9.cpp | 27 ++++++++++++++--------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp index c4df4b90e..8d4000861 100644 --- a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp +++ b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp @@ -4168,6 +4168,23 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_SetVertexData4f) HRESULT hRet = D3D_OK; + // Get the vertex shader flags (if any is active) : + uint32_t ActiveVertexAttributeFlags = 0; + if (VshHandleIsVertexShader(g_CurrentXboxVertexShaderHandle)) { + LOG_TEST_CASE("D3DDevice_SetVertexData4f with active VertexShader"); + X_D3DVertexShader* pXboxVertexShader = VshHandleToXboxVertexShader(g_CurrentXboxVertexShaderHandle); + if (!(pXboxVertexShader->Flags & 0x10/*=X_VERTEXSHADER_PROGRAM*/)) { + ActiveVertexAttributeFlags = pXboxVertexShader->Flags; + } + + // If we have an active vertex shader, we also write the input to a vertex shader constant + // This allows us to implement Xbox functionality where SetVertexData4f can be used to specify attributes + // not present in the vertex declaration. + // We use range 193 and up to store these values, as Xbox shaders stop at c192! + FLOAT values[] = {a,b,c,d}; + g_pD3DDevice->SetVertexShaderConstantF(193 + Register, values, 1); + } + // Grow g_InlineVertexBuffer_Table to contain at least current, and a potentially next vertex if (g_InlineVertexBuffer_TableLength <= g_InlineVertexBuffer_TableOffset + 1) { if (g_InlineVertexBuffer_TableLength == 0) { @@ -4185,16 +4202,6 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_SetVertexData4f) // Set first vertex to zero (preventing leaks from prior Begin/End calls) g_InlineVertexBuffer_Table[0] = {}; - // Get the vertex shader flags (if any is active) : - uint32_t ActiveVertexAttributeFlags = 0; - if (VshHandleIsVertexShader(g_CurrentXboxVertexShaderHandle)) { - LOG_TEST_CASE("D3DDevice_SetVertexData4f with active VertexShader"); - X_D3DVertexShader *pXboxVertexShader = VshHandleToXboxVertexShader(g_CurrentXboxVertexShaderHandle); - if (!(pXboxVertexShader->Flags & 0x10/*=X_VERTEXSHADER_PROGRAM*/)) { - ActiveVertexAttributeFlags = pXboxVertexShader->Flags; - } - } - // Handle persistent vertex attribute flags, by resetting non-persistent colors // to their default value (and leaving the persistent colors alone - see the // "Copy all attributes of the previous vertex" comment below) : From 5bfb98c31204e91802453ebf2f906c44ad913235 Mon Sep 17 00:00:00 2001 From: Luke Usher Date: Wed, 24 Jul 2019 14:39:58 +0100 Subject: [PATCH 03/15] Read registers not present in vertex buffers from SetVertexData4f registers --- src/core/hle/D3D8/XbVertexShader.cpp | 82 ++++++++++++++-------------- 1 file changed, 42 insertions(+), 40 deletions(-) diff --git a/src/core/hle/D3D8/XbVertexShader.cpp b/src/core/hle/D3D8/XbVertexShader.cpp index 994748e97..54a2d360d 100644 --- a/src/core/hle/D3D8/XbVertexShader.cpp +++ b/src/core/hle/D3D8/XbVertexShader.cpp @@ -486,8 +486,8 @@ static const char* OReg_Name[] = "a0.x" }; -std::array RegVDeclIsUsed; -std::array RegVDeclUsageOverride; +std::array RegVIsPresentInDeclaration; +std::array RegVIsUsedByShader; /* 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 g_CxbxVertexShaders; @@ -870,6 +870,8 @@ XTL::D3DDECLUSAGE Xb2PCRegisterType return PCRegisterType; } +extern XTL::D3DCAPS g_D3DCaps; + static void VshWriteShader(VSH_XBOX_SHADER *pShader, std::stringstream& pDisassembly, XTL::D3DVERTEXELEMENT *pRecompiled, @@ -898,18 +900,28 @@ static void VshWriteShader(VSH_XBOX_SHADER *pShader, } if (Truncate) { + std::stringstream moveConstantsToTemporaries; + pDisassembly << "; Input usage declarations --\n"; unsigned i = 0; 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; DWORD usage = Xb2PCRegisterType(i, PCUsageIndex); - // If an override exists, use it - if (RegVDeclUsageOverride[i] >= 0) { - usage = RegVDeclUsageOverride[i]; - } - std::stringstream dclStream; switch (usage) { case XTL::D3DDECLUSAGE_POSITION: @@ -946,7 +958,9 @@ static void VshWriteShader(VSH_XBOX_SHADER *pShader, } 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++) @@ -1525,8 +1539,6 @@ static boolean VshConvertShader(VSH_XBOX_SHADER *pShader, { using namespace XTL; - extern XTL::D3DCAPS g_D3DCaps; - const DWORD temporaryCount = g_D3DCaps.VS20Caps.NumTemps; 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) { - 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; - extern XTL::D3DCAPS g_D3DCaps; - XTL::DWORD VertexRegister = VshGetVertexRegister(*pToken); - XTL::BYTE HostVertexRegister; XTL::BOOL NeedPatching = FALSE; XTL::BYTE Index; DbgVshPrintf("\t\tD3DVSD_REG("); - BYTE XboxVertexRegister = Xb2PCRegisterType(VertexRegister, Index); - HostVertexRegister = XboxVertexRegister; + BYTE HostVertexRegisterType = Xb2PCRegisterType(VertexRegister, Index); DbgVshPrintf(", "); + // Add this regiseter to the list of declared registers + RegVIsPresentInDeclaration[VertexRegister] = true; + XTL::DWORD XboxVertexElementDataType = (*pToken & X_D3DVSD_DATATYPEMASK) >> X_D3DVSD_DATATYPESHIFT; XTL::BYTE HostVertexElementDataType = 0; XTL::WORD HostVertexElementByteSize = 0; @@ -2041,32 +2061,21 @@ static void VshConvertToken_STREAMDATA_REG( DbgVshPrintf("D3DVSDT_FLOAT2"); HostVertexElementDataType = D3DDECLTYPE_FLOAT2; HostVertexElementByteSize = 2 * sizeof(FLOAT); - //HostVertexRegister = D3DDECLUSAGE_TEXCOORD; break; case X_D3DVSDT_FLOAT3: // 0x32: DbgVshPrintf("D3DVSDT_FLOAT3"); HostVertexElementDataType = D3DDECLTYPE_FLOAT3; HostVertexElementByteSize = 3 * sizeof(FLOAT); - - /* - if (pPatchData->pCurrentVertexShaderStreamInfo->DeclPosition) { - pPatchData->pCurrentVertexShaderStreamInfo->DeclPosition = true; - HostVertexRegister = D3DDECLUSAGE_POSITION; - } else { - HostVertexRegister = D3DDECLUSAGE_NORMAL; - } */ break; case X_D3DVSDT_FLOAT4: // 0x42: DbgVshPrintf("D3DVSDT_FLOAT4"); HostVertexElementDataType = D3DDECLTYPE_FLOAT4; HostVertexElementByteSize = 4 * sizeof(FLOAT); - //HostVertexRegister = D3DDECLUSAGE_COLOR; break; case X_D3DVSDT_D3DCOLOR: // 0x40: DbgVshPrintf("D3DVSDT_D3DCOLOR"); HostVertexElementDataType = D3DDECLTYPE_D3DCOLOR; HostVertexElementByteSize = 1 * sizeof(D3DCOLOR); - //HostVertexRegister = D3DDECLUSAGE_COLOR; break; case X_D3DVSDT_SHORT2: // 0x25: DbgVshPrintf("D3DVSDT_SHORT2"); @@ -2241,14 +2250,9 @@ static void VshConvertToken_STREAMDATA_REG( pRecompiled->Offset = pPatchData->pCurrentVertexShaderStreamInfo->HostVertexStride; pRecompiled->Type = HostVertexElementDataType; pRecompiled->Method = D3DDECLMETHOD_DEFAULT; - pRecompiled->Usage = HostVertexRegister; + pRecompiled->Usage = HostVertexRegisterType; pRecompiled->UsageIndex = Index; - // If the xbox and host register number and usage differ, store an override! - if (XboxVertexRegister != HostVertexRegister) { - RegVDeclUsageOverride[XboxVertexRegister] = HostVertexRegister; - } - pRecompiled++; pPatchData->pCurrentVertexShaderStreamInfo->HostVertexStride += HostVertexElementByteSize; @@ -2332,7 +2336,7 @@ DWORD XTL::EmuRecompileVshDeclaration CxbxVertexShaderInfo *pVertexShaderInfo ) { - RegVDeclUsageOverride.fill(-1); + RegVIsPresentInDeclaration.fill(false); // First of all some info: // We have to figure out which flags are set and then @@ -2382,8 +2386,6 @@ DWORD XTL::EmuRecompileVshDeclaration return D3D_OK; } -extern XTL::D3DCAPS g_D3DCaps; - // recompile xbox vertex shader function extern HRESULT XTL::EmuRecompileVshFunction ( @@ -2413,9 +2415,9 @@ extern HRESULT XTL::EmuRecompileVshFunction DWORD* pDeclEnd = (DWORD*)((BYTE*)pDeclToken + DeclarationSize); do { 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 - LOG_TEST_CASE("RegNum > 12"); + LOG_TEST_CASE("RegNum > NumTemps"); pDeclToken++; continue; } @@ -2458,7 +2460,7 @@ extern HRESULT XTL::EmuRecompileVshFunction if(SUCCEEDED(hRet)) { - RegVDeclIsUsed.fill(false); + RegVIsUsedByShader.fill(false); for (pToken = (DWORD*)((uint8_t*)pFunction + sizeof(VSH_SHADER_HEADER)); !EOI; pToken += VSH_INSTRUCTION_SIZE) { From 893a25baf263c4ca66f54f47c07b776fd001f103 Mon Sep 17 00:00:00 2001 From: Luke Usher Date: Wed, 24 Jul 2019 15:26:50 +0100 Subject: [PATCH 04/15] Pass default values at SetVertexShader time --- src/core/hle/D3D8/Direct3D9/Direct3D9.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp index 8d4000861..b96efaa90 100644 --- a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp +++ b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp @@ -7126,6 +7126,15 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_SetVertexShader) DEBUG_D3DRESULT(hRet, "g_pD3DDevice->SetVertexDeclaration"); hRet = g_pD3DDevice->SetVertexShader((XTL::IDirect3DVertexShader9*)pVertexShader->Handle); DEBUG_D3DRESULT(hRet, "g_pD3DDevice->SetVertexShader(VshHandleIsVertexShader)"); + + // Set default constant values for specular, diffuse, etc + static const float ColorBlack[4] = { 0,0,0,0 }; + static const float ColorWhite[4] = { 1,1,1,1 }; + + g_pD3DDevice->SetVertexShaderConstantF(193 + X_D3DVSDE_DIFFUSE, ColorWhite, 1); + g_pD3DDevice->SetVertexShaderConstantF(193 + X_D3DVSDE_BACKDIFFUSE, ColorWhite, 1); + g_pD3DDevice->SetVertexShaderConstantF(193 + X_D3DVSDE_SPECULAR, ColorBlack, 1); + g_pD3DDevice->SetVertexShaderConstantF(193 + X_D3DVSDE_BACKSPECULAR, ColorBlack, 1); } else { hRet = g_pD3DDevice->SetVertexShader(nullptr); DEBUG_D3DRESULT(hRet, "g_pD3DDevice->SetVertexShader"); From fb871f283f994d4d9216fba157be1e59c4d53d5f Mon Sep 17 00:00:00 2001 From: Luke Usher Date: Wed, 24 Jul 2019 15:36:56 +0100 Subject: [PATCH 05/15] Prevent new R registers being trashed --- src/core/hle/D3D8/XbVertexShader.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/core/hle/D3D8/XbVertexShader.cpp b/src/core/hle/D3D8/XbVertexShader.cpp index 54a2d360d..c3d01fc69 100644 --- a/src/core/hle/D3D8/XbVertexShader.cpp +++ b/src/core/hle/D3D8/XbVertexShader.cpp @@ -1542,6 +1542,12 @@ static boolean VshConvertShader(VSH_XBOX_SHADER *pShader, const DWORD temporaryCount = g_D3DCaps.VS20Caps.NumTemps; boolean RUsage[VSH_MAX_TEMPORARY_REGISTERS] = { FALSE }; + // Set the last 13 register to used (they are used for SetVertexData4f Constants) + for (int i = 0; i <= 13; i++) { + RUsage[VSH_MAX_TEMPORARY_REGISTERS - i] = true; + } + + // TODO: What about state shaders and such? pShader->ShaderHeader.Version = VERSION_VS; From 6326602232614cb976f9572881ce7cb511e2dda5 Mon Sep 17 00:00:00 2001 From: Luke Usher Date: Wed, 24 Jul 2019 18:34:39 +0100 Subject: [PATCH 06/15] Writeback vertex attributes --- src/core/hle/D3D8/Direct3D9/Direct3D9.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp index b96efaa90..2c9757fc6 100644 --- a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp +++ b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp @@ -4320,6 +4320,7 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_SetVertexData4f) { g_InlineVertexBuffer_Table[o].Diffuse = D3DCOLOR_COLORVALUE(a, b, c, d); g_InlineVertexBuffer_FVF |= D3DFVF_DIFFUSE; + HLE_write_NV2A_vertex_attribute_slot(X_D3DVSDE_DIFFUSE, g_InlineVertexBuffer_Table[o].Diffuse); break; } @@ -4327,6 +4328,7 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_SetVertexData4f) { g_InlineVertexBuffer_Table[o].Specular = D3DCOLOR_COLORVALUE(a, b, c, d); g_InlineVertexBuffer_FVF |= D3DFVF_SPECULAR; + HLE_write_NV2A_vertex_attribute_slot(X_D3DVSDE_SPECULAR, g_InlineVertexBuffer_Table[o].Specular); break; } @@ -4343,6 +4345,7 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_SetVertexData4f) { g_InlineVertexBuffer_Table[o].BackDiffuse = D3DCOLOR_COLORVALUE(a, b, c, d); EmuLog(LOG_LEVEL::WARNING, "Host Direct3D8 doesn''t support FVF BACKDIFFUSE"); + HLE_write_NV2A_vertex_attribute_slot(X_D3DVSDE_BACKDIFFUSE, g_InlineVertexBuffer_Table[o].BackDiffuse); break; } @@ -4350,6 +4353,7 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_SetVertexData4f) { g_InlineVertexBuffer_Table[o].BackSpecular = D3DCOLOR_COLORVALUE(a, b, c, d); EmuLog(LOG_LEVEL::WARNING, "Host Direct3D8 doesn''t support FVF BACKSPECULAR"); + HLE_write_NV2A_vertex_attribute_slot(X_D3DVSDE_BACKSPECULAR, g_InlineVertexBuffer_Table[o].BackSpecular); break; } From b62b8341cc2965c2069c197c6c0060ecff8cf2ac Mon Sep 17 00:00:00 2001 From: Luke Usher Date: Wed, 24 Jul 2019 18:37:03 +0100 Subject: [PATCH 07/15] 3925 fog disable hack --- src/core/hle/D3D8/XbState.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/core/hle/D3D8/XbState.cpp b/src/core/hle/D3D8/XbState.cpp index 969b0ad4f..f68e6630a 100644 --- a/src/core/hle/D3D8/XbState.cpp +++ b/src/core/hle/D3D8/XbState.cpp @@ -103,7 +103,16 @@ void UpdateDeferredRenderStates() Value = *(DWORD*)&fogValue; } } break; - case XTL::X_D3DRS_FOGENABLE: + case XTL::X_D3DRS_FOGENABLE: + if (g_LibVersion_D3D8 == 3925) { + // HACK: Many 3925 games only show a black screen if fog is enabled + // Initially, this was thought to be bad offsets, but it has been verified to be correct + // Unitl we find out the true underlying cause, disable fog and carry on + // Test Cases: Halo, Silent Hill 2. + LOG_TEST_CASE("Applying 3925 fog disable hack"); + Value = false; + } + break; case XTL::X_D3DRS_FOGTABLEMODE: case XTL::X_D3DRS_FOGDENSITY: case XTL::X_D3DRS_RANGEFOGENABLE: From bcc7f0c65076b22c0b36f57287d5c4b230386c11 Mon Sep 17 00:00:00 2001 From: Luke Usher Date: Thu, 25 Jul 2019 07:14:53 +0100 Subject: [PATCH 08/15] Remove R12 replace hack: VS2_X has enough registers --- src/core/hle/D3D8/XbVertexShader.cpp | 62 ---------------------------- 1 file changed, 62 deletions(-) diff --git a/src/core/hle/D3D8/XbVertexShader.cpp b/src/core/hle/D3D8/XbVertexShader.cpp index c3d01fc69..bf6524402 100644 --- a/src/core/hle/D3D8/XbVertexShader.cpp +++ b/src/core/hle/D3D8/XbVertexShader.cpp @@ -1766,69 +1766,7 @@ static boolean VshConvertShader(VSH_XBOX_SHADER *pShader, i++; } } - int16_t R12Replacement = -1; - if(temporaryCount <= 12 && RUsage[12]) - { - // Sigh, they absolutely had to use r12, didn't they? - for (int i = temporaryCount - 1; i >= 0; i--) - { - if(!RUsage[i]) - { - R12Replacement = i; - break; - } - } - if(R12Replacement == -1) - { - EmuLog(LOG_LEVEL::WARNING, "Vertex shader uses all r registers, including r12; impossible to convert!"); - return FALSE; - } - for (int j = 0; j < pShader->IntermediateCount; j++) - { - VSH_INTERMEDIATE_FORMAT* pIntermediate = &pShader->Intermediate[j]; - if(pIntermediate->Output.Type == IMD_OUTPUT_O && - pIntermediate->Output.Address == OREG_OPOS) - { - // Found instruction writing to oPos - pIntermediate->Output.Type = IMD_OUTPUT_R; - pIntermediate->Output.Address = R12Replacement; - } - for (int k = 0; k < 3; k++) - { - if(pIntermediate->Parameters[k].Active) - { - if(pIntermediate->Parameters[k].Parameter.ParameterType == PARAM_R && - pIntermediate->Parameters[k].Parameter.Address == 12) - { - // Found a r12 used as a parameter; replace - pIntermediate->Parameters[k].Parameter.Address = R12Replacement; - } - else if(pIntermediate->Parameters[k].Parameter.ParameterType == PARAM_C && - pIntermediate->Parameters[k].Parameter.Address == 58 && - !pIntermediate->Parameters[k].IndexesWithA0_X) - { - // Found c-38, replace it with r12.w - pIntermediate->Parameters[k].Parameter.ParameterType = PARAM_R; - pIntermediate->Parameters[k].Parameter.Address = R12Replacement; - VshSetSwizzle(&pIntermediate->Parameters[k], SWIZZLE_W, SWIZZLE_W, SWIZZLE_W, SWIZZLE_W); - } - } - } - } - // Insert mov oPos, r## in the end - VSH_INTERMEDIATE_FORMAT *pOPosWriteBack = VshNewIntermediate(pShader); - pOPosWriteBack->InstructionType = IMD_ILU; - pOPosWriteBack->ILU = ILU_MOV; - pOPosWriteBack->MAC = MAC_NOP; - pOPosWriteBack->Output.Type = IMD_OUTPUT_O; - pOPosWriteBack->Output.Address = OREG_OPOS; - VshSetOutputMask(&pOPosWriteBack->Output, TRUE, TRUE, TRUE, TRUE); - pOPosWriteBack->Parameters[0].Active = TRUE; - pOPosWriteBack->Parameters[0].Parameter.ParameterType = PARAM_R; - pOPosWriteBack->Parameters[0].Parameter.Address = R12Replacement; - VshSetSwizzle(&pOPosWriteBack->Parameters[0], SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W); - } return TRUE; } From 6ced17697771c9fe95a68b811278752f3324ee24 Mon Sep 17 00:00:00 2001 From: Luke Usher Date: Thu, 25 Jul 2019 07:39:24 +0100 Subject: [PATCH 09/15] Cleanup + R12 oPos readback --- src/core/hle/D3D8/XbVertexShader.cpp | 44 +++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/src/core/hle/D3D8/XbVertexShader.cpp b/src/core/hle/D3D8/XbVertexShader.cpp index bf6524402..f552becff 100644 --- a/src/core/hle/D3D8/XbVertexShader.cpp +++ b/src/core/hle/D3D8/XbVertexShader.cpp @@ -1459,7 +1459,7 @@ static void VshRemoveScreenSpaceInstructions(VSH_XBOX_SHADER *pShader) // If we couldn't find the generic screen space transformation we're // assuming that the shader writes direct screen coordinates that must be // normalized. This hack will fail if (a) the shader uses custom screen - // space transformation, (b) reads r10 or r11 after we have written to + // space transformation, (b) reads r13 or r12 after we have written to // them, or (c) doesn't reserve c-38 and c-37 for scale and offset. if(deleted != 3) { @@ -1472,17 +1472,17 @@ static void VshRemoveScreenSpaceInstructions(VSH_XBOX_SHADER *pShader) if( pIntermediate->Output.Type == IMD_OUTPUT_O && pIntermediate->Output.Address == OREG_OPOS) { - // Redirect output to r11. + // Redirect output to r12. pIntermediate->Output.Type = IMD_OUTPUT_R; - pIntermediate->Output.Address = 11; + pIntermediate->Output.Address = 12; - // Scale r11 to r10. (mul r10.[mask], r11, c58) + // Scale r12 to r13. (mul r13.[mask], r12, c58) VSH_INTERMEDIATE_FORMAT MulIntermediate; MulIntermediate.IsCombined = FALSE; MulIntermediate.InstructionType = IMD_MAC; MulIntermediate.MAC = MAC_MUL; MulIntermediate.Output.Type = IMD_OUTPUT_R; - MulIntermediate.Output.Address = 10; + MulIntermediate.Output.Address = 13; MulIntermediate.Output.Mask[0] = pIntermediate->Output.Mask[0]; MulIntermediate.Output.Mask[1] = pIntermediate->Output.Mask[1]; MulIntermediate.Output.Mask[2] = pIntermediate->Output.Mask[2]; @@ -1490,7 +1490,7 @@ static void VshRemoveScreenSpaceInstructions(VSH_XBOX_SHADER *pShader) MulIntermediate.Parameters[0].Active = TRUE; MulIntermediate.Parameters[0].IndexesWithA0_X = FALSE; MulIntermediate.Parameters[0].Parameter.ParameterType = PARAM_R; - MulIntermediate.Parameters[0].Parameter.Address = 11; + MulIntermediate.Parameters[0].Parameter.Address = 12; MulIntermediate.Parameters[0].Parameter.Neg = FALSE; VshSetSwizzle(&MulIntermediate.Parameters[0], SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W); MulIntermediate.Parameters[1].Active = TRUE; @@ -1502,13 +1502,13 @@ static void VshRemoveScreenSpaceInstructions(VSH_XBOX_SHADER *pShader) MulIntermediate.Parameters[2].Active = FALSE; VshInsertIntermediate(pShader, &MulIntermediate, ++i); - // Add offset with r10 to oPos (add oPos.[mask], r10, c59) + // Add offset with r13 to oPos (add oPos.[mask], r13, c59) VSH_INTERMEDIATE_FORMAT AddIntermediate = MulIntermediate; AddIntermediate.MAC = MAC_ADD; AddIntermediate.Output.Type = IMD_OUTPUT_O; AddIntermediate.Output.Address = OREG_OPOS; AddIntermediate.Parameters[0].Parameter.ParameterType = PARAM_R; - AddIntermediate.Parameters[0].Parameter.Address = 10; + AddIntermediate.Parameters[0].Parameter.Address = 13; AddIntermediate.Parameters[1].Parameter.Address = ConvertCRegister(59); VshInsertIntermediate(pShader, &AddIntermediate, ++i); } @@ -1767,6 +1767,34 @@ static boolean VshConvertShader(VSH_XBOX_SHADER *pShader, } } + // Finally, iterate through the shader, replace all writes to oPos with writes to r12 + // This fixes shaders that read from r12 expecting to see oPos + for (int i = 0; i < pShader->IntermediateCount; i++) { + VSH_INTERMEDIATE_FORMAT* pIntermediate = &pShader->Intermediate[i]; + if (pIntermediate->Output.Type == IMD_OUTPUT_O && pIntermediate->Output.Address == OREG_OPOS) { + pIntermediate->Output.Type = IMD_OUTPUT_R; + pIntermediate->Output.Address = 12; + } + } + + // We append one additional instruction to mov oPos, r12 + VSH_INTERMEDIATE_FORMAT MovIntermediate = {0}; + MovIntermediate.MAC = MAC_MOV; + MovIntermediate.Output.Type = IMD_OUTPUT_O; + MovIntermediate.Output.Address = OREG_OPOS; + MovIntermediate.Output.Mask[0] = true; + MovIntermediate.Output.Mask[1] = true; + MovIntermediate.Output.Mask[2] = true; + MovIntermediate.Output.Mask[3] = true; + MovIntermediate.Parameters[0].Active = true; + MovIntermediate.Parameters[0].Parameter.ParameterType = PARAM_R; + MovIntermediate.Parameters[0].Parameter.Address = 12; + MovIntermediate.Parameters[0].Parameter.Swizzle[0] = SWIZZLE_X; + MovIntermediate.Parameters[0].Parameter.Swizzle[1] = SWIZZLE_Y; + MovIntermediate.Parameters[0].Parameter.Swizzle[2] = SWIZZLE_Z; + MovIntermediate.Parameters[0].Parameter.Swizzle[3] = SWIZZLE_W; + VshInsertIntermediate(pShader, &MovIntermediate, pShader->IntermediateCount); + return TRUE; } From ae4dbce372598ddde50e68149e0741e1893a6788 Mon Sep 17 00:00:00 2001 From: Luke Usher Date: Thu, 25 Jul 2019 12:11:59 +0100 Subject: [PATCH 10/15] Comment out warnings that pollute the log --- src/core/hle/D3D8/Direct3D9/Direct3D9.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp index 2c9757fc6..ccbaea242 100644 --- a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp +++ b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp @@ -4335,7 +4335,7 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_SetVertexData4f) case X_D3DVSDE_FOG: // Xbox extension { g_InlineVertexBuffer_Table[o].Fog = a; // TODO : What about the other (b, c and d) arguments? - EmuLog(LOG_LEVEL::WARNING, "Host Direct3D8 doesn''t support FVF FOG"); + //EmuLog(LOG_LEVEL::WARNING, "Host Direct3D8 doesn''t support FVF FOG"); break; } @@ -4344,7 +4344,7 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_SetVertexData4f) case X_D3DVSDE_BACKDIFFUSE: // Xbox extension { g_InlineVertexBuffer_Table[o].BackDiffuse = D3DCOLOR_COLORVALUE(a, b, c, d); - EmuLog(LOG_LEVEL::WARNING, "Host Direct3D8 doesn''t support FVF BACKDIFFUSE"); + //EmuLog(LOG_LEVEL::WARNING, "Host Direct3D8 doesn''t support FVF BACKDIFFUSE"); HLE_write_NV2A_vertex_attribute_slot(X_D3DVSDE_BACKDIFFUSE, g_InlineVertexBuffer_Table[o].BackDiffuse); break; } @@ -4352,7 +4352,7 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_SetVertexData4f) case X_D3DVSDE_BACKSPECULAR: // Xbox extension { g_InlineVertexBuffer_Table[o].BackSpecular = D3DCOLOR_COLORVALUE(a, b, c, d); - EmuLog(LOG_LEVEL::WARNING, "Host Direct3D8 doesn''t support FVF BACKSPECULAR"); + //EmuLog(LOG_LEVEL::WARNING, "Host Direct3D8 doesn''t support FVF BACKSPECULAR"); HLE_write_NV2A_vertex_attribute_slot(X_D3DVSDE_BACKSPECULAR, g_InlineVertexBuffer_Table[o].BackSpecular); break; } From 35ce3e7fb174d554f6e3a0235f50b8041965364e Mon Sep 17 00:00:00 2001 From: Luke Usher Date: Thu, 25 Jul 2019 16:23:39 +0100 Subject: [PATCH 11/15] Treat all vertex registers as 'User Defined' --- src/core/hle/D3D8/XbVertexShader.cpp | 56 ++++++++++------------------ 1 file changed, 19 insertions(+), 37 deletions(-) diff --git a/src/core/hle/D3D8/XbVertexShader.cpp b/src/core/hle/D3D8/XbVertexShader.cpp index f552becff..b7bfd7faf 100644 --- a/src/core/hle/D3D8/XbVertexShader.cpp +++ b/src/core/hle/D3D8/XbVertexShader.cpp @@ -919,42 +919,11 @@ static void VshWriteShader(VSH_XBOX_SHADER *pShader, continue; } - BYTE PCUsageIndex = 0; - DWORD usage = Xb2PCRegisterType(i, PCUsageIndex); - - std::stringstream dclStream; - switch (usage) { - case XTL::D3DDECLUSAGE_POSITION: - dclStream << "dcl_position" << (int)PCUsageIndex; - break; - case XTL::D3DDECLUSAGE_BLENDWEIGHT: - dclStream << "dcl_blendweight"; - break; - case XTL::D3DDECLUSAGE_BLENDINDICES: - dclStream << "dcl_blendindices"; - break; - case XTL::D3DDECLUSAGE_NORMAL: - dclStream << "dcl_normal"; - break; - case XTL::D3DDECLUSAGE_COLOR: - dclStream << "dcl_color" << (int)PCUsageIndex; - break; - case XTL::D3DDECLUSAGE_FOG: - dclStream << "dcl_fog"; - break; - case XTL::D3DDECLUSAGE_TEXCOORD: - dclStream << "dcl_texcoord" << (int)PCUsageIndex; - break; - case XTL::D3DDECLUSAGE_PSIZE: - dclStream << "dcl_psize"; - break; - default: - dclStream << "dcl_unknown ("<< (int)PCUsageIndex << ")"; - LOG_TEST_CASE("Encountered unknown declaration"); - break; - } - - pDisassembly << dclStream.str() << " v" << i << "\n"; + // dcl_texcoord can be useds for any user-defined data + // We need this because there is no reliable way to detect the real usage + // Xbox has no concept of 'usage types', it only requires a list of attribute register numbers. + // So we treat them all as 'user-defined' + pDisassembly << "dcl_texcoord" << i << " v" << i << "\n"; } i++; @@ -2011,8 +1980,21 @@ static void VshConvertToken_STREAMDATA_REG( XTL::BOOL NeedPatching = FALSE; XTL::BYTE Index; + BYTE HostVertexRegisterType; + // If this is a fixed-function shader, use Xb2PCRegisterType DbgVshPrintf("\t\tD3DVSD_REG("); - BYTE HostVertexRegisterType = Xb2PCRegisterType(VertexRegister, Index); + if (IsFixedFunction) { + HostVertexRegisterType = Xb2PCRegisterType(VertexRegister, Index); + } else { + // D3DDECLUSAGE_TEXCOORD can be useds for any user-defined data + // We need this because there is no reliable way to detect the real usage + // Xbox has no concept of 'usage types', it only requires a list of attribute register numbers. + // So we treat them all as 'user-defined' with an Index of the Vertex Register Index + // this prevents information loss in shaders due to non-matching dcl types! + HostVertexRegisterType = D3DDECLUSAGE_TEXCOORD; + Index = VertexRegister; + DbgVshPrintf("%d", Index); + } DbgVshPrintf(", "); // Add this regiseter to the list of declared registers From d2e65f0e676a6b5a9a22299b2d5b0146a1bc4a60 Mon Sep 17 00:00:00 2001 From: Luke Usher Date: Fri, 26 Jul 2019 14:15:48 +0100 Subject: [PATCH 12/15] Fix vOffset/vScale overwritten by nv2a constants --- src/core/hle/D3D8/Direct3D9/Direct3D9.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp index ccbaea242..233ef84cb 100644 --- a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp +++ b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp @@ -7520,6 +7520,11 @@ void XTL::CxbxUpdateNativeD3DResources() // We handle that case by updating any constants that have the dirty flag set on the nv2a. auto nv2a = g_NV2A->GetDeviceState(); for(int i = 0; i < 192; i++) { + // Skip vOffset and vScale constants, we don't want our values to be overwritten by accident + if (i == 58 || i == 59) { + continue; + } + if (nv2a->pgraph.vsh_constants_dirty[i]) { g_pD3DDevice->SetVertexShaderConstantF(i, (float*)&nv2a->pgraph.vsh_constants[i][0], 1); nv2a->pgraph.vsh_constants_dirty[i] = false; From cdd962e5a4304b84391603c977f44a7412dd9753 Mon Sep 17 00:00:00 2001 From: Luke Usher Date: Fri, 26 Jul 2019 16:51:20 +0100 Subject: [PATCH 13/15] 3925 alpha test hack --- src/core/hle/D3D8/Direct3D9/Direct3D9.cpp | 11 ++++++++++- src/core/hle/D3D8/XbState.cpp | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp index 233ef84cb..df86afe32 100644 --- a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp +++ b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp @@ -6498,7 +6498,16 @@ VOID __fastcall XTL::EMUPATCH(D3DDevice_SetRenderState_Simple) // Just log and return EmuLog(LOG_LEVEL::DEBUG, "RenderState_Simple(0x%.08X (%s), 0x%.08X) was ignored!", Method, DxbxRenderStateInfo[XboxRenderStateIndex].S, Value); return; - case X_D3DRS_ALPHATESTENABLE: case X_D3DRS_ALPHABLENDENABLE: + case X_D3DRS_ALPHATESTENABLE: + if (g_LibVersion_D3D8 == 3925) { + // HACK: Many 3925 have missing polygons when this is ture + // Until we find out the true underlying cause, and carry on + // Test Cases: Halo, Silent Hill 2. + LOG_TEST_CASE("Applying 3925 alpha test disable hack"); + Value = false; + } + break; + case X_D3DRS_ALPHABLENDENABLE: case X_D3DRS_ALPHAREF: case X_D3DRS_ZWRITEENABLE: case X_D3DRS_DITHERENABLE: case X_D3DRS_STENCILREF: case X_D3DRS_STENCILMASK: case X_D3DRS_STENCILWRITEMASK: diff --git a/src/core/hle/D3D8/XbState.cpp b/src/core/hle/D3D8/XbState.cpp index f68e6630a..8e6b57fe9 100644 --- a/src/core/hle/D3D8/XbState.cpp +++ b/src/core/hle/D3D8/XbState.cpp @@ -107,7 +107,7 @@ void UpdateDeferredRenderStates() if (g_LibVersion_D3D8 == 3925) { // HACK: Many 3925 games only show a black screen if fog is enabled // Initially, this was thought to be bad offsets, but it has been verified to be correct - // Unitl we find out the true underlying cause, disable fog and carry on + // Until we find out the true underlying cause, disable fog and carry on // Test Cases: Halo, Silent Hill 2. LOG_TEST_CASE("Applying 3925 fog disable hack"); Value = false; From ab3b8f84ae561db760080d1f00c8e5f0afe3cba3 Mon Sep 17 00:00:00 2001 From: Luke Usher Date: Sat, 27 Jul 2019 08:54:45 +0100 Subject: [PATCH 14/15] Fix potential stack corruption, thanks revel8n --- src/core/hle/D3D8/XbVertexShader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/hle/D3D8/XbVertexShader.cpp b/src/core/hle/D3D8/XbVertexShader.cpp index b7bfd7faf..213edcccb 100644 --- a/src/core/hle/D3D8/XbVertexShader.cpp +++ b/src/core/hle/D3D8/XbVertexShader.cpp @@ -1512,7 +1512,7 @@ static boolean VshConvertShader(VSH_XBOX_SHADER *pShader, boolean RUsage[VSH_MAX_TEMPORARY_REGISTERS] = { FALSE }; // Set the last 13 register to used (they are used for SetVertexData4f Constants) - for (int i = 0; i <= 13; i++) { + for (int i = 1; i <= 13; i++) { RUsage[VSH_MAX_TEMPORARY_REGISTERS - i] = true; } From 31253815e120ddcba18dde2fbc8ace61fd5e5a42 Mon Sep 17 00:00:00 2001 From: Luke Usher Date: Mon, 29 Jul 2019 09:19:10 +0100 Subject: [PATCH 15/15] Define constants + fix typos --- src/core/hle/D3D8/Direct3D9/Direct3D9.cpp | 16 ++++++++-------- src/core/hle/D3D8/XbD3D8Types.h | 4 ++++ src/core/hle/D3D8/XbVertexShader.cpp | 6 +++--- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp index df86afe32..1becddbf7 100644 --- a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp +++ b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp @@ -4182,7 +4182,7 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_SetVertexData4f) // not present in the vertex declaration. // We use range 193 and up to store these values, as Xbox shaders stop at c192! FLOAT values[] = {a,b,c,d}; - g_pD3DDevice->SetVertexShaderConstantF(193 + Register, values, 1); + g_pD3DDevice->SetVertexShaderConstantF(X_D3DVS_CONSTREG_VERTEXDATA4F_BASE + Register, values, 1); } // Grow g_InlineVertexBuffer_Table to contain at least current, and a potentially next vertex @@ -6500,7 +6500,7 @@ VOID __fastcall XTL::EMUPATCH(D3DDevice_SetRenderState_Simple) return; case X_D3DRS_ALPHATESTENABLE: if (g_LibVersion_D3D8 == 3925) { - // HACK: Many 3925 have missing polygons when this is ture + // HACK: Many 3925 have missing polygons when this is true // Until we find out the true underlying cause, and carry on // Test Cases: Halo, Silent Hill 2. LOG_TEST_CASE("Applying 3925 alpha test disable hack"); @@ -7144,10 +7144,10 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_SetVertexShader) static const float ColorBlack[4] = { 0,0,0,0 }; static const float ColorWhite[4] = { 1,1,1,1 }; - g_pD3DDevice->SetVertexShaderConstantF(193 + X_D3DVSDE_DIFFUSE, ColorWhite, 1); - g_pD3DDevice->SetVertexShaderConstantF(193 + X_D3DVSDE_BACKDIFFUSE, ColorWhite, 1); - g_pD3DDevice->SetVertexShaderConstantF(193 + X_D3DVSDE_SPECULAR, ColorBlack, 1); - g_pD3DDevice->SetVertexShaderConstantF(193 + X_D3DVSDE_BACKSPECULAR, ColorBlack, 1); + g_pD3DDevice->SetVertexShaderConstantF(X_D3DVS_CONSTREG_VERTEXDATA4F_BASE + X_D3DVSDE_DIFFUSE, ColorWhite, 1); + g_pD3DDevice->SetVertexShaderConstantF(X_D3DVS_CONSTREG_VERTEXDATA4F_BASE + X_D3DVSDE_BACKDIFFUSE, ColorWhite, 1); + g_pD3DDevice->SetVertexShaderConstantF(X_D3DVS_CONSTREG_VERTEXDATA4F_BASE + X_D3DVSDE_SPECULAR, ColorBlack, 1); + g_pD3DDevice->SetVertexShaderConstantF(X_D3DVS_CONSTREG_VERTEXDATA4F_BASE + X_D3DVSDE_BACKSPECULAR, ColorBlack, 1); } else { hRet = g_pD3DDevice->SetVertexShader(nullptr); DEBUG_D3DRESULT(hRet, "g_pD3DDevice->SetVertexShader"); @@ -7528,9 +7528,9 @@ void XTL::CxbxUpdateNativeD3DResources() // Some titles set Vertex Shader constants directly via pushbuffers rather than through D3D // We handle that case by updating any constants that have the dirty flag set on the nv2a. auto nv2a = g_NV2A->GetDeviceState(); - for(int i = 0; i < 192; i++) { + for(int i = 0; i < X_D3DVS_CONSTREG_COUNT; i++) { // Skip vOffset and vScale constants, we don't want our values to be overwritten by accident - if (i == 58 || i == 59) { + if (i == X_D3DSCM_RESERVED_CONSTANT1_CORRECTED || i == X_D3DSCM_RESERVED_CONSTANT2_CORRECTED) { continue; } diff --git a/src/core/hle/D3D8/XbD3D8Types.h b/src/core/hle/D3D8/XbD3D8Types.h index 32e243367..f7d894beb 100644 --- a/src/core/hle/D3D8/XbD3D8Types.h +++ b/src/core/hle/D3D8/XbD3D8Types.h @@ -1081,6 +1081,10 @@ typedef DWORD X_VERTEXSHADERCONSTANTMODE; #define X_D3DSCM_CORRECTION 96 // Add 96 to arrive at the range 0..191 (instead of 96..95) #define X_D3DVS_CONSTREG_COUNT 192 +#define X_D3DSCM_RESERVED_CONSTANT1_CORRECTED (X_D3DSCM_RESERVED_CONSTANT1 + X_D3DSCM_CORRECTION) +#define X_D3DSCM_RESERVED_CONSTANT2_CORRECTED (X_D3DSCM_RESERVED_CONSTANT2 + X_D3DSCM_CORRECTION) +#define X_D3DVS_CONSTREG_VERTEXDATA4F_BASE (X_D3DVS_CONSTREG_COUNT + 1) + // Vertex shader types #define X_VST_NORMAL 1 #define X_VST_READWRITE 2 diff --git a/src/core/hle/D3D8/XbVertexShader.cpp b/src/core/hle/D3D8/XbVertexShader.cpp index 213edcccb..7694fc766 100644 --- a/src/core/hle/D3D8/XbVertexShader.cpp +++ b/src/core/hle/D3D8/XbVertexShader.cpp @@ -913,7 +913,7 @@ static void VshWriteShader(VSH_XBOX_SHADER *pShader, // 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"; + moveConstantsToTemporaries << "mov r" << (temporaryRegisterBase + i) << ", c" << (X_D3DVS_CONSTREG_VERTEXDATA4F_BASE + i) << "\n"; LOG_TEST_CASE("Shader uses undeclared Vertex Input Registers"); i++; continue; @@ -1617,7 +1617,7 @@ static boolean VshConvertShader(VSH_XBOX_SHADER *pShader, 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 read from temporary registers 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; @@ -1997,7 +1997,7 @@ static void VshConvertToken_STREAMDATA_REG( } DbgVshPrintf(", "); - // Add this regiseter to the list of declared registers + // Add this register to the list of declared registers RegVIsPresentInDeclaration[VertexRegister] = true; XTL::DWORD XboxVertexElementDataType = (*pToken & X_D3DVSD_DATATYPEMASK) >> X_D3DVSD_DATATYPESHIFT;