GS: Refactor renderer switching

- Fix automatic renderer causing delay when changing settings.
 - Make the Debug -> Switch Renderer menu actually save.
This commit is contained in:
Stenzek 2023-12-31 17:45:13 +10:00 committed by Connor McLaughlin
parent 68df8bf8ea
commit f388de26ab
16 changed files with 148 additions and 145 deletions

View File

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

View File

@ -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<GSRendererType>(
Host::GetBaseIntSettingValue("EmuCore/GS", "Renderer", static_cast<int>(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<int>(renderer));
Host::CommitBaseSettingChanges();
g_emu_thread->applySettings();
// clear all others
for (QObject* obj : m_ui.menuDebugSwitchRenderer->children())
{
if (QAction* act = qobject_cast<QAction*>(obj); act && act != action)
act->setChecked(false);
}
});
}
}

View File

@ -205,6 +205,7 @@ private:
void setupAdditionalUi();
void connectSignals();
void createRendererSwitchMenu();
void recreate();
void recreateSettings();
void destroySubWindows();

View File

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

View File

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

View File

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

View File

@ -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,12 +220,10 @@ 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<const Pcsx2Config::GSOptions*> 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);
if (GSConfig.UserHacks_ReadTCOnClose)
@ -218,7 +231,7 @@ bool GSreopen(bool recreate_device, bool recreate_renderer, const Pcsx2Config::G
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,16 +242,13 @@ bool GSreopen(bool recreate_device, bool recreate_renderer, const Pcsx2Config::G
u8* basemem = g_gs_renderer->GetRegsMem();
freezeData fd = {};
std::unique_ptr<u8[]> fd_data;
if (recreate_renderer)
{
if (g_gs_renderer->Freeze(&fd, true) != 0)
{
Console.Error("(GSreopen) Failed to get GS freeze size");
return false;
}
fd_data = std::make_unique<u8[]>(fd.size);
std::unique_ptr<u8[]> fd_data = std::make_unique<u8[]>(fd.size);
fd.data = fd_data.get();
if (g_gs_renderer->Freeze(&fd, false) != 0)
{
@ -247,13 +257,6 @@ bool GSreopen(bool recreate_device, bool recreate_renderer, const Pcsx2Config::G
}
CloseGSRenderer();
}
else
{
// Make sure nothing is left over.
g_gs_renderer->PurgeTextureCache(true, true, true);
g_gs_renderer->PurgePool();
}
if (recreate_device)
{
@ -261,8 +264,7 @@ bool GSreopen(bool recreate_device, bool recreate_renderer, const Pcsx2Config::G
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,23 +283,18 @@ bool GSreopen(bool recreate_device, bool recreate_renderer, const Pcsx2Config::G
}
}
}
else if (recreate_renderer)
{
if (!OpenGSRenderer(GSConfig.Renderer, basemem))
if (!OpenGSRenderer(new_renderer, basemem))
{
Console.Error("(GSreopen) Failed to create new renderer");
return false;
}
}
if (recreate_renderer)
{
if (g_gs_renderer->Defrost(&fd) != 0)
{
Console.Error("(GSreopen) Failed to defrost");
return false;
}
}
if (!capture_filename.empty())
g_gs_renderer->BeginCapture(std::move(capture_filename), capture_size);
@ -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<int>(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))
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,

View File

@ -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<const Pcsx2Config::GSOptions*> 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<u32>* pixels);
void GSJoinSnapshotThreads();
@ -135,3 +134,5 @@ namespace Host
void OnCaptureStarted(const std::string& filename);
void OnCaptureStopped();
}
extern Pcsx2Config::GSOptions GSConfig;

View File

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

View File

@ -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;
preferred_renderer = GSRendererType::Metal;
#elif defined(_WIN32)
// Use D3D device info to select renderer.
return D3D::GetPreferredRenderer();
preferred_renderer = D3D::GetPreferredRenderer();
#else
// Linux: Prefer Vulkan if the driver isn't buggy.
#if defined(ENABLE_VULKAN)
if (GSDeviceVK::IsSuitableDefaultRenderer())
return GSRendererType::VK;
preferred_renderer = GSRendererType::VK;
#endif
// 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)

View File

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

View File

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

View File

@ -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<float>(GSConfig.UpscaleMultiplier));

View File

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

View File

@ -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<u32>* pixels);

View File

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