CopyRects accounts for host resource scaling

Fixes Crash Tag Team Racing resolution scaling issue
This commit is contained in:
Anthony Miles 2020-09-02 22:58:59 +12:00
parent ee6a61c364
commit fc655cdca5
1 changed files with 33 additions and 9 deletions

View File

@ -4921,7 +4921,7 @@ VOID WINAPI xbox::EMUPATCH(D3DDevice_CopyRects)
// We skip the trampoline to prevent unnecessary work // We skip the trampoline to prevent unnecessary work
// As our surfaces remain on the GPU, calling the trampoline would just // As our surfaces remain on the GPU, calling the trampoline would just
// result in a memcpy from an empty Xbox surface to another empty Xbox Surface // result in a memcpy from an empty Xbox surface to another empty Xbox Surface
D3DSURFACE_DESC SourceDesc, DestinationDesc; D3DSURFACE_DESC hostSourceDesc, hostDestDesc;
auto pHostSourceSurface = GetHostSurface(pSourceSurface); auto pHostSourceSurface = GetHostSurface(pSourceSurface);
auto pHostDestSurface = GetHostSurface(pDestinationSurface); auto pHostDestSurface = GetHostSurface(pDestinationSurface);
@ -4932,16 +4932,16 @@ VOID WINAPI xbox::EMUPATCH(D3DDevice_CopyRects)
return; return;
} }
pHostSourceSurface->GetDesc(&SourceDesc); pHostSourceSurface->GetDesc(&hostSourceDesc);
pHostDestSurface->GetDesc(&DestinationDesc); pHostDestSurface->GetDesc(&hostDestDesc);
// If the source is a render-target and the destination is not, we need force it to be re-created as one // If the source is a render-target and the destination is not, we need force it to be re-created as one
// This is because StrechRects cannot copy from a Render-Target to a Non-Render Target // This is because StrechRects cannot copy from a Render-Target to a Non-Render Target
// Test Case: Crash Bandicoot: Wrath of Cortex attemps to copy the render-target to a texture // Test Case: Crash Bandicoot: Wrath of Cortex attemps to copy the render-target to a texture
// This fixes an issue on the pause screen where the screenshot of the current scene was not displayed correctly // This fixes an issue on the pause screen where the screenshot of the current scene was not displayed correctly
if ((SourceDesc.Usage & D3DUSAGE_RENDERTARGET) != 0 && (DestinationDesc.Usage & D3DUSAGE_RENDERTARGET) == 0) { if ((hostSourceDesc.Usage & D3DUSAGE_RENDERTARGET) != 0 && (hostDestDesc.Usage & D3DUSAGE_RENDERTARGET) == 0) {
pHostDestSurface = GetHostSurface(pDestinationSurface, D3DUSAGE_RENDERTARGET); pHostDestSurface = GetHostSurface(pDestinationSurface, D3DUSAGE_RENDERTARGET);
pHostDestSurface->GetDesc(&DestinationDesc); pHostDestSurface->GetDesc(&hostDestDesc);
} }
// If no rectangles were given, default to 1 (entire surface) // If no rectangles were given, default to 1 (entire surface)
@ -4949,6 +4949,13 @@ VOID WINAPI xbox::EMUPATCH(D3DDevice_CopyRects)
cRects = 1; cRects = 1;
} }
// Get Xbox surface dimensions
// Host resources may be scaled so we'll account for that later
auto xboxSourceWidth = GetPixelContainerWidth(pSourceSurface);
auto xboxSourceHeight = GetPixelContainerHeight(pSourceSurface);
auto xboxDestWidth = GetPixelContainerWidth(pDestinationSurface);
auto xboxDestHeight = GetPixelContainerHeight(pDestinationSurface);
for (UINT i = 0; i < cRects; i++) { for (UINT i = 0; i < cRects; i++) {
RECT SourceRect, DestRect; RECT SourceRect, DestRect;
@ -4956,9 +4963,9 @@ VOID WINAPI xbox::EMUPATCH(D3DDevice_CopyRects)
SourceRect = pSourceRectsArray[i]; SourceRect = pSourceRectsArray[i];
} else { } else {
SourceRect.left = 0; SourceRect.left = 0;
SourceRect.right = SourceDesc.Width; SourceRect.right = xboxSourceWidth;
SourceRect.top = 0; SourceRect.top = 0;
SourceRect.bottom = SourceDesc.Height; SourceRect.bottom = xboxSourceHeight;
} }
if (pDestPointsArray != nullptr) { if (pDestPointsArray != nullptr) {
@ -4970,11 +4977,28 @@ VOID WINAPI xbox::EMUPATCH(D3DDevice_CopyRects)
DestRect = SourceRect; DestRect = SourceRect;
} else { } else {
DestRect.left = 0; DestRect.left = 0;
DestRect.right = DestinationDesc.Width; DestRect.right = xboxDestWidth;
DestRect.top = 0; DestRect.top = 0;
DestRect.bottom = DestinationDesc.Height; DestRect.bottom = xboxDestHeight;
} }
// Scale the source and destination rects
auto sourceScaleX = (uint32_t)hostSourceDesc.Width / xboxSourceWidth;
auto sourceScaleY = (uint32_t)hostSourceDesc.Height / xboxSourceHeight;
SourceRect.left *= sourceScaleX;
SourceRect.right *= sourceScaleX;
SourceRect.top *= sourceScaleY;
SourceRect.bottom *= sourceScaleY;
auto destScaleX = (uint32_t) hostDestDesc.Width / xboxDestWidth;
auto destScaleY = (uint32_t) hostDestDesc.Height / xboxDestHeight;
DestRect.left *= destScaleX;
DestRect.right *= destScaleX;
DestRect.top *= destScaleY;
DestRect.bottom *= destScaleY;
HRESULT hRet = g_pD3DDevice->StretchRect(pHostSourceSurface, &SourceRect, pHostDestSurface, &DestRect, D3DTEXF_NONE); HRESULT hRet = g_pD3DDevice->StretchRect(pHostSourceSurface, &SourceRect, pHostDestSurface, &DestRect, D3DTEXF_NONE);
if (FAILED(hRet)) { if (FAILED(hRet)) {
LOG_TEST_CASE("D3DDevice_CopyRects: Failed to copy surface"); LOG_TEST_CASE("D3DDevice_CopyRects: Failed to copy surface");