Initial work on depth copies

This commit is contained in:
Henrik Rydgård 2023-02-13 23:28:10 +01:00
parent 27a03de826
commit 62a6f351d5
5 changed files with 66 additions and 20 deletions

View File

@ -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) {

View File

@ -97,6 +97,7 @@ struct CompatFlags {
bool DisallowFramebufferAtOffset;
bool RockmanDash2SoundFix;
bool ReadbackDepth;
bool BlockTransferDepth;
};
struct VRCompat {

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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