From 62a6f351d5aae180a49282069e3cfe88d1e850b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 13 Feb 2023 23:28:10 +0100 Subject: [PATCH] Initial work on depth copies --- Core/Compatibility.cpp | 1 + Core/Compatibility.h | 1 + GPU/Common/FramebufferManagerCommon.cpp | 69 ++++++++++++++++++------- GPU/Common/FramebufferManagerCommon.h | 3 +- assets/compat.ini | 12 +++++ 5 files changed, 66 insertions(+), 20 deletions(-) diff --git a/Core/Compatibility.cpp b/Core/Compatibility.cpp index 35d3b7cd9a..f6cf4a644c 100644 --- a/Core/Compatibility.cpp +++ b/Core/Compatibility.cpp @@ -126,6 +126,7 @@ void Compatibility::CheckSettings(IniFile &iniFile, const std::string &gameID) { CheckSetting(iniFile, gameID, "DisallowFramebufferAtOffset", &flags_.DisallowFramebufferAtOffset); CheckSetting(iniFile, gameID, "RockmanDash2SoundFix", &flags_.RockmanDash2SoundFix); CheckSetting(iniFile, gameID, "ReadbackDepth", &flags_.ReadbackDepth); + CheckSetting(iniFile, gameID, "BlockTransferDepth", &flags_.BlockTransferDepth); } void Compatibility::CheckVRSettings(IniFile &iniFile, const std::string &gameID) { diff --git a/Core/Compatibility.h b/Core/Compatibility.h index dbc62c256c..d34722f4fa 100644 --- a/Core/Compatibility.h +++ b/Core/Compatibility.h @@ -97,6 +97,7 @@ struct CompatFlags { bool DisallowFramebufferAtOffset; bool RockmanDash2SoundFix; bool ReadbackDepth; + bool BlockTransferDepth; }; struct VRCompat { diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 54ad12f6f0..9ce0585990 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -1908,12 +1908,13 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size, } std::string BlockTransferRect::ToString() const { - int bpp = BufferFormatBytesPerPixel(vfb->fb_format); - return StringFromFormat("%08x/%d/%s seq:%d %d,%d %dx%d", vfb->fb_address, vfb->FbStrideInBytes(), GeBufferFormatToString(vfb->fb_format), vfb->colorBindSeq, x_bytes / bpp, y, w_bytes / bpp, h); + int bpp = BufferFormatBytesPerPixel(channel == RASTER_DEPTH ? GE_FORMAT_DEPTH16 : vfb->fb_format); + return StringFromFormat("%s %08x/%d/%s seq:%d %d,%d %dx%d", RasterChannelToString(channel), vfb->fb_address, vfb->FbStrideInBytes(), GeBufferFormatToString(vfb->fb_format), vfb->colorBindSeq, x_bytes / bpp, y, w_bytes / bpp, h); } -// Only looks for color buffers for now. -// The only known game to block transfer depth buffers is Iron Man, see #16530. +// This is used when looking for framebuffers for a block transfer. +// The only known game to block transfer depth buffers is Iron Man, see #16530, so +// we have a compat flag and pretty limited functionality for that. bool FramebufferManagerCommon::FindTransferFramebuffer(u32 basePtr, int stride_pixels, int x_pixels, int y, int w_pixels, int h, int bpp, bool destination, BlockTransferRect *rect) { basePtr &= 0x3FFFFFFF; if (Memory::IsVRAMAddress(basePtr)) @@ -1938,11 +1939,20 @@ bool FramebufferManagerCommon::FindTransferFramebuffer(u32 basePtr, int stride_p // We are only looking at color for now, have not found any block transfers of depth data (although it's plausible). for (auto vfb : vfbs_) { + BlockTransferRect candidate{ vfb, RASTER_COLOR }; + // Check for easily detected depth copies for logging purposes. // Depth copies are not that useful though because you manually need to account for swizzle, so - // not sure if games will use them. - if (vfb->z_address == basePtr) { + // not sure if games will use them. Actually we do have a case, Iron Man in issue #16530. + if (vfb->z_address == basePtr && vfb->z_stride == stride_pixels && PSP_CoreParameter().compat.flags().BlockTransferDepth) { WARN_LOG_N_TIMES(z_xfer, 5, G3D, "FindTransferFramebuffer: found matching depth buffer, %08x (dest=%d, bpp=%d)", basePtr, (int)destination, bpp); + candidate.channel = RASTER_DEPTH; + candidate.x_bytes = x_pixels * 2; + candidate.w_bytes = w_pixels * 2; + candidate.y = y; + candidate.h = h; + candidates.push_back(candidate); + continue; } const u32 vfb_address = vfb->fb_address; @@ -1956,7 +1966,6 @@ bool FramebufferManagerCommon::FindTransferFramebuffer(u32 basePtr, int stride_p const u32 vfb_byteStride = vfb->FbStrideInBytes(); const u32 vfb_byteWidth = vfb->WidthInBytes(); - BlockTransferRect candidate{ vfb }; candidate.w_bytes = w_pixels * bpp; candidate.h = h; @@ -2018,7 +2027,18 @@ bool FramebufferManagerCommon::FindTransferFramebuffer(u32 basePtr, int stride_p for (size_t i = 0; i < candidates.size(); i++) { const BlockTransferRect *candidate = &candidates[i]; - bool better = !best || candidate->vfb->colorBindSeq > best->vfb->colorBindSeq; + bool better = !best; + if (!better) { + if (candidate->channel == best->channel) { + better = candidate->vfb->BindSeq(candidate->channel) > best->vfb->BindSeq(candidate->channel); + } else { + // Prefer color over depth. + if (candidate->channel == RASTER_COLOR && best->channel == RASTER_DEPTH) { + better = true; + } + } + } + if ((candidate->vfb->usageFlags & FB_USAGE_CLUT) && candidate->x_bytes == 0 && candidate->y == 0 && destination) { // Hack to prioritize copies to clut buffers. best = candidate; @@ -2258,6 +2278,13 @@ bool FramebufferManagerCommon::NotifyBlockTransferBefore(u32 dstBasePtr, int dst bool srcBuffer = FindTransferFramebuffer(srcBasePtr, srcStride, srcX, srcY, width, height, bpp, false, &srcRect); bool dstBuffer = FindTransferFramebuffer(dstBasePtr, dstStride, dstX, dstY, width, height, bpp, true, &dstRect); + if (srcRect.channel == RASTER_DEPTH) { + // Ignore the found buffer if it's not 16-bit - we create a new more suitable one instead. + if (dstRect.channel == RASTER_COLOR && dstRect.vfb->fb_format == GE_FORMAT_8888) { + dstBuffer = false; + } + } + if (srcBuffer && !dstBuffer) { // In here, we can't read from dstRect. if (PSP_CoreParameter().compat.flags().BlockTransferAllowCreateFB || @@ -2265,19 +2292,23 @@ bool FramebufferManagerCommon::NotifyBlockTransferBefore(u32 dstBasePtr, int dst Memory::IsVRAMAddress(srcRect.vfb->fb_address) && Memory::IsVRAMAddress(dstBasePtr))) { GEBufferFormat ramFormat; // Try to guess the appropriate format. We only know the bpp from the block transfer command (16 or 32 bit). - if (bpp == 4) { - // Only one possibility unless it's doing split pixel tricks (which we could detect through stride maybe). - ramFormat = GE_FORMAT_8888; - } else if (srcRect.vfb->fb_format != GE_FORMAT_8888) { - // We guess that the game will interpret the data the same as it was in the source of the copy. - // Seems like a likely good guess, and works in Test Drive Unlimited. - ramFormat = srcRect.vfb->fb_format; + if (srcRect.channel == RASTER_COLOR) { + if (bpp == 4) { + // Only one possibility unless it's doing split pixel tricks (which we could detect through stride maybe). + ramFormat = GE_FORMAT_8888; + } else if (srcRect.vfb->fb_format != GE_FORMAT_8888) { + // We guess that the game will interpret the data the same as it was in the source of the copy. + // Seems like a likely good guess, and works in Test Drive Unlimited. + ramFormat = srcRect.vfb->fb_format; + } else { + // No info left - just fall back to something. But this is definitely split pixel tricks. + ramFormat = GE_FORMAT_5551; + } + dstBuffer = true; + dstRect.vfb = CreateRAMFramebuffer(dstBasePtr, width, height, dstStride, ramFormat); } else { - // No info left - just fall back to something. But this is definitely split pixel tricks. - ramFormat = GE_FORMAT_5551; + dstRect.vfb = CreateRAMFramebuffer(dstBasePtr, width, height, dstStride, GE_FORMAT_DEPTH16); } - dstBuffer = true; - dstRect.vfb = CreateRAMFramebuffer(dstBasePtr, width, height, dstStride, ramFormat); } } diff --git a/GPU/Common/FramebufferManagerCommon.h b/GPU/Common/FramebufferManagerCommon.h index 26ed26128d..c2bdac1607 100644 --- a/GPU/Common/FramebufferManagerCommon.h +++ b/GPU/Common/FramebufferManagerCommon.h @@ -159,6 +159,7 @@ struct VirtualFramebuffer { inline int Stride(RasterChannel channel) const { return channel == RASTER_COLOR ? fb_stride : z_stride; } inline u32 Address(RasterChannel channel) const { return channel == RASTER_COLOR ? fb_address : z_address; } inline int Format(RasterChannel channel) const { return channel == RASTER_COLOR ? fb_format : GE_FORMAT_DEPTH16; } + inline int BindSeq(RasterChannel channel) const { return channel == RASTER_COLOR ? colorBindSeq : depthBindSeq; } int BufferByteSize(RasterChannel channel) const { return channel == RASTER_COLOR ? fb_stride * height * (fb_format == GE_FORMAT_8888 ? 4 : 2) : z_stride * height * 2; @@ -242,7 +243,7 @@ inline Draw::DataFormat GEFormatToThin3D(GEBufferFormat geFormat) { // Makes it easy to see if blits match etc. struct BlockTransferRect { VirtualFramebuffer *vfb; - // RasterChannel channel; // We currently only deal with color for block copies. + RasterChannel channel; // We usually only deal with color, but we have limited depth block transfer support now. int x_bytes; int y; diff --git a/assets/compat.ini b/assets/compat.ini index 58f88da370..2cfaf38ffe 100644 --- a/assets/compat.ini +++ b/assets/compat.ini @@ -698,6 +698,11 @@ ULKS46010 = true ULJM05223 = true ULJM05362 = true +# Iron Man, see [BlockTransferDepth] below. +ULES01070 = true +ULES01071 = true +ULUS10347 = true + # Note! This whole flag is disabled temporarily by appending "Disabled" to its name). See 7914 [YugiohSaveFixDisabled] # The cause of Yu-gi-oh series 's bad save (cannot save) are load "save status" and use cwcheat, @@ -1458,3 +1463,10 @@ SYPH04036 = true # Prototype? # Syphon Filter - Combat Ops (weird multiplayer-only variant) NPUG80114 = true NPEG00004 = true + +[BlockTransferDepth] +# Iron Man - see issue #16530 +# Note that this option also requires IntraVRAMBlockTransferAllowCreateFB. +ULES01070 = true +ULES01071 = true +ULUS10347 = true