Guard against nested SetTransform/MultiplyTransform calls

In the case of 25 to Life, MultiplyTransform calls SetTransform
which corrupted the host's internal state. Introduce a guard variable
to ensure we call to host only once per the patch chain and keep
the internal state pristine
This commit is contained in:
Silent 2020-10-26 18:54:39 +01:00
parent acff986fe1
commit 4dd9aaeed7
No known key found for this signature in database
GPG Key ID: AE53149BB0C45AF1
1 changed files with 64 additions and 32 deletions

View File

@ -6465,8 +6465,36 @@ void CxbxImpl_SetTransform
DEBUG_D3DRESULT(hRet, "g_pD3DDevice->SetTransform");
}
// MultiplyTransform can call SetTransform, nested call detection is required
// Test case: 25 to Life
static thread_local uint32_t setTransformCount = 0;
// LTCG specific D3DDevice_SetTransform function...
// This uses a custom calling convention where parameter is passed in EAX, EDX
// Naked functions must not contain objects that would require unwinding
// so we cheat a bit by stashing the function body in a separate function
static void D3DDevice_SetTransform_0_Inner
(
D3DTRANSFORMSTATETYPE State,
CONST D3DMATRIX *pMatrix
)
{
NestedPatchCounter call(setTransformCount);
__asm {
// Trampoline to guest code to remove the need for a GetTransform patch
mov eax, State
mov edx, pMatrix
call XB_TRMP(D3DDevice_SetTransform_0)
}
if (call.GetLevel() == 0) {
// Skip if this patch is called from MultiplyTransform
CxbxImpl_SetTransform(State, pMatrix);
}
}
__declspec(naked) xbox::void_xt WINAPI xbox::EMUPATCH(D3DDevice_SetTransform_0)
(
)
@ -6481,11 +6509,9 @@ __declspec(naked) xbox::void_xt WINAPI xbox::EMUPATCH(D3DDevice_SetTransform_0)
sub esp, __LOCAL_SIZE
mov State, eax
mov pMatrix, edx
// Trampoline to guest code to remove the need for a GetTransform patch
call XB_TRMP(D3DDevice_SetTransform_0)
}
CxbxImpl_SetTransform(State, pMatrix);
D3DDevice_SetTransform_0_Inner(State, pMatrix);
// epilogue
__asm {
@ -6504,10 +6530,15 @@ xbox::void_xt WINAPI xbox::EMUPATCH(D3DDevice_SetTransform)
CONST D3DMATRIX *pMatrix
)
{
NestedPatchCounter call(setTransformCount);
// Trampoline to guest code to remove the need for a GetTransform patch
XB_TRMP(D3DDevice_SetTransform)(State, pMatrix);
if (call.GetLevel() == 0) {
// Skip if this patch is called from MultiplyTransform
CxbxImpl_SetTransform(State, pMatrix);
}
}
// ******************************************************************
// * patch: D3DDevice_MultiplyTransform
@ -6523,6 +6554,7 @@ xbox::void_xt WINAPI xbox::EMUPATCH(D3DDevice_MultiplyTransform)
LOG_FUNC_ARG(pMatrix)
LOG_FUNC_END;
NestedPatchCounter call(setTransformCount);
// Trampoline to guest code to remove the need for a GetTransform patch
XB_TRMP(D3DDevice_MultiplyTransform)(State, pMatrix);