Qt: Unrestrict resolution scale up to device limits
This commit is contained in:
parent
7927ec647f
commit
4b61a3cbf3
|
@ -404,7 +404,7 @@ static SettingsPage s_settings_page = SettingsPage::Interface;
|
||||||
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 GPUDevice::AdapterInfoList s_graphics_adapter_list_cache;
|
||||||
static std::vector<std::string> s_fullscreen_mode_list_cache;
|
static std::vector<std::string> s_fullscreen_mode_list_cache;
|
||||||
static std::vector<PostProcessingStageInfo> s_postprocessing_stages;
|
static std::vector<PostProcessingStageInfo> s_postprocessing_stages;
|
||||||
static std::vector<const HotkeyInfo*> s_hotkey_list_cache;
|
static std::vector<const HotkeyInfo*> s_hotkey_list_cache;
|
||||||
|
@ -2781,10 +2781,13 @@ void FullscreenUI::SwitchToGameSettings(const GameList::Entry* entry)
|
||||||
|
|
||||||
void FullscreenUI::PopulateGraphicsAdapterList()
|
void FullscreenUI::PopulateGraphicsAdapterList()
|
||||||
{
|
{
|
||||||
GPUDevice::AdapterAndModeList ml(g_gpu_device->GetAdapterAndModeList());
|
const GPURenderer renderer =
|
||||||
s_graphics_adapter_list_cache = std::move(ml.adapter_names);
|
Settings::ParseRendererName(GetEffectiveTinyStringSetting(GetEditingSettingsInterface(false), "GPU", "Renderer",
|
||||||
s_fullscreen_mode_list_cache = std::move(ml.fullscreen_modes);
|
Settings::GetRendererName(Settings::DEFAULT_GPU_RENDERER))
|
||||||
s_fullscreen_mode_list_cache.insert(s_fullscreen_mode_list_cache.begin(), FSUI_STR("Borderless Fullscreen"));
|
.c_str())
|
||||||
|
.value_or(Settings::DEFAULT_GPU_RENDERER);
|
||||||
|
|
||||||
|
s_graphics_adapter_list_cache = GPUDevice::GetAdapterListForAPI(Settings::GetRenderAPIForRenderer(renderer));
|
||||||
}
|
}
|
||||||
|
|
||||||
void FullscreenUI::PopulateGameListDirectoryCache(SettingsInterface* si)
|
void FullscreenUI::PopulateGameListDirectoryCache(SettingsInterface* si)
|
||||||
|
@ -4160,24 +4163,22 @@ void FullscreenUI::DrawDisplaySettingsPage()
|
||||||
.value_or(Settings::DEFAULT_GPU_RENDERER);
|
.value_or(Settings::DEFAULT_GPU_RENDERER);
|
||||||
const bool is_hardware = (renderer != GPURenderer::Software);
|
const bool is_hardware = (renderer != GPURenderer::Software);
|
||||||
|
|
||||||
std::optional<SmallString> strvalue =
|
std::optional<SmallString> current_adapter =
|
||||||
bsi->GetOptionalSmallStringValue("GPU", "Adapter", game_settings ? std::nullopt : std::optional<const char*>(""));
|
bsi->GetOptionalSmallStringValue("GPU", "Adapter", game_settings ? std::nullopt : std::optional<const char*>(""));
|
||||||
|
|
||||||
if (MenuButtonWithValue(FSUI_CSTR("GPU Adapter"), FSUI_CSTR("Selects the GPU to use for rendering."),
|
if (MenuButtonWithValue(FSUI_CSTR("GPU Adapter"), FSUI_CSTR("Selects the GPU to use for rendering."),
|
||||||
strvalue.has_value() ? (strvalue->empty() ? FSUI_CSTR("Default") : strvalue->c_str()) :
|
current_adapter.has_value() ? (current_adapter->empty() ? FSUI_CSTR("Default") : current_adapter->c_str()) :
|
||||||
FSUI_CSTR("Use Global Setting")))
|
FSUI_CSTR("Use Global Setting")))
|
||||||
{
|
{
|
||||||
GPUDevice::AdapterAndModeList aml(g_gpu_device->GetAdapterAndModeList());
|
|
||||||
|
|
||||||
ImGuiFullscreen::ChoiceDialogOptions options;
|
ImGuiFullscreen::ChoiceDialogOptions options;
|
||||||
options.reserve(aml.adapter_names.size() + 2);
|
options.reserve(s_graphics_adapter_list_cache.size() + 2);
|
||||||
if (game_settings)
|
if (game_settings)
|
||||||
options.emplace_back(FSUI_STR("Use Global Setting"), !strvalue.has_value());
|
options.emplace_back(FSUI_STR("Use Global Setting"), !current_adapter.has_value());
|
||||||
options.emplace_back(FSUI_STR("Default"), strvalue.has_value() && strvalue->empty());
|
options.emplace_back(FSUI_STR("Default"), current_adapter.has_value() && current_adapter->empty());
|
||||||
for (std::string& mode : aml.adapter_names)
|
for (const GPUDevice::AdapterInfo& adapter : s_graphics_adapter_list_cache)
|
||||||
{
|
{
|
||||||
const bool checked = (strvalue.has_value() && strvalue.value() == mode);
|
const bool checked = (current_adapter.has_value() && current_adapter.value() == adapter.name);
|
||||||
options.emplace_back(std::move(mode), checked);
|
options.emplace_back(adapter.name, checked);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto callback = [game_settings](s32 index, const std::string& title, bool checked) {
|
auto callback = [game_settings](s32 index, const std::string& title, bool checked) {
|
||||||
|
@ -4204,7 +4205,7 @@ void FullscreenUI::DrawDisplaySettingsPage()
|
||||||
OpenChoiceDialog(FSUI_ICONSTR(ICON_FA_TV, "GPU Adapter"), false, std::move(options), std::move(callback));
|
OpenChoiceDialog(FSUI_ICONSTR(ICON_FA_TV, "GPU Adapter"), false, std::move(options), std::move(callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
strvalue = bsi->GetOptionalSmallStringValue("GPU", "FullscreenMode",
|
std::optional<SmallString> strvalue = bsi->GetOptionalSmallStringValue("GPU", "FullscreenMode",
|
||||||
game_settings ? std::nullopt : std::optional<const char*>(""));
|
game_settings ? std::nullopt : std::optional<const char*>(""));
|
||||||
|
|
||||||
if (MenuButtonWithValue(
|
if (MenuButtonWithValue(
|
||||||
|
@ -4212,17 +4213,36 @@ void FullscreenUI::DrawDisplaySettingsPage()
|
||||||
strvalue.has_value() ? (strvalue->empty() ? FSUI_CSTR("Borderless Fullscreen") : strvalue->c_str()) :
|
strvalue.has_value() ? (strvalue->empty() ? FSUI_CSTR("Borderless Fullscreen") : strvalue->c_str()) :
|
||||||
FSUI_CSTR("Use Global Setting")))
|
FSUI_CSTR("Use Global Setting")))
|
||||||
{
|
{
|
||||||
GPUDevice::AdapterAndModeList aml(g_gpu_device->GetAdapterAndModeList());
|
const GPUDevice::AdapterInfo* selected_adapter = nullptr;
|
||||||
|
if (current_adapter.has_value())
|
||||||
|
{
|
||||||
|
for (const GPUDevice::AdapterInfo& ai : s_graphics_adapter_list_cache)
|
||||||
|
{
|
||||||
|
if (ai.name == current_adapter->view())
|
||||||
|
{
|
||||||
|
selected_adapter = &ai;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!s_graphics_adapter_list_cache.empty())
|
||||||
|
selected_adapter = &s_graphics_adapter_list_cache.front();
|
||||||
|
}
|
||||||
|
|
||||||
ImGuiFullscreen::ChoiceDialogOptions options;
|
ImGuiFullscreen::ChoiceDialogOptions options;
|
||||||
options.reserve(aml.fullscreen_modes.size() + 2);
|
options.reserve((selected_adapter ? selected_adapter->fullscreen_modes.size() : 0) + 2);
|
||||||
if (game_settings)
|
if (game_settings)
|
||||||
options.emplace_back(FSUI_STR("Use Global Setting"), !strvalue.has_value());
|
options.emplace_back(FSUI_STR("Use Global Setting"), !strvalue.has_value());
|
||||||
options.emplace_back(FSUI_STR("Borderless Fullscreen"), strvalue.has_value() && strvalue->empty());
|
options.emplace_back(FSUI_STR("Borderless Fullscreen"), strvalue.has_value() && strvalue->empty());
|
||||||
for (std::string& mode : aml.fullscreen_modes)
|
if (selected_adapter)
|
||||||
{
|
{
|
||||||
const bool checked = (strvalue.has_value() && strvalue.value() == mode);
|
for (const std::string& mode : selected_adapter->fullscreen_modes)
|
||||||
options.emplace_back(std::move(mode), checked);
|
{
|
||||||
|
const bool checked = (strvalue.has_value() && strvalue.value() == mode);
|
||||||
|
options.emplace_back(mode, checked);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto callback = [game_settings](s32 index, const std::string& title, bool checked) {
|
auto callback = [game_settings](s32 index, const std::string& title, bool checked) {
|
||||||
|
|
|
@ -8,14 +8,7 @@
|
||||||
#include "settingswindow.h"
|
#include "settingswindow.h"
|
||||||
#include "settingwidgetbinder.h"
|
#include "settingwidgetbinder.h"
|
||||||
|
|
||||||
// For enumerating adapters.
|
#include <algorithm>
|
||||||
#ifdef _WIN32
|
|
||||||
#include "util/d3d11_device.h"
|
|
||||||
#include "util/d3d12_device.h"
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_VULKAN
|
|
||||||
#include "util/vulkan_device.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static QVariant GetMSAAModeValue(uint multisamples, bool ssaa)
|
static QVariant GetMSAAModeValue(uint multisamples, bool ssaa)
|
||||||
{
|
{
|
||||||
|
@ -51,7 +44,6 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget*
|
||||||
|
|
||||||
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.renderer, "GPU", "Renderer", &Settings::ParseRendererName,
|
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.renderer, "GPU", "Renderer", &Settings::ParseRendererName,
|
||||||
&Settings::GetRendererName, Settings::DEFAULT_GPU_RENDERER);
|
&Settings::GetRendererName, Settings::DEFAULT_GPU_RENDERER);
|
||||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.resolutionScale, "GPU", "ResolutionScale", 1);
|
|
||||||
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.textureFiltering, "GPU", "TextureFilter",
|
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.textureFiltering, "GPU", "TextureFilter",
|
||||||
&Settings::ParseTextureFilterName, &Settings::GetTextureFilterName,
|
&Settings::ParseTextureFilterName, &Settings::GetTextureFilterName,
|
||||||
Settings::DEFAULT_GPU_TEXTURE_FILTER);
|
Settings::DEFAULT_GPU_TEXTURE_FILTER);
|
||||||
|
@ -89,10 +81,6 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget*
|
||||||
|
|
||||||
connect(m_ui.renderer, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
connect(m_ui.renderer, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
||||||
&GraphicsSettingsWidget::updateRendererDependentOptions);
|
&GraphicsSettingsWidget::updateRendererDependentOptions);
|
||||||
connect(m_ui.adapter, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
|
||||||
&GraphicsSettingsWidget::onAdapterChanged);
|
|
||||||
connect(m_ui.resolutionScale, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
|
||||||
&GraphicsSettingsWidget::updateResolutionDependentOptions);
|
|
||||||
connect(m_ui.textureFiltering, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
connect(m_ui.textureFiltering, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
||||||
&GraphicsSettingsWidget::updateResolutionDependentOptions);
|
&GraphicsSettingsWidget::updateResolutionDependentOptions);
|
||||||
connect(m_ui.displayAspectRatio, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
connect(m_ui.displayAspectRatio, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
||||||
|
@ -102,23 +90,6 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget*
|
||||||
connect(m_ui.trueColor, &QCheckBox::checkStateChanged, this, &GraphicsSettingsWidget::onTrueColorChanged);
|
connect(m_ui.trueColor, &QCheckBox::checkStateChanged, this, &GraphicsSettingsWidget::onTrueColorChanged);
|
||||||
connect(m_ui.pgxpEnable, &QCheckBox::checkStateChanged, this, &GraphicsSettingsWidget::updatePGXPSettingsEnabled);
|
connect(m_ui.pgxpEnable, &QCheckBox::checkStateChanged, this, &GraphicsSettingsWidget::updatePGXPSettingsEnabled);
|
||||||
|
|
||||||
if (!dialog->isPerGameSettings() ||
|
|
||||||
(dialog->containsSettingValue("GPU", "Multisamples") || dialog->containsSettingValue("GPU", "PerSampleShading")))
|
|
||||||
{
|
|
||||||
const QVariant current_msaa_mode(
|
|
||||||
GetMSAAModeValue(static_cast<uint>(dialog->getEffectiveIntValue("GPU", "Multisamples", 1)),
|
|
||||||
dialog->getEffectiveBoolValue("GPU", "PerSampleShading", false)));
|
|
||||||
const int current_msaa_index = m_ui.msaaMode->findData(current_msaa_mode);
|
|
||||||
if (current_msaa_index >= 0)
|
|
||||||
m_ui.msaaMode->setCurrentIndex(current_msaa_index);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_ui.msaaMode->setCurrentIndex(0);
|
|
||||||
}
|
|
||||||
connect(m_ui.msaaMode, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
|
||||||
&GraphicsSettingsWidget::onMSAAModeChanged);
|
|
||||||
|
|
||||||
// Advanced Tab
|
// Advanced Tab
|
||||||
|
|
||||||
SettingWidgetBinder::BindWidgetToEnumSetting(
|
SettingWidgetBinder::BindWidgetToEnumSetting(
|
||||||
|
@ -151,9 +122,6 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget*
|
||||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.forceRoundedTexcoords, "GPU", "ForceRoundTextureCoordinates",
|
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.forceRoundedTexcoords, "GPU", "ForceRoundTextureCoordinates",
|
||||||
false);
|
false);
|
||||||
|
|
||||||
connect(m_ui.fullscreenMode, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
|
||||||
&GraphicsSettingsWidget::onFullscreenModeChanged);
|
|
||||||
|
|
||||||
// PGXP Tab
|
// PGXP Tab
|
||||||
|
|
||||||
SettingWidgetBinder::BindWidgetToFloatSetting(sif, m_ui.pgxpGeometryTolerance, "GPU", "PGXPTolerance", -1.0f);
|
SettingWidgetBinder::BindWidgetToFloatSetting(sif, m_ui.pgxpGeometryTolerance, "GPU", "PGXPTolerance", -1.0f);
|
||||||
|
@ -582,16 +550,6 @@ void GraphicsSettingsWidget::setupAdditionalUi()
|
||||||
QString::fromUtf8(Settings::GetDisplayAlignmentDisplayName(static_cast<DisplayAlignment>(i))));
|
QString::fromUtf8(Settings::GetDisplayAlignmentDisplayName(static_cast<DisplayAlignment>(i))));
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
|
||||||
if (m_dialog->isPerGameSettings())
|
|
||||||
m_ui.msaaMode->addItem(tr("Use Global Setting"));
|
|
||||||
m_ui.msaaMode->addItem(tr("Disabled"), GetMSAAModeValue(1, false));
|
|
||||||
for (uint i = 2; i <= 32; i *= 2)
|
|
||||||
m_ui.msaaMode->addItem(tr("%1x MSAA").arg(i), GetMSAAModeValue(i, false));
|
|
||||||
for (uint i = 2; i <= 32; i *= 2)
|
|
||||||
m_ui.msaaMode->addItem(tr("%1x SSAA").arg(i), GetMSAAModeValue(i, true));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (u32 i = 0; i < static_cast<u32>(GPULineDetectMode::Count); i++)
|
for (u32 i = 0; i < static_cast<u32>(GPULineDetectMode::Count); i++)
|
||||||
{
|
{
|
||||||
m_ui.gpuLineDetectMode->addItem(
|
m_ui.gpuLineDetectMode->addItem(
|
||||||
|
@ -694,75 +652,134 @@ void GraphicsSettingsWidget::updateRendererDependentOptions()
|
||||||
|
|
||||||
void GraphicsSettingsWidget::populateGPUAdaptersAndResolutions(RenderAPI render_api)
|
void GraphicsSettingsWidget::populateGPUAdaptersAndResolutions(RenderAPI render_api)
|
||||||
{
|
{
|
||||||
GPUDevice::AdapterAndModeList aml;
|
// Don't re-query, it's expensive.
|
||||||
switch (render_api)
|
if (m_adapters_render_api != render_api)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
m_adapters_render_api = render_api;
|
||||||
case RenderAPI::D3D11:
|
m_adapters = GPUDevice::GetAdapterListForAPI(render_api);
|
||||||
aml = D3D11Device::StaticGetAdapterAndModeList();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case RenderAPI::D3D12:
|
|
||||||
aml = D3D12Device::StaticGetAdapterAndModeList();
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
#ifdef __APPLE__
|
|
||||||
case RenderAPI::Metal:
|
|
||||||
aml = GPUDevice::WrapGetMetalAdapterAndModeList();
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_VULKAN
|
|
||||||
case RenderAPI::Vulkan:
|
|
||||||
aml = VulkanDevice::StaticGetAdapterAndModeList();
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
const GPUDevice::AdapterInfo* current_adapter = nullptr;
|
||||||
const std::string current_adapter(m_dialog->getEffectiveStringValue("GPU", "Adapter", ""));
|
SettingsInterface* const sif = m_dialog->getSettingsInterface();
|
||||||
QSignalBlocker blocker(m_ui.adapter);
|
|
||||||
|
|
||||||
// add the default entry - we'll fall back to this if the GPU no longer exists, or there's no options
|
{
|
||||||
|
m_ui.adapter->disconnect();
|
||||||
m_ui.adapter->clear();
|
m_ui.adapter->clear();
|
||||||
m_ui.adapter->addItem(tr("(Default)"));
|
m_ui.adapter->addItem(tr("(Default)"), QVariant(QString()));
|
||||||
|
|
||||||
// add the other adapters
|
const std::string current_adapter_name = m_dialog->getEffectiveStringValue("GPU", "Adapter", "");
|
||||||
for (const std::string& adapter_name : aml.adapter_names)
|
for (const GPUDevice::AdapterInfo& adapter : m_adapters)
|
||||||
{
|
{
|
||||||
m_ui.adapter->addItem(QString::fromStdString(adapter_name));
|
const QString qadaptername = QString::fromStdString(adapter.name);
|
||||||
|
m_ui.adapter->addItem(qadaptername, QVariant(qadaptername));
|
||||||
if (adapter_name == current_adapter)
|
if (adapter.name == current_adapter_name)
|
||||||
m_ui.adapter->setCurrentIndex(m_ui.adapter->count() - 1);
|
current_adapter = &adapter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// default adapter
|
||||||
|
if (!m_adapters.empty() && current_adapter_name.empty())
|
||||||
|
current_adapter = &m_adapters.front();
|
||||||
|
|
||||||
// disable it if we don't have a choice
|
// disable it if we don't have a choice
|
||||||
m_ui.adapter->setEnabled(!aml.adapter_names.empty());
|
m_ui.adapter->setEnabled(!m_adapters.empty());
|
||||||
|
SettingWidgetBinder::BindWidgetToStringSetting(sif, m_ui.adapter, "GPU", "Adapter");
|
||||||
|
connect(m_ui.adapter, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
||||||
|
&GraphicsSettingsWidget::updateRendererDependentOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const std::string current_mode(m_dialog->getEffectiveStringValue("GPU", "FullscreenMode", ""));
|
m_ui.fullscreenMode->disconnect();
|
||||||
QSignalBlocker blocker(m_ui.fullscreenMode);
|
|
||||||
|
|
||||||
m_ui.fullscreenMode->clear();
|
m_ui.fullscreenMode->clear();
|
||||||
m_ui.fullscreenMode->addItem(tr("Borderless Fullscreen"));
|
|
||||||
m_ui.fullscreenMode->setCurrentIndex(0);
|
|
||||||
|
|
||||||
for (const std::string& mode_name : aml.fullscreen_modes)
|
m_ui.fullscreenMode->addItem(tr("Borderless Fullscreen"), QVariant(QString()));
|
||||||
|
if (current_adapter)
|
||||||
{
|
{
|
||||||
m_ui.fullscreenMode->addItem(QString::fromStdString(mode_name));
|
for (const std::string& mode_name : current_adapter->fullscreen_modes)
|
||||||
|
{
|
||||||
if (mode_name == current_mode)
|
const QString qmodename = QString::fromStdString(mode_name);
|
||||||
m_ui.fullscreenMode->setCurrentIndex(m_ui.fullscreenMode->count() - 1);
|
m_ui.fullscreenMode->addItem(qmodename, QVariant(qmodename));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// disable it if we don't have a choice
|
// disable it if we don't have a choice
|
||||||
m_ui.fullscreenMode->setEnabled(!aml.fullscreen_modes.empty());
|
m_ui.fullscreenMode->setEnabled(current_adapter && !current_adapter->fullscreen_modes.empty());
|
||||||
|
SettingWidgetBinder::BindWidgetToStringSetting(sif, m_ui.fullscreenMode, "GPU", "FullscreenMode");
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: MSAA modes
|
{
|
||||||
|
m_ui.resolutionScale->disconnect();
|
||||||
|
m_ui.resolutionScale->clear();
|
||||||
|
|
||||||
|
static constexpr const std::pair<int, const char*> templates[] = {
|
||||||
|
{0, QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "Automatic (Based on Window Size)")},
|
||||||
|
{1, QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "1x Native (Default)")},
|
||||||
|
{3, QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "3x Native (for 720p)")},
|
||||||
|
{5, QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "5x Native (for 1080p)")},
|
||||||
|
{6, QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "6x Native (for 1440p)")},
|
||||||
|
{9, QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "9x Native (for 4K)")},
|
||||||
|
};
|
||||||
|
|
||||||
|
const int max_scale =
|
||||||
|
static_cast<int>(current_adapter ? std::max<u32>(current_adapter->max_texture_size / 1024, 1) : 16);
|
||||||
|
for (int scale = 0; scale <= max_scale; scale++)
|
||||||
|
{
|
||||||
|
const auto it = std::find_if(std::begin(templates), std::end(templates),
|
||||||
|
[&scale](const std::pair<int, const char*>& it) { return scale == it.first; });
|
||||||
|
m_ui.resolutionScale->addItem((it != std::end(templates)) ?
|
||||||
|
qApp->translate("GraphicsSettingsWidget", it->second) :
|
||||||
|
qApp->translate("GraphicsSettingsWidget", "%1x Native").arg(scale));
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.resolutionScale, "GPU", "ResolutionScale", 1);
|
||||||
|
connect(m_ui.resolutionScale, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
||||||
|
&GraphicsSettingsWidget::updateResolutionDependentOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
m_ui.msaaMode->disconnect();
|
||||||
|
m_ui.msaaMode->clear();
|
||||||
|
|
||||||
|
if (m_dialog->isPerGameSettings())
|
||||||
|
m_ui.msaaMode->addItem(tr("Use Global Setting"));
|
||||||
|
|
||||||
|
const u32 max_multisamples = current_adapter ? current_adapter->max_multisamples : 8;
|
||||||
|
m_ui.msaaMode->addItem(tr("Disabled"), GetMSAAModeValue(1, false));
|
||||||
|
for (uint i = 2; i <= max_multisamples; i *= 2)
|
||||||
|
m_ui.msaaMode->addItem(tr("%1x MSAA").arg(i), GetMSAAModeValue(i, false));
|
||||||
|
for (uint i = 2; i <= max_multisamples; i *= 2)
|
||||||
|
m_ui.msaaMode->addItem(tr("%1x SSAA").arg(i), GetMSAAModeValue(i, true));
|
||||||
|
|
||||||
|
if (!m_dialog->isPerGameSettings() || (m_dialog->containsSettingValue("GPU", "Multisamples") ||
|
||||||
|
m_dialog->containsSettingValue("GPU", "PerSampleShading")))
|
||||||
|
{
|
||||||
|
const QVariant current_msaa_mode(
|
||||||
|
GetMSAAModeValue(static_cast<uint>(m_dialog->getEffectiveIntValue("GPU", "Multisamples", 1)),
|
||||||
|
m_dialog->getEffectiveBoolValue("GPU", "PerSampleShading", false)));
|
||||||
|
const int current_msaa_index = m_ui.msaaMode->findData(current_msaa_mode);
|
||||||
|
if (current_msaa_index >= 0)
|
||||||
|
m_ui.msaaMode->setCurrentIndex(current_msaa_index);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_ui.msaaMode->setCurrentIndex(0);
|
||||||
|
}
|
||||||
|
connect(m_ui.msaaMode, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [this]() {
|
||||||
|
const int index = m_ui.msaaMode->currentIndex();
|
||||||
|
if (m_dialog->isPerGameSettings() && index == 0)
|
||||||
|
{
|
||||||
|
m_dialog->removeSettingValue("GPU", "Multisamples");
|
||||||
|
m_dialog->removeSettingValue("GPU", "PerSampleShading");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uint multisamples;
|
||||||
|
bool ssaa;
|
||||||
|
DecodeMSAAModeValue(m_ui.msaaMode->itemData(index), &multisamples, &ssaa);
|
||||||
|
m_dialog->setIntSettingValue("GPU", "Multisamples", static_cast<int>(multisamples));
|
||||||
|
m_dialog->setBoolSettingValue("GPU", "PerSampleShading", ssaa);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GraphicsSettingsWidget::updatePGXPSettingsEnabled()
|
void GraphicsSettingsWidget::updatePGXPSettingsEnabled()
|
||||||
|
@ -785,18 +802,6 @@ void GraphicsSettingsWidget::updatePGXPSettingsEnabled()
|
||||||
m_ui.pgxpDepthClearThresholdLabel->setEnabled(depth_enabled);
|
m_ui.pgxpDepthClearThresholdLabel->setEnabled(depth_enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GraphicsSettingsWidget::onAdapterChanged()
|
|
||||||
{
|
|
||||||
if (m_ui.adapter->currentIndex() == 0)
|
|
||||||
{
|
|
||||||
// default
|
|
||||||
m_dialog->removeSettingValue("GPU", "Adapter");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_dialog->setStringSettingValue("GPU", "Adapter", m_ui.adapter->currentText().toUtf8().constData());
|
|
||||||
}
|
|
||||||
|
|
||||||
void GraphicsSettingsWidget::onAspectRatioChanged()
|
void GraphicsSettingsWidget::onAspectRatioChanged()
|
||||||
{
|
{
|
||||||
const DisplayAspectRatio ratio =
|
const DisplayAspectRatio ratio =
|
||||||
|
@ -828,24 +833,6 @@ void GraphicsSettingsWidget::updateResolutionDependentOptions()
|
||||||
onTrueColorChanged();
|
onTrueColorChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GraphicsSettingsWidget::onMSAAModeChanged()
|
|
||||||
{
|
|
||||||
const int index = m_ui.msaaMode->currentIndex();
|
|
||||||
if (m_dialog->isPerGameSettings() && index == 0)
|
|
||||||
{
|
|
||||||
m_dialog->removeSettingValue("GPU", "Multisamples");
|
|
||||||
m_dialog->removeSettingValue("GPU", "PerSampleShading");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
uint multisamples;
|
|
||||||
bool ssaa;
|
|
||||||
DecodeMSAAModeValue(m_ui.msaaMode->itemData(index), &multisamples, &ssaa);
|
|
||||||
m_dialog->setIntSettingValue("GPU", "Multisamples", static_cast<int>(multisamples));
|
|
||||||
m_dialog->setBoolSettingValue("GPU", "PerSampleShading", ssaa);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GraphicsSettingsWidget::onTrueColorChanged()
|
void GraphicsSettingsWidget::onTrueColorChanged()
|
||||||
{
|
{
|
||||||
const int resolution_scale = m_dialog->getEffectiveIntValue("GPU", "ResolutionScale", 1);
|
const int resolution_scale = m_dialog->getEffectiveIntValue("GPU", "ResolutionScale", 1);
|
||||||
|
@ -879,18 +866,6 @@ void GraphicsSettingsWidget::onDownsampleModeChanged()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GraphicsSettingsWidget::onFullscreenModeChanged()
|
|
||||||
{
|
|
||||||
if (m_ui.fullscreenMode->currentIndex() == 0)
|
|
||||||
{
|
|
||||||
// default
|
|
||||||
m_dialog->removeSettingValue("GPU", "FullscreenMode");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_dialog->setStringSettingValue("GPU", "FullscreenMode", m_ui.fullscreenMode->currentText().toUtf8().constData());
|
|
||||||
}
|
|
||||||
|
|
||||||
void GraphicsSettingsWidget::onEnableAnyTextureReplacementsChanged()
|
void GraphicsSettingsWidget::onEnableAnyTextureReplacementsChanged()
|
||||||
{
|
{
|
||||||
const bool any_replacements_enabled =
|
const bool any_replacements_enabled =
|
||||||
|
|
|
@ -7,7 +7,8 @@
|
||||||
|
|
||||||
#include "ui_graphicssettingswidget.h"
|
#include "ui_graphicssettingswidget.h"
|
||||||
|
|
||||||
enum class RenderAPI : u32;
|
#include "util/gpu_device.h"
|
||||||
|
|
||||||
enum class GPURenderer : u8;
|
enum class GPURenderer : u8;
|
||||||
|
|
||||||
class SettingsWindow;
|
class SettingsWindow;
|
||||||
|
@ -27,13 +28,10 @@ private Q_SLOTS:
|
||||||
void updateRendererDependentOptions();
|
void updateRendererDependentOptions();
|
||||||
void updatePGXPSettingsEnabled();
|
void updatePGXPSettingsEnabled();
|
||||||
|
|
||||||
void onAdapterChanged();
|
|
||||||
void onAspectRatioChanged();
|
void onAspectRatioChanged();
|
||||||
void updateResolutionDependentOptions();
|
void updateResolutionDependentOptions();
|
||||||
void onMSAAModeChanged();
|
|
||||||
void onTrueColorChanged();
|
void onTrueColorChanged();
|
||||||
void onDownsampleModeChanged();
|
void onDownsampleModeChanged();
|
||||||
void onFullscreenModeChanged();
|
|
||||||
void onEnableAnyTextureReplacementsChanged();
|
void onEnableAnyTextureReplacementsChanged();
|
||||||
void onEnableVRAMWriteDumpingChanged();
|
void onEnableVRAMWriteDumpingChanged();
|
||||||
|
|
||||||
|
@ -57,4 +55,7 @@ private:
|
||||||
Ui::GraphicsSettingsWidget m_ui;
|
Ui::GraphicsSettingsWidget m_ui;
|
||||||
|
|
||||||
SettingsWindow* m_dialog;
|
SettingsWindow* m_dialog;
|
||||||
|
|
||||||
|
GPUDevice::AdapterInfoList m_adapters;
|
||||||
|
RenderAPI m_adapters_render_api = RenderAPI::None;
|
||||||
};
|
};
|
||||||
|
|
|
@ -94,93 +94,7 @@
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="1">
|
<item row="0" column="1">
|
||||||
<widget class="QComboBox" name="resolutionScale">
|
<widget class="QComboBox" name="resolutionScale" />
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>Automatic (Based on Window Size)</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>1x Native (Default)</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>2x Native</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>3x Native (for 720p)</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>4x Native</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>5x Native (for 1080p)</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>6x Native (for 1440p)</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>7x Native</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>8x Native</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>9x Native (for 4K)</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>10x Native</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>11x Native</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>12x Native</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>13x Native</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>14x Native</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>15x Native</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>16x Native</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
</widget>
|
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="0">
|
<item row="1" column="0">
|
||||||
<widget class="QLabel" name="gpuDownsampleLabel">
|
<widget class="QLabel" name="gpuDownsampleLabel">
|
||||||
|
|
|
@ -685,39 +685,6 @@ void D3D11Device::SubmitPresent()
|
||||||
Panic("Not supported by this API.");
|
Panic("Not supported by this API.");
|
||||||
}
|
}
|
||||||
|
|
||||||
GPUDevice::AdapterAndModeList D3D11Device::StaticGetAdapterAndModeList()
|
|
||||||
{
|
|
||||||
AdapterAndModeList ret;
|
|
||||||
std::unique_lock lock(s_instance_mutex);
|
|
||||||
|
|
||||||
// Device shouldn't be torn down since we have the lock.
|
|
||||||
if (g_gpu_device && g_gpu_device->GetRenderAPI() == RenderAPI::D3D11)
|
|
||||||
{
|
|
||||||
GetAdapterAndModeList(&ret, D3D11Device::GetInstance().m_dxgi_factory.Get());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ComPtr<IDXGIFactory5> factory = D3DCommon::CreateFactory(false, nullptr);
|
|
||||||
if (factory)
|
|
||||||
GetAdapterAndModeList(&ret, factory.Get());
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void D3D11Device::GetAdapterAndModeList(AdapterAndModeList* ret, IDXGIFactory5* factory)
|
|
||||||
{
|
|
||||||
ret->adapter_names = D3DCommon::GetAdapterNames(factory);
|
|
||||||
ret->fullscreen_modes = D3DCommon::GetFullscreenModes(factory, {});
|
|
||||||
}
|
|
||||||
|
|
||||||
GPUDevice::AdapterAndModeList D3D11Device::GetAdapterAndModeList()
|
|
||||||
{
|
|
||||||
AdapterAndModeList ret;
|
|
||||||
GetAdapterAndModeList(&ret, m_dxgi_factory.Get());
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool D3D11Device::CreateTimestampQueries()
|
bool D3D11Device::CreateTimestampQueries()
|
||||||
{
|
{
|
||||||
for (u32 i = 0; i < NUM_TIMESTAMP_QUERIES; i++)
|
for (u32 i = 0; i < NUM_TIMESTAMP_QUERIES; i++)
|
||||||
|
|
|
@ -43,7 +43,6 @@ public:
|
||||||
bool UpdateWindow() override;
|
bool UpdateWindow() override;
|
||||||
void ResizeWindow(s32 new_window_width, s32 new_window_height, float new_window_scale) override;
|
void ResizeWindow(s32 new_window_width, s32 new_window_height, float new_window_scale) override;
|
||||||
bool SupportsExclusiveFullscreen() const override;
|
bool SupportsExclusiveFullscreen() const override;
|
||||||
AdapterAndModeList GetAdapterAndModeList() override;
|
|
||||||
void DestroySurface() override;
|
void DestroySurface() override;
|
||||||
|
|
||||||
std::string GetDriverInfo() const override;
|
std::string GetDriverInfo() const override;
|
||||||
|
@ -110,8 +109,6 @@ public:
|
||||||
void UnbindPipeline(D3D11Pipeline* pl);
|
void UnbindPipeline(D3D11Pipeline* pl);
|
||||||
void UnbindTexture(D3D11Texture* tex);
|
void UnbindTexture(D3D11Texture* tex);
|
||||||
|
|
||||||
static AdapterAndModeList StaticGetAdapterAndModeList();
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool CreateDevice(std::string_view adapter, bool threaded_presentation,
|
bool CreateDevice(std::string_view adapter, bool threaded_presentation,
|
||||||
std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features,
|
std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features,
|
||||||
|
@ -133,8 +130,6 @@ private:
|
||||||
static constexpr u32 UNIFORM_BUFFER_ALIGNMENT_DISCARD = 16;
|
static constexpr u32 UNIFORM_BUFFER_ALIGNMENT_DISCARD = 16;
|
||||||
static constexpr u8 NUM_TIMESTAMP_QUERIES = 3;
|
static constexpr u8 NUM_TIMESTAMP_QUERIES = 3;
|
||||||
|
|
||||||
static void GetAdapterAndModeList(AdapterAndModeList* ret, IDXGIFactory5* factory);
|
|
||||||
|
|
||||||
void SetFeatures(FeatureMask disabled_features);
|
void SetFeatures(FeatureMask disabled_features);
|
||||||
|
|
||||||
u32 GetSwapChainBufferCount() const;
|
u32 GetSwapChainBufferCount() const;
|
||||||
|
|
|
@ -754,39 +754,6 @@ void D3D12Device::DestroyDeferredObjects(u64 fence_value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void D3D12Device::GetAdapterAndModeList(AdapterAndModeList* ret, IDXGIFactory5* factory)
|
|
||||||
{
|
|
||||||
ret->adapter_names = D3DCommon::GetAdapterNames(factory);
|
|
||||||
ret->fullscreen_modes = D3DCommon::GetFullscreenModes(factory, {});
|
|
||||||
}
|
|
||||||
|
|
||||||
GPUDevice::AdapterAndModeList D3D12Device::StaticGetAdapterAndModeList()
|
|
||||||
{
|
|
||||||
AdapterAndModeList ret;
|
|
||||||
std::unique_lock lock(s_instance_mutex);
|
|
||||||
|
|
||||||
// Device shouldn't be torn down since we have the lock.
|
|
||||||
if (g_gpu_device && g_gpu_device->GetRenderAPI() == RenderAPI::D3D12)
|
|
||||||
{
|
|
||||||
GetAdapterAndModeList(&ret, D3D12Device::GetInstance().m_dxgi_factory.Get());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ComPtr<IDXGIFactory5> factory = D3DCommon::CreateFactory(false, nullptr);
|
|
||||||
if (factory)
|
|
||||||
GetAdapterAndModeList(&ret, factory.Get());
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
GPUDevice::AdapterAndModeList D3D12Device::GetAdapterAndModeList()
|
|
||||||
{
|
|
||||||
AdapterAndModeList ret;
|
|
||||||
GetAdapterAndModeList(&ret, m_dxgi_factory.Get());
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
RenderAPI D3D12Device::GetRenderAPI() const
|
RenderAPI D3D12Device::GetRenderAPI() const
|
||||||
{
|
{
|
||||||
return RenderAPI::D3D12;
|
return RenderAPI::D3D12;
|
||||||
|
|
|
@ -64,8 +64,6 @@ public:
|
||||||
bool UpdateWindow() override;
|
bool UpdateWindow() override;
|
||||||
void ResizeWindow(s32 new_window_width, s32 new_window_height, float new_window_scale) override;
|
void ResizeWindow(s32 new_window_width, s32 new_window_height, float new_window_scale) override;
|
||||||
|
|
||||||
static AdapterAndModeList StaticGetAdapterAndModeList();
|
|
||||||
AdapterAndModeList GetAdapterAndModeList() override;
|
|
||||||
void DestroySurface() override;
|
void DestroySurface() override;
|
||||||
|
|
||||||
std::string GetDriverInfo() const override;
|
std::string GetDriverInfo() const override;
|
||||||
|
@ -220,8 +218,6 @@ private:
|
||||||
|
|
||||||
using SamplerMap = std::unordered_map<u64, D3D12DescriptorHandle>;
|
using SamplerMap = std::unordered_map<u64, D3D12DescriptorHandle>;
|
||||||
|
|
||||||
static void GetAdapterAndModeList(AdapterAndModeList* ret, IDXGIFactory5* factory);
|
|
||||||
|
|
||||||
void SetFeatures(FeatureMask disabled_features);
|
void SetFeatures(FeatureMask disabled_features);
|
||||||
|
|
||||||
u32 GetSwapChainBufferCount() const;
|
u32 GetSwapChainBufferCount() const;
|
||||||
|
|
|
@ -92,10 +92,10 @@ Microsoft::WRL::ComPtr<IDXGIFactory5> D3DCommon::CreateFactory(bool debug, Error
|
||||||
return factory;
|
return factory;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string FixupDuplicateAdapterNames(const std::vector<std::string>& adapter_names, std::string adapter_name)
|
static std::string FixupDuplicateAdapterNames(const GPUDevice::AdapterInfoList& adapter_names, std::string adapter_name)
|
||||||
{
|
{
|
||||||
if (std::any_of(adapter_names.begin(), adapter_names.end(),
|
if (std::any_of(adapter_names.begin(), adapter_names.end(),
|
||||||
[&adapter_name](const std::string& other) { return (adapter_name == other); }))
|
[&adapter_name](const GPUDevice::AdapterInfo& other) { return (adapter_name == other.name); }))
|
||||||
{
|
{
|
||||||
std::string original_adapter_name = std::move(adapter_name);
|
std::string original_adapter_name = std::move(adapter_name);
|
||||||
|
|
||||||
|
@ -104,21 +104,26 @@ 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 (
|
||||||
[&adapter_name](const std::string& other) { return (adapter_name == other); }));
|
std::any_of(adapter_names.begin(), adapter_names.end(),
|
||||||
|
[&adapter_name](const GPUDevice::AdapterInfo& other) { return (adapter_name == other.name); }));
|
||||||
}
|
}
|
||||||
|
|
||||||
return adapter_name;
|
return adapter_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> D3DCommon::GetAdapterNames(IDXGIFactory5* factory)
|
GPUDevice::AdapterInfoList D3DCommon::GetAdapterInfoList()
|
||||||
{
|
{
|
||||||
std::vector<std::string> adapter_names;
|
GPUDevice::AdapterInfoList adapters;
|
||||||
|
|
||||||
|
Microsoft::WRL::ComPtr<IDXGIFactory5> factory = CreateFactory(false, nullptr);
|
||||||
|
if (!factory)
|
||||||
|
return adapters;
|
||||||
|
|
||||||
Microsoft::WRL::ComPtr<IDXGIAdapter1> adapter;
|
Microsoft::WRL::ComPtr<IDXGIAdapter1> adapter;
|
||||||
for (u32 index = 0;; index++)
|
for (u32 index = 0;; index++)
|
||||||
{
|
{
|
||||||
const HRESULT hr = factory->EnumAdapters1(index, adapter.ReleaseAndGetAddressOf());
|
HRESULT hr = factory->EnumAdapters1(index, adapter.ReleaseAndGetAddressOf());
|
||||||
if (hr == DXGI_ERROR_NOT_FOUND)
|
if (hr == DXGI_ERROR_NOT_FOUND)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -128,50 +133,51 @@ std::vector<std::string> D3DCommon::GetAdapterNames(IDXGIFactory5* factory)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
adapter_names.push_back(FixupDuplicateAdapterNames(adapter_names, 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.
|
||||||
|
GPUDevice::AdapterInfo ai;
|
||||||
|
ai.name = FixupDuplicateAdapterNames(adapters, GetAdapterName(adapter.Get()));
|
||||||
|
ai.max_texture_size = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION;
|
||||||
|
ai.max_multisamples = 8;
|
||||||
|
ai.supports_sample_shading = true;
|
||||||
|
|
||||||
|
Microsoft::WRL::ComPtr<IDXGIOutput> output;
|
||||||
|
if (SUCCEEDED(hr = adapter->EnumOutputs(0, output.ReleaseAndGetAddressOf())))
|
||||||
|
{
|
||||||
|
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(GPUDevice::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
|
||||||
|
{
|
||||||
|
// Adapter may not have any outputs, don't spam the error log in this case.
|
||||||
|
if (hr != DXGI_ERROR_NOT_FOUND)
|
||||||
|
ERROR_LOG("EnumOutputs() failed: {:08X}", static_cast<unsigned>(hr));
|
||||||
|
}
|
||||||
|
|
||||||
|
adapters.push_back(std::move(ai));
|
||||||
}
|
}
|
||||||
|
|
||||||
return adapter_names;
|
return adapters;
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::string> D3DCommon::GetFullscreenModes(IDXGIFactory5* factory, std::string_view adapter_name)
|
|
||||||
{
|
|
||||||
std::vector<std::string> modes;
|
|
||||||
HRESULT hr;
|
|
||||||
|
|
||||||
Microsoft::WRL::ComPtr<IDXGIAdapter1> adapter = GetChosenOrFirstAdapter(factory, adapter_name);
|
|
||||||
if (!adapter)
|
|
||||||
return modes;
|
|
||||||
|
|
||||||
Microsoft::WRL::ComPtr<IDXGIOutput> output;
|
|
||||||
if (FAILED(hr = adapter->EnumOutputs(0, &output)))
|
|
||||||
{
|
|
||||||
ERROR_LOG("EnumOutputs() failed: {:08X}", static_cast<unsigned>(hr));
|
|
||||||
return modes;
|
|
||||||
}
|
|
||||||
|
|
||||||
UINT num_modes = 0;
|
|
||||||
if (FAILED(hr = output->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, 0, &num_modes, nullptr)))
|
|
||||||
{
|
|
||||||
ERROR_LOG("GetDisplayModeList() failed: {:08X}", static_cast<unsigned>(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())))
|
|
||||||
{
|
|
||||||
ERROR_LOG("GetDisplayModeList() (2) failed: {:08X}", static_cast<unsigned>(hr));
|
|
||||||
return modes;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const DXGI_MODE_DESC& mode : dmodes)
|
|
||||||
{
|
|
||||||
modes.push_back(GPUDevice::GetFullscreenModeString(mode.Width, mode.Height,
|
|
||||||
static_cast<float>(mode.RefreshRate.Numerator) /
|
|
||||||
static_cast<float>(mode.RefreshRate.Denominator)));
|
|
||||||
}
|
|
||||||
|
|
||||||
return modes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool D3DCommon::GetRequestedExclusiveFullscreenModeDesc(IDXGIFactory5* factory, const RECT& window_rect, u32 width,
|
bool D3DCommon::GetRequestedExclusiveFullscreenModeDesc(IDXGIFactory5* factory, const RECT& window_rect, u32 width,
|
||||||
|
@ -256,7 +262,7 @@ Microsoft::WRL::ComPtr<IDXGIAdapter1> D3DCommon::GetAdapterByName(IDXGIFactory5*
|
||||||
|
|
||||||
// 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;
|
GPUDevice::AdapterInfoList adapters;
|
||||||
|
|
||||||
Microsoft::WRL::ComPtr<IDXGIAdapter1> adapter;
|
Microsoft::WRL::ComPtr<IDXGIAdapter1> adapter;
|
||||||
for (u32 index = 0;; index++)
|
for (u32 index = 0;; index++)
|
||||||
|
@ -271,14 +277,16 @@ Microsoft::WRL::ComPtr<IDXGIAdapter1> D3DCommon::GetAdapterByName(IDXGIFactory5*
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string adapter_name = FixupDuplicateAdapterNames(adapter_names, GetAdapterName(adapter.Get()));
|
std::string adapter_name = FixupDuplicateAdapterNames(adapters, GetAdapterName(adapter.Get()));
|
||||||
if (adapter_name == name)
|
if (adapter_name == name)
|
||||||
{
|
{
|
||||||
VERBOSE_LOG("Found adapter '{}'", adapter_name);
|
VERBOSE_LOG("Found adapter '{}'", adapter_name);
|
||||||
return adapter;
|
return adapter;
|
||||||
}
|
}
|
||||||
|
|
||||||
adapter_names.push_back(std::move(adapter_name));
|
GPUDevice::AdapterInfo ai;
|
||||||
|
ai.name = std::move(adapter_name);
|
||||||
|
adapters.push_back(std::move(ai));
|
||||||
}
|
}
|
||||||
|
|
||||||
ERROR_LOG("Adapter '{}' not found.", name);
|
ERROR_LOG("Adapter '{}' not found.", name);
|
||||||
|
|
|
@ -35,10 +35,7 @@ D3D_FEATURE_LEVEL GetDeviceMaxFeatureLevel(IDXGIAdapter1* adapter);
|
||||||
Microsoft::WRL::ComPtr<IDXGIFactory5> CreateFactory(bool debug, Error* error);
|
Microsoft::WRL::ComPtr<IDXGIFactory5> CreateFactory(bool debug, Error* error);
|
||||||
|
|
||||||
// returns a list of all adapter names
|
// returns a list of all adapter names
|
||||||
std::vector<std::string> GetAdapterNames(IDXGIFactory5* factory);
|
GPUDevice::AdapterInfoList GetAdapterInfoList();
|
||||||
|
|
||||||
// returns a list of fullscreen modes for the specified adapter
|
|
||||||
std::vector<std::string> GetFullscreenModes(IDXGIFactory5* factory, 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,
|
||||||
|
|
|
@ -292,6 +292,45 @@ bool GPUDevice::IsSameRenderAPI(RenderAPI lhs, RenderAPI rhs)
|
||||||
(rhs == RenderAPI::OpenGL || rhs == RenderAPI::OpenGLES)));
|
(rhs == RenderAPI::OpenGL || rhs == RenderAPI::OpenGLES)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GPUDevice::AdapterInfoList GPUDevice::GetAdapterListForAPI(RenderAPI api)
|
||||||
|
{
|
||||||
|
AdapterInfoList ret;
|
||||||
|
|
||||||
|
switch (api)
|
||||||
|
{
|
||||||
|
#ifdef ENABLE_VULKAN
|
||||||
|
case RenderAPI::Vulkan:
|
||||||
|
ret = VulkanDevice::GetAdapterList();
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ENABLE_OPENGL
|
||||||
|
case RenderAPI::OpenGL:
|
||||||
|
case RenderAPI::OpenGLES:
|
||||||
|
// No way of querying.
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
case RenderAPI::D3D11:
|
||||||
|
case RenderAPI::D3D12:
|
||||||
|
ret = D3DCommon::GetAdapterInfoList();
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
case RenderAPI::Metal:
|
||||||
|
ret = WrapGetMetalAdapterList();
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
bool GPUDevice::Create(std::string_view adapter, std::string_view shader_cache_path, u32 shader_cache_version,
|
bool GPUDevice::Create(std::string_view adapter, std::string_view shader_cache_path, u32 shader_cache_version,
|
||||||
bool debug_device, GPUVSyncMode vsync, bool allow_present_throttle, bool threaded_presentation,
|
bool debug_device, GPUVSyncMode vsync, bool allow_present_throttle, bool threaded_presentation,
|
||||||
std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features, Error* error)
|
std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features, Error* error)
|
||||||
|
|
|
@ -509,11 +509,15 @@ public:
|
||||||
u32 num_uploads;
|
u32 num_uploads;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AdapterAndModeList
|
struct AdapterInfo
|
||||||
{
|
{
|
||||||
std::vector<std::string> adapter_names;
|
std::string name;
|
||||||
std::vector<std::string> fullscreen_modes;
|
std::vector<std::string> fullscreen_modes;
|
||||||
|
u32 max_texture_size;
|
||||||
|
u32 max_multisamples;
|
||||||
|
bool supports_sample_shading;
|
||||||
};
|
};
|
||||||
|
using AdapterInfoList = std::vector<AdapterInfo>;
|
||||||
|
|
||||||
struct PooledTextureDeleter
|
struct PooledTextureDeleter
|
||||||
{
|
{
|
||||||
|
@ -543,6 +547,9 @@ public:
|
||||||
/// Returns true if the render API is the same (e.g. GLES and GL).
|
/// Returns true if the render API is the same (e.g. GLES and GL).
|
||||||
static bool IsSameRenderAPI(RenderAPI lhs, RenderAPI rhs);
|
static bool IsSameRenderAPI(RenderAPI lhs, RenderAPI rhs);
|
||||||
|
|
||||||
|
/// Returns a list of adapters for the given API.
|
||||||
|
static AdapterInfoList GetAdapterListForAPI(RenderAPI api);
|
||||||
|
|
||||||
/// Parses a fullscreen mode into its components (width * height @ refresh hz)
|
/// Parses a fullscreen mode into its components (width * height @ refresh hz)
|
||||||
static bool GetRequestedExclusiveFullscreenMode(u32* width, u32* height, float* refresh_rate);
|
static bool GetRequestedExclusiveFullscreenMode(u32* width, u32* height, float* refresh_rate);
|
||||||
|
|
||||||
|
@ -572,12 +579,6 @@ public:
|
||||||
return counts[static_cast<u8>(layout)];
|
return counts[static_cast<u8>(layout)];
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __APPLE__
|
|
||||||
// We have to define these in the base class, because they're in Objective C++.
|
|
||||||
static std::unique_ptr<GPUDevice> WrapNewMetalDevice();
|
|
||||||
static AdapterAndModeList WrapGetMetalAdapterAndModeList();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ALWAYS_INLINE const Features& GetFeatures() const { return m_features; }
|
ALWAYS_INLINE const Features& GetFeatures() const { return m_features; }
|
||||||
ALWAYS_INLINE u32 GetMaxTextureSize() const { return m_max_texture_size; }
|
ALWAYS_INLINE u32 GetMaxTextureSize() const { return m_max_texture_size; }
|
||||||
ALWAYS_INLINE u32 GetMaxMultisamples() const { return m_max_multisamples; }
|
ALWAYS_INLINE u32 GetMaxMultisamples() const { return m_max_multisamples; }
|
||||||
|
@ -605,7 +606,6 @@ public:
|
||||||
virtual bool UpdateWindow() = 0;
|
virtual bool UpdateWindow() = 0;
|
||||||
|
|
||||||
virtual bool SupportsExclusiveFullscreen() const;
|
virtual bool SupportsExclusiveFullscreen() const;
|
||||||
virtual AdapterAndModeList GetAdapterAndModeList() = 0;
|
|
||||||
|
|
||||||
/// Call when the window size changes externally to recreate any resources.
|
/// Call when the window size changes externally to recreate any resources.
|
||||||
virtual void ResizeWindow(s32 new_window_width, s32 new_window_height, float new_window_scale) = 0;
|
virtual void ResizeWindow(s32 new_window_width, s32 new_window_height, float new_window_scale) = 0;
|
||||||
|
@ -801,6 +801,12 @@ private:
|
||||||
|
|
||||||
using TexturePool = std::deque<TexturePoolEntry>;
|
using TexturePool = std::deque<TexturePoolEntry>;
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
// We have to define these in the base class, because they're in Objective C++.
|
||||||
|
static std::unique_ptr<GPUDevice> WrapNewMetalDevice();
|
||||||
|
static AdapterInfoList WrapGetMetalAdapterList();
|
||||||
|
#endif
|
||||||
|
|
||||||
void OpenShaderCache(std::string_view base_path, u32 version);
|
void OpenShaderCache(std::string_view base_path, u32 version);
|
||||||
void CloseShaderCache();
|
void CloseShaderCache();
|
||||||
bool CreateResources(Error* error);
|
bool CreateResources(Error* error);
|
||||||
|
|
|
@ -204,8 +204,6 @@ public:
|
||||||
|
|
||||||
bool UpdateWindow() override;
|
bool UpdateWindow() override;
|
||||||
void ResizeWindow(s32 new_window_width, s32 new_window_height, float new_window_scale) override;
|
void ResizeWindow(s32 new_window_width, s32 new_window_height, float new_window_scale) override;
|
||||||
|
|
||||||
AdapterAndModeList GetAdapterAndModeList() override;
|
|
||||||
void DestroySurface() override;
|
void DestroySurface() override;
|
||||||
|
|
||||||
std::string GetDriverInfo() const override;
|
std::string GetDriverInfo() const override;
|
||||||
|
@ -286,8 +284,6 @@ public:
|
||||||
static void DeferRelease(id obj);
|
static void DeferRelease(id obj);
|
||||||
static void DeferRelease(u64 fence_counter, id obj);
|
static void DeferRelease(u64 fence_counter, id obj);
|
||||||
|
|
||||||
static AdapterAndModeList StaticGetAdapterAndModeList();
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool CreateDevice(std::string_view adapter, bool threaded_presentation,
|
bool CreateDevice(std::string_view adapter, bool threaded_presentation,
|
||||||
std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features,
|
std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features,
|
||||||
|
|
|
@ -87,6 +87,32 @@ static GPUTexture::Format GetTextureFormatForMTLFormat(MTLPixelFormat fmt)
|
||||||
return GPUTexture::Format::Unknown;
|
return GPUTexture::Format::Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u32 GetMetalMaxTextureSize(id<MTLDevice> device)
|
||||||
|
{
|
||||||
|
// https://gist.github.com/kylehowells/63d0723abc9588eb734cade4b7df660d
|
||||||
|
if ([device supportsFamily:MTLGPUFamilyMacCatalyst1] || [device supportsFamily:MTLGPUFamilyMac1] ||
|
||||||
|
[device supportsFamily:MTLGPUFamilyApple3])
|
||||||
|
{
|
||||||
|
return 16384;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 8192;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 GetMetalMaxMultisamples(id<MTLDevice> device)
|
||||||
|
{
|
||||||
|
u32 max_multisamples = 0;
|
||||||
|
for (u32 multisamples = 1; multisamples < 16; multisamples *= 2)
|
||||||
|
{
|
||||||
|
if (![device supportsTextureSampleCount:multisamples])
|
||||||
|
break;
|
||||||
|
max_multisamples = multisamples;
|
||||||
|
}
|
||||||
|
return max_multisamples;
|
||||||
|
}
|
||||||
|
|
||||||
template<typename F>
|
template<typename F>
|
||||||
static void RunOnMainThread(F&& f)
|
static void RunOnMainThread(F&& f)
|
||||||
{
|
{
|
||||||
|
@ -204,16 +230,8 @@ bool MetalDevice::CreateDevice(std::string_view adapter, bool threaded_presentat
|
||||||
|
|
||||||
void MetalDevice::SetFeatures(FeatureMask disabled_features)
|
void MetalDevice::SetFeatures(FeatureMask disabled_features)
|
||||||
{
|
{
|
||||||
// https://gist.github.com/kylehowells/63d0723abc9588eb734cade4b7df660d
|
m_max_texture_size = GetMetalMaxTextureSize(m_device);
|
||||||
if ([m_device supportsFamily:MTLGPUFamilyMacCatalyst1] || [m_device supportsFamily:MTLGPUFamilyMac1] ||
|
m_max_multisamples = GetMetalMaxMultisamples(m_device);
|
||||||
[m_device supportsFamily:MTLGPUFamilyApple3])
|
|
||||||
{
|
|
||||||
m_max_texture_size = 16384;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_max_texture_size = 8192;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Framebuffer fetch requires MSL 2.3 and an Apple GPU family.
|
// Framebuffer fetch requires MSL 2.3 and an Apple GPU family.
|
||||||
const bool supports_fbfetch = [m_device supportsFamily:MTLGPUFamilyApple1];
|
const bool supports_fbfetch = [m_device supportsFamily:MTLGPUFamilyApple1];
|
||||||
|
@ -222,14 +240,6 @@ void MetalDevice::SetFeatures(FeatureMask disabled_features)
|
||||||
const bool supports_barriers =
|
const bool supports_barriers =
|
||||||
([m_device supportsFamily:MTLGPUFamilyMac1] && ![m_device supportsFamily:MTLGPUFamilyApple3]);
|
([m_device supportsFamily:MTLGPUFamilyMac1] && ![m_device supportsFamily:MTLGPUFamilyApple3]);
|
||||||
|
|
||||||
m_max_multisamples = 0;
|
|
||||||
for (u32 multisamples = 1; multisamples < 16; multisamples *= 2)
|
|
||||||
{
|
|
||||||
if (![m_device supportsTextureSampleCount:multisamples])
|
|
||||||
break;
|
|
||||||
m_max_multisamples = multisamples;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_features.dual_source_blend = !(disabled_features & FEATURE_MASK_DUAL_SOURCE_BLEND);
|
m_features.dual_source_blend = !(disabled_features & FEATURE_MASK_DUAL_SOURCE_BLEND);
|
||||||
m_features.framebuffer_fetch = !(disabled_features & FEATURE_MASK_FRAMEBUFFER_FETCH) && supports_fbfetch;
|
m_features.framebuffer_fetch = !(disabled_features & FEATURE_MASK_FRAMEBUFFER_FETCH) && supports_fbfetch;
|
||||||
m_features.per_sample_shading = true;
|
m_features.per_sample_shading = true;
|
||||||
|
@ -538,26 +548,6 @@ bool MetalDevice::IsRenderTargetBound(const GPUTexture* tex) const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
GPUDevice::AdapterAndModeList MetalDevice::StaticGetAdapterAndModeList()
|
|
||||||
{
|
|
||||||
AdapterAndModeList ret;
|
|
||||||
@autoreleasepool
|
|
||||||
{
|
|
||||||
NSArray<id<MTLDevice>>* devices = [MTLCopyAllDevices() autorelease];
|
|
||||||
const u32 count = static_cast<u32>([devices count]);
|
|
||||||
ret.adapter_names.reserve(count);
|
|
||||||
for (u32 i = 0; i < count; i++)
|
|
||||||
ret.adapter_names.emplace_back([devices[i].name UTF8String]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
GPUDevice::AdapterAndModeList MetalDevice::GetAdapterAndModeList()
|
|
||||||
{
|
|
||||||
return StaticGetAdapterAndModeList();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MetalDevice::SetGPUTimingEnabled(bool enabled)
|
bool MetalDevice::SetGPUTimingEnabled(bool enabled)
|
||||||
{
|
{
|
||||||
if (m_gpu_timing_enabled == enabled)
|
if (m_gpu_timing_enabled == enabled)
|
||||||
|
@ -2505,7 +2495,24 @@ std::unique_ptr<GPUDevice> GPUDevice::WrapNewMetalDevice()
|
||||||
return std::unique_ptr<GPUDevice>(new MetalDevice());
|
return std::unique_ptr<GPUDevice>(new MetalDevice());
|
||||||
}
|
}
|
||||||
|
|
||||||
GPUDevice::AdapterAndModeList GPUDevice::WrapGetMetalAdapterAndModeList()
|
GPUDevice::AdapterInfoList GPUDevice::WrapGetMetalAdapterList()
|
||||||
{
|
{
|
||||||
return MetalDevice::StaticGetAdapterAndModeList();
|
AdapterInfoList ret;
|
||||||
|
@autoreleasepool
|
||||||
|
{
|
||||||
|
NSArray<id<MTLDevice>>* devices = [MTLCopyAllDevices() autorelease];
|
||||||
|
const u32 count = static_cast<u32>([devices count]);
|
||||||
|
ret.reserve(count);
|
||||||
|
for (u32 i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
AdapterInfo ai;
|
||||||
|
ai.name = [devices[i].name UTF8String];
|
||||||
|
ai.max_texture_size = GetMetalMaxTextureSize(devices[i]);
|
||||||
|
ai.max_multisamples = GetMetalMaxMultisamples(devices[i]);
|
||||||
|
ai.supports_sample_shading = true;
|
||||||
|
ret.push_back(std::move(ai));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,11 +111,6 @@ OpenGLContext::OpenGLContext(const WindowInfo& wi) : m_wi(wi)
|
||||||
|
|
||||||
OpenGLContext::~OpenGLContext() = default;
|
OpenGLContext::~OpenGLContext() = default;
|
||||||
|
|
||||||
std::vector<OpenGLContext::FullscreenModeInfo> OpenGLContext::EnumerateFullscreenModes()
|
|
||||||
{
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<OpenGLContext> OpenGLContext::Create(const WindowInfo& wi, Error* error)
|
std::unique_ptr<OpenGLContext> OpenGLContext::Create(const WindowInfo& wi, Error* error)
|
||||||
{
|
{
|
||||||
static constexpr std::array<Version, 14> vlist = {{{Profile::Core, 4, 6},
|
static constexpr std::array<Version, 14> vlist = {{{Profile::Core, 4, 6},
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <span>
|
#include <span>
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
class Error;
|
class Error;
|
||||||
|
|
||||||
|
@ -33,13 +32,6 @@ public:
|
||||||
int minor_version;
|
int minor_version;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FullscreenModeInfo
|
|
||||||
{
|
|
||||||
u32 width;
|
|
||||||
u32 height;
|
|
||||||
float refresh_rate;
|
|
||||||
};
|
|
||||||
|
|
||||||
ALWAYS_INLINE const WindowInfo& GetWindowInfo() const { return m_wi; }
|
ALWAYS_INLINE const WindowInfo& GetWindowInfo() const { return m_wi; }
|
||||||
ALWAYS_INLINE bool IsGLES() const { return (m_version.profile == Profile::ES); }
|
ALWAYS_INLINE bool IsGLES() const { return (m_version.profile == Profile::ES); }
|
||||||
ALWAYS_INLINE u32 GetSurfaceWidth() const { return m_wi.surface_width; }
|
ALWAYS_INLINE u32 GetSurfaceWidth() const { return m_wi.surface_width; }
|
||||||
|
@ -57,8 +49,6 @@ public:
|
||||||
virtual bool SetSwapInterval(s32 interval) = 0;
|
virtual bool SetSwapInterval(s32 interval) = 0;
|
||||||
virtual std::unique_ptr<OpenGLContext> CreateSharedContext(const WindowInfo& wi, Error* error) = 0;
|
virtual std::unique_ptr<OpenGLContext> CreateSharedContext(const WindowInfo& wi, Error* error) = 0;
|
||||||
|
|
||||||
virtual std::vector<FullscreenModeInfo> EnumerateFullscreenModes();
|
|
||||||
|
|
||||||
static std::unique_ptr<OpenGLContext> Create(const WindowInfo& wi, Error* error);
|
static std::unique_ptr<OpenGLContext> Create(const WindowInfo& wi, Error* error);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -663,21 +663,6 @@ void OpenGLDevice::DestroyFramebuffer(GLuint fbo)
|
||||||
glDeleteFramebuffers(1, &fbo);
|
glDeleteFramebuffers(1, &fbo);
|
||||||
}
|
}
|
||||||
|
|
||||||
GPUDevice::AdapterAndModeList OpenGLDevice::GetAdapterAndModeList()
|
|
||||||
{
|
|
||||||
AdapterAndModeList aml;
|
|
||||||
|
|
||||||
if (m_gl_context)
|
|
||||||
{
|
|
||||||
for (const OpenGLContext::FullscreenModeInfo& fmi : m_gl_context->EnumerateFullscreenModes())
|
|
||||||
{
|
|
||||||
aml.fullscreen_modes.push_back(GetFullscreenModeString(fmi.width, fmi.height, fmi.refresh_rate));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return aml;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLDevice::DestroySurface()
|
void OpenGLDevice::DestroySurface()
|
||||||
{
|
{
|
||||||
if (!m_gl_context)
|
if (!m_gl_context)
|
||||||
|
|
|
@ -48,8 +48,6 @@ public:
|
||||||
|
|
||||||
std::string GetDriverInfo() const override;
|
std::string GetDriverInfo() const override;
|
||||||
|
|
||||||
AdapterAndModeList GetAdapterAndModeList() override;
|
|
||||||
|
|
||||||
std::unique_ptr<GPUTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
std::unique_ptr<GPUTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
||||||
GPUTexture::Type type, GPUTexture::Format format,
|
GPUTexture::Type type, GPUTexture::Format format,
|
||||||
const void* data = nullptr, u32 data_stride = 0) override;
|
const void* data = nullptr, u32 data_stride = 0) override;
|
||||||
|
|
|
@ -315,28 +315,76 @@ VulkanDevice::GPUList VulkanDevice::EnumerateGPUs(VkInstance instance)
|
||||||
VkPhysicalDeviceProperties props = {};
|
VkPhysicalDeviceProperties props = {};
|
||||||
vkGetPhysicalDeviceProperties(device, &props);
|
vkGetPhysicalDeviceProperties(device, &props);
|
||||||
|
|
||||||
std::string gpu_name = props.deviceName;
|
VkPhysicalDeviceFeatures available_features = {};
|
||||||
|
vkGetPhysicalDeviceFeatures(device, &available_features);
|
||||||
|
|
||||||
|
AdapterInfo ai;
|
||||||
|
ai.name = props.deviceName;
|
||||||
|
ai.max_texture_size = std::min(props.limits.maxFramebufferWidth, props.limits.maxImageDimension2D);
|
||||||
|
ai.max_multisamples = GetMaxMultisamples(device, props);
|
||||||
|
ai.supports_sample_shading = available_features.sampleRateShading;
|
||||||
|
|
||||||
// handle duplicate adapter names
|
// handle duplicate adapter names
|
||||||
if (std::any_of(gpus.begin(), gpus.end(), [&gpu_name](const auto& other) { return (gpu_name == other.second); }))
|
if (std::any_of(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 (
|
} while (
|
||||||
std::any_of(gpus.begin(), gpus.end(), [&gpu_name](const auto& other) { return (gpu_name == other.second); }));
|
std::any_of(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;
|
return gpus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VulkanDevice::GPUList VulkanDevice::EnumerateGPUs()
|
||||||
|
{
|
||||||
|
GPUList ret;
|
||||||
|
std::unique_lock lock(s_instance_mutex);
|
||||||
|
|
||||||
|
// Device shouldn't be torn down since we have the lock.
|
||||||
|
if (g_gpu_device && g_gpu_device->GetRenderAPI() == RenderAPI::Vulkan && Vulkan::IsVulkanLibraryLoaded())
|
||||||
|
{
|
||||||
|
ret = EnumerateGPUs(VulkanDevice::GetInstance().m_instance);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (Vulkan::LoadVulkanLibrary(nullptr))
|
||||||
|
{
|
||||||
|
OptionalExtensions oe = {};
|
||||||
|
const VkInstance instance = CreateVulkanInstance(WindowInfo(), &oe, false, false);
|
||||||
|
if (instance != VK_NULL_HANDLE)
|
||||||
|
{
|
||||||
|
if (Vulkan::LoadVulkanInstanceFunctions(instance))
|
||||||
|
ret = EnumerateGPUs(instance);
|
||||||
|
|
||||||
|
vkDestroyInstance(instance, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vulkan::UnloadVulkanLibrary();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
GPUDevice::AdapterInfoList VulkanDevice::GetAdapterList()
|
||||||
|
{
|
||||||
|
AdapterInfoList ret;
|
||||||
|
GPUList gpus = EnumerateGPUs();
|
||||||
|
ret.reserve(gpus.size());
|
||||||
|
for (auto& [physical_device, adapter_info] : gpus)
|
||||||
|
ret.push_back(std::move(adapter_info));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
bool VulkanDevice::SelectDeviceExtensions(ExtensionList* extension_list, bool enable_surface)
|
bool VulkanDevice::SelectDeviceExtensions(ExtensionList* extension_list, bool enable_surface)
|
||||||
{
|
{
|
||||||
u32 extension_count = 0;
|
u32 extension_count = 0;
|
||||||
|
@ -1853,67 +1901,21 @@ void VulkanDevice::DestroyFramebuffer(VkFramebuffer fbo)
|
||||||
VulkanDevice::GetInstance().DeferFramebufferDestruction(fbo);
|
VulkanDevice::GetInstance().DeferFramebufferDestruction(fbo);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanDevice::GetAdapterAndModeList(AdapterAndModeList* ret, VkInstance instance)
|
|
||||||
{
|
|
||||||
GPUList gpus = EnumerateGPUs(instance);
|
|
||||||
ret->adapter_names.clear();
|
|
||||||
for (auto& [gpu, name] : gpus)
|
|
||||||
ret->adapter_names.push_back(std::move(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
GPUDevice::AdapterAndModeList VulkanDevice::StaticGetAdapterAndModeList()
|
|
||||||
{
|
|
||||||
AdapterAndModeList ret;
|
|
||||||
std::unique_lock lock(s_instance_mutex);
|
|
||||||
|
|
||||||
// Device shouldn't be torn down since we have the lock.
|
|
||||||
if (g_gpu_device && g_gpu_device->GetRenderAPI() == RenderAPI::Vulkan && Vulkan::IsVulkanLibraryLoaded())
|
|
||||||
{
|
|
||||||
GetAdapterAndModeList(&ret, VulkanDevice::GetInstance().m_instance);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (Vulkan::LoadVulkanLibrary(nullptr))
|
|
||||||
{
|
|
||||||
OptionalExtensions oe = {};
|
|
||||||
const VkInstance instance = CreateVulkanInstance(WindowInfo(), &oe, false, false);
|
|
||||||
if (instance != VK_NULL_HANDLE)
|
|
||||||
{
|
|
||||||
if (Vulkan::LoadVulkanInstanceFunctions(instance))
|
|
||||||
GetAdapterAndModeList(&ret, instance);
|
|
||||||
|
|
||||||
vkDestroyInstance(instance, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
Vulkan::UnloadVulkanLibrary();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
GPUDevice::AdapterAndModeList VulkanDevice::GetAdapterAndModeList()
|
|
||||||
{
|
|
||||||
AdapterAndModeList ret;
|
|
||||||
GetAdapterAndModeList(&ret, m_instance);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VulkanDevice::IsSuitableDefaultRenderer()
|
bool VulkanDevice::IsSuitableDefaultRenderer()
|
||||||
{
|
{
|
||||||
#ifdef __ANDROID__
|
#ifdef __ANDROID__
|
||||||
// No way in hell.
|
// No way in hell.
|
||||||
return false;
|
return false;
|
||||||
#else
|
#else
|
||||||
AdapterAndModeList aml = StaticGetAdapterAndModeList();
|
GPUList gpus = EnumerateGPUs();
|
||||||
if (aml.adapter_names.empty())
|
if (gpus.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 = aml.adapter_names.front();
|
const std::string& name = gpus.front().second.name;
|
||||||
INFO_LOG("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).
|
||||||
|
@ -2000,8 +2002,8 @@ bool VulkanDevice::CreateDevice(std::string_view adapter, bool threaded_presenta
|
||||||
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++)
|
||||||
{
|
{
|
||||||
INFO_LOG("GPU {}: {}", gpu_index, gpus[gpu_index].second);
|
INFO_LOG("GPU {}: {}", gpu_index, gpus[gpu_index].second.name);
|
||||||
if (gpus[gpu_index].second == adapter)
|
if (gpus[gpu_index].second.name == adapter)
|
||||||
{
|
{
|
||||||
m_physical_device = gpus[gpu_index].first;
|
m_physical_device = gpus[gpu_index].first;
|
||||||
break;
|
break;
|
||||||
|
@ -2010,13 +2012,13 @@ bool VulkanDevice::CreateDevice(std::string_view adapter, bool threaded_presenta
|
||||||
|
|
||||||
if (gpu_index == static_cast<u32>(gpus.size()))
|
if (gpu_index == static_cast<u32>(gpus.size()))
|
||||||
{
|
{
|
||||||
WARNING_LOG("Requested GPU '{}' not found, using first ({})", adapter, gpus[0].second);
|
WARNING_LOG("Requested GPU '{}' not found, using first ({})", adapter, gpus[0].second.name);
|
||||||
m_physical_device = gpus[0].first;
|
m_physical_device = gpus[0].first;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
INFO_LOG("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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2542,35 +2544,40 @@ void VulkanDevice::InsertDebugMessage(const char* msg)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VulkanDevice::CheckFeatures(FeatureMask disabled_features)
|
u32 VulkanDevice::GetMaxMultisamples(VkPhysicalDevice physical_device, const VkPhysicalDeviceProperties& properties)
|
||||||
{
|
{
|
||||||
m_max_texture_size = m_device_properties.limits.maxImageDimension2D;
|
|
||||||
|
|
||||||
VkImageFormatProperties color_properties = {};
|
VkImageFormatProperties color_properties = {};
|
||||||
vkGetPhysicalDeviceImageFormatProperties(m_physical_device, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_TYPE_2D,
|
vkGetPhysicalDeviceImageFormatProperties(physical_device, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_TYPE_2D,
|
||||||
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, 0,
|
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, 0,
|
||||||
&color_properties);
|
&color_properties);
|
||||||
VkImageFormatProperties depth_properties = {};
|
VkImageFormatProperties depth_properties = {};
|
||||||
vkGetPhysicalDeviceImageFormatProperties(m_physical_device, VK_FORMAT_D32_SFLOAT, VK_IMAGE_TYPE_2D,
|
vkGetPhysicalDeviceImageFormatProperties(physical_device, VK_FORMAT_D32_SFLOAT, VK_IMAGE_TYPE_2D,
|
||||||
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, 0,
|
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, 0,
|
||||||
&depth_properties);
|
&depth_properties);
|
||||||
const VkSampleCountFlags combined_properties = m_device_properties.limits.framebufferColorSampleCounts &
|
const VkSampleCountFlags combined_properties = properties.limits.framebufferColorSampleCounts &
|
||||||
m_device_properties.limits.framebufferDepthSampleCounts &
|
properties.limits.framebufferDepthSampleCounts &
|
||||||
color_properties.sampleCounts & depth_properties.sampleCounts;
|
color_properties.sampleCounts & depth_properties.sampleCounts;
|
||||||
if (combined_properties & VK_SAMPLE_COUNT_64_BIT)
|
if (combined_properties & VK_SAMPLE_COUNT_64_BIT)
|
||||||
m_max_multisamples = 64;
|
return 64;
|
||||||
else if (combined_properties & VK_SAMPLE_COUNT_32_BIT)
|
else if (combined_properties & VK_SAMPLE_COUNT_32_BIT)
|
||||||
m_max_multisamples = 32;
|
return 32;
|
||||||
else if (combined_properties & VK_SAMPLE_COUNT_16_BIT)
|
else if (combined_properties & VK_SAMPLE_COUNT_16_BIT)
|
||||||
m_max_multisamples = 16;
|
return 16;
|
||||||
else if (combined_properties & VK_SAMPLE_COUNT_8_BIT)
|
else if (combined_properties & VK_SAMPLE_COUNT_8_BIT)
|
||||||
m_max_multisamples = 8;
|
return 8;
|
||||||
else if (combined_properties & VK_SAMPLE_COUNT_4_BIT)
|
else if (combined_properties & VK_SAMPLE_COUNT_4_BIT)
|
||||||
m_max_multisamples = 4;
|
return 4;
|
||||||
else if (combined_properties & VK_SAMPLE_COUNT_2_BIT)
|
else if (combined_properties & VK_SAMPLE_COUNT_2_BIT)
|
||||||
m_max_multisamples = 2;
|
return 2;
|
||||||
else
|
else
|
||||||
m_max_multisamples = 1;
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VulkanDevice::CheckFeatures(FeatureMask disabled_features)
|
||||||
|
{
|
||||||
|
m_max_texture_size =
|
||||||
|
std::min(m_device_properties.limits.maxImageDimension2D, m_device_properties.limits.maxFramebufferWidth);
|
||||||
|
m_max_multisamples = GetMaxMultisamples(m_physical_device, m_device_properties);
|
||||||
|
|
||||||
m_features.dual_source_blend =
|
m_features.dual_source_blend =
|
||||||
!(disabled_features & FEATURE_MASK_DUAL_SOURCE_BLEND) && m_device_features.dualSrcBlend;
|
!(disabled_features & FEATURE_MASK_DUAL_SOURCE_BLEND) && m_device_features.dualSrcBlend;
|
||||||
|
|
|
@ -66,15 +66,18 @@ public:
|
||||||
VulkanDevice();
|
VulkanDevice();
|
||||||
~VulkanDevice() override;
|
~VulkanDevice() override;
|
||||||
|
|
||||||
|
// Returns a list of Vulkan-compatible GPUs.
|
||||||
|
using GPUList = std::vector<std::pair<VkPhysicalDevice, AdapterInfo>>;
|
||||||
|
static GPUList EnumerateGPUs(VkInstance instance);
|
||||||
|
static GPUList EnumerateGPUs();
|
||||||
|
static AdapterInfoList GetAdapterList();
|
||||||
|
|
||||||
RenderAPI GetRenderAPI() const override;
|
RenderAPI GetRenderAPI() const override;
|
||||||
|
|
||||||
bool HasSurface() const override;
|
bool HasSurface() const override;
|
||||||
|
|
||||||
bool UpdateWindow() override;
|
bool UpdateWindow() override;
|
||||||
void ResizeWindow(s32 new_window_width, s32 new_window_height, float new_window_scale) override;
|
void ResizeWindow(s32 new_window_width, s32 new_window_height, float new_window_scale) override;
|
||||||
|
|
||||||
static AdapterAndModeList StaticGetAdapterAndModeList();
|
|
||||||
AdapterAndModeList GetAdapterAndModeList() override;
|
|
||||||
void DestroySurface() override;
|
void DestroySurface() override;
|
||||||
|
|
||||||
std::string GetDriverInfo() const override;
|
std::string GetDriverInfo() const override;
|
||||||
|
@ -287,16 +290,10 @@ private:
|
||||||
using CleanupObjectFunction = void (*)(VulkanDevice& dev, void* obj);
|
using CleanupObjectFunction = void (*)(VulkanDevice& dev, void* obj);
|
||||||
using SamplerMap = std::unordered_map<u64, VkSampler>;
|
using SamplerMap = std::unordered_map<u64, VkSampler>;
|
||||||
|
|
||||||
static void GetAdapterAndModeList(AdapterAndModeList* ret, VkInstance instance);
|
|
||||||
|
|
||||||
// Helper method to create a Vulkan instance.
|
// Helper method to create a Vulkan instance.
|
||||||
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);
|
|
||||||
|
|
||||||
bool ValidatePipelineCacheHeader(const VK_PIPELINE_CACHE_HEADER& header);
|
bool ValidatePipelineCacheHeader(const VK_PIPELINE_CACHE_HEADER& header);
|
||||||
void FillPipelineCacheHeader(VK_PIPELINE_CACHE_HEADER* header);
|
void FillPipelineCacheHeader(VK_PIPELINE_CACHE_HEADER* header);
|
||||||
|
|
||||||
|
@ -331,6 +328,8 @@ private:
|
||||||
|
|
||||||
bool CheckFeatures(FeatureMask disabled_features);
|
bool CheckFeatures(FeatureMask disabled_features);
|
||||||
|
|
||||||
|
static u32 GetMaxMultisamples(VkPhysicalDevice physical_device, const VkPhysicalDeviceProperties& properties);
|
||||||
|
|
||||||
bool CreateAllocator();
|
bool CreateAllocator();
|
||||||
void DestroyAllocator();
|
void DestroyAllocator();
|
||||||
bool CreateCommandBuffers();
|
bool CreateCommandBuffers();
|
||||||
|
|
Loading…
Reference in New Issue