diff --git a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp index 77b627291..e5923641e 100644 --- a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp +++ b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp @@ -195,7 +195,6 @@ static XTL::DWORD *g_Xbox_D3DDevice; // TODO: This should be a static DWORD g_dwVertexShaderUsage = 0; // Unused. If needed, move to XbVertexShader.cpp */ -static std::array g_VertexShaderSlots = { 0 }; XTL::DWORD g_Xbox_VertexShader_Handle = 0; // Static Function(s) @@ -3532,28 +3531,24 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_LoadVertexShader) // Handle is always address of an X_D3DVertexShader struct, thus always or-ed with 1 (X_D3DFVF_RESERVED0) // Address is the slot (offset) from which the program must be written onwards (as whole DWORDS) // D3DDevice_LoadVertexShader pushes the program contained in the Xbox VertexShader struct to the NV2A - if(Address < g_VertexShaderSlots.size()) { + auto CxbxVertexShaderSlotPtr = GetCxbxVertexShaderSlotPtr(Address); + if(CxbxVertexShaderSlotPtr) { CxbxVertexShader * pCxbxVertexShader = GetCxbxVertexShader(Handle); if (pCxbxVertexShader) { int upToSlot = Address + pCxbxVertexShader->XboxNrAddressSlots; - if (upToSlot > g_VertexShaderSlots.size()) { + if (upToSlot > X_VSH_MAX_INSTRUCTION_COUNT) { LOG_TEST_CASE("Shader does not fit in vertex shader slots"); return; } // Skip the header DWORD at the beginning auto pTokens = &pCxbxVertexShader->pXboxFunctionCopy[1]; - for (DWORD i = 0; i < pCxbxVertexShader->XboxNrAddressSlots * X_VSH_INSTRUCTION_SIZE; i++) { - g_VertexShaderSlots[Address][i] = pTokens[i]; - } + memcpy(CxbxVertexShaderSlotPtr, pTokens, pCxbxVertexShader->XboxNrAddressSlots * X_VSH_INSTRUCTION_SIZE_BYTES); } else { LOG_TEST_CASE("LoadVertexShader called with unrecognized handle %d", Handle); } } - else { - LOG_TEST_CASE("LoadVertexShader address %d out of range", Address); - } } // LTCG specific D3DDevice_SelectVertexShader function... @@ -3625,16 +3620,13 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_SelectVertexShader) SetCxbxVertexShader(pCxbxVertexShader); } - if (Address < g_VertexShaderSlots.size()) { + auto pTokens = GetCxbxVertexShaderSlotPtr(Address); + if (pTokens) { // Create a vertex shader from the tokens - auto pTokens = &g_VertexShaderSlots[Address][0]; DWORD shaderSize; auto shaderKey = g_VertexShaderSource.CreateShader(pTokens, &shaderSize); g_pD3DDevice->SetVertexShader(g_VertexShaderSource.GetShader(shaderKey)); } - else { - LOG_TEST_CASE("SelectVertexShader address %d out of range", Address); - } if (FAILED(hRet)) { @@ -8144,11 +8136,13 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_LoadVertexShaderProgram) // D3DDevice_LoadVertexShaderProgram splits the given function buffer into batch-wise pushes to the NV2A // Copy shader instructions to shader slots + auto CxbxVertexShaderSlotPtr = GetCxbxVertexShaderSlotPtr(Address); + if (CxbxVertexShaderSlotPtr == nullptr) + return; + auto shaderHeader = *((XTL::X_VSH_SHADER_HEADER*) pFunction); auto tokens = &pFunction[1]; - for (int i = 0; i < shaderHeader.NumInst * X_VSH_INSTRUCTION_SIZE; i++) { - g_VertexShaderSlots[Address][i] = tokens[i]; - } + memcpy(CxbxVertexShaderSlotPtr, tokens, shaderHeader.NumInst * X_VSH_INSTRUCTION_SIZE_BYTES); } // ****************************************************************** diff --git a/src/core/hle/D3D8/XbVertexShader.cpp b/src/core/hle/D3D8/XbVertexShader.cpp index 0e0bbe97d..af5ce8e30 100644 --- a/src/core/hle/D3D8/XbVertexShader.cpp +++ b/src/core/hle/D3D8/XbVertexShader.cpp @@ -1247,6 +1247,18 @@ extern boolean IsValidCurrentShader(void) // XTL_EmuIDirect3DDevice_GetVertexShader, just check g_Xbox_VertexShader_Handle : return VshHandleIsValidShader(g_Xbox_VertexShader_Handle); } + +static DWORD g_CxbxVertexShaderSlots[X_VSH_MAX_INSTRUCTION_COUNT * X_VSH_INSTRUCTION_SIZE] = { 0 }; + +DWORD* GetCxbxVertexShaderSlotPtr(const DWORD SlotIndexAddress) +{ + if (SlotIndexAddress < X_VSH_MAX_INSTRUCTION_COUNT) { + return &g_CxbxVertexShaderSlots[SlotIndexAddress * X_VSH_INSTRUCTION_SIZE]; + } else { + LOG_TEST_CASE("SlotIndexAddress %d out of range", SlotIndexAddress); + return nullptr; + } +} CxbxVertexDeclaration *GetCxbxVertexDeclaration(DWORD XboxVertexShaderHandle) { diff --git a/src/core/hle/D3D8/XbVertexShader.h b/src/core/hle/D3D8/XbVertexShader.h index 99f1fc480..13347854c 100644 --- a/src/core/hle/D3D8/XbVertexShader.h +++ b/src/core/hle/D3D8/XbVertexShader.h @@ -232,7 +232,8 @@ extern boolean IsValidCurrentShader(void); inline boolean VshHandleIsVertexShader(DWORD Handle) { return (Handle & X_D3DFVF_RESERVED0) ? TRUE : FALSE; } inline boolean VshHandleIsFVF(DWORD Handle) { return !VshHandleIsVertexShader(Handle); } inline XTL::X_D3DVertexShader *VshHandleToXboxVertexShader(DWORD Handle) { return (XTL::X_D3DVertexShader *)(Handle & ~X_D3DFVF_RESERVED0);} - + +extern DWORD* GetCxbxVertexShaderSlotPtr(const DWORD SlotIndexAddress); extern CxbxVertexShader* GetCxbxVertexShader(DWORD XboxVertexShaderHandle); extern void SetCxbxVertexShader(DWORD XboxVertexShaderHandle, CxbxVertexShader* shader);