mirror of https://github.com/PCSX2/pcsx2.git
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:
parent
68df8bf8ea
commit
f388de26ab
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -205,6 +205,7 @@ private:
|
|||
|
||||
void setupAdditionalUi();
|
||||
void connectSignals();
|
||||
void createRendererSwitchMenu();
|
||||
void recreate();
|
||||
void recreateSettings();
|
||||
void destroySubWindows();
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
126
pcsx2/GS/GS.cpp
126
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<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);
|
||||
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<u8[]> 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<u8[]>(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<u8[]> fd_data = std::make_unique<u8[]>(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<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))
|
||||
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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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];
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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))
|
||||
{
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue