Skip to content

Commit

Permalink
GS: Uncap upscale multiplier subject to GPU limits
Browse files Browse the repository at this point in the history
  • Loading branch information
stenzek committed Jul 2, 2024
1 parent 46e3046 commit 315d30f
Show file tree
Hide file tree
Showing 18 changed files with 313 additions and 197 deletions.
112 changes: 94 additions & 18 deletions pcsx2-qt/Settings/GraphicsSettingsWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,13 +140,6 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget*
//////////////////////////////////////////////////////////////////////////
// HW Settings
//////////////////////////////////////////////////////////////////////////
static const char* upscale_entries[] = {"Native (PS2) (Default)", "1.25x Native", "1.5x Native", "1.75x Native", "2x Native (~720p)",
"2.25x Native", "2.5x Native", "2.75x Native", "3x Native (~1080p)", "3.5x Native", "4x Native (~1440p/2K)", "5x Native (~1620p)",
"6x Native (~2160p/4K)", "7x Native (~2520p)", "8x Native (~2880p/5K)", nullptr};
static const char* upscale_values[] = {
"1", "1.25", "1.5", "1.75", "2", "2.25", "2.5", "2.75", "3", "3.5", "4", "5", "6", "7", "8", nullptr};
SettingWidgetBinder::BindWidgetToEnumSetting(
sif, m_ui.upscaleMultiplier, "EmuCore/GS", "upscale_multiplier", upscale_entries, upscale_values, "1.0");
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.textureFiltering, "EmuCore/GS", "filter", static_cast<int>(BiFiltering::PS2));
SettingWidgetBinder::BindWidgetToIntSetting(
sif, m_ui.trilinearFiltering, "EmuCore/GS", "TriFilter", static_cast<int>(TriFiltering::Automatic), -1);
Expand All @@ -158,6 +151,8 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget*
sif, m_ui.blending, "EmuCore/GS", "accurate_blending_unit", static_cast<int>(AccBlendLevel::Basic));
SettingWidgetBinder::BindWidgetToIntSetting(
sif, m_ui.texturePreloading, "EmuCore/GS", "texture_preloading", static_cast<int>(TexturePreloadingLevel::Off));
connect(m_ui.upscaleMultiplier, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
&GraphicsSettingsWidget::onUpscaleMultiplierChanged);
connect(m_ui.trilinearFiltering, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
&GraphicsSettingsWidget::onTrilinearFilteringChanged);
onTrilinearFilteringChanged();
Expand Down Expand Up @@ -1036,10 +1031,9 @@ void GraphicsSettingsWidget::updateRendererDependentOptions()
m_ui.exclusiveFullscreenControl->setEnabled(is_auto || is_vk);

// populate adapters
std::vector<std::string> adapters;
std::vector<std::string> fullscreen_modes;
GSGetAdaptersAndFullscreenModes(type, &adapters, &fullscreen_modes);

std::vector<GSAdapterInfo> adapters = GSGetAdapterInfo(type);
const GSAdapterInfo* current_adapter_info = nullptr;

// fill+select adapters
{
QSignalBlocker sb(m_ui.adapterDropdown);
Expand All @@ -1062,12 +1056,17 @@ void GraphicsSettingsWidget::updateRendererDependentOptions()
}
}

for (const std::string& adapter : adapters)
for (const GSAdapterInfo& adapter : adapters)
{
m_ui.adapterDropdown->addItem(QString::fromStdString(adapter));
if (current_adapter == adapter)
m_ui.adapterDropdown->addItem(QString::fromStdString(adapter.name));
if (current_adapter == adapter.name)
{
m_ui.adapterDropdown->setCurrentIndex(m_ui.adapterDropdown->count() - 1);
current_adapter_info = &adapter;
}
}

current_adapter_info = (current_adapter_info || adapters.empty()) ? current_adapter_info : &adapters.front();
}

// fill+select fullscreen modes
Expand All @@ -1090,13 +1089,90 @@ void GraphicsSettingsWidget::updateRendererDependentOptions()
}
}

for (const std::string& fs_mode : fullscreen_modes)
if (current_adapter_info)
{
m_ui.fullscreenModes->addItem(QString::fromStdString(fs_mode));
if (current_mode == fs_mode)
m_ui.fullscreenModes->setCurrentIndex(m_ui.fullscreenModes->count() - 1);
for (const std::string& fs_mode : current_adapter_info->fullscreen_modes)
{
m_ui.fullscreenModes->addItem(QString::fromStdString(fs_mode));
if (current_mode == fs_mode)
m_ui.fullscreenModes->setCurrentIndex(m_ui.fullscreenModes->count() - 1);
}
}
}

// assume the GPU can do 10K textures.
const u32 max_upscale_multiplier = std::max(current_adapter_info ? current_adapter_info->max_upscale_multiplier : 0u, 10u);
populateUpscaleMultipliers(max_upscale_multiplier);
}

void GraphicsSettingsWidget::populateUpscaleMultipliers(u32 max_upscale_multiplier)
{
static constexpr std::pair<const char*, float> templates[] = {
{QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "Native (PS2) (Default)"), 1.0f},
{QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "1.25x Native"), 1.25f},
{QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "1.5x Native"), 1.5f},
{QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "1.75x Native"), 1.75f},
{QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "2x Native (~720p)"), 2.0f},
{QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "2.25x Native"), 2.25f},
{QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "2.5x Native"), 2.5f},
{QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "2.75x Native"), 2.75f},
{QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "3x Native (~1080p)"), 3.0f},
{QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "3.5x Native"), 3.5f},
{QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "4x Native (~1440p/2K)"), 4.0f},
{QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "5x Native (~1620p)"), 5.0f},
{QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "6x Native (~2160p/4K)"), 6.0f},
{QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "7x Native (~2520p)"), 7.0f},
{QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "8x Native (~2880p/5K)"), 8.0f},
};
static constexpr u32 max_template_multiplier = 8;

// Limit the dropdown to 12x if we're not showing advanced settings. Save the noobs.
static constexpr u32 max_non_advanced_multiplier = 12;

QSignalBlocker sb(m_ui.upscaleMultiplier);
m_ui.upscaleMultiplier->clear();

for (const auto& [name, value] : templates)
{
if (value > max_upscale_multiplier)
continue;

m_ui.upscaleMultiplier->addItem(tr(name), QVariant(value));
}
const u32 max_shown_multiplier = QtHost::ShouldShowAdvancedSettings() ?
max_upscale_multiplier :
std::min(max_upscale_multiplier, max_non_advanced_multiplier);
for (u32 i = max_template_multiplier + 1; i <= max_shown_multiplier; i++)
m_ui.upscaleMultiplier->addItem(tr("%1x Native ").arg(i), QVariant(static_cast<float>(i)));

const float global_value = Host::GetBaseFloatSettingValue("EmuCore/GS", "upscale_multiplier", 1.0f);
if (m_dialog->isPerGameSettings())
{
m_ui.upscaleMultiplier->addItem(tr("Use Global Setting [%1]").arg(QStringLiteral("%1x").arg(global_value)));

const std::optional<float> config_value = m_dialog->getFloatValue("EmuCore/GS", "upscale_multiplier", std::nullopt);
if (config_value.has_value())
{
if (int index = m_ui.upscaleMultiplier->findData(QVariant(config_value.value())); index > 0)
m_ui.upscaleMultiplier->setCurrentIndex(index);
}
else
{
m_ui.upscaleMultiplier->setCurrentIndex(0);
}
}
else
{
if (int index = m_ui.upscaleMultiplier->findData(QVariant(global_value)); index > 0)
m_ui.upscaleMultiplier->setCurrentIndex(index);
}
}

void GraphicsSettingsWidget::onUpscaleMultiplierChanged()
{
const QVariant data = m_ui.upscaleMultiplier->currentData();
m_dialog->setFloatSettingValue("EmuCore/GS", "upscale_multiplier",
data.isValid() ? std::optional<float>(data.toFloat()) : std::optional<float>());
}

void GraphicsSettingsWidget::resetManualHardwareFixes()
Expand Down
2 changes: 2 additions & 0 deletions pcsx2-qt/Settings/GraphicsSettingsWidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ private Q_SLOTS:
void onSWTextureFilteringChange();
void onRendererChanged(int index);
void onAdapterChanged(int index);
void onUpscaleMultiplierChanged();
void onTrilinearFilteringChanged();
void onGpuPaletteConversionChanged(int state);
void onCPUSpriteRenderBWChanged();
Expand All @@ -46,6 +47,7 @@ private Q_SLOTS:
private:
GSRendererType getEffectiveRenderer() const;
void updateRendererDependentOptions();
void populateUpscaleMultipliers(u32 max_upscale_multiplier);
void resetManualHardwareFixes();

SettingsWindow* m_dialog;
Expand Down
48 changes: 37 additions & 11 deletions pcsx2/GS/GS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@
#include "common/SmallString.h"
#include "common/StringUtil.h"

#include "IconsFontAwesome5.h"

#include "fmt/format.h"

#include <fstream>
Expand Down Expand Up @@ -171,6 +173,24 @@ static void CloseGSDevice(bool clear_state)
g_gs_device.reset();
}

static void GSClampUpscaleMultiplier(Pcsx2Config::GSOptions& config)
{
const u32 max_upscale_multiplier = GSGetMaxUpscaleMultiplier(g_gs_device->GetMaxTextureSize());
if (config.UpscaleMultiplier <= static_cast<float>(max_upscale_multiplier))
{
// Shouldn't happen, but just in case.
if (config.UpscaleMultiplier < 1.0f)
config.UpscaleMultiplier = 1.0f;
return;
}

Host::AddIconOSDMessage("GSUpscaleMultiplierInvalid", ICON_FA_EXCLAMATION_TRIANGLE,
fmt::format(TRANSLATE_FS("GS", "Configured upscale multiplier {}x is above your GPU's supported multiplier of {}x."),
config.UpscaleMultiplier, max_upscale_multiplier),
Host::OSD_WARNING_DURATION);
config.UpscaleMultiplier = static_cast<float>(max_upscale_multiplier);
}

static bool OpenGSRenderer(GSRendererType renderer, u8* basemem)
{
// Must be done first, initialization routines in GSState use GSIsHardwareRenderer().
Expand All @@ -184,6 +204,7 @@ static bool OpenGSRenderer(GSRendererType renderer, u8* basemem)
}
else if (renderer != GSRendererType::SW)
{
GSClampUpscaleMultiplier(GSConfig);
g_gs_renderer = std::make_unique<GSRendererHW>();
}
else
Expand Down Expand Up @@ -548,9 +569,9 @@ std::optional<float> GSGetHostRefreshRate()
return surface_refresh_rate;
}

void GSGetAdaptersAndFullscreenModes(
GSRendererType renderer, std::vector<std::string>* adapters, std::vector<std::string>* fullscreen_modes)
std::vector<GSAdapterInfo> GSGetAdapterInfo(GSRendererType renderer)
{
std::vector<GSAdapterInfo> ret;
switch (renderer)
{
#ifdef _WIN32
Expand All @@ -559,36 +580,38 @@ void GSGetAdaptersAndFullscreenModes(
{
auto factory = D3D::CreateFactory(false);
if (factory)
{
if (adapters)
*adapters = D3D::GetAdapterNames(factory.get());
if (fullscreen_modes)
*fullscreen_modes = D3D::GetFullscreenModes(factory.get(), EmuConfig.GS.Adapter);
}
ret = D3D::GetAdapterInfo(factory.get());
}
break;
#endif

#ifdef ENABLE_VULKAN
case GSRendererType::VK:
{
GSDeviceVK::GetAdaptersAndFullscreenModes(adapters, fullscreen_modes);
ret = GSDeviceVK::GetAdapterInfo();
}
break;
#endif

#ifdef __APPLE__
case GSRendererType::Metal:
{
if (adapters)
*adapters = GetMetalAdapterList();
ret = GetMetalAdapterList();
}
break;
#endif

default:
break;
}

return ret;
}

u32 GSGetMaxUpscaleMultiplier(u32 max_texture_size)
{
// Maximum GS target size is 1280x1280. Assume we want to upscale the max size target.
return std::max(max_texture_size / 1280, 1u);
}

GSVideoMode GSgetDisplayMode()
Expand Down Expand Up @@ -712,6 +735,9 @@ void GSUpdateConfig(const Pcsx2Config::GSOptions& new_config)
return;
}

// Ensure upscale multiplier is in range.
GSClampUpscaleMultiplier(GSConfig);

// Options which aren't using the global struct yet, so we need to recreate all GS objects.
if (GSConfig.SWExtraThreads != old_config.SWExtraThreads ||
GSConfig.SWExtraThreadsHeight != old_config.SWExtraThreadsHeight)
Expand Down
12 changes: 10 additions & 2 deletions pcsx2/GS/GS.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,14 @@ enum class GSDisplayAlignment
RightOrBottom
};

struct GSAdapterInfo
{
std::string name;
std::vector<std::string> fullscreen_modes;
u32 max_texture_size;
u32 max_upscale_multiplier;
};

class SmallStringBase;

// Returns the ID for the specified function, otherwise -1.
Expand Down Expand Up @@ -83,8 +91,8 @@ GSRendererType GSGetCurrentRenderer();
bool GSIsHardwareRenderer();
bool GSWantsExclusiveFullscreen();
std::optional<float> GSGetHostRefreshRate();
void GSGetAdaptersAndFullscreenModes(
GSRendererType renderer, std::vector<std::string>* adapters, std::vector<std::string>* fullscreen_modes);
std::vector<GSAdapterInfo> GSGetAdapterInfo(GSRendererType renderer);
u32 GSGetMaxUpscaleMultiplier(u32 max_texture_size);
GSVideoMode GSgetDisplayMode();
void GSgetInternalResolution(int* width, int* height);
void GSgetStats(SmallStringBase& info);
Expand Down
9 changes: 5 additions & 4 deletions pcsx2/GS/Renderers/Common/GSDevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,8 @@ void GSDevice::TextureRecycleDeleter::operator()(GSTexture* const tex)

GSTexture* GSDevice::FetchSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format, bool clear, bool prefer_unused_texture)
{
const GSVector2i size(width, height);
const GSVector2i size(std::clamp(width, 1, static_cast<int>(g_gs_device->GetMaxTextureSize())),
std::clamp(height, 1, static_cast<int>(g_gs_device->GetMaxTextureSize())));
FastList<GSTexture*>& pool = m_pool[type != GSTexture::Type::Texture];

GSTexture* t = nullptr;
Expand Down Expand Up @@ -475,14 +476,14 @@ GSTexture* GSDevice::FetchSurface(GSTexture::Type type, int width, int height, i
}
else
{
t = CreateSurface(type, width, height, levels, format);
t = CreateSurface(type, size.x, size.y, levels, format);
if (!t)
{
Console.Error("GS: Memory allocation failure for %dx%d texture. Purging pool and retrying.", width, height);
ERROR_LOG("GS: Memory allocation failure for {}x{} texture. Purging pool and retrying.", size.x, size.y);
PurgePool();
if (!t)
{
Console.Error("GS: Memory allocation failure for %dx%d texture after purging pool.", width, height);
ERROR_LOG("GS: Memory allocation failure for {}x{} texture after purging pool.", size.x, size.y);
return nullptr;
}
}
Expand Down
2 changes: 2 additions & 0 deletions pcsx2/GS/Renderers/Common/GSDevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -804,6 +804,7 @@ class GSDevice : public GSAlignedClass<32>

protected:
FeatureSupport m_features;
u32 m_max_texture_size = 0;

struct
{
Expand Down Expand Up @@ -888,6 +889,7 @@ class GSDevice : public GSAlignedClass<32>
__fi u64 GetPoolMemoryUsage() const { return m_pool_memory_usage; }

__fi FeatureSupport Features() const { return m_features; }
__fi u32 GetMaxTextureSize() const { return m_max_texture_size; }

__fi const WindowInfo& GetWindowInfo() const { return m_window_info; }
__fi s32 GetWindowWidth() const { return static_cast<s32>(m_window_info.surface_width); }
Expand Down
Loading

0 comments on commit 315d30f

Please sign in to comment.