GS: Uncap upscale multiplier subject to GPU limits

This commit is contained in:
Stenzek 2024-07-01 00:21:03 +10:00 committed by Connor McLaughlin
parent 46e30467de
commit 315d30fe4c
18 changed files with 316 additions and 200 deletions

View File

@ -140,13 +140,6 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget*
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// HW Settings // 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.textureFiltering, "EmuCore/GS", "filter", static_cast<int>(BiFiltering::PS2));
SettingWidgetBinder::BindWidgetToIntSetting( SettingWidgetBinder::BindWidgetToIntSetting(
sif, m_ui.trilinearFiltering, "EmuCore/GS", "TriFilter", static_cast<int>(TriFiltering::Automatic), -1); sif, m_ui.trilinearFiltering, "EmuCore/GS", "TriFilter", static_cast<int>(TriFiltering::Automatic), -1);
@ -158,6 +151,8 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget*
sif, m_ui.blending, "EmuCore/GS", "accurate_blending_unit", static_cast<int>(AccBlendLevel::Basic)); sif, m_ui.blending, "EmuCore/GS", "accurate_blending_unit", static_cast<int>(AccBlendLevel::Basic));
SettingWidgetBinder::BindWidgetToIntSetting( SettingWidgetBinder::BindWidgetToIntSetting(
sif, m_ui.texturePreloading, "EmuCore/GS", "texture_preloading", static_cast<int>(TexturePreloadingLevel::Off)); 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, connect(m_ui.trilinearFiltering, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
&GraphicsSettingsWidget::onTrilinearFilteringChanged); &GraphicsSettingsWidget::onTrilinearFilteringChanged);
onTrilinearFilteringChanged(); onTrilinearFilteringChanged();
@ -1036,10 +1031,9 @@ void GraphicsSettingsWidget::updateRendererDependentOptions()
m_ui.exclusiveFullscreenControl->setEnabled(is_auto || is_vk); m_ui.exclusiveFullscreenControl->setEnabled(is_auto || is_vk);
// populate adapters // populate adapters
std::vector<std::string> adapters; std::vector<GSAdapterInfo> adapters = GSGetAdapterInfo(type);
std::vector<std::string> fullscreen_modes; const GSAdapterInfo* current_adapter_info = nullptr;
GSGetAdaptersAndFullscreenModes(type, &adapters, &fullscreen_modes);
// fill+select adapters // fill+select adapters
{ {
QSignalBlocker sb(m_ui.adapterDropdown); QSignalBlocker sb(m_ui.adapterDropdown);
@ -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)); m_ui.adapterDropdown->addItem(QString::fromStdString(adapter.name));
if (current_adapter == adapter) if (current_adapter == adapter.name)
{
m_ui.adapterDropdown->setCurrentIndex(m_ui.adapterDropdown->count() - 1); 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 // fill+select fullscreen modes
@ -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)); for (const std::string& fs_mode : current_adapter_info->fullscreen_modes)
if (current_mode == fs_mode) {
m_ui.fullscreenModes->setCurrentIndex(m_ui.fullscreenModes->count() - 1); 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() void GraphicsSettingsWidget::resetManualHardwareFixes()

View File

@ -29,6 +29,7 @@ private Q_SLOTS:
void onSWTextureFilteringChange(); void onSWTextureFilteringChange();
void onRendererChanged(int index); void onRendererChanged(int index);
void onAdapterChanged(int index); void onAdapterChanged(int index);
void onUpscaleMultiplierChanged();
void onTrilinearFilteringChanged(); void onTrilinearFilteringChanged();
void onGpuPaletteConversionChanged(int state); void onGpuPaletteConversionChanged(int state);
void onCPUSpriteRenderBWChanged(); void onCPUSpriteRenderBWChanged();
@ -46,6 +47,7 @@ private Q_SLOTS:
private: private:
GSRendererType getEffectiveRenderer() const; GSRendererType getEffectiveRenderer() const;
void updateRendererDependentOptions(); void updateRendererDependentOptions();
void populateUpscaleMultipliers(u32 max_upscale_multiplier);
void resetManualHardwareFixes(); void resetManualHardwareFixes();
SettingsWindow* m_dialog; SettingsWindow* m_dialog;

View File

@ -48,6 +48,8 @@
#include "common/SmallString.h" #include "common/SmallString.h"
#include "common/StringUtil.h" #include "common/StringUtil.h"
#include "IconsFontAwesome5.h"
#include "fmt/format.h" #include "fmt/format.h"
#include <fstream> #include <fstream>
@ -171,6 +173,24 @@ static void CloseGSDevice(bool clear_state)
g_gs_device.reset(); 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) static bool OpenGSRenderer(GSRendererType renderer, u8* basemem)
{ {
// Must be done first, initialization routines in GSState use GSIsHardwareRenderer(). // Must be done first, initialization routines in GSState use GSIsHardwareRenderer().
@ -184,6 +204,7 @@ static bool OpenGSRenderer(GSRendererType renderer, u8* basemem)
} }
else if (renderer != GSRendererType::SW) else if (renderer != GSRendererType::SW)
{ {
GSClampUpscaleMultiplier(GSConfig);
g_gs_renderer = std::make_unique<GSRendererHW>(); g_gs_renderer = std::make_unique<GSRendererHW>();
} }
else else
@ -548,9 +569,9 @@ std::optional<float> GSGetHostRefreshRate()
return surface_refresh_rate; return surface_refresh_rate;
} }
void GSGetAdaptersAndFullscreenModes( std::vector<GSAdapterInfo> GSGetAdapterInfo(GSRendererType renderer)
GSRendererType renderer, std::vector<std::string>* adapters, std::vector<std::string>* fullscreen_modes)
{ {
std::vector<GSAdapterInfo> ret;
switch (renderer) switch (renderer)
{ {
#ifdef _WIN32 #ifdef _WIN32
@ -559,12 +580,7 @@ void GSGetAdaptersAndFullscreenModes(
{ {
auto factory = D3D::CreateFactory(false); auto factory = D3D::CreateFactory(false);
if (factory) if (factory)
{ ret = D3D::GetAdapterInfo(factory.get());
if (adapters)
*adapters = D3D::GetAdapterNames(factory.get());
if (fullscreen_modes)
*fullscreen_modes = D3D::GetFullscreenModes(factory.get(), EmuConfig.GS.Adapter);
}
} }
break; break;
#endif #endif
@ -572,7 +588,7 @@ void GSGetAdaptersAndFullscreenModes(
#ifdef ENABLE_VULKAN #ifdef ENABLE_VULKAN
case GSRendererType::VK: case GSRendererType::VK:
{ {
GSDeviceVK::GetAdaptersAndFullscreenModes(adapters, fullscreen_modes); ret = GSDeviceVK::GetAdapterInfo();
} }
break; break;
#endif #endif
@ -580,8 +596,7 @@ void GSGetAdaptersAndFullscreenModes(
#ifdef __APPLE__ #ifdef __APPLE__
case GSRendererType::Metal: case GSRendererType::Metal:
{ {
if (adapters) ret = GetMetalAdapterList();
*adapters = GetMetalAdapterList();
} }
break; break;
#endif #endif
@ -589,6 +604,14 @@ void GSGetAdaptersAndFullscreenModes(
default: default:
break; 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() GSVideoMode GSgetDisplayMode()
@ -712,6 +735,9 @@ void GSUpdateConfig(const Pcsx2Config::GSOptions& new_config)
return; 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. // Options which aren't using the global struct yet, so we need to recreate all GS objects.
if (GSConfig.SWExtraThreads != old_config.SWExtraThreads || if (GSConfig.SWExtraThreads != old_config.SWExtraThreads ||
GSConfig.SWExtraThreadsHeight != old_config.SWExtraThreadsHeight) GSConfig.SWExtraThreadsHeight != old_config.SWExtraThreadsHeight)

View File

@ -41,6 +41,14 @@ enum class GSDisplayAlignment
RightOrBottom RightOrBottom
}; };
struct GSAdapterInfo
{
std::string name;
std::vector<std::string> fullscreen_modes;
u32 max_texture_size;
u32 max_upscale_multiplier;
};
class SmallStringBase; class SmallStringBase;
// Returns the ID for the specified function, otherwise -1. // Returns the ID for the specified function, otherwise -1.
@ -83,8 +91,8 @@ GSRendererType GSGetCurrentRenderer();
bool GSIsHardwareRenderer(); bool GSIsHardwareRenderer();
bool GSWantsExclusiveFullscreen(); bool GSWantsExclusiveFullscreen();
std::optional<float> GSGetHostRefreshRate(); std::optional<float> GSGetHostRefreshRate();
void GSGetAdaptersAndFullscreenModes( std::vector<GSAdapterInfo> GSGetAdapterInfo(GSRendererType renderer);
GSRendererType renderer, std::vector<std::string>* adapters, std::vector<std::string>* fullscreen_modes); u32 GSGetMaxUpscaleMultiplier(u32 max_texture_size);
GSVideoMode GSgetDisplayMode(); GSVideoMode GSgetDisplayMode();
void GSgetInternalResolution(int* width, int* height); void GSgetInternalResolution(int* width, int* height);
void GSgetStats(SmallStringBase& info); void GSgetStats(SmallStringBase& info);

View File

@ -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) 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]; FastList<GSTexture*>& pool = m_pool[type != GSTexture::Type::Texture];
GSTexture* t = nullptr; GSTexture* t = nullptr;
@ -475,14 +476,14 @@ GSTexture* GSDevice::FetchSurface(GSTexture::Type type, int width, int height, i
} }
else else
{ {
t = CreateSurface(type, width, height, levels, format); t = CreateSurface(type, size.x, size.y, levels, format);
if (!t) 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(); PurgePool();
if (!t) 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; return nullptr;
} }
} }

View File

@ -804,6 +804,7 @@ public:
protected: protected:
FeatureSupport m_features; FeatureSupport m_features;
u32 m_max_texture_size = 0;
struct struct
{ {
@ -888,6 +889,7 @@ public:
__fi u64 GetPoolMemoryUsage() const { return m_pool_memory_usage; } __fi u64 GetPoolMemoryUsage() const { return m_pool_memory_usage; }
__fi FeatureSupport Features() const { return m_features; } __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 const WindowInfo& GetWindowInfo() const { return m_window_info; }
__fi s32 GetWindowWidth() const { return static_cast<s32>(m_window_info.surface_width); } __fi s32 GetWindowWidth() const { return static_cast<s32>(m_window_info.surface_width); }

View File

@ -42,10 +42,10 @@ wil::com_ptr_nothrow<IDXGIFactory5> D3D::CreateFactory(bool debug)
return factory; return factory;
} }
static std::string FixupDuplicateAdapterNames(const std::vector<std::string>& adapter_names, std::string adapter_name) static std::string FixupDuplicateAdapterNames(const std::vector<GSAdapterInfo>& adapters, std::string adapter_name)
{ {
if (std::any_of(adapter_names.begin(), adapter_names.end(), if (std::any_of(adapters.begin(), adapters.end(),
[&adapter_name](const std::string& other) { return (adapter_name == other); })) [&adapter_name](const GSAdapterInfo& other) { return (adapter_name == other.name); }))
{ {
std::string original_adapter_name = std::move(adapter_name); std::string original_adapter_name = std::move(adapter_name);
@ -54,73 +54,72 @@ static std::string FixupDuplicateAdapterNames(const std::vector<std::string>& ad
{ {
adapter_name = fmt::format("{} ({})", original_adapter_name.c_str(), current_extra); adapter_name = fmt::format("{} ({})", original_adapter_name.c_str(), current_extra);
current_extra++; current_extra++;
} while (std::any_of(adapter_names.begin(), adapter_names.end(), } while (std::any_of(adapters.begin(), adapters.end(),
[&adapter_name](const std::string& other) { return (adapter_name == other); })); [&adapter_name](const GSAdapterInfo& other) { return (adapter_name == other.name); }));
} }
return adapter_name; return adapter_name;
} }
std::vector<std::string> D3D::GetAdapterNames(IDXGIFactory5* factory) std::vector<GSAdapterInfo> D3D::GetAdapterInfo(IDXGIFactory5* factory)
{ {
std::vector<std::string> adapter_names; std::vector<GSAdapterInfo> adapters;
wil::com_ptr_nothrow<IDXGIAdapter1> adapter; wil::com_ptr_nothrow<IDXGIAdapter1> adapter;
for (u32 index = 0;; index++) for (u32 index = 0;; index++)
{ {
const HRESULT hr = factory->EnumAdapters1(index, adapter.put()); HRESULT hr = factory->EnumAdapters1(index, adapter.put());
if (hr == DXGI_ERROR_NOT_FOUND) if (hr == DXGI_ERROR_NOT_FOUND)
break; break;
if (FAILED(hr)) if (FAILED(hr))
{ {
Console.Error(fmt::format("IDXGIFactory2::EnumAdapters() returned %08X", hr)); ERROR_LOG("IDXGIFactory2::EnumAdapters() returned {:08X}", static_cast<unsigned>(hr));
continue; continue;
} }
adapter_names.push_back(FixupDuplicateAdapterNames(adapter_names, GetAdapterName(adapter.get()))); GSAdapterInfo ai;
ai.name = FixupDuplicateAdapterNames(adapters, GetAdapterName(adapter.get()));
// Unfortunately we can't get any properties such as feature level without creating the device.
// So just assume a max of the D3D11 max across the board.
ai.max_texture_size = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION;
ai.max_upscale_multiplier = GSGetMaxUpscaleMultiplier(ai.max_texture_size);
wil::com_ptr_nothrow<IDXGIOutput> output;
if (SUCCEEDED(hr = adapter->EnumOutputs(0, &output)))
{
UINT num_modes = 0;
if (SUCCEEDED(hr = output->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, 0, &num_modes, nullptr)))
{
std::vector<DXGI_MODE_DESC> dmodes(num_modes);
if (SUCCEEDED(hr = output->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, 0, &num_modes, dmodes.data())))
{
for (const DXGI_MODE_DESC& mode : dmodes)
{
ai.fullscreen_modes.push_back(GSDevice::GetFullscreenModeString(mode.Width, mode.Height,
static_cast<float>(mode.RefreshRate.Numerator) / static_cast<float>(mode.RefreshRate.Denominator)));
}
}
else
{
ERROR_LOG("GetDisplayModeList() (2) failed: {:08X}", static_cast<unsigned>(hr));
}
}
else
{
ERROR_LOG("GetDisplayModeList() failed: {:08X}", static_cast<unsigned>(hr));
}
}
else
{
ERROR_LOG("EnumOutputs() failed: {:08X}", static_cast<unsigned>(hr));
}
adapters.push_back(std::move(ai));
} }
return adapter_names; return adapters;
}
std::vector<std::string> D3D::GetFullscreenModes(IDXGIFactory5* factory, const std::string_view adapter_name)
{
std::vector<std::string> modes;
HRESULT hr;
wil::com_ptr_nothrow<IDXGIAdapter1> adapter = GetChosenOrFirstAdapter(factory, adapter_name);
if (!adapter)
return modes;
wil::com_ptr_nothrow<IDXGIOutput> output;
if (FAILED(hr = adapter->EnumOutputs(0, &output)))
{
Console.Error("EnumOutputs() failed: %08X", hr);
return modes;
}
UINT num_modes = 0;
if (FAILED(hr = output->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, 0, &num_modes, nullptr)))
{
Console.Error("GetDisplayModeList() failed: %08X", hr);
return modes;
}
std::vector<DXGI_MODE_DESC> dmodes(num_modes);
if (FAILED(hr = output->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, 0, &num_modes, dmodes.data())))
{
Console.Error("GetDisplayModeList() (2) failed: %08X", hr);
return modes;
}
for (const DXGI_MODE_DESC& mode : dmodes)
{
modes.push_back(GSDevice::GetFullscreenModeString(mode.Width, mode.Height,
static_cast<float>(mode.RefreshRate.Numerator) / static_cast<float>(mode.RefreshRate.Denominator)));
}
return modes;
} }
bool D3D::GetRequestedExclusiveFullscreenModeDesc(IDXGIFactory5* factory, const RECT& window_rect, u32 width, bool D3D::GetRequestedExclusiveFullscreenModeDesc(IDXGIFactory5* factory, const RECT& window_rect, u32 width,
@ -187,7 +186,7 @@ bool D3D::GetRequestedExclusiveFullscreenModeDesc(IDXGIFactory5* factory, const
if (FAILED(hr = intersecting_output->FindClosestMatchingMode(&request_mode, fullscreen_mode, nullptr)) || if (FAILED(hr = intersecting_output->FindClosestMatchingMode(&request_mode, fullscreen_mode, nullptr)) ||
request_mode.Format != format) request_mode.Format != format)
{ {
Console.Error("Failed to find closest matching mode, hr=%08X", hr); ERROR_LOG("Failed to find closest matching mode, hr={:08X}", static_cast<unsigned>(hr));
return false; return false;
} }
@ -203,7 +202,7 @@ wil::com_ptr_nothrow<IDXGIAdapter1> D3D::GetAdapterByName(IDXGIFactory5* factory
// This might seem a bit odd to cache the names.. but there's a method to the madness. // This might seem a bit odd to cache the names.. but there's a method to the madness.
// We might have two GPUs with the same name... :) // We might have two GPUs with the same name... :)
std::vector<std::string> adapter_names; std::vector<GSAdapterInfo> adapter_names;
wil::com_ptr_nothrow<IDXGIAdapter1> adapter; wil::com_ptr_nothrow<IDXGIAdapter1> adapter;
for (u32 index = 0;; index++) for (u32 index = 0;; index++)
@ -214,18 +213,19 @@ wil::com_ptr_nothrow<IDXGIAdapter1> D3D::GetAdapterByName(IDXGIFactory5* factory
if (FAILED(hr)) if (FAILED(hr))
{ {
Console.Error(fmt::format("IDXGIFactory2::EnumAdapters() returned %08X", hr)); ERROR_LOG("IDXGIFactory2::EnumAdapters() returned {:08X}", static_cast<unsigned>(hr));
continue; continue;
} }
std::string adapter_name = FixupDuplicateAdapterNames(adapter_names, GetAdapterName(adapter.get())); GSAdapterInfo ai;
if (adapter_name == name) ai.name = FixupDuplicateAdapterNames(adapter_names, GetAdapterName(adapter.get()));
if (ai.name == name)
{ {
Console.WriteLn(fmt::format("D3D: Found adapter '{}'", adapter_name)); INFO_LOG("D3D: Found adapter '{}'", ai.name);
return adapter; return adapter;
} }
adapter_names.push_back(std::move(adapter_name)); adapter_names.push_back(std::move(ai));
} }
Console.Warning(fmt::format("Adapter '{}' not found.", name)); Console.Warning(fmt::format("Adapter '{}' not found.", name));
@ -404,9 +404,7 @@ GSRendererType D3D::GetPreferredRenderer()
if (check_for_mapping_layers()) if (check_for_mapping_layers())
return false; return false;
std::vector<std::string> vk_adapter_names; if (!GSDeviceVK::EnumerateGPUs().empty())
GSDeviceVK::GetAdaptersAndFullscreenModes(&vk_adapter_names, nullptr);
if (!vk_adapter_names.empty())
return true; return true;
Host::AddIconOSDMessage("VKDriverUnsupported", ICON_FA_TV, TRANSLATE_STR("GS", Host::AddIconOSDMessage("VKDriverUnsupported", ICON_FA_TV, TRANSLATE_STR("GS",

View File

@ -6,7 +6,8 @@
#include "common/RedtapeWindows.h" #include "common/RedtapeWindows.h"
#include "common/RedtapeWilCom.h" #include "common/RedtapeWilCom.h"
#include "pcsx2/Config.h" #include "Config.h"
#include "GS/GS.h"
#include <d3d11_1.h> #include <d3d11_1.h>
#include <dxgi1_5.h> #include <dxgi1_5.h>
@ -19,11 +20,8 @@ namespace D3D
// create a dxgi factory // create a dxgi factory
wil::com_ptr_nothrow<IDXGIFactory5> CreateFactory(bool debug); wil::com_ptr_nothrow<IDXGIFactory5> CreateFactory(bool debug);
// returns a list of all adapter names // returns a list of all adapter information
std::vector<std::string> GetAdapterNames(IDXGIFactory5* factory); std::vector<GSAdapterInfo> GetAdapterInfo(IDXGIFactory5* factory);
// returns a list of fullscreen modes for the specified adapter
std::vector<std::string> GetFullscreenModes(IDXGIFactory5* factory, const std::string_view adapter_name);
// returns the fullscreen mode to use for the specified dimensions // returns the fullscreen mode to use for the specified dimensions
bool GetRequestedExclusiveFullscreenModeDesc(IDXGIFactory5* factory, const RECT& window_rect, u32 width, u32 height, bool GetRequestedExclusiveFullscreenModeDesc(IDXGIFactory5* factory, const RECT& window_rect, u32 width, u32 height,

View File

@ -595,13 +595,10 @@ void GSDevice11::SetFeatures(IDXGIAdapter1* adapter)
m_features.vs_expand = false; m_features.vs_expand = false;
} }
} }
}
int GSDevice11::GetMaxTextureSize() const m_max_texture_size = (m_feature_level >= D3D_FEATURE_LEVEL_11_0) ?
{ D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION :
return (m_feature_level >= D3D_FEATURE_LEVEL_11_0) ? D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION;
D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION :
D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION;
} }
bool GSDevice11::HasSurface() const bool GSDevice11::HasSurface() const
@ -1185,10 +1182,8 @@ void GSDevice11::InsertDebugMessage(DebugMessageCategory category, const char* f
GSTexture* GSDevice11::CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) GSTexture* GSDevice11::CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format)
{ {
D3D11_TEXTURE2D_DESC desc = {}; D3D11_TEXTURE2D_DESC desc = {};
desc.Width = width;
// Texture limit for D3D10/11 min 1, max 8192 D3D10, max 16384 D3D11. desc.Height = height;
desc.Width = std::clamp(width, 1, GetMaxTextureSize());
desc.Height = std::clamp(height, 1, GetMaxTextureSize());
desc.Format = GSTexture11::GetDXGIFormat(format); desc.Format = GSTexture11::GetDXGIFormat(format);
desc.MipLevels = levels; desc.MipLevels = levels;
desc.ArraySize = 1; desc.ArraySize = 1;

View File

@ -91,7 +91,6 @@ private:
}; };
void SetFeatures(IDXGIAdapter1* adapter); void SetFeatures(IDXGIAdapter1* adapter);
int GetMaxTextureSize() const;
u32 GetSwapChainBufferCount() const; u32 GetSwapChainBufferCount() const;
bool CreateSwapChain(); bool CreateSwapChain();

View File

@ -1227,6 +1227,8 @@ bool GSDevice12::CheckFeatures()
SupportsTextureFormat(DXGI_FORMAT_BC3_UNORM); SupportsTextureFormat(DXGI_FORMAT_BC3_UNORM);
m_features.bptc_textures = SupportsTextureFormat(DXGI_FORMAT_BC7_UNORM); m_features.bptc_textures = SupportsTextureFormat(DXGI_FORMAT_BC7_UNORM);
m_max_texture_size = D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION;
BOOL allow_tearing_supported = false; BOOL allow_tearing_supported = false;
HRESULT hr = m_dxgi_factory->CheckFeatureSupport( HRESULT hr = m_dxgi_factory->CheckFeatureSupport(
DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allow_tearing_supported, sizeof(allow_tearing_supported)); DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allow_tearing_supported, sizeof(allow_tearing_supported));
@ -1289,22 +1291,19 @@ void GSDevice12::LookupNativeFormat(GSTexture::Format format, DXGI_FORMAT* d3d_f
GSTexture* GSDevice12::CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) GSTexture* GSDevice12::CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format)
{ {
const u32 clamped_width = static_cast<u32>(std::clamp<int>(width, 1, D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION));
const u32 clamped_height = static_cast<u32>(std::clamp<int>(height, 1, D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION));
DXGI_FORMAT dxgi_format, srv_format, rtv_format, dsv_format; DXGI_FORMAT dxgi_format, srv_format, rtv_format, dsv_format;
LookupNativeFormat(format, &dxgi_format, &srv_format, &rtv_format, &dsv_format); LookupNativeFormat(format, &dxgi_format, &srv_format, &rtv_format, &dsv_format);
const DXGI_FORMAT uav_format = (type == GSTexture::Type::RWTexture) ? dxgi_format : DXGI_FORMAT_UNKNOWN; const DXGI_FORMAT uav_format = (type == GSTexture::Type::RWTexture) ? dxgi_format : DXGI_FORMAT_UNKNOWN;
std::unique_ptr<GSTexture12> tex(GSTexture12::Create(type, format, clamped_width, clamped_height, levels, std::unique_ptr<GSTexture12> tex(GSTexture12::Create(type, format, width, height, levels,
dxgi_format, srv_format, rtv_format, dsv_format, uav_format)); dxgi_format, srv_format, rtv_format, dsv_format, uav_format));
if (!tex) if (!tex)
{ {
// We're probably out of vram, try flushing the command buffer to release pending textures. // We're probably out of vram, try flushing the command buffer to release pending textures.
PurgePool(); PurgePool();
ExecuteCommandListAndRestartRenderPass(true, "Couldn't allocate texture."); ExecuteCommandListAndRestartRenderPass(true, "Couldn't allocate texture.");
tex = GSTexture12::Create(type, format, clamped_width, clamped_height, levels, dxgi_format, srv_format, tex = GSTexture12::Create(type, format, width, height, levels, dxgi_format, srv_format,
rtv_format, dsv_format, uav_format); rtv_format, dsv_format, uav_format);
} }

View File

@ -25,12 +25,25 @@ GSDevice* MakeGSDeviceMTL()
return new GSDeviceMTL(); return new GSDeviceMTL();
} }
std::vector<std::string> GetMetalAdapterList() std::vector<GSAdapterInfo> GetMetalAdapterList()
{ @autoreleasepool { { @autoreleasepool {
std::vector<std::string> list; std::vector<GSAdapterInfo> list;
auto devs = MRCTransfer(MTLCopyAllDevices()); auto devs = MRCTransfer(MTLCopyAllDevices());
for (id<MTLDevice> dev in devs.Get()) for (id<MTLDevice> dev in devs.Get())
list.push_back([[dev name] UTF8String]); {
GSAdapterInfo ai;
ai.name = [[dev name] UTF8String];
ai.max_texture_size = 8192;
if ([dev supportsFeatureSet:MTLFeatureSet_macOS_GPUFamily1_v1])
ai.max_texture_size = 16384;
if (@available(macOS 10.15, iOS 13.0, *))
if ([dev supportsFamily:MTLGPUFamilyApple3])
ai.max_texture_size = 16384;
ai.max_upscale_multiplier = GSGetMaxUpscaleMultiplier(ai.max_texture_size);
list.push_back(std::move(ai));
}
return list; return list;
}} }}
@ -507,8 +520,8 @@ GSTexture* GSDeviceMTL::CreateSurface(GSTexture::Type type, int width, int heigh
MTLTextureDescriptor* desc = [MTLTextureDescriptor MTLTextureDescriptor* desc = [MTLTextureDescriptor
texture2DDescriptorWithPixelFormat:fmt texture2DDescriptorWithPixelFormat:fmt
width:std::max(1, std::min(width, m_dev.features.max_texsize)) width:width
height:std::max(1, std::min(height, m_dev.features.max_texsize)) height:height
mipmapped:levels > 1]; mipmapped:levels > 1];
if (levels > 1) if (levels > 1)
@ -905,6 +918,7 @@ bool GSDeviceMTL::Create(GSVSyncMode vsync_mode, bool allow_present_throttle)
m_features.stencil_buffer = true; m_features.stencil_buffer = true;
m_features.cas_sharpening = true; m_features.cas_sharpening = true;
m_features.test_and_sample_depth = true; m_features.test_and_sample_depth = true;
m_max_texture_size = m_dev.features.max_texsize;
// Init metal stuff // Init metal stuff
m_fn_constants = MRCTransfer([MTLFunctionConstantValues new]); m_fn_constants = MRCTransfer([MTLFunctionConstantValues new]);

View File

@ -3,6 +3,8 @@
#pragma once #pragma once
#include "GS/GS.h"
#include <string> #include <string>
#include <vector> #include <vector>
@ -12,6 +14,6 @@
class GSDevice; class GSDevice;
GSDevice* MakeGSDeviceMTL(); GSDevice* MakeGSDeviceMTL();
std::vector<std::string> GetMetalAdapterList(); std::vector<GSAdapterInfo> GetMetalAdapterList();
#endif #endif

View File

@ -767,6 +767,10 @@ bool GSDeviceOGL::CheckFeatures(bool& buggy_pbo)
(point_range[0] <= GSConfig.UpscaleMultiplier && point_range[1] >= GSConfig.UpscaleMultiplier); (point_range[0] <= GSConfig.UpscaleMultiplier && point_range[1] >= GSConfig.UpscaleMultiplier);
m_features.line_expand = false; m_features.line_expand = false;
GLint max_texture_size = 1024;
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
m_max_texture_size = std::max(1024u, static_cast<u32>(max_texture_size));
Console.WriteLn("Using %s for point expansion, %s for line expansion and %s for sprite expansion.", Console.WriteLn("Using %s for point expansion, %s for line expansion and %s for sprite expansion.",
m_features.point_expand ? "hardware" : (m_features.vs_expand ? "vertex expanding" : "UNSUPPORTED"), m_features.point_expand ? "hardware" : (m_features.vs_expand ? "vertex expanding" : "UNSUPPORTED"),
m_features.line_expand ? "hardware" : (m_features.vs_expand ? "vertex expanding" : "UNSUPPORTED"), m_features.line_expand ? "hardware" : (m_features.vs_expand ? "vertex expanding" : "UNSUPPORTED"),

View File

@ -291,24 +291,58 @@ GSDeviceVK::GPUList GSDeviceVK::EnumerateGPUs(VkInstance instance)
if (has_missing_extension) if (has_missing_extension)
continue; continue;
std::string gpu_name = props.deviceName; GSAdapterInfo ai;
ai.name = props.deviceName;
ai.max_texture_size = std::min(props.limits.maxFramebufferWidth, props.limits.maxImageDimension2D);
ai.max_upscale_multiplier = GSGetMaxUpscaleMultiplier(ai.max_texture_size);
// handle duplicate adapter names // handle duplicate adapter names
if (std::any_of( if (std::any_of(
gpus.begin(), gpus.end(), [&gpu_name](const auto& other) { return (gpu_name == other.second); })) gpus.begin(), gpus.end(), [&ai](const auto& other) { return (ai.name == other.second.name); }))
{ {
std::string original_adapter_name = std::move(gpu_name); std::string original_adapter_name = std::move(ai.name);
u32 current_extra = 2; u32 current_extra = 2;
do do
{ {
gpu_name = fmt::format("{} ({})", original_adapter_name, current_extra); ai.name = fmt::format("{} ({})", original_adapter_name, current_extra);
current_extra++; current_extra++;
} while (std::any_of( } while (std::any_of(
gpus.begin(), gpus.end(), [&gpu_name](const auto& other) { return (gpu_name == other.second); })); gpus.begin(), gpus.end(), [&ai](const auto& other) { return (ai.name == other.second.name); }));
} }
gpus.emplace_back(device, std::move(gpu_name)); gpus.emplace_back(device, std::move(ai));
}
return gpus;
}
GSDeviceVK::GPUList GSDeviceVK::EnumerateGPUs()
{
std::unique_lock lock(s_instance_mutex);
// Device shouldn't be torn down since we have the lock.
GPUList gpus;
if (g_gs_device && Vulkan::IsVulkanLibraryLoaded())
{
gpus = EnumerateGPUs(GSDeviceVK::GetInstance()->GetVulkanInstance());
}
else
{
if (Vulkan::LoadVulkanLibrary(nullptr))
{
OptionalExtensions oe = {};
const VkInstance instance = CreateVulkanInstance(WindowInfo(), &oe, false, false);
if (instance != VK_NULL_HANDLE)
{
if (Vulkan::LoadVulkanInstanceFunctions(instance))
gpus = EnumerateGPUs(instance);
vkDestroyInstance(instance, nullptr);
}
Vulkan::UnloadVulkanLibrary();
}
} }
return gpus; return gpus;
@ -1928,58 +1962,28 @@ bool GSDeviceVK::AllocatePreinitializedGPUBuffer(u32 size, VkBuffer* gpu_buffer,
} }
void GSDeviceVK::GPUListToAdapterNames(std::vector<std::string>* dest, VkInstance instance) std::vector<GSAdapterInfo> GSDeviceVK::GetAdapterInfo()
{ {
GPUList gpus = EnumerateGPUs(instance); GPUList gpus = EnumerateGPUs();
dest->clear(); std::vector<GSAdapterInfo> ret;
dest->reserve(gpus.size()); ret.reserve(gpus.size());
for (auto& [gpu, name] : gpus) for (auto& [physical_device, ai] : gpus)
dest->push_back(std::move(name)); ret.push_back(std::move(ai));
} return ret;
void GSDeviceVK::GetAdaptersAndFullscreenModes(
std::vector<std::string>* adapters, std::vector<std::string>* fullscreen_modes)
{
std::unique_lock lock(s_instance_mutex);
// Device shouldn't be torn down since we have the lock.
if (g_gs_device && Vulkan::IsVulkanLibraryLoaded())
{
if (adapters)
GPUListToAdapterNames(adapters, GSDeviceVK::GetInstance()->GetVulkanInstance());
}
else
{
if (Vulkan::LoadVulkanLibrary(nullptr))
{
OptionalExtensions oe = {};
const VkInstance instance = CreateVulkanInstance(WindowInfo(), &oe, false, false);
if (instance != VK_NULL_HANDLE)
{
if (Vulkan::LoadVulkanInstanceFunctions(instance))
GPUListToAdapterNames(adapters, instance);
vkDestroyInstance(instance, nullptr);
}
Vulkan::UnloadVulkanLibrary();
}
}
} }
bool GSDeviceVK::IsSuitableDefaultRenderer() bool GSDeviceVK::IsSuitableDefaultRenderer()
{ {
std::vector<std::string> adapters; GPUList gpus = EnumerateGPUs();
GetAdaptersAndFullscreenModes(&adapters, nullptr); if (gpus.empty())
if (adapters.empty())
{ {
// No adapters, not gonna be able to use VK. // No adapters, not gonna be able to use VK.
return false; return false;
} }
// Check the first GPU, should be enough. // Check the first GPU, should be enough.
const std::string& name = adapters.front(); const std::string& name = gpus.front().second.name;
Console.WriteLn(fmt::format("Using Vulkan GPU '{}' for automatic renderer check.", name)); INFO_LOG("Using Vulkan GPU '{}' for automatic renderer check.", name);
// Any software rendering (LLVMpipe, SwiftShader). // Any software rendering (LLVMpipe, SwiftShader).
if (StringUtil::StartsWithNoCase(name, "llvmpipe") || StringUtil::StartsWithNoCase(name, "SwiftShader")) if (StringUtil::StartsWithNoCase(name, "llvmpipe") || StringUtil::StartsWithNoCase(name, "SwiftShader"))
@ -2451,18 +2455,17 @@ bool GSDeviceVK::CreateDeviceAndSwapChain()
m_instance = CreateVulkanInstance(m_window_info, &m_optional_extensions, enable_debug_utils, enable_validation_layer); m_instance = CreateVulkanInstance(m_window_info, &m_optional_extensions, enable_debug_utils, enable_validation_layer);
if (m_instance == VK_NULL_HANDLE) if (m_instance == VK_NULL_HANDLE)
{ {
Host::ReportErrorAsync( Host::ReportErrorAsync("Error", "Failed to create Vulkan instance. Does your GPU and/or driver support Vulkan?");
"Error", "Failed to create Vulkan instance. Does your GPU and/or driver support Vulkan?");
return false; return false;
} }
Console.Error("Vulkan validation/debug layers requested but are unavailable. Creating non-debug device."); ERROR_LOG("Vulkan validation/debug layers requested but are unavailable. Creating non-debug device.");
} }
} }
if (!Vulkan::LoadVulkanInstanceFunctions(m_instance)) if (!Vulkan::LoadVulkanInstanceFunctions(m_instance))
{ {
Console.Error("Failed to load Vulkan instance functions"); ERROR_LOG("Failed to load Vulkan instance functions");
return false; return false;
} }
@ -2478,8 +2481,8 @@ bool GSDeviceVK::CreateDeviceAndSwapChain()
u32 gpu_index = 0; u32 gpu_index = 0;
for (; gpu_index < static_cast<u32>(gpus.size()); gpu_index++) for (; gpu_index < static_cast<u32>(gpus.size()); gpu_index++)
{ {
Console.WriteLn(fmt::format("GPU {}: {}", gpu_index, gpus[gpu_index].second)); DEV_LOG("GPU {}: {}", gpu_index, gpus[gpu_index].second.name);
if (gpus[gpu_index].second == GSConfig.Adapter) if (gpus[gpu_index].second.name == GSConfig.Adapter)
{ {
m_physical_device = gpus[gpu_index].first; m_physical_device = gpus[gpu_index].first;
break; break;
@ -2488,14 +2491,13 @@ bool GSDeviceVK::CreateDeviceAndSwapChain()
if (gpu_index == static_cast<u32>(gpus.size())) if (gpu_index == static_cast<u32>(gpus.size()))
{ {
Console.Warning( WARNING_LOG("Requested GPU '{}' not found, using first ({})", GSConfig.Adapter, gpus[0].second.name);
fmt::format("Requested GPU '{}' not found, using first ({})", GSConfig.Adapter, gpus[0].second));
m_physical_device = gpus[0].first; m_physical_device = gpus[0].first;
} }
} }
else else
{ {
Console.WriteLn(fmt::format("No GPU requested, using first ({})", gpus[0].second)); INFO_LOG("No GPU requested, using first ({})", gpus[0].second.name);
m_physical_device = gpus[0].first; m_physical_device = gpus[0].first;
} }
@ -2647,6 +2649,8 @@ bool GSDeviceVK::CheckFeatures()
Host::OSD_WARNING_DURATION); Host::OSD_WARNING_DURATION);
} }
m_max_texture_size = m_device_properties.limits.maxImageDimension2D;
return true; return true;
} }
@ -2693,18 +2697,13 @@ VkFormat GSDeviceVK::LookupNativeFormat(GSTexture::Format format) const
GSTexture* GSDeviceVK::CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) GSTexture* GSDeviceVK::CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format)
{ {
const u32 clamped_width = std::unique_ptr<GSTexture> tex = GSTextureVK::Create(type, format, width, height, levels);
static_cast<u32>(std::clamp<int>(width, 1, m_device_properties.limits.maxImageDimension2D));
const u32 clamped_height =
static_cast<u32>(std::clamp<int>(height, 1, m_device_properties.limits.maxImageDimension2D));
std::unique_ptr<GSTexture> tex(GSTextureVK::Create(type, format, clamped_width, clamped_height, levels));
if (!tex) if (!tex)
{ {
// We're probably out of vram, try flushing the command buffer to release pending textures. // We're probably out of vram, try flushing the command buffer to release pending textures.
PurgePool(); PurgePool();
ExecuteCommandBufferAndRestartRenderPass(true, "Couldn't allocate texture."); ExecuteCommandBufferAndRestartRenderPass(true, "Couldn't allocate texture.");
tex = GSTextureVK::Create(type, format, clamped_width, clamped_height, levels); tex = GSTextureVK::Create(type, format, width, height, levels);
} }
return tex.release(); return tex.release();

View File

@ -129,11 +129,6 @@ private:
static VkInstance CreateVulkanInstance(const WindowInfo& wi, OptionalExtensions* oe, bool enable_debug_utils, static VkInstance CreateVulkanInstance(const WindowInfo& wi, OptionalExtensions* oe, bool enable_debug_utils,
bool enable_validation_layer); bool enable_validation_layer);
// Returns a list of Vulkan-compatible GPUs.
using GPUList = std::vector<std::pair<VkPhysicalDevice, std::string>>;
static GPUList EnumerateGPUs(VkInstance instance);
static void GPUListToAdapterNames(std::vector<std::string>* dest, VkInstance instance);
// Enable/disable debug message runtime. // Enable/disable debug message runtime.
bool EnableDebugUtils(); bool EnableDebugUtils();
void DisableDebugUtils(); void DisableDebugUtils();
@ -474,8 +469,11 @@ public:
__fi static GSDeviceVK* GetInstance() { return static_cast<GSDeviceVK*>(g_gs_device.get()); } __fi static GSDeviceVK* GetInstance() { return static_cast<GSDeviceVK*>(g_gs_device.get()); }
static void GetAdaptersAndFullscreenModes( // Returns a list of Vulkan-compatible GPUs.
std::vector<std::string>* adapters, std::vector<std::string>* fullscreen_modes); using GPUList = std::vector<std::pair<VkPhysicalDevice, GSAdapterInfo>>;
static GPUList EnumerateGPUs();
static GPUList EnumerateGPUs(VkInstance instance);
static std::vector<GSAdapterInfo> GetAdapterInfo();
/// Returns true if Vulkan is suitable as a default for the devices in the system. /// Returns true if Vulkan is suitable as a default for the devices in the system.
static bool IsSuitableDefaultRenderer(); static bool IsSuitableDefaultRenderer();

View File

@ -402,8 +402,7 @@ namespace FullscreenUI
static std::unique_ptr<INISettingsInterface> s_game_settings_interface; static std::unique_ptr<INISettingsInterface> s_game_settings_interface;
static std::unique_ptr<GameList::Entry> s_game_settings_entry; static std::unique_ptr<GameList::Entry> s_game_settings_entry;
static std::vector<std::pair<std::string, bool>> s_game_list_directories_cache; static std::vector<std::pair<std::string, bool>> s_game_list_directories_cache;
static std::vector<std::string> s_graphics_adapter_list_cache; static std::vector<GSAdapterInfo> s_graphics_adapter_list_cache;
static std::vector<std::string> s_fullscreen_mode_list_cache;
static Patch::PatchInfoList s_game_patch_list; static Patch::PatchInfoList s_game_patch_list;
static std::vector<std::string> s_enabled_game_patch_cache; static std::vector<std::string> s_enabled_game_patch_cache;
static Patch::PatchInfoList s_game_cheats_list; static Patch::PatchInfoList s_game_cheats_list;
@ -762,7 +761,6 @@ void FullscreenUI::Shutdown(bool clear_state)
s_game_cheats_list = {}; s_game_cheats_list = {};
s_enabled_game_patch_cache = {}; s_enabled_game_patch_cache = {};
s_game_patch_list = {}; s_game_patch_list = {};
s_fullscreen_mode_list_cache = {};
s_graphics_adapter_list_cache = {}; s_graphics_adapter_list_cache = {};
s_current_game_title = {}; s_current_game_title = {};
s_current_game_subtitle = {}; s_current_game_subtitle = {};
@ -2736,7 +2734,7 @@ void FullscreenUI::SwitchToGameSettings(const GameList::Entry* entry)
void FullscreenUI::PopulateGraphicsAdapterList() void FullscreenUI::PopulateGraphicsAdapterList()
{ {
GSGetAdaptersAndFullscreenModes(GSConfig.Renderer, &s_graphics_adapter_list_cache, &s_fullscreen_mode_list_cache); s_graphics_adapter_list_cache = GSGetAdapterInfo(GSConfig.Renderer);
} }
void FullscreenUI::PopulateGameListDirectoryCache(SettingsInterface* si) void FullscreenUI::PopulateGameListDirectoryCache(SettingsInterface* si)

View File

@ -883,9 +883,6 @@ void Pcsx2Config::GSOptions::LoadSave(SettingsWrapper& wrap)
SettingsWrapIntEnumEx(Renderer, "Renderer"); SettingsWrapIntEnumEx(Renderer, "Renderer");
SettingsWrapEntryEx(UpscaleMultiplier, "upscale_multiplier"); SettingsWrapEntryEx(UpscaleMultiplier, "upscale_multiplier");
// ~51x would the upper bound here for 32768x32768 textures, but you'll run out VRAM long before then.
UpscaleMultiplier = std::clamp(UpscaleMultiplier, 1.0f, 50.0f);
SettingsWrapBitBoolEx(HWMipmap, "hw_mipmap"); SettingsWrapBitBoolEx(HWMipmap, "hw_mipmap");
SettingsWrapIntEnumEx(AccurateBlendingUnit, "accurate_blending_unit"); SettingsWrapIntEnumEx(AccurateBlendingUnit, "accurate_blending_unit");
SettingsWrapIntEnumEx(TextureFiltering, "filter"); SettingsWrapIntEnumEx(TextureFiltering, "filter");