diff --git a/pcsx2-gsrunner/Main.cpp b/pcsx2-gsrunner/Main.cpp index 15e7bbd811..35a7666413 100644 --- a/pcsx2-gsrunner/Main.cpp +++ b/pcsx2-gsrunner/Main.cpp @@ -250,7 +250,7 @@ void Host::BeginPresentFrame() GSQueueSnapshot(dump_path); } - if (GSConfig.UseHardwareRenderer()) + if (GSIsHardwareRenderer()) { const u32 last_draws = s_total_internal_draws; const u32 last_uploads = s_total_uploads; diff --git a/pcsx2-qt/MainWindow.cpp b/pcsx2-qt/MainWindow.cpp index 26fa7fe2b9..d68e968fe5 100644 --- a/pcsx2-qt/MainWindow.cpp +++ b/pcsx2-qt/MainWindow.cpp @@ -399,6 +399,8 @@ void MainWindow::connectSignals() Qt::QueuedConnection); connect(m_game_list_widget, &GameListWidget::addGameDirectoryRequested, this, [this]() { getSettingsWindow()->getGameListSettingsWidget()->addSearchDirectory(this); }); + + createRendererSwitchMenu(); } void MainWindow::connectVMThreadSignals(EmuThread* thread) @@ -431,16 +433,48 @@ void MainWindow::connectVMThreadSignals(EmuThread* thread) connect(m_ui.actionToggleSoftwareRendering, &QAction::triggered, thread, &EmuThread::toggleSoftwareRendering); connect(m_ui.actionDebugger, &QAction::triggered, this, &MainWindow::openDebugger); connect(m_ui.actionReloadPatches, &QAction::triggered, thread, &EmuThread::reloadPatches); +} - static constexpr GSRendererType renderers[] = { -#ifdef _WIN32 - GSRendererType::DX11, GSRendererType::DX12, +void MainWindow::createRendererSwitchMenu() +{ + static constexpr const GSRendererType renderers[] = { + GSRendererType::Auto, +#if defined(_WIN32) + GSRendererType::DX11, + GSRendererType::DX12, +#elif defined(__APPLE__) + GSRendererType::Metal, #endif - GSRendererType::OGL, GSRendererType::VK, GSRendererType::SW, GSRendererType::Null}; - for (GSRendererType renderer : renderers) +#ifdef ENABLE_OPENGL + GSRendererType::OGL, +#endif +#ifdef ENABLE_VULKAN + GSRendererType::VK, +#endif + GSRendererType::SW, + GSRendererType::Null, + }; + const GSRendererType current_renderer = static_cast( + Host::GetBaseIntSettingValue("EmuCore/GS", "Renderer", static_cast(GSRendererType::Auto))); + for (const GSRendererType renderer : renderers) { - connect(m_ui.menuDebugSwitchRenderer->addAction(QString::fromUtf8(Pcsx2Config::GSOptions::GetRendererName(renderer))), - &QAction::triggered, [renderer] { g_emu_thread->switchRenderer(renderer); }); + QAction* action = m_ui.menuDebugSwitchRenderer->addAction( + QString::fromUtf8(Pcsx2Config::GSOptions::GetRendererName(renderer))); + action->setCheckable(true); + action->setChecked(current_renderer == renderer); + connect(action, + &QAction::triggered, [this, action, renderer] { + Host::SetBaseIntSettingValue("EmuCore/GS", "Renderer", static_cast(renderer)); + Host::CommitBaseSettingChanges(); + g_emu_thread->applySettings(); + + // clear all others + for (QObject* obj : m_ui.menuDebugSwitchRenderer->children()) + { + if (QAction* act = qobject_cast(obj); act && act != action) + act->setChecked(false); + } + }); } } diff --git a/pcsx2-qt/MainWindow.h b/pcsx2-qt/MainWindow.h index 0f4220e67a..5eb23d2210 100644 --- a/pcsx2-qt/MainWindow.h +++ b/pcsx2-qt/MainWindow.h @@ -205,6 +205,7 @@ private: void setupAdditionalUi(); void connectSignals(); + void createRendererSwitchMenu(); void recreate(); void recreateSettings(); void destroySubWindows(); diff --git a/pcsx2-qt/QtHost.cpp b/pcsx2-qt/QtHost.cpp index 3dbd31ad76..ef74c87f61 100644 --- a/pcsx2-qt/QtHost.cpp +++ b/pcsx2-qt/QtHost.cpp @@ -610,20 +610,6 @@ void EmuThread::toggleSoftwareRendering() MTGS::ToggleSoftwareRendering(); } -void EmuThread::switchRenderer(GSRendererType renderer) -{ - if (!isOnEmuThread()) - { - QMetaObject::invokeMethod(this, "switchRenderer", Qt::QueuedConnection, Q_ARG(GSRendererType, renderer)); - return; - } - - if (!VMManager::HasValidVM()) - return; - - MTGS::SwitchRenderer(renderer, EmuConfig.GS.InterlaceMode); -} - void EmuThread::changeDisc(CDVD_SourceType source, const QString& path) { if (!isOnEmuThread()) diff --git a/pcsx2-qt/QtHost.h b/pcsx2-qt/QtHost.h index 5f9111a823..a1dfab7af5 100644 --- a/pcsx2-qt/QtHost.h +++ b/pcsx2-qt/QtHost.h @@ -92,7 +92,6 @@ public Q_SLOTS: void reloadGameSettings(); void updateEmuFolders(); void toggleSoftwareRendering(); - void switchRenderer(GSRendererType renderer); void changeDisc(CDVD_SourceType source, const QString& path); void setELFOverride(const QString& path); void changeGSDump(const QString& path); diff --git a/pcsx2/Counters.cpp b/pcsx2/Counters.cpp index 06e346563f..65989a92d2 100644 --- a/pcsx2/Counters.cpp +++ b/pcsx2/Counters.cpp @@ -434,7 +434,6 @@ extern uint eecount_on_last_vdec; extern bool FMVstarted; extern bool EnableFMV; -static bool RendererSwitched = false; static bool s_last_fmv_state = false; static __fi void DoFMVSwitch() @@ -479,15 +478,12 @@ static __fi void DoFMVSwitch() break; } - if (EmuConfig.Gamefixes.SoftwareRendererFMVHack && (GSConfig.UseHardwareRenderer() || (RendererSwitched && GSConfig.Renderer == GSRendererType::SW))) + if (EmuConfig.Gamefixes.SoftwareRendererFMVHack && EmuConfig.GS.UseHardwareRenderer()) { - RendererSwitched = GSConfig.UseHardwareRenderer(); DevCon.Warning("FMV Switch"); // we don't use the sw toggle here, because it'll change back to auto if set to sw - MTGS::SwitchRenderer(new_fmv_state ? GSRendererType::SW : EmuConfig.GS.Renderer, new_fmv_state ? GSInterlaceMode::AdaptiveTFF : EmuConfig.GS.InterlaceMode, false); + MTGS::SetSoftwareRendering(new_fmv_state, new_fmv_state ? GSInterlaceMode::AdaptiveTFF : EmuConfig.GS.InterlaceMode, false); } - else - RendererSwitched = false; } static __fi void VSyncStart(u32 sCycle) diff --git a/pcsx2/GS/GS.cpp b/pcsx2/GS/GS.cpp index 98e7bc3433..de39e15ee0 100644 --- a/pcsx2/GS/GS.cpp +++ b/pcsx2/GS/GS.cpp @@ -53,6 +53,8 @@ Pcsx2Config::GSOptions GSConfig; +static GSRendererType GSCurrentRenderer; + static u64 s_next_manual_present_time; void GSinit() @@ -70,6 +72,17 @@ void GSshutdown() GSJoinSnapshotThreads(); } +GSRendererType GSGetCurrentRenderer() +{ + return GSCurrentRenderer; +} + +bool GSIsHardwareRenderer() +{ + // Null gets flagged as hw. + return (GSCurrentRenderer != GSRendererType::SW); +} + static RenderAPI GetAPIForRenderer(GSRendererType renderer) { switch (renderer) @@ -93,6 +106,7 @@ static RenderAPI GetAPIForRenderer(GSRendererType renderer) return RenderAPI::Metal; #endif + // We could end up here if we ever removed a renderer. default: return GetAPIForRenderer(GSUtil::GetPreferredRenderer()); } @@ -191,6 +205,7 @@ static bool OpenGSRenderer(GSRendererType renderer, u8* basemem) g_gs_renderer->ResetPCRTC(); g_gs_renderer->UpdateRenderFixes(); g_perfmon.Reset(); + GSCurrentRenderer = renderer; return true; } @@ -205,20 +220,18 @@ static void CloseGSRenderer() } } -bool GSreopen(bool recreate_device, bool recreate_renderer, const Pcsx2Config::GSOptions& old_config) +bool GSreopen(bool recreate_device, GSRendererType new_renderer, std::optional old_config) { - Console.WriteLn("Reopening GS with %s device and %s renderer", recreate_device ? "new" : "existing", - recreate_renderer ? "new" : "existing"); + Console.WriteLn("Reopening GS with %s device", recreate_device ? "new" : "existing"); - if (recreate_renderer) - g_gs_renderer->Flush(GSState::GSFlushReason::GSREOPEN); + g_gs_renderer->Flush(GSState::GSFlushReason::GSREOPEN); if (GSConfig.UserHacks_ReadTCOnClose) g_gs_renderer->ReadbackTextureCache(); std::string capture_filename; GSVector2i capture_size; - if (GSCapture::IsCapturing() && (recreate_renderer || recreate_device)) + if (GSCapture::IsCapturing()) { capture_filename = GSCapture::GetNextCaptureFileName(); capture_size = GSCapture::GetSize(); @@ -229,40 +242,29 @@ bool GSreopen(bool recreate_device, bool recreate_renderer, const Pcsx2Config::G u8* basemem = g_gs_renderer->GetRegsMem(); freezeData fd = {}; - std::unique_ptr fd_data; - if (recreate_renderer) + if (g_gs_renderer->Freeze(&fd, true) != 0) { - if (g_gs_renderer->Freeze(&fd, true) != 0) - { - Console.Error("(GSreopen) Failed to get GS freeze size"); - return false; - } - - fd_data = std::make_unique(fd.size); - fd.data = fd_data.get(); - if (g_gs_renderer->Freeze(&fd, false) != 0) - { - Console.Error("(GSreopen) Failed to freeze GS"); - return false; - } - - CloseGSRenderer(); + Console.Error("(GSreopen) Failed to get GS freeze size"); + return false; } - else + + std::unique_ptr fd_data = std::make_unique(fd.size); + fd.data = fd_data.get(); + if (g_gs_renderer->Freeze(&fd, false) != 0) { - // Make sure nothing is left over. - g_gs_renderer->PurgeTextureCache(true, true, true); - g_gs_renderer->PurgePool(); + Console.Error("(GSreopen) Failed to freeze GS"); + return false; } + CloseGSRenderer(); + if (recreate_device) { // We need a new render window when changing APIs. const bool recreate_window = (g_gs_device->GetRenderAPI() != GetAPIForRenderer(GSConfig.Renderer)); CloseGSDevice(false); - if (!OpenGSDevice(GSConfig.Renderer, false, recreate_window) || - (recreate_renderer && !OpenGSRenderer(GSConfig.Renderer, basemem))) + if (!OpenGSDevice(new_renderer, false, recreate_window)) { Host::AddKeyedOSDMessage("GSReopenFailed", TRANSLATE_STR("GS", "Failed to reopen, restoring old configuration."), @@ -270,9 +272,10 @@ bool GSreopen(bool recreate_device, bool recreate_renderer, const Pcsx2Config::G CloseGSDevice(false); - GSConfig = old_config; - if (!OpenGSDevice(GSConfig.Renderer, false, recreate_window) || - (recreate_renderer && !OpenGSRenderer(GSConfig.Renderer, basemem))) + if (old_config.has_value()) + GSConfig = *old_config.value(); + + if (!OpenGSDevice(GSConfig.Renderer, false, recreate_window)) { pxFailRel("Failed to reopen GS on old config"); Host::ReleaseRenderWindow(); @@ -280,22 +283,17 @@ bool GSreopen(bool recreate_device, bool recreate_renderer, const Pcsx2Config::G } } } - else if (recreate_renderer) + + if (!OpenGSRenderer(new_renderer, basemem)) { - if (!OpenGSRenderer(GSConfig.Renderer, basemem)) - { - Console.Error("(GSreopen) Failed to create new renderer"); - return false; - } + Console.Error("(GSreopen) Failed to create new renderer"); + return false; } - if (recreate_renderer) + if (g_gs_renderer->Defrost(&fd) != 0) { - if (g_gs_renderer->Defrost(&fd) != 0) - { - Console.Error("(GSreopen) Failed to defrost"); - return false; - } + Console.Error("(GSreopen) Failed to defrost"); + return false; } if (!capture_filename.empty()) @@ -306,12 +304,11 @@ bool GSreopen(bool recreate_device, bool recreate_renderer, const Pcsx2Config::G bool GSopen(const Pcsx2Config::GSOptions& config, GSRendererType renderer, u8* basemem) { + GSConfig = config; + if (renderer == GSRendererType::Auto) renderer = GSUtil::GetPreferredRenderer(); - GSConfig = config; - GSConfig.Renderer = renderer; - bool res = OpenGSDevice(renderer, true, false); if (res) { @@ -491,7 +488,7 @@ void GSThrottlePresentation() void GSGameChanged() { - if (GSConfig.UseHardwareRenderer()) + if (GSIsHardwareRenderer()) GSTextureReplacements::GameChanged(); } @@ -610,7 +607,7 @@ void GSgetStats(SmallStringBase& info) { GSPerfMon& pm = g_perfmon; const char* api_name = GSDevice::RenderAPIToString(g_gs_device->GetRenderAPI()); - if (GSConfig.Renderer == GSRendererType::SW) + if (GSCurrentRenderer == GSRendererType::SW) { const double fps = GetVerticalFrequency(); const double fillrate = pm.Get(GSPerfMon::Fillrate); @@ -623,7 +620,7 @@ void GSgetStats(SmallStringBase& info) pm.Get(GSPerfMon::Unswizzle) / 1024, fps * fillrate / (1024 * 1024)); } - else if (GSConfig.Renderer == GSRendererType::Null) + else if (GSCurrentRenderer == GSRendererType::Null) { fmt::format_to(std::back_inserter(info), "{} Null", api_name); } @@ -678,7 +675,7 @@ void GSgetTitleStats(std::string& info) "Automatic", "None", "Weave tff", "Weave bff", "Bob tff", "Bob bff", "Blend tff", "Blend bff", "Adaptive tff", "Adaptive bff"}; const char* api_name = GSDevice::RenderAPIToString(g_gs_device->GetRenderAPI()); - const char* hw_sw_name = (GSConfig.Renderer == GSRendererType::Null) ? " Null" : (GSConfig.UseHardwareRenderer() ? " HW" : " SW"); + const char* hw_sw_name = (GSCurrentRenderer == GSRendererType::Null) ? " Null" : (GSIsHardwareRenderer() ? " HW" : " SW"); const char* deinterlace_mode = deinterlace_modes[static_cast(GSConfig.InterlaceMode)]; const char* interlace_mode = ReportInterlaceMode(); @@ -690,11 +687,9 @@ void GSUpdateConfig(const Pcsx2Config::GSOptions& new_config) { Pcsx2Config::GSOptions old_config(std::move(GSConfig)); GSConfig = new_config; - GSConfig.Renderer = (GSConfig.Renderer == GSRendererType::Auto) ? GSUtil::GetPreferredRenderer() : GSConfig.Renderer; if (!g_gs_renderer) return; - // Handle OSD scale changes by pushing a window resize through. if (new_config.OsdScale != old_config.OsdScale) ImGuiManager::WindowResized(); @@ -702,7 +697,7 @@ void GSUpdateConfig(const Pcsx2Config::GSOptions& new_config) // Options which need a full teardown/recreate. if (!GSConfig.RestartOptionsAreEqual(old_config)) { - if (!GSreopen(true, true, old_config)) + if (!GSreopen(true, GSConfig.Renderer, &old_config)) pxFailRel("Failed to do full GS reopen"); return; } @@ -711,7 +706,7 @@ void GSUpdateConfig(const Pcsx2Config::GSOptions& new_config) if (GSConfig.SWExtraThreads != old_config.SWExtraThreads || GSConfig.SWExtraThreadsHeight != old_config.SWExtraThreadsHeight) { - if (!GSreopen(false, true, old_config)) + if (!GSreopen(false, GSConfig.Renderer, &old_config)) pxFailRel("Failed to do quick GS reopen"); return; @@ -731,7 +726,7 @@ void GSUpdateConfig(const Pcsx2Config::GSOptions& new_config) // reload texture cache when trilinear filtering or TC options change if ( - (GSConfig.UseHardwareRenderer() && GSConfig.HWMipmap != old_config.HWMipmap) || + (GSIsHardwareRenderer() && GSConfig.HWMipmap != old_config.HWMipmap) || GSConfig.TexturePreloading != old_config.TexturePreloading || GSConfig.TriFilter != old_config.TriFilter || GSConfig.GPUPaletteConversion != old_config.GPUPaletteConversion || @@ -755,7 +750,7 @@ void GSUpdateConfig(const Pcsx2Config::GSOptions& new_config) g_gs_device->ClearSamplerCache(); // texture dumping/replacement options - if (GSConfig.UseHardwareRenderer()) + if (GSIsHardwareRenderer()) GSTextureReplacements::UpdateConfig(old_config); // clear the hash texture cache since we might have replacements now @@ -773,21 +768,18 @@ void GSUpdateConfig(const Pcsx2Config::GSOptions& new_config) } } -void GSSwitchRenderer(GSRendererType new_renderer, GSInterlaceMode new_interlace) +void GSSetSoftwareRendering(bool software_renderer, GSInterlaceMode new_interlace) { - if (new_renderer == GSRendererType::Auto) - new_renderer = GSUtil::GetPreferredRenderer(); - - if (!g_gs_renderer || GSConfig.Renderer == new_renderer) + if (!g_gs_renderer) return; - const bool is_software_switch = (new_renderer == GSRendererType::SW || GSConfig.Renderer == GSRendererType::SW); - const Pcsx2Config::GSOptions old_config(GSConfig); - GSConfig.Renderer = new_renderer; GSConfig.InterlaceMode = new_interlace; - if (!GSreopen(!is_software_switch, true, old_config)) - pxFailRel("Failed to reopen GS for renderer switch."); + if (!GSIsHardwareRenderer() != software_renderer) + { + if (!GSreopen(false, software_renderer ? GSRendererType::SW : GSConfig.Renderer, std::nullopt)) + pxFailRel("Failed to reopen GS for renderer switch."); + } } bool GSSaveSnapshotToMemory(u32 window_width, u32 window_height, bool apply_aspect, bool crop_borders, diff --git a/pcsx2/GS/GS.h b/pcsx2/GS/GS.h index f293f2536a..f96ffd336d 100644 --- a/pcsx2/GS/GS.h +++ b/pcsx2/GS/GS.h @@ -49,9 +49,6 @@ enum class GSDisplayAlignment RightOrBottom }; -extern Pcsx2Config::GSOptions GSConfig; - -class HostDisplay; class SmallStringBase; // Returns the ID for the specified function, otherwise -1. @@ -62,7 +59,7 @@ s16 GSLookupMoveHandlerFunctionId(const std::string_view& name); void GSinit(); void GSshutdown(); bool GSopen(const Pcsx2Config::GSOptions& config, GSRendererType renderer, u8* basemem); -bool GSreopen(bool recreate_device, bool recreate_renderer, const Pcsx2Config::GSOptions& old_config); +bool GSreopen(bool recreate_device, GSRendererType new_renderer, std::optional old_config); void GSreset(bool hardware_reset); void GSclose(); void GSgifSoftReset(u32 mask); @@ -90,6 +87,8 @@ void GSResizeDisplayWindow(int width, int height, float scale); void GSUpdateDisplayWindow(); void GSSetVSyncMode(VsyncMode mode); +GSRendererType GSGetCurrentRenderer(); +bool GSIsHardwareRenderer(); bool GSWantsExclusiveFullscreen(); bool GSGetHostRefreshRate(float* refresh_rate); void GSGetAdaptersAndFullscreenModes( @@ -105,7 +104,7 @@ void GSgetTitleStats(std::string& info); void GSTranslateWindowToDisplayCoordinates(float window_x, float window_y, float* display_x, float* display_y); void GSUpdateConfig(const Pcsx2Config::GSOptions& new_config); -void GSSwitchRenderer(GSRendererType new_renderer, GSInterlaceMode new_interlace); +void GSSetSoftwareRendering(bool software_renderer, GSInterlaceMode new_interlace); bool GSSaveSnapshotToMemory(u32 window_width, u32 window_height, bool apply_aspect, bool crop_borders, u32* width, u32* height, std::vector* pixels); void GSJoinSnapshotThreads(); @@ -135,3 +134,5 @@ namespace Host void OnCaptureStarted(const std::string& filename); void OnCaptureStopped(); } + +extern Pcsx2Config::GSOptions GSConfig; diff --git a/pcsx2/GS/GSState.cpp b/pcsx2/GS/GSState.cpp index 0fcaaeb847..9fbca53083 100644 --- a/pcsx2/GS/GSState.cpp +++ b/pcsx2/GS/GSState.cpp @@ -125,7 +125,7 @@ std::string GSState::GetDrawDumpPath(const char* format, ...) { std::va_list ap; va_start(ap, format); - const std::string& base = GSConfig.UseHardwareRenderer() ? GSConfig.HWDumpDirectory : GSConfig.SWDumpDirectory; + const std::string& base = GSIsHardwareRenderer() ? GSConfig.HWDumpDirectory : GSConfig.SWDumpDirectory; std::string ret(Path::Combine(base, StringUtil::StdStringFromFormatV(format, ap))); va_end(ap); return ret; @@ -165,7 +165,7 @@ void GSState::Reset(bool hardware_reset) // bounds value. This means that draws get skipped until the game sets a proper scissor up, which is definitely going to happen // after reset (otherwise it'd only ever render 1x1). // - if (!hardware_reset && GSConfig.UseHardwareRenderer()) + if (!hardware_reset && GSIsHardwareRenderer()) m_env.CTXT[i].scissor.cull = GSVector4i::xffffffff(); m_env.CTXT[i].offset.fb = m_mem.GetOffset(m_env.CTXT[i].FRAME.Block(), m_env.CTXT[i].FRAME.FBW, m_env.CTXT[i].FRAME.PSM); @@ -4421,14 +4421,14 @@ GSVector2i GSState::GSPCRTCRegs::GetFramebufferSize(int display) if (combined_rect.z >= 2048) { const int high_x = (PCRTCDisplays[0].framebufferRect.x > PCRTCDisplays[1].framebufferRect.x) ? PCRTCDisplays[0].framebufferRect.x : PCRTCDisplays[1].framebufferRect.x; - combined_rect.z -= GSConfig.UseHardwareRenderer() ? 2048 : high_x; + combined_rect.z -= GSIsHardwareRenderer() ? 2048 : high_x; combined_rect.x = 0; } if (combined_rect.w >= 2048) { const int high_y = (PCRTCDisplays[0].framebufferRect.y > PCRTCDisplays[1].framebufferRect.y) ? PCRTCDisplays[0].framebufferRect.y : PCRTCDisplays[1].framebufferRect.y; - combined_rect.w -= GSConfig.UseHardwareRenderer() ? 2048 : high_y; + combined_rect.w -= GSIsHardwareRenderer() ? 2048 : high_y; combined_rect.y = 0; } @@ -4442,7 +4442,7 @@ GSVector2i GSState::GSPCRTCRegs::GetFramebufferSize(int display) } // Hardware mode needs a wider framebuffer as it can't offset the read. - if (GSConfig.UseHardwareRenderer()) + if (GSIsHardwareRenderer()) { combined_rect.z += std::max(PCRTCDisplays[0].framebufferOffsets.x, PCRTCDisplays[1].framebufferOffsets.x); combined_rect.w += std::max(PCRTCDisplays[0].framebufferOffsets.y, PCRTCDisplays[1].framebufferOffsets.y); @@ -4612,7 +4612,7 @@ void GSState::GSPCRTCRegs::RemoveFramebufferOffset(int display) if (display >= 0) { // Hardware needs nothing but handling for wrapped framebuffers. - if (GSConfig.UseHardwareRenderer()) + if (GSIsHardwareRenderer()) { if (PCRTCDisplays[display].framebufferRect.z >= 2048) { @@ -4648,7 +4648,7 @@ void GSState::GSPCRTCRegs::RemoveFramebufferOffset(int display) // Software Mode Note: // This code is to read the framebuffer nicely block aligned in software, then leave the remaining offset in to the block. // In hardware mode this doesn't happen, it reads the whole framebuffer, so we need to keep the offset. - if (!GSConfig.UseHardwareRenderer()) + if (!GSIsHardwareRenderer()) { const GSLocalMemory::psm_t& psm = GSLocalMemory::m_psm[PCRTCDisplays[1].PSM]; diff --git a/pcsx2/GS/GSUtil.cpp b/pcsx2/GS/GSUtil.cpp index 7c4c3b93ad..d242f93734 100644 --- a/pcsx2/GS/GSUtil.cpp +++ b/pcsx2/GS/GSUtil.cpp @@ -195,28 +195,35 @@ u32 GSUtil::GetChannelMask(u32 spsm, u32 fbmsk) GSRendererType GSUtil::GetPreferredRenderer() { + // Memorize the value, so we don't keep re-querying it. + static GSRendererType preferred_renderer = GSRendererType::Auto; + if (preferred_renderer == GSRendererType::Auto) + { #if defined(__APPLE__) - // Mac: Prefer Metal hardware. - return GSRendererType::Metal; + // Mac: Prefer Metal hardware. + preferred_renderer = GSRendererType::Metal; #elif defined(_WIN32) - // Use D3D device info to select renderer. - return D3D::GetPreferredRenderer(); + // Use D3D device info to select renderer. + preferred_renderer = D3D::GetPreferredRenderer(); #else - // Linux: Prefer Vulkan if the driver isn't buggy. + // Linux: Prefer Vulkan if the driver isn't buggy. #if defined(ENABLE_VULKAN) - if (GSDeviceVK::IsSuitableDefaultRenderer()) - return GSRendererType::VK; + if (GSDeviceVK::IsSuitableDefaultRenderer()) + preferred_renderer = GSRendererType::VK; #endif - // Otherwise, whatever is available. + // Otherwise, whatever is available. #if defined(ENABLE_OPENGL) - return GSRendererType::OGL; + preferred_renderer = GSRendererType::OGL; #elif defined(ENABLE_VULKAN) - return GSRendererType::VK; + preferred_renderer = GSRendererType::VK; #else - return GSRendererType::SW; + preferred_renderer = GSRendererType::SW; #endif #endif + } + + return preferred_renderer; } const char* psm_str(int psm) diff --git a/pcsx2/GS/Renderers/Common/GSRenderer.cpp b/pcsx2/GS/Renderers/Common/GSRenderer.cpp index f026b91783..4b41e59363 100644 --- a/pcsx2/GS/Renderers/Common/GSRenderer.cpp +++ b/pcsx2/GS/Renderers/Common/GSRenderer.cpp @@ -511,7 +511,7 @@ bool GSRenderer::BeginPresentFrame(bool frame_skip) // Device lost, something went really bad. // Let's just toss out everything, and try to hobble on. - if (!GSreopen(true, false, GSConfig)) + if (!GSreopen(true, GSGetCurrentRenderer(), std::nullopt)) { pxFailRel("Failed to recreate GS device after loss."); return false; diff --git a/pcsx2/ImGui/FullscreenUI.cpp b/pcsx2/ImGui/FullscreenUI.cpp index 3a616730a4..04fcd44217 100644 --- a/pcsx2/ImGui/FullscreenUI.cpp +++ b/pcsx2/ImGui/FullscreenUI.cpp @@ -4824,7 +4824,7 @@ void FullscreenUI::DrawPauseMenu(MainWindowType type) ClosePauseMenu(); } - if (ActiveButton(GSConfig.UseHardwareRenderer() ? (FSUI_ICONSTR(ICON_FA_PAINT_BRUSH, "Switch To Software Renderer")) : + if (ActiveButton(GSIsHardwareRenderer() ? (FSUI_ICONSTR(ICON_FA_PAINT_BRUSH, "Switch To Software Renderer")) : (FSUI_ICONSTR(ICON_FA_PAINT_BRUSH, "Switch To Hardware Renderer")), false)) { diff --git a/pcsx2/ImGui/ImGuiOverlays.cpp b/pcsx2/ImGui/ImGuiOverlays.cpp index 54efe28374..da61d57e20 100644 --- a/pcsx2/ImGui/ImGuiOverlays.cpp +++ b/pcsx2/ImGui/ImGuiOverlays.cpp @@ -355,7 +355,7 @@ void ImGuiManager::DrawSettingsOverlay() EmuConfig.EnableNoInterlacingPatches ? "N" : ""); } - if (GSConfig.UseHardwareRenderer()) + if (GSIsHardwareRenderer()) { if ((GSConfig.UpscaleMultiplier - std::floor(GSConfig.UpscaleMultiplier)) > 0.01) APPEND("IR={:.2f} ", static_cast(GSConfig.UpscaleMultiplier)); diff --git a/pcsx2/MTGS.cpp b/pcsx2/MTGS.cpp index 74d1559dde..2d7c2d5696 100644 --- a/pcsx2/MTGS.cpp +++ b/pcsx2/MTGS.cpp @@ -268,7 +268,7 @@ void MTGS::PostVsyncStart(bool registers_written) void MTGS::InitAndReadFIFO(u8* mem, u32 qwc) { - if (EmuConfig.GS.HWDownloadMode >= GSHardwareDownloadMode::Unsynchronized && GSConfig.UseHardwareRenderer()) + if (EmuConfig.GS.HWDownloadMode >= GSHardwareDownloadMode::Unsynchronized && GSIsHardwareRenderer()) { if (EmuConfig.GS.HWDownloadMode == GSHardwareDownloadMode::Unsynchronized) GSReadLocalMemoryUnsync(mem, qwc, vif1.BITBLTBUF._u64, vif1.TRXPOS._u64, vif1.TRXREG._u64); @@ -977,18 +977,19 @@ void MTGS::UpdateVSyncMode() SetVSyncMode(Host::GetEffectiveVSyncMode()); } -void MTGS::SwitchRenderer(GSRendererType renderer, GSInterlaceMode interlace, bool display_message /* = true */) +void MTGS::SetSoftwareRendering(bool software, GSInterlaceMode interlace, bool display_message /* = true */) { pxAssertRel(IsOpen(), "MTGS is running"); if (display_message) { - Host::AddIconOSDMessage("SwitchRenderer", ICON_FA_MAGIC, fmt::format("Switching to {} renderer...", - Pcsx2Config::GSOptions::GetRendererName(renderer)), Host::OSD_INFO_DURATION); + Host::AddIconOSDMessage("SwitchRenderer", ICON_FA_MAGIC, software ? + TRANSLATE_STR("GS", "Switching to software renderer...") : TRANSLATE_STR("GS", "Switching to hardware renderer..."), + Host::OSD_QUICK_DURATION); } - RunOnGSThread([renderer, interlace]() { - GSSwitchRenderer(renderer, interlace); + RunOnGSThread([software, interlace]() { + GSSetSoftwareRendering(software, interlace); }); // See note in ApplySettings() for reasoning here. @@ -996,22 +997,10 @@ void MTGS::SwitchRenderer(GSRendererType renderer, GSInterlaceMode interlace, bo WaitGS(false, false, false); } -void MTGS::SetSoftwareRendering(bool software, bool display_message /* = true */) -{ - // for hardware, use the chosen api in the base config, or auto if base is set to sw - GSRendererType new_renderer; - if (!software) - new_renderer = EmuConfig.GS.UseHardwareRenderer() ? EmuConfig.GS.Renderer : GSRendererType::Auto; - else - new_renderer = GSRendererType::SW; - - SwitchRenderer(new_renderer, EmuConfig.GS.InterlaceMode, display_message); -} - void MTGS::ToggleSoftwareRendering() { // reading from the GS thread.. but should be okay here - SetSoftwareRendering(GSConfig.Renderer != GSRendererType::SW); + SetSoftwareRendering(GSIsHardwareRenderer(), EmuConfig.GS.InterlaceMode); } bool MTGS::SaveMemorySnapshot(u32 window_width, u32 window_height, bool apply_aspect, bool crop_borders, diff --git a/pcsx2/MTGS.h b/pcsx2/MTGS.h index 4d9eed518b..6f2cb77773 100644 --- a/pcsx2/MTGS.h +++ b/pcsx2/MTGS.h @@ -72,8 +72,7 @@ namespace MTGS void UpdateDisplayWindow(); void SetVSyncMode(VsyncMode mode); void UpdateVSyncMode(); - void SwitchRenderer(GSRendererType renderer, GSInterlaceMode interlace, bool display_message = true); - void SetSoftwareRendering(bool software, bool display_message = true); + void SetSoftwareRendering(bool software, GSInterlaceMode interlace, bool display_message = true); void ToggleSoftwareRendering(); bool SaveMemorySnapshot(u32 window_width, u32 window_height, bool apply_aspect, bool crop_borders, u32* width, u32* height, std::vector* pixels); diff --git a/pcsx2/Pcsx2Config.cpp b/pcsx2/Pcsx2Config.cpp index 83b357a1f1..880fdd0f40 100644 --- a/pcsx2/Pcsx2Config.cpp +++ b/pcsx2/Pcsx2Config.cpp @@ -962,8 +962,7 @@ void Pcsx2Config::GSOptions::LoadSave(SettingsWrapper& wrap) #undef GSSettingStringEx // Sanity check: don't dump a bunch of crap in the current working directory. - const std::string& dump_dir = UseHardwareRenderer() ? HWDumpDirectory : SWDumpDirectory; - if (DumpGSData && dump_dir.empty()) + if (DumpGSData && (HWDumpDirectory.empty() || SWDumpDirectory.empty())) { Console.Error("Draw dumping is enabled but directory is unconfigured, please set one."); DumpGSData = false;