Implement compat flag proposed in #18423, forcing readbacks in Juiced 2

In-game, there's no slowdown, and this fixes the decal editor. So it's
no use allowing readbacks to be turned off in this game.

See issue #18423
This commit is contained in:
Henrik Rydgård 2024-07-20 11:23:34 +02:00
parent 5c26aa4c96
commit ef95e24169
5 changed files with 48 additions and 34 deletions

View file

@ -138,6 +138,7 @@ void Compatibility::CheckSettings(IniFile &iniFile, const std::string &gameID) {
CheckSetting(iniFile, gameID, "TacticsOgreEliminateDebugReadback", &flags_.TacticsOgreEliminateDebugReadback);
CheckSetting(iniFile, gameID, "FramebufferAllowLargeVerticalOffset", &flags_.FramebufferAllowLargeVerticalOffset);
CheckSetting(iniFile, gameID, "DisableMemcpySlicing", &flags_.DisableMemcpySlicing);
CheckSetting(iniFile, gameID, "ForceEnableGPUReadback", &flags_.ForceEnableGPUReadback);
}
void Compatibility::CheckVRSettings(IniFile &iniFile, const std::string &gameID) {

View file

@ -108,6 +108,7 @@ struct CompatFlags {
bool TacticsOgreEliminateDebugReadback;
bool FramebufferAllowLargeVerticalOffset;
bool DisableMemcpySlicing;
bool ForceEnableGPUReadback;
};
struct VRCompat {

View file

@ -421,7 +421,7 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(Framebuffer
const int x_offset = (params.fb_address - v->fb_address) / bpp;
if (x_offset < params.fb_stride && v->height >= drawing_height) {
// Pretty certainly a pure render-to-X-offset.
WARN_LOG_REPORT_ONCE(renderoffset, Log::HLE, "Rendering to framebuffer offset at %08x +%dx%d (stride %d)", v->fb_address, x_offset, 0, v->fb_stride);
WARN_LOG_REPORT_ONCE(renderoffset, Log::FrameBuf, "Rendering to framebuffer offset at %08x +%dx%d (stride %d)", v->fb_address, x_offset, 0, v->fb_stride);
normal_vfb = v;
gstate_c.SetCurRTOffset(x_offset, 0);
normal_vfb->width = std::max((int)normal_vfb->width, x_offset + drawing_width);
@ -622,11 +622,11 @@ void FramebufferManagerCommon::SetDepthFrameBuffer(bool isClearingDepth) {
if (currentRenderVfb_->z_address != boundDepthBuffer || currentRenderVfb_->z_stride != boundDepthStride) {
if (currentRenderVfb_->fb_address == boundDepthBuffer) {
// Disallow setting depth buffer to the same address as the color buffer, usually means it's not used.
WARN_LOG_N_TIMES(z_reassign, 5, Log::G3D, "Ignoring color matching depth buffer at %08x", boundDepthBuffer);
WARN_LOG_N_TIMES(z_reassign, 5, Log::FrameBuf, "Ignoring color matching depth buffer at %08x", boundDepthBuffer);
boundDepthBuffer = 0;
boundDepthStride = 0;
}
WARN_LOG_N_TIMES(z_reassign, 5, Log::G3D, "Framebuffer at %08x/%d has switched associated depth buffer from %08x to %08x, updating.",
WARN_LOG_N_TIMES(z_reassign, 5, Log::FrameBuf, "Framebuffer at %08x/%d has switched associated depth buffer from %08x to %08x, updating.",
currentRenderVfb_->fb_address, currentRenderVfb_->fb_stride, currentRenderVfb_->z_address, boundDepthBuffer);
// Technically, here we should copy away the depth buffer to another framebuffer that uses that z_address, or maybe
@ -717,7 +717,7 @@ void FramebufferManagerCommon::CopyToDepthFromOverlappingFramebuffers(VirtualFra
} else if (source.channel == RASTER_COLOR && draw_->GetDeviceCaps().fragmentShaderDepthWriteSupported) {
VirtualFramebuffer *src = source.vfb;
if (src->fb_format != GE_FORMAT_565) {
WARN_LOG_ONCE(not565, Log::G3D, "fb_format of buffer at %08x not 565 as expected", src->fb_address);
WARN_LOG_ONCE(not565, Log::FrameBuf, "fb_format of buffer at %08x not 565 as expected", src->fb_address);
}
// Really hate to do this, but tracking the depth swizzle state across multiple
@ -880,11 +880,11 @@ void FramebufferManagerCommon::CopyToColorFromOverlappingFramebuffers(VirtualFra
pass_name = "copy_color";
} else {
if (PSP_CoreParameter().compat.flags().BlueToAlpha) {
WARN_LOG_ONCE(bta, Log::G3D, "WARNING: Reinterpret encountered with BlueToAlpha on");
WARN_LOG_ONCE(bta, Log::FrameBuf, "WARNING: Reinterpret encountered with BlueToAlpha on");
}
// Reinterpret!
WARN_LOG_N_TIMES(reint, 5, Log::G3D, "Reinterpret detected from %08x_%s to %08x_%s",
WARN_LOG_N_TIMES(reint, 5, Log::FrameBuf, "Reinterpret detected from %08x_%s to %08x_%s",
src->fb_address, GeBufferFormatToString(src->fb_format),
dst->fb_address, GeBufferFormatToString(dst->fb_format));
@ -1047,7 +1047,7 @@ void FramebufferManagerCommon::DownloadFramebufferOnSwitch(VirtualFramebuffer *v
// Saving each frame would be slow.
// TODO: This type of download could be made async, for less stutter on framebuffer creation.
if (g_Config.iSkipGPUReadbackMode == (int)SkipGPUReadbackMode::NO_SKIP && !PSP_CoreParameter().compat.flags().DisableFirstFrameReadback) {
if (GetSkipGPUReadbackMode() == SkipGPUReadbackMode::NO_SKIP && !PSP_CoreParameter().compat.flags().DisableFirstFrameReadback) {
ReadFramebufferToMemory(vfb, 0, 0, vfb->safeWidth, vfb->safeHeight, RASTER_COLOR, Draw::ReadbackMode::BLOCK);
vfb->usageFlags = (vfb->usageFlags | FB_USAGE_DOWNLOAD | FB_USAGE_FIRST_FRAME_SAVED) & ~FB_USAGE_DOWNLOAD_CLEAR;
vfb->safeWidth = 0;
@ -1063,7 +1063,7 @@ bool FramebufferManagerCommon::ShouldDownloadFramebufferColor(const VirtualFrame
bool FramebufferManagerCommon::ShouldDownloadFramebufferDepth(const VirtualFramebuffer *vfb) {
// Download depth buffer for Syphon Filter lens flares
if (!PSP_CoreParameter().compat.flags().ReadbackDepth || g_Config.iSkipGPUReadbackMode != (int)SkipGPUReadbackMode::NO_SKIP) {
if (!PSP_CoreParameter().compat.flags().ReadbackDepth || GetSkipGPUReadbackMode() != SkipGPUReadbackMode::NO_SKIP) {
return false;
}
return (vfb->usageFlags & FB_USAGE_RENDER_DEPTH) != 0 && vfb->width >= 480 && vfb->height >= 272;
@ -1123,9 +1123,10 @@ void FramebufferManagerCommon::NotifyRenderFramebufferSwitched(VirtualFramebuffe
void FramebufferManagerCommon::PerformWriteFormattedFromMemory(u32 addr, int size, int stride, GEBufferFormat fmt) {
// Note: UpdateFromMemory() is still called later.
// This is a special case where we have extra information prior to the invalidation.
// This is a special case where we have extra information prior to the invalidation,
// because it's called from sceJpeg, sceMpeg, scePsmf etc.
// TODO: Could possibly be an offset...
// TODO: Could possibly be at an offset...
// Also, stride needs better handling.
VirtualFramebuffer *vfb = ResolveVFB(addr, stride, fmt);
if (vfb) {
@ -1134,7 +1135,7 @@ void FramebufferManagerCommon::PerformWriteFormattedFromMemory(u32 addr, int siz
vfb->colorBindSeq = GetBindSeqCount();
if (vfb->fb_stride < stride) {
DEBUG_LOG(Log::ME, "Changing stride for %08x from %d to %d", addr, vfb->fb_stride, stride);
INFO_LOG(Log::FrameBuf, "Changing stride for %08x from %d to %d", addr, vfb->fb_stride, stride);
const int bpp = BufferFormatBytesPerPixel(fmt);
ResizeFramebufFBO(vfb, stride, size / (bpp * stride));
// Resizing may change the viewport/etc.
@ -1986,7 +1987,7 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size,
// Not likely to be a correct color format copy for this buffer. Ignore it, there will either be RAM
// that can be displayed from, or another matching buffer with the right format if rendering is going on.
// If we had scoring here, we should strongly penalize this target instead of ignoring it.
WARN_LOG_N_TIMES(notify_copy_2x, 5, Log::G3D, "Framebuffer size %08x conspicuously not matching copy size %08x for source in NotifyFramebufferCopy. Ignoring.", size, vfb_size);
WARN_LOG_N_TIMES(notify_copy_2x, 5, Log::FrameBuf, "Framebuffer size %08x conspicuously not matching copy size %08x for source in NotifyFramebufferCopy. Ignoring.", size, vfb_size);
continue;
}
@ -1994,7 +1995,7 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size,
// Seems likely we are looking at a potential copy of 32-bit pixels (like video) to an old 16-bit buffer,
// which is very likely simply the wrong target, so skip it. See issue #17740 where this happens in Naruto Ultimate Ninja Heroes 2.
// Probably no point to give it a bad score and let it pass to sorting, as we're pretty sure here.
WARN_LOG_N_TIMES(notify_copy_2x, 5, Log::G3D, "Framebuffer size %08x too small for %08x bytes of data and also 16-bit (%s), and not rendered to this frame. Ignoring.", vfb_size, size, GeBufferFormatToString(vfb->fb_format));
WARN_LOG_N_TIMES(notify_copy_2x, 5, Log::FrameBuf, "Framebuffer size %08x too small for %08x bytes of data and also 16-bit (%s), and not rendered to this frame. Ignoring.", vfb_size, size, GeBufferFormatToString(vfb->fb_format));
continue;
}
@ -2034,7 +2035,7 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size,
// Not likely to be a correct color format copy for this buffer. Ignore it, there will either be RAM
// that can be displayed from, or another matching buffer with the right format if rendering is going on.
// If we had scoring here, we should strongly penalize this target instead of ignoring it.
WARN_LOG_N_TIMES(notify_copy_2x, 5, Log::G3D, "Framebuffer size %08x conspicuously not matching copy size %08x for dest in NotifyFramebufferCopy. Ignoring.", size, vfb_size);
WARN_LOG_N_TIMES(notify_copy_2x, 5, Log::FrameBuf, "Framebuffer size %08x conspicuously not matching copy size %08x for dest in NotifyFramebufferCopy. Ignoring.", size, vfb_size);
continue;
}
@ -2095,7 +2096,7 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size,
log += "\n";
}
}
WARN_LOG(Log::G3D, "Copy: Multiple src vfb candidates for (src: %08x, size: %d):\n%s (%s)", src, size, log.c_str(), RasterChannelToString(channel));
WARN_LOG(Log::FrameBuf, "Copy: Multiple src vfb candidates for (src: %08x, size: %d):\n%s (%s)", src, size, log.c_str(), RasterChannelToString(channel));
}
}
@ -2110,7 +2111,7 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size,
log += "\n";
}
}
WARN_LOG(Log::G3D, "Copy: Multiple dst vfb candidates for (dst: %08x, size: %d):\n%s (%s)", src, size, log.c_str(), RasterChannelToString(channel));
WARN_LOG(Log::FrameBuf, "Copy: Multiple dst vfb candidates for (dst: %08x, size: %d):\n%s (%s)", src, size, log.c_str(), RasterChannelToString(channel));
}
}
@ -2124,7 +2125,7 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size,
if (!dstBuffer && srcBuffer && channel != RASTER_DEPTH) {
// Note - if we're here, we're in a memcpy, not a block transfer. Not allowing IntraVRAMBlockTransferAllowCreateFB.
// Technically, that makes BlockTransferAllowCreateFB a bit of a misnomer.
bool allowCreateFB = (PSP_CoreParameter().compat.flags().BlockTransferAllowCreateFB || g_Config.iSkipGPUReadbackMode == (int)SkipGPUReadbackMode::COPY_TO_TEXTURE);
bool allowCreateFB = (PSP_CoreParameter().compat.flags().BlockTransferAllowCreateFB || GetSkipGPUReadbackMode() == SkipGPUReadbackMode::COPY_TO_TEXTURE);
if (allowCreateFB && !(flags & GPUCopyFlag::DISALLOW_CREATE_VFB)) {
dstBuffer = CreateRAMFramebuffer(dst, srcBuffer->width, srcBuffer->height, srcBuffer->fb_stride, srcBuffer->fb_format);
dstY = 0;
@ -2140,9 +2141,9 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size,
if (dstBuffer && srcBuffer) {
if (srcBuffer == dstBuffer) {
WARN_LOG_ONCE(dstsrccpy, Log::G3D, "Intra-buffer memcpy (not supported) %08x -> %08x (size: %x)", src, dst, size);
WARN_LOG_ONCE(dstsrccpy, Log::FrameBuf, "Intra-buffer memcpy (not supported) %08x -> %08x (size: %x)", src, dst, size);
} else {
WARN_LOG_ONCE(dstnotsrccpy, Log::G3D, "Inter-buffer memcpy %08x -> %08x (size: %x)", src, dst, size);
WARN_LOG_ONCE(dstnotsrccpy, Log::FrameBuf, "Inter-buffer memcpy %08x -> %08x (size: %x)", src, dst, size);
// Just do the blit!
BlitFramebuffer(dstBuffer, 0, dstY, srcBuffer, 0, srcY, srcBuffer->width, srcH, 0, channel, "Blit_InterBufferMemcpy");
SetColorUpdated(dstBuffer, skipDrawReason);
@ -2153,7 +2154,7 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size,
if (flags & GPUCopyFlag::MEMSET) {
gpuStats.numClears++;
}
WARN_LOG_N_TIMES(btucpy, 5, Log::G3D, "Memcpy fbo upload %08x -> %08x (size: %x)", src, dst, size);
WARN_LOG_N_TIMES(btucpy, 5, Log::FrameBuf, "Memcpy fbo upload %08x -> %08x (size: %x)", src, dst, size);
FlushBeforeCopy();
// TODO: Hot Shots Golf makes a lot of these during the "meter", to copy back the image to the screen, it copies line by line.
@ -2168,13 +2169,13 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size,
// This is a memcpy, let's still copy just in case.
return false;
} else if (srcBuffer) {
WARN_LOG_N_TIMES(btdcpy, 5, Log::G3D, "Memcpy fbo download %08x -> %08x", src, dst);
WARN_LOG_N_TIMES(btdcpy, 5, Log::FrameBuf, "Memcpy fbo download %08x -> %08x", src, dst);
FlushBeforeCopy();
// TODO: In Hot Shots Golf, check if we can do a readback to a framebuffer here.
// Again we have the problem though that it's doing a lot of small copies here, one for each line.
if (srcH == 0 || srcY + srcH > srcBuffer->bufferHeight) {
WARN_LOG_ONCE(btdcpyheight, Log::G3D, "Memcpy fbo download %08x -> %08x skipped, %d+%d is taller than %d", src, dst, srcY, srcH, srcBuffer->bufferHeight);
} else if (g_Config.iSkipGPUReadbackMode == (int)SkipGPUReadbackMode::NO_SKIP && (!srcBuffer->memoryUpdated || channel == RASTER_DEPTH)) {
WARN_LOG_ONCE(btdcpyheight, Log::FrameBuf, "Memcpy fbo download %08x -> %08x skipped, %d+%d is taller than %d", src, dst, srcY, srcH, srcBuffer->bufferHeight);
} else if (GetSkipGPUReadbackMode() == SkipGPUReadbackMode::NO_SKIP && (!srcBuffer->memoryUpdated || channel == RASTER_DEPTH)) {
Draw::ReadbackMode readbackMode = Draw::ReadbackMode::BLOCK;
if (PSP_CoreParameter().compat.flags().AllowDelayedReadbacks) {
readbackMode = Draw::ReadbackMode::OLD_DATA_OK;
@ -2203,7 +2204,7 @@ bool FramebufferManagerCommon::FindTransferFramebuffer(u32 basePtr, int stride_p
rect->vfb = nullptr;
if (!stride_pixels) {
WARN_LOG(Log::G3D, "Zero stride in FindTransferFrameBuffer, ignoring");
WARN_LOG(Log::FrameBuf, "Zero stride in FindTransferFrameBuffer, ignoring");
return false;
}
@ -2226,7 +2227,7 @@ bool FramebufferManagerCommon::FindTransferFramebuffer(u32 basePtr, int stride_p
// and also #17878 where a game does ram->buffer to an auto-swizzling (|0x600000) address,
// to initialize Z with a pre-rendered depth buffer.
if (vfb->z_address == basePtr && vfb->BufferByteStride(RASTER_DEPTH) == byteStride && PSP_CoreParameter().compat.flags().BlockTransferDepth) {
WARN_LOG_N_TIMES(z_xfer, 5, Log::G3D, "FindTransferFramebuffer: found matching depth buffer, %08x (dest=%d, bpp=%d)", basePtr, (int)destination, bpp);
WARN_LOG_N_TIMES(z_xfer, 5, Log::FrameBuf, "FindTransferFramebuffer: found matching depth buffer, %08x (dest=%d, bpp=%d)", basePtr, (int)destination, bpp);
candidate.channel = RASTER_DEPTH;
candidate.x_bytes = x_pixels * bpp;
candidate.w_bytes = w_pixels * bpp;
@ -2336,7 +2337,7 @@ bool FramebufferManagerCommon::FindTransferFramebuffer(u32 basePtr, int stride_p
for (size_t i = 0; i < candidates.size(); i++) {
log += " - " + candidates[i].ToString() + "\n";
}
WARN_LOG(Log::G3D, "Multiple framebuffer candidates for %08x/%d/%d %d,%d %dx%d (dest = %d):\n%s", basePtr, stride_pixels, bpp, x_pixels, y, w_pixels, h, (int)destination, log.c_str());
WARN_LOG(Log::FrameBuf, "Multiple framebuffer candidates for %08x/%d/%d %d,%d %dx%d (dest = %d):\n%s", basePtr, stride_pixels, bpp, x_pixels, y, w_pixels, h, (int)destination, log.c_str());
}
}
@ -2345,14 +2346,14 @@ bool FramebufferManagerCommon::FindTransferFramebuffer(u32 basePtr, int stride_p
return true;
} else {
if (Memory::IsVRAMAddress(basePtr) && destination && h >= 128) {
WARN_LOG_N_TIMES(nocands, 5, Log::G3D, "Didn't find a destination candidate for %08x/%d/%d %d,%d %dx%d", basePtr, stride_pixels, bpp, x_pixels, y, w_pixels, h);
WARN_LOG_N_TIMES(nocands, 5, Log::FrameBuf, "Didn't find a destination candidate for %08x/%d/%d %d,%d %dx%d", basePtr, stride_pixels, bpp, x_pixels, y, w_pixels, h);
}
return false;
}
}
VirtualFramebuffer *FramebufferManagerCommon::CreateRAMFramebuffer(uint32_t fbAddress, int width, int height, int stride, GEBufferFormat format) {
INFO_LOG(Log::G3D, "Creating RAM framebuffer at %08x (%dx%d, stride %d, fb_format %d)", fbAddress, width, height, stride, format);
INFO_LOG(Log::FrameBuf, "Creating RAM framebuffer at %08x (%dx%d, stride %d, fb_format %d)", fbAddress, width, height, stride, format);
RasterChannel channel = format == GE_FORMAT_DEPTH16 ? RASTER_DEPTH : RASTER_COLOR;
@ -2588,7 +2589,7 @@ bool FramebufferManagerCommon::NotifyBlockTransferBefore(u32 dstBasePtr, int dst
if (srcBuffer && !dstBuffer) {
// In here, we can't read from dstRect.
if (PSP_CoreParameter().compat.flags().BlockTransferAllowCreateFB ||
g_Config.iSkipGPUReadbackMode == (int)SkipGPUReadbackMode::COPY_TO_TEXTURE ||
GetSkipGPUReadbackMode() == SkipGPUReadbackMode::COPY_TO_TEXTURE ||
(PSP_CoreParameter().compat.flags().IntraVRAMBlockTransferAllowCreateFB &&
Memory::IsVRAMAddress(srcRect.vfb->fb_address) && Memory::IsVRAMAddress(dstBasePtr))) {
GEBufferFormat ramFormat;
@ -2716,7 +2717,7 @@ bool FramebufferManagerCommon::NotifyBlockTransferBefore(u32 dstBasePtr, int dst
srcBasePtr, srcRect.x_bytes / bpp, srcRect.y, srcStride,
dstBasePtr, dstRect.x_bytes / bpp, dstRect.y, dstStride);
FlushBeforeCopy();
if (g_Config.iSkipGPUReadbackMode == (int)SkipGPUReadbackMode::NO_SKIP && !srcRect.vfb->memoryUpdated) {
if (GetSkipGPUReadbackMode() == SkipGPUReadbackMode::NO_SKIP && !srcRect.vfb->memoryUpdated) {
const int srcBpp = BufferFormatBytesPerPixel(srcRect.vfb->fb_format);
const float srcXFactor = (float)bpp / srcBpp;
const bool tooTall = srcY + srcRect.h > srcRect.vfb->bufferHeight;
@ -2740,6 +2741,14 @@ bool FramebufferManagerCommon::NotifyBlockTransferBefore(u32 dstBasePtr, int dst
}
}
SkipGPUReadbackMode FramebufferManagerCommon::GetSkipGPUReadbackMode() {
if (PSP_CoreParameter().compat.flags().ForceEnableGPUReadback) {
return SkipGPUReadbackMode::NO_SKIP;
} else {
return (SkipGPUReadbackMode)g_Config.iSkipGPUReadbackMode;
}
}
void FramebufferManagerCommon::NotifyBlockTransferAfter(u32 dstBasePtr, int dstStride, int dstX, int dstY, u32 srcBasePtr, int srcStride, int srcX, int srcY, int width, int height, int bpp, u32 skipDrawReason) {
// If it's a block transfer direct to the screen, and we're not using buffers, draw immediately.
// We may still do a partial block draw below if this doesn't pass.
@ -3105,7 +3114,7 @@ bool FramebufferManagerCommon::GetOutputFramebuffer(GPUDebugBuffer &buffer) {
// can't entirely be rid of the CPU path.) -- unknown
void FramebufferManagerCommon::ReadbackFramebuffer(VirtualFramebuffer *vfb, int x, int y, int w, int h, RasterChannel channel, Draw::ReadbackMode mode) {
if (w <= 0 || h <= 0) {
ERROR_LOG(Log::G3D, "Bad inputs to ReadbackFramebufferSync: %d %d %d %d", x, y, w, h);
ERROR_LOG(Log::FrameBuf, "Bad inputs to ReadbackFramebufferSync: %d %d %d %d", x, y, w, h);
return;
}
@ -3141,7 +3150,7 @@ void FramebufferManagerCommon::ReadbackFramebuffer(VirtualFramebuffer *vfb, int
// We always need to convert from the framebuffer native format.
// Right now that's always 8888.
DEBUG_LOG(Log::G3D, "Reading framebuffer to mem, fb_address = %08x, ptr=%p", fb_address, destPtr);
DEBUG_LOG(Log::FrameBuf, "Reading framebuffer to mem, fb_address = %08x, ptr=%p", fb_address, destPtr);
if (channel == RASTER_DEPTH) {
_assert_msg_(vfb && vfb->z_address != 0 && vfb->z_stride != 0, "Depth buffer invalid");
@ -3574,7 +3583,7 @@ VirtualFramebuffer *FramebufferManagerCommon::ResolveFramebufferColorToFormat(Vi
vfb->fb_format = newFormat;
// stride stays the same since it's in pixels.
WARN_LOG(Log::G3D, "Creating %s clone of %08x/%08x/%s (%dx%d -> %dx%d)", GeBufferFormatToString(newFormat), src->fb_address, src->z_address, GeBufferFormatToString(src->fb_format), src->width, src->height, vfb->width, vfb->height);
WARN_LOG(Log::FrameBuf, "Creating %s clone of %08x/%08x/%s (%dx%d -> %dx%d)", GeBufferFormatToString(newFormat), src->fb_address, src->z_address, GeBufferFormatToString(src->fb_format), src->width, src->height, vfb->width, vfb->height);
char tag[128];
FormatFramebufferName(vfb, tag, sizeof(tag));

View file

@ -30,6 +30,7 @@
#include "Common/CommonTypes.h"
#include "Common/Log.h"
#include "Common/GPU/thin3d.h"
#include "Core/ConfigValues.h"
#include "GPU/GPU.h"
#include "GPU/ge_constants.h"
#include "GPU/GPUInterface.h"
@ -548,6 +549,8 @@ protected:
return fbBindSeqCount_++;
}
static SkipGPUReadbackMode GetSkipGPUReadbackMode();
PresentationCommon *presentation_ = nullptr;
Draw::DrawContext *draw_ = nullptr;

View file

@ -356,7 +356,7 @@ void EmuScreen::bootGame(const Path &filename) {
g_OSD.Show(OSDType::MESSAGE_WARNING, gr->T("BufferedRenderingRequired", "Warning: This game requires Rendering Mode to be set to Buffered."), 10.0f);
}
if (PSP_CoreParameter().compat.flags().RequireBlockTransfer && g_Config.iSkipGPUReadbackMode != (int)SkipGPUReadbackMode::NO_SKIP) {
if (PSP_CoreParameter().compat.flags().RequireBlockTransfer && g_Config.iSkipGPUReadbackMode != (int)SkipGPUReadbackMode::NO_SKIP && !PSP_CoreParameter().compat.flags().ForceEnableGPUReadback) {
auto gr = GetI18NCategory(I18NCat::GRAPHICS);
g_OSD.Show(OSDType::MESSAGE_WARNING, gr->T("BlockTransferRequired", "Warning: This game requires Skip GPU Readbacks be set to No."), 10.0f);
}