diff --git a/Core/Config.cpp b/Core/Config.cpp index 21667199ce..627672e5eb 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -658,7 +658,7 @@ static const ConfigSetting graphicsSettings[] = { ConfigSetting("TextureShader", &g_Config.sTextureShaderName, "Off", CfgFlag::PER_GAME), ConfigSetting("ShaderChainRequires60FPS", &g_Config.bShaderChainRequires60FPS, false, CfgFlag::PER_GAME), - ConfigSetting("SkipGPUReadbacks", &g_Config.bSkipGPUReadbacks, false, CfgFlag::PER_GAME | CfgFlag::REPORT), + ConfigSetting("SkipGPUReadbackMode", &g_Config.iSkipGPUReadbackMode, false, CfgFlag::PER_GAME | CfgFlag::REPORT), ConfigSetting("GfxDebugOutput", &g_Config.bGfxDebugOutput, false, CfgFlag::DONT_SAVE), ConfigSetting("LogFrameDrops", &g_Config.bLogFrameDrops, false, CfgFlag::DEFAULT), diff --git a/Core/Config.h b/Core/Config.h index d7fc96dcde..10eecfdd29 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -235,7 +235,7 @@ public: float fCwCheatScrollPosition; float fGameListScrollPosition; int iBloomHack; //0 = off, 1 = safe, 2 = balanced, 3 = aggressive - bool bSkipGPUReadbacks; + int iSkipGPUReadbackMode; // 0 = off, 1 = skip, 2 = to texture int iSplineBezierQuality; // 0 = low , 1 = Intermediate , 2 = High bool bHardwareTessellation; bool bShaderCache; // Hidden ini-only setting, useful for debugging shader compile times. diff --git a/Core/ConfigValues.h b/Core/ConfigValues.h index f7f9457a2c..6d38311805 100644 --- a/Core/ConfigValues.h +++ b/Core/ConfigValues.h @@ -176,3 +176,9 @@ enum class DisplayFramerateMode : int { FORCE_60HZ_METHOD1, FORCE_60HZ_METHOD2, }; + +enum class SkipGPUReadbackMode : int { + NO, + SKIP, + COPY_TO_TEXTURE, +}; diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index bce9ec3872..eb89d48c67 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -1024,7 +1024,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.bSkipGPUReadbacks && !PSP_CoreParameter().compat.flags().DisableFirstFrameReadback) { + if (g_Config.iSkipGPUReadbackMode == (int)SkipGPUReadbackMode::NO && !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; @@ -1040,7 +1040,7 @@ bool FramebufferManagerCommon::ShouldDownloadFramebufferColor(const VirtualFrame bool FramebufferManagerCommon::ShouldDownloadFramebufferDepth(const VirtualFramebuffer *vfb) const { // Download depth buffer for Syphon Filter lens flares - if (!PSP_CoreParameter().compat.flags().ReadbackDepth || g_Config.bSkipGPUReadbacks) { + if (!PSP_CoreParameter().compat.flags().ReadbackDepth || g_Config.iSkipGPUReadbackMode != (int)SkipGPUReadbackMode::NO) { return false; } return (vfb->usageFlags & FB_USAGE_RENDER_DEPTH) != 0 && vfb->width >= 480 && vfb->height >= 272; @@ -2080,7 +2080,8 @@ 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. - if (PSP_CoreParameter().compat.flags().BlockTransferAllowCreateFB && !(flags & GPUCopyFlag::DISALLOW_CREATE_VFB)) { + bool allowCreateFB = (PSP_CoreParameter().compat.flags().BlockTransferAllowCreateFB || g_Config.iSkipGPUReadbackMode == (int)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; } @@ -2129,7 +2130,7 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size, // 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, G3D, "Memcpy fbo download %08x -> %08x skipped, %d+%d is taller than %d", src, dst, srcY, srcH, srcBuffer->bufferHeight); - } else if (!g_Config.bSkipGPUReadbacks && (!srcBuffer->memoryUpdated || channel == RASTER_DEPTH)) { + } else if (g_Config.iSkipGPUReadbackMode == (int)SkipGPUReadbackMode::NO && (!srcBuffer->memoryUpdated || channel == RASTER_DEPTH)) { Draw::ReadbackMode readbackMode = Draw::ReadbackMode::BLOCK; if (PSP_CoreParameter().compat.flags().AllowDelayedReadbacks) { readbackMode = Draw::ReadbackMode::OLD_DATA_OK; @@ -2543,6 +2544,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 || (PSP_CoreParameter().compat.flags().IntraVRAMBlockTransferAllowCreateFB && Memory::IsVRAMAddress(srcRect.vfb->fb_address) && Memory::IsVRAMAddress(dstBasePtr))) { GEBufferFormat ramFormat; @@ -2666,7 +2668,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.bSkipGPUReadbacks && !srcRect.vfb->memoryUpdated) { + if (g_Config.iSkipGPUReadbackMode == (int)SkipGPUReadbackMode::NO && !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; diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index 83870d5bff..441cd5ce1c 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -347,9 +347,9 @@ 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.bSkipGPUReadbacks) { + if (PSP_CoreParameter().compat.flags().RequireBlockTransfer && g_Config.iSkipGPUReadbackMode != (int)SkipGPUReadbackMode::NO) { auto gr = GetI18NCategory(I18NCat::GRAPHICS); - g_OSD.Show(OSDType::MESSAGE_WARNING, gr->T("BlockTransferRequired", "Warning: This game requires Simulate Block Transfer Mode to be set to On."), 10.0f); + g_OSD.Show(OSDType::MESSAGE_WARNING, gr->T("BlockTransferRequired", "Warning: This game requires Skip GPU Readbacks be set to No."), 10.0f); } if (PSP_CoreParameter().compat.flags().RequireDefaultCPUClock && g_Config.iLockedCPUSpeed != 0) { diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 8a1b22f7e0..f8512394a1 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -407,7 +407,9 @@ void GameSettingsScreen::CreateGraphicsSettings(UI::ViewGroup *graphicsSettings) }); skipBufferEffects->SetDisabledPtr(&g_Config.bSoftwareRendering); - CheckBox *skipGPUReadbacks = graphicsSettings->Add(new CheckBox(&g_Config.bSkipGPUReadbacks, gr->T("Skip GPU Readbacks"))); + static const char *skipGpuReadbackModes[] = { "No (default)", "Skip", "Copy to texture" }; + + PopupMultiChoice *skipGPUReadbacks = graphicsSettings->Add(new PopupMultiChoice(&g_Config.iSkipGPUReadbackMode, gr->T("Skip GPU Readbacks"), skipGpuReadbackModes, 0, ARRAY_SIZE(skipGpuReadbackModes), I18NCat::GRAPHICS, screenManager())); skipGPUReadbacks->SetDisabledPtr(&g_Config.bSoftwareRendering); CheckBox *texBackoff = graphicsSettings->Add(new CheckBox(&g_Config.bTextureBackoffCache, gr->T("Lazy texture caching", "Lazy texture caching (speedup)"))); diff --git a/headless/Headless.cpp b/headless/Headless.cpp index 551176cbc3..c59aa15ffe 100644 --- a/headless/Headless.cpp +++ b/headless/Headless.cpp @@ -468,7 +468,7 @@ int main(int argc, const char* argv[]) g_Config.sReportHost.clear(); g_Config.bAutoSaveSymbolMap = false; g_Config.bSkipBufferEffects = false; - g_Config.bSkipGPUReadbacks = false; + g_Config.iSkipGPUReadbackMode = (int)SkipGPUReadbackMode::NO; g_Config.bHardwareTransform = true; g_Config.iAnisotropyLevel = 0; // When testing mipmapping we really don't want this. g_Config.iMultiSampleLevel = 0; diff --git a/libretro/libretro.cpp b/libretro/libretro.cpp index de6792012f..a93f010b90 100644 --- a/libretro/libretro.cpp +++ b/libretro/libretro.cpp @@ -634,9 +634,9 @@ static void check_variables(CoreParameter &coreParam) if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { if (!strcmp(var.value, "disabled")) - g_Config.bSkipGPUReadbacks = false; + g_Config.iSkipGPUReadbackMode = (int)SkipGPUReadbackMode::SKIP; else - g_Config.bSkipGPUReadbacks = true; + g_Config.iSkipGPUReadbackMode = (int)SkipGPUReadbackMode::NO; } var.key = "ppsspp_frameskip";