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
// 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
D3DSURFACE_DESC SourceDesc, DestinationDesc;
D3DSURFACE_DESC hostSourceDesc, hostDestDesc;
auto pHostSourceSurface = GetHostSurface(pSourceSurface);
auto pHostDestSurface = GetHostSurface(pDestinationSurface);
@ -4932,16 +4932,16 @@ VOID WINAPI xbox::EMUPATCH(D3DDevice_CopyRects)
return;
}
pHostSourceSurface->GetDesc(&SourceDesc);
pHostDestSurface->GetDesc(&DestinationDesc);
pHostSourceSurface->GetDesc(&hostSourceDesc);
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
// 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
// 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->GetDesc(&DestinationDesc);
pHostDestSurface->GetDesc(&hostDestDesc);
}
// If no rectangles were given, default to 1 (entire surface)
@ -4949,6 +4949,13 @@ VOID WINAPI xbox::EMUPATCH(D3DDevice_CopyRects)
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++) {
RECT SourceRect, DestRect;
@ -4956,9 +4963,9 @@ VOID WINAPI xbox::EMUPATCH(D3DDevice_CopyRects)
SourceRect = pSourceRectsArray[i];
} else {
SourceRect.left = 0;
SourceRect.right = SourceDesc.Width;
SourceRect.right = xboxSourceWidth;
SourceRect.top = 0;
SourceRect.bottom = SourceDesc.Height;
SourceRect.bottom = xboxSourceHeight;
}
if (pDestPointsArray != nullptr) {
@ -4970,11 +4977,28 @@ VOID WINAPI xbox::EMUPATCH(D3DDevice_CopyRects)
DestRect = SourceRect;
} else {
DestRect.left = 0;
DestRect.right = DestinationDesc.Width;
DestRect.right = xboxDestWidth;
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);
if (FAILED(hRet)) {
LOG_TEST_CASE("D3DDevice_CopyRects: Failed to copy surface");