mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-22 05:45:38 +00:00
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<GameList::Entry> s_game_settings_entry;
|
||||
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<PostProcessingStageInfo> s_postprocessing_stages;
|
||||
static std::vector<const HotkeyInfo*> s_hotkey_list_cache;
|
||||
|
@ -2781,10 +2781,13 @@ void FullscreenUI::SwitchToGameSettings(const GameList::Entry* entry)
|
|||
|
||||
void FullscreenUI::PopulateGraphicsAdapterList()
|
||||
{
|
||||
GPUDevice::AdapterAndModeList ml(g_gpu_device->GetAdapterAndModeList());
|
||||
s_graphics_adapter_list_cache = std::move(ml.adapter_names);
|
||||
s_fullscreen_mode_list_cache = std::move(ml.fullscreen_modes);
|
||||
s_fullscreen_mode_list_cache.insert(s_fullscreen_mode_list_cache.begin(), FSUI_STR("Borderless Fullscreen"));
|
||||
const GPURenderer renderer =
|
||||
Settings::ParseRendererName(GetEffectiveTinyStringSetting(GetEditingSettingsInterface(false), "GPU", "Renderer",
|
||||
Settings::GetRendererName(Settings::DEFAULT_GPU_RENDERER))
|
||||
.c_str())
|
||||
.value_or(Settings::DEFAULT_GPU_RENDERER);
|
||||
|
||||
s_graphics_adapter_list_cache = GPUDevice::GetAdapterListForAPI(Settings::GetRenderAPIForRenderer(renderer));
|
||||
}
|
||||
|
||||
void FullscreenUI::PopulateGameListDirectoryCache(SettingsInterface* si)
|
||||
|
@ -4160,24 +4163,22 @@ void FullscreenUI::DrawDisplaySettingsPage()
|
|||
.value_or(Settings::DEFAULT_GPU_RENDERER);
|
||||
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*>(""));
|
||||
|
||||
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")))
|
||||
{
|
||||
GPUDevice::AdapterAndModeList aml(g_gpu_device->GetAdapterAndModeList());
|
||||
|
||||
ImGuiFullscreen::ChoiceDialogOptions options;
|
||||
options.reserve(aml.adapter_names.size() + 2);
|
||||
options.reserve(s_graphics_adapter_list_cache.size() + 2);
|
||||
if (game_settings)
|
||||
options.emplace_back(FSUI_STR("Use Global Setting"), !strvalue.has_value());
|
||||
options.emplace_back(FSUI_STR("Default"), strvalue.has_value() && strvalue->empty());
|
||||
for (std::string& mode : aml.adapter_names)
|
||||
options.emplace_back(FSUI_STR("Use Global Setting"), !current_adapter.has_value());
|
||||
options.emplace_back(FSUI_STR("Default"), current_adapter.has_value() && current_adapter->empty());
|
||||
for (const GPUDevice::AdapterInfo& adapter : s_graphics_adapter_list_cache)
|
||||
{
|
||||
const bool checked = (strvalue.has_value() && strvalue.value() == mode);
|
||||
options.emplace_back(std::move(mode), checked);
|
||||
const bool checked = (current_adapter.has_value() && current_adapter.value() == adapter.name);
|
||||
options.emplace_back(adapter.name, 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));
|
||||
}
|
||||
|
||||
strvalue = bsi->GetOptionalSmallStringValue("GPU", "FullscreenMode",
|
||||
std::optional<SmallString> strvalue = bsi->GetOptionalSmallStringValue("GPU", "FullscreenMode",
|
||||
game_settings ? std::nullopt : std::optional<const char*>(""));
|
||||
|
||||
if (MenuButtonWithValue(
|
||||
|
@ -4212,17 +4213,36 @@ void FullscreenUI::DrawDisplaySettingsPage()
|
|||
strvalue.has_value() ? (strvalue->empty() ? FSUI_CSTR("Borderless Fullscreen") : strvalue->c_str()) :
|
||||
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;
|
||||
options.reserve(aml.fullscreen_modes.size() + 2);
|
||||
options.reserve((selected_adapter ? selected_adapter->fullscreen_modes.size() : 0) + 2);
|
||||
if (game_settings)
|
||||
options.emplace_back(FSUI_STR("Use Global Setting"), !strvalue.has_value());
|
||||
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);
|
||||
options.emplace_back(std::move(mode), checked);
|
||||
for (const std::string& mode : selected_adapter->fullscreen_modes)
|
||||
{
|
||||
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) {
|
||||
|
|
|
@ -8,14 +8,7 @@
|
|||
#include "settingswindow.h"
|
||||
#include "settingwidgetbinder.h"
|
||||
|
||||
// For enumerating adapters.
|
||||
#ifdef _WIN32
|
||||
#include "util/d3d11_device.h"
|
||||
#include "util/d3d12_device.h"
|
||||
#endif
|
||||
#ifdef ENABLE_VULKAN
|
||||
#include "util/vulkan_device.h"
|
||||
#endif
|
||||
#include <algorithm>
|
||||
|
||||
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,
|
||||
&Settings::GetRendererName, Settings::DEFAULT_GPU_RENDERER);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.resolutionScale, "GPU", "ResolutionScale", 1);
|
||||
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.textureFiltering, "GPU", "TextureFilter",
|
||||
&Settings::ParseTextureFilterName, &Settings::GetTextureFilterName,
|
||||
Settings::DEFAULT_GPU_TEXTURE_FILTER);
|
||||
|
@ -89,10 +81,6 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget*
|
|||
|
||||
connect(m_ui.renderer, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
||||
&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,
|
||||
&GraphicsSettingsWidget::updateResolutionDependentOptions);
|
||||
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.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
|
||||
|
||||
SettingWidgetBinder::BindWidgetToEnumSetting(
|
||||
|
@ -151,9 +122,6 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget*
|
|||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.forceRoundedTexcoords, "GPU", "ForceRoundTextureCoordinates",
|
||||
false);
|
||||
|
||||
connect(m_ui.fullscreenMode, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
||||
&GraphicsSettingsWidget::onFullscreenModeChanged);
|
||||
|
||||
// PGXP Tab
|
||||
|
||||
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))));
|
||||
}
|
||||
|
||||
{
|
||||
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++)
|
||||
{
|
||||
m_ui.gpuLineDetectMode->addItem(
|
||||
|
@ -694,75 +652,134 @@ void GraphicsSettingsWidget::updateRendererDependentOptions()
|
|||
|
||||
void GraphicsSettingsWidget::populateGPUAdaptersAndResolutions(RenderAPI render_api)
|
||||
{
|
||||
GPUDevice::AdapterAndModeList aml;
|
||||
switch (render_api)
|
||||
// Don't re-query, it's expensive.
|
||||
if (m_adapters_render_api != render_api)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
case RenderAPI::D3D11:
|
||||
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;
|
||||
m_adapters_render_api = render_api;
|
||||
m_adapters = GPUDevice::GetAdapterListForAPI(render_api);
|
||||
}
|
||||
|
||||
{
|
||||
const std::string current_adapter(m_dialog->getEffectiveStringValue("GPU", "Adapter", ""));
|
||||
QSignalBlocker blocker(m_ui.adapter);
|
||||
const GPUDevice::AdapterInfo* current_adapter = nullptr;
|
||||
SettingsInterface* const sif = m_dialog->getSettingsInterface();
|
||||
|
||||
// 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->addItem(tr("(Default)"));
|
||||
m_ui.adapter->addItem(tr("(Default)"), QVariant(QString()));
|
||||
|
||||
// add the other adapters
|
||||
for (const std::string& adapter_name : aml.adapter_names)
|
||||
const std::string current_adapter_name = m_dialog->getEffectiveStringValue("GPU", "Adapter", "");
|
||||
for (const GPUDevice::AdapterInfo& adapter : m_adapters)
|
||||
{
|
||||
m_ui.adapter->addItem(QString::fromStdString(adapter_name));
|
||||
|
||||
if (adapter_name == current_adapter)
|
||||
m_ui.adapter->setCurrentIndex(m_ui.adapter->count() - 1);
|
||||
const QString qadaptername = QString::fromStdString(adapter.name);
|
||||
m_ui.adapter->addItem(qadaptername, QVariant(qadaptername));
|
||||
if (adapter.name == current_adapter_name)
|
||||
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
|
||||
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", ""));
|
||||
QSignalBlocker blocker(m_ui.fullscreenMode);
|
||||
|
||||
m_ui.fullscreenMode->disconnect();
|
||||
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));
|
||||
|
||||
if (mode_name == current_mode)
|
||||
m_ui.fullscreenMode->setCurrentIndex(m_ui.fullscreenMode->count() - 1);
|
||||
for (const std::string& mode_name : current_adapter->fullscreen_modes)
|
||||
{
|
||||
const QString qmodename = QString::fromStdString(mode_name);
|
||||
m_ui.fullscreenMode->addItem(qmodename, QVariant(qmodename));
|
||||
}
|
||||
}
|
||||
|
||||
// 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()
|
||||
|
@ -785,18 +802,6 @@ void GraphicsSettingsWidget::updatePGXPSettingsEnabled()
|
|||
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()
|
||||
{
|
||||
const DisplayAspectRatio ratio =
|
||||
|
@ -828,24 +833,6 @@ void GraphicsSettingsWidget::updateResolutionDependentOptions()
|
|||
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()
|
||||
{
|
||||
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()
|
||||
{
|
||||
const bool any_replacements_enabled =
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
|
||||
#include "ui_graphicssettingswidget.h"
|
||||
|
||||
enum class RenderAPI : u32;
|
||||
#include "util/gpu_device.h"
|
||||
|
||||
enum class GPURenderer : u8;
|
||||
|
||||
class SettingsWindow;
|
||||
|
@ -27,13 +28,10 @@ private Q_SLOTS:
|
|||
void updateRendererDependentOptions();
|
||||
void updatePGXPSettingsEnabled();
|
||||
|
||||
void onAdapterChanged();
|
||||
void onAspectRatioChanged();
|
||||
void updateResolutionDependentOptions();
|
||||
void onMSAAModeChanged();
|
||||
void onTrueColorChanged();
|
||||
void onDownsampleModeChanged();
|
||||
void onFullscreenModeChanged();
|
||||
void onEnableAnyTextureReplacementsChanged();
|
||||
void onEnableVRAMWriteDumpingChanged();
|
||||
|
||||
|
@ -57,4 +55,7 @@ private:
|
|||
Ui::GraphicsSettingsWidget m_ui;
|
||||
|
||||
SettingsWindow* m_dialog;
|
||||
|
||||
GPUDevice::AdapterInfoList m_adapters;
|
||||
RenderAPI m_adapters_render_api = RenderAPI::None;
|
||||
};
|
||||
|
|
|
@ -94,93 +94,7 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<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>
|
||||
<widget class="QComboBox" name="resolutionScale" />
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="gpuDownsampleLabel">
|
||||
|
|
|
@ -685,39 +685,6 @@ void D3D11Device::SubmitPresent()
|
|||
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()
|
||||
{
|
||||
for (u32 i = 0; i < NUM_TIMESTAMP_QUERIES; i++)
|
||||
|
|
|
@ -43,7 +43,6 @@ public:
|
|||
bool UpdateWindow() override;
|
||||
void ResizeWindow(s32 new_window_width, s32 new_window_height, float new_window_scale) override;
|
||||
bool SupportsExclusiveFullscreen() const override;
|
||||
AdapterAndModeList GetAdapterAndModeList() override;
|
||||
void DestroySurface() override;
|
||||
|
||||
std::string GetDriverInfo() const override;
|
||||
|
@ -110,8 +109,6 @@ public:
|
|||
void UnbindPipeline(D3D11Pipeline* pl);
|
||||
void UnbindTexture(D3D11Texture* tex);
|
||||
|
||||
static AdapterAndModeList StaticGetAdapterAndModeList();
|
||||
|
||||
protected:
|
||||
bool CreateDevice(std::string_view adapter, bool threaded_presentation,
|
||||
std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features,
|
||||
|
@ -133,8 +130,6 @@ private:
|
|||
static constexpr u32 UNIFORM_BUFFER_ALIGNMENT_DISCARD = 16;
|
||||
static constexpr u8 NUM_TIMESTAMP_QUERIES = 3;
|
||||
|
||||
static void GetAdapterAndModeList(AdapterAndModeList* ret, IDXGIFactory5* factory);
|
||||
|
||||
void SetFeatures(FeatureMask disabled_features);
|
||||
|
||||
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
|
||||
{
|
||||
return RenderAPI::D3D12;
|
||||
|
|
|
@ -64,8 +64,6 @@ public:
|
|||
bool UpdateWindow() 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;
|
||||
|
||||
std::string GetDriverInfo() const override;
|
||||
|
@ -220,8 +218,6 @@ private:
|
|||
|
||||
using SamplerMap = std::unordered_map<u64, D3D12DescriptorHandle>;
|
||||
|
||||
static void GetAdapterAndModeList(AdapterAndModeList* ret, IDXGIFactory5* factory);
|
||||
|
||||
void SetFeatures(FeatureMask disabled_features);
|
||||
|
||||
u32 GetSwapChainBufferCount() const;
|
||||
|
|
|
@ -92,10 +92,10 @@ Microsoft::WRL::ComPtr<IDXGIFactory5> D3DCommon::CreateFactory(bool debug, Error
|
|||
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(),
|
||||
[&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);
|
||||
|
||||
|
@ -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);
|
||||
current_extra++;
|
||||
} while (std::any_of(adapter_names.begin(), adapter_names.end(),
|
||||
[&adapter_name](const std::string& other) { return (adapter_name == other); }));
|
||||
} while (
|
||||
std::any_of(adapter_names.begin(), adapter_names.end(),
|
||||
[&adapter_name](const GPUDevice::AdapterInfo& other) { return (adapter_name == other.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;
|
||||
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)
|
||||
break;
|
||||
|
||||
|
@ -128,50 +133,51 @@ std::vector<std::string> D3DCommon::GetAdapterNames(IDXGIFactory5* factory)
|
|||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
return adapters;
|
||||
}
|
||||
|
||||
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.
|
||||
// We might have two GPUs with the same name... :)
|
||||
std::vector<std::string> adapter_names;
|
||||
GPUDevice::AdapterInfoList adapters;
|
||||
|
||||
Microsoft::WRL::ComPtr<IDXGIAdapter1> adapter;
|
||||
for (u32 index = 0;; index++)
|
||||
|
@ -271,14 +277,16 @@ Microsoft::WRL::ComPtr<IDXGIAdapter1> D3DCommon::GetAdapterByName(IDXGIFactory5*
|
|||
continue;
|
||||
}
|
||||
|
||||
std::string adapter_name = FixupDuplicateAdapterNames(adapter_names, GetAdapterName(adapter.Get()));
|
||||
std::string adapter_name = FixupDuplicateAdapterNames(adapters, GetAdapterName(adapter.Get()));
|
||||
if (adapter_name == name)
|
||||
{
|
||||
VERBOSE_LOG("Found adapter '{}'", adapter_name);
|
||||
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);
|
||||
|
|
|
@ -35,10 +35,7 @@ D3D_FEATURE_LEVEL GetDeviceMaxFeatureLevel(IDXGIAdapter1* adapter);
|
|||
Microsoft::WRL::ComPtr<IDXGIFactory5> CreateFactory(bool debug, Error* error);
|
||||
|
||||
// returns a list of all adapter names
|
||||
std::vector<std::string> GetAdapterNames(IDXGIFactory5* factory);
|
||||
|
||||
// returns a list of fullscreen modes for the specified adapter
|
||||
std::vector<std::string> GetFullscreenModes(IDXGIFactory5* factory, std::string_view adapter_name);
|
||||
GPUDevice::AdapterInfoList GetAdapterInfoList();
|
||||
|
||||
// returns the fullscreen mode to use for the specified dimensions
|
||||
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)));
|
||||
}
|
||||
|
||||
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 debug_device, GPUVSyncMode vsync, bool allow_present_throttle, bool threaded_presentation,
|
||||
std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features, Error* error)
|
||||
|
|
|
@ -509,11 +509,15 @@ public:
|
|||
u32 num_uploads;
|
||||
};
|
||||
|
||||
struct AdapterAndModeList
|
||||
struct AdapterInfo
|
||||
{
|
||||
std::vector<std::string> adapter_names;
|
||||
std::string name;
|
||||
std::vector<std::string> fullscreen_modes;
|
||||
u32 max_texture_size;
|
||||
u32 max_multisamples;
|
||||
bool supports_sample_shading;
|
||||
};
|
||||
using AdapterInfoList = std::vector<AdapterInfo>;
|
||||
|
||||
struct PooledTextureDeleter
|
||||
{
|
||||
|
@ -543,6 +547,9 @@ public:
|
|||
/// Returns true if the render API is the same (e.g. GLES and GL).
|
||||
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)
|
||||
static bool GetRequestedExclusiveFullscreenMode(u32* width, u32* height, float* refresh_rate);
|
||||
|
||||
|
@ -572,12 +579,6 @@ public:
|
|||
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 u32 GetMaxTextureSize() const { return m_max_texture_size; }
|
||||
ALWAYS_INLINE u32 GetMaxMultisamples() const { return m_max_multisamples; }
|
||||
|
@ -605,7 +606,6 @@ public:
|
|||
virtual bool UpdateWindow() = 0;
|
||||
|
||||
virtual bool SupportsExclusiveFullscreen() const;
|
||||
virtual AdapterAndModeList GetAdapterAndModeList() = 0;
|
||||
|
||||
/// 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;
|
||||
|
@ -801,6 +801,12 @@ private:
|
|||
|
||||
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 CloseShaderCache();
|
||||
bool CreateResources(Error* error);
|
||||
|
|
|
@ -204,8 +204,6 @@ public:
|
|||
|
||||
bool UpdateWindow() override;
|
||||
void ResizeWindow(s32 new_window_width, s32 new_window_height, float new_window_scale) override;
|
||||
|
||||
AdapterAndModeList GetAdapterAndModeList() override;
|
||||
void DestroySurface() override;
|
||||
|
||||
std::string GetDriverInfo() const override;
|
||||
|
@ -286,8 +284,6 @@ public:
|
|||
static void DeferRelease(id obj);
|
||||
static void DeferRelease(u64 fence_counter, id obj);
|
||||
|
||||
static AdapterAndModeList StaticGetAdapterAndModeList();
|
||||
|
||||
protected:
|
||||
bool CreateDevice(std::string_view adapter, bool threaded_presentation,
|
||||
std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features,
|
||||
|
|
|
@ -87,6 +87,32 @@ static GPUTexture::Format GetTextureFormatForMTLFormat(MTLPixelFormat fmt)
|
|||
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>
|
||||
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)
|
||||
{
|
||||
// https://gist.github.com/kylehowells/63d0723abc9588eb734cade4b7df660d
|
||||
if ([m_device supportsFamily:MTLGPUFamilyMacCatalyst1] || [m_device supportsFamily:MTLGPUFamilyMac1] ||
|
||||
[m_device supportsFamily:MTLGPUFamilyApple3])
|
||||
{
|
||||
m_max_texture_size = 16384;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_max_texture_size = 8192;
|
||||
}
|
||||
m_max_texture_size = GetMetalMaxTextureSize(m_device);
|
||||
m_max_multisamples = GetMetalMaxMultisamples(m_device);
|
||||
|
||||
// Framebuffer fetch requires MSL 2.3 and an Apple GPU family.
|
||||
const bool supports_fbfetch = [m_device supportsFamily:MTLGPUFamilyApple1];
|
||||
|
@ -222,14 +240,6 @@ void MetalDevice::SetFeatures(FeatureMask disabled_features)
|
|||
const bool supports_barriers =
|
||||
([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.framebuffer_fetch = !(disabled_features & FEATURE_MASK_FRAMEBUFFER_FETCH) && supports_fbfetch;
|
||||
m_features.per_sample_shading = true;
|
||||
|
@ -538,26 +548,6 @@ bool MetalDevice::IsRenderTargetBound(const GPUTexture* tex) const
|
|||
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)
|
||||
{
|
||||
if (m_gpu_timing_enabled == enabled)
|
||||
|
@ -2505,7 +2495,24 @@ std::unique_ptr<GPUDevice> GPUDevice::WrapNewMetalDevice()
|
|||
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;
|
||||
|
||||
std::vector<OpenGLContext::FullscreenModeInfo> OpenGLContext::EnumerateFullscreenModes()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
std::unique_ptr<OpenGLContext> OpenGLContext::Create(const WindowInfo& wi, Error* error)
|
||||
{
|
||||
static constexpr std::array<Version, 14> vlist = {{{Profile::Core, 4, 6},
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
#include <memory>
|
||||
#include <span>
|
||||
#include <vector>
|
||||
|
||||
class Error;
|
||||
|
||||
|
@ -33,13 +32,6 @@ public:
|
|||
int minor_version;
|
||||
};
|
||||
|
||||
struct FullscreenModeInfo
|
||||
{
|
||||
u32 width;
|
||||
u32 height;
|
||||
float refresh_rate;
|
||||
};
|
||||
|
||||
ALWAYS_INLINE const WindowInfo& GetWindowInfo() const { return m_wi; }
|
||||
ALWAYS_INLINE bool IsGLES() const { return (m_version.profile == Profile::ES); }
|
||||
ALWAYS_INLINE u32 GetSurfaceWidth() const { return m_wi.surface_width; }
|
||||
|
@ -57,8 +49,6 @@ public:
|
|||
virtual bool SetSwapInterval(s32 interval) = 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);
|
||||
|
||||
protected:
|
||||
|
|
|
@ -663,21 +663,6 @@ void OpenGLDevice::DestroyFramebuffer(GLuint 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()
|
||||
{
|
||||
if (!m_gl_context)
|
||||
|
|
|
@ -48,8 +48,6 @@ public:
|
|||
|
||||
std::string GetDriverInfo() const override;
|
||||
|
||||
AdapterAndModeList GetAdapterAndModeList() override;
|
||||
|
||||
std::unique_ptr<GPUTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
||||
GPUTexture::Type type, GPUTexture::Format format,
|
||||
const void* data = nullptr, u32 data_stride = 0) override;
|
||||
|
|
|
@ -315,28 +315,76 @@ VulkanDevice::GPUList VulkanDevice::EnumerateGPUs(VkInstance instance)
|
|||
VkPhysicalDeviceProperties 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
|
||||
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;
|
||||
do
|
||||
{
|
||||
gpu_name = fmt::format("{} ({})", original_adapter_name, current_extra);
|
||||
ai.name = fmt::format("{} ({})", original_adapter_name, current_extra);
|
||||
current_extra++;
|
||||
} 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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
u32 extension_count = 0;
|
||||
|
@ -1853,67 +1901,21 @@ void VulkanDevice::DestroyFramebuffer(VkFramebuffer 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()
|
||||
{
|
||||
#ifdef __ANDROID__
|
||||
// No way in hell.
|
||||
return false;
|
||||
#else
|
||||
AdapterAndModeList aml = StaticGetAdapterAndModeList();
|
||||
if (aml.adapter_names.empty())
|
||||
GPUList gpus = EnumerateGPUs();
|
||||
if (gpus.empty())
|
||||
{
|
||||
// No adapters, not gonna be able to use VK.
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
// Any software rendering (LLVMpipe, SwiftShader).
|
||||
|
@ -2000,8 +2002,8 @@ bool VulkanDevice::CreateDevice(std::string_view adapter, bool threaded_presenta
|
|||
u32 gpu_index = 0;
|
||||
for (; gpu_index < static_cast<u32>(gpus.size()); gpu_index++)
|
||||
{
|
||||
INFO_LOG("GPU {}: {}", gpu_index, gpus[gpu_index].second);
|
||||
if (gpus[gpu_index].second == adapter)
|
||||
INFO_LOG("GPU {}: {}", gpu_index, gpus[gpu_index].second.name);
|
||||
if (gpus[gpu_index].second.name == adapter)
|
||||
{
|
||||
m_physical_device = gpus[gpu_index].first;
|
||||
break;
|
||||
|
@ -2010,13 +2012,13 @@ bool VulkanDevice::CreateDevice(std::string_view adapter, bool threaded_presenta
|
|||
|
||||
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;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -2542,35 +2544,40 @@ void VulkanDevice::InsertDebugMessage(const char* msg)
|
|||
#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 = {};
|
||||
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,
|
||||
&color_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,
|
||||
&depth_properties);
|
||||
const VkSampleCountFlags combined_properties = m_device_properties.limits.framebufferColorSampleCounts &
|
||||
m_device_properties.limits.framebufferDepthSampleCounts &
|
||||
const VkSampleCountFlags combined_properties = properties.limits.framebufferColorSampleCounts &
|
||||
properties.limits.framebufferDepthSampleCounts &
|
||||
color_properties.sampleCounts & depth_properties.sampleCounts;
|
||||
if (combined_properties & VK_SAMPLE_COUNT_64_BIT)
|
||||
m_max_multisamples = 64;
|
||||
return 64;
|
||||
else if (combined_properties & VK_SAMPLE_COUNT_32_BIT)
|
||||
m_max_multisamples = 32;
|
||||
return 32;
|
||||
else if (combined_properties & VK_SAMPLE_COUNT_16_BIT)
|
||||
m_max_multisamples = 16;
|
||||
return 16;
|
||||
else if (combined_properties & VK_SAMPLE_COUNT_8_BIT)
|
||||
m_max_multisamples = 8;
|
||||
return 8;
|
||||
else if (combined_properties & VK_SAMPLE_COUNT_4_BIT)
|
||||
m_max_multisamples = 4;
|
||||
return 4;
|
||||
else if (combined_properties & VK_SAMPLE_COUNT_2_BIT)
|
||||
m_max_multisamples = 2;
|
||||
return 2;
|
||||
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 =
|
||||
!(disabled_features & FEATURE_MASK_DUAL_SOURCE_BLEND) && m_device_features.dualSrcBlend;
|
||||
|
|
|
@ -66,15 +66,18 @@ public:
|
|||
VulkanDevice();
|
||||
~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;
|
||||
|
||||
bool HasSurface() const override;
|
||||
|
||||
bool UpdateWindow() 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;
|
||||
|
||||
std::string GetDriverInfo() const override;
|
||||
|
@ -287,16 +290,10 @@ private:
|
|||
using CleanupObjectFunction = void (*)(VulkanDevice& dev, void* obj);
|
||||
using SamplerMap = std::unordered_map<u64, VkSampler>;
|
||||
|
||||
static void GetAdapterAndModeList(AdapterAndModeList* ret, VkInstance instance);
|
||||
|
||||
// Helper method to create a Vulkan instance.
|
||||
static VkInstance CreateVulkanInstance(const WindowInfo& wi, OptionalExtensions* oe, bool enable_debug_utils,
|
||||
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);
|
||||
void FillPipelineCacheHeader(VK_PIPELINE_CACHE_HEADER* header);
|
||||
|
||||
|
@ -331,6 +328,8 @@ private:
|
|||
|
||||
bool CheckFeatures(FeatureMask disabled_features);
|
||||
|
||||
static u32 GetMaxMultisamples(VkPhysicalDevice physical_device, const VkPhysicalDeviceProperties& properties);
|
||||
|
||||
bool CreateAllocator();
|
||||
void DestroyAllocator();
|
||||
bool CreateCommandBuffers();
|
||||
|
|
Loading…
Reference in a new issue