From a007ac6b9ccc23861f5a5c6967d535220ed794b0 Mon Sep 17 00:00:00 2001 From: lat9nq <22451773+lat9nq@users.noreply.github.com> Date: Sun, 7 May 2023 09:48:26 -0400 Subject: [PATCH] configure_graphics_advance: Generate UI at runtime We can iterate through the AdvancedGraphics settings and generate the UI during runtime. This doesn't help runtime efficiency, but it helps a ton in reducing the amount of work a developer needs in order to add a new setting. --- src/common/settings.h | 53 +++- src/core/telemetry_session.cpp | 2 + src/video_core/textures/texture.cpp | 4 +- src/yuzu/CMakeLists.txt | 2 + .../configuration/configuration_shared.cpp | 153 ++++++++++++ src/yuzu/configuration/configuration_shared.h | 6 + src/yuzu/configuration/configure_dialog.cpp | 8 +- src/yuzu/configuration/configure_dialog.h | 1 + .../configure_graphics_advanced.cpp | 168 +++---------- .../configure_graphics_advanced.h | 20 +- .../configure_graphics_advanced.ui | 234 +----------------- src/yuzu/configuration/configure_per_game.cpp | 9 +- src/yuzu/configuration/configure_per_game.h | 1 + src/yuzu/configuration/shared_translation.cpp | 170 +++++++++++++ src/yuzu/configuration/shared_translation.h | 18 ++ 15 files changed, 449 insertions(+), 400 deletions(-) create mode 100644 src/yuzu/configuration/shared_translation.cpp create mode 100644 src/yuzu/configuration/shared_translation.h diff --git a/src/common/settings.h b/src/common/settings.h index df4bcb0539..48f86d0aae 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -20,6 +20,15 @@ namespace Settings { +enum class AnisotropyMode : u32 { + Automatic = 0, + Default = 1, + X2 = 2, + X4 = 3, + X8 = 4, + X16 = 5, +}; + enum class AstcDecodeMode : u32 { CPU = 0, GPU = 1, @@ -49,6 +58,7 @@ enum class GPUAccuracy : u32 { Normal = 0, High = 1, Extreme = 2, + MaxEnum = 3, }; enum class CPUAccuracy : u32 { @@ -166,11 +176,16 @@ public: virtual Category Category() const = 0; virtual constexpr bool Switchable() const = 0; virtual std::string ToString() const = 0; + virtual std::string ToStringGlobal() const { + return {}; + } virtual void LoadString(const std::string& load) = 0; virtual const std::string& GetLabel() const = 0; virtual std::string DefaultToString() const = 0; virtual bool Save() const = 0; virtual std::type_index TypeId() const = 0; + virtual bool IsEnum() const = 0; + virtual bool RuntimeModfiable() const = 0; virtual void SetGlobal(bool global) {} virtual bool UsingGlobal() const { return false; @@ -188,7 +203,7 @@ public: * configurations. Specifying a default value and label is required. A minimum and maximum range * can be specified for sanitization. */ -template +template class Setting : public BasicSetting { protected: Setting() = default; @@ -282,6 +297,14 @@ public: return category; } + [[nodiscard]] bool RuntimeModfiable() const override { + return runtime_modifiable; + } + + [[nodiscard]] bool IsEnum() const override { + return std::is_enum::value; + } + /** * Returns whether the current setting is Switchable. * @@ -291,7 +314,7 @@ public: return false; } -private: +protected: std::string ToString(const Type& value_) const { if constexpr (std::is_same()) { return value_; @@ -408,8 +431,8 @@ protected: * * By default, the global setting is used. */ -template -class SwitchableSetting : virtual public Setting { +template +class SwitchableSetting : virtual public Setting { public: /** * Sets a default value, label, and setting value. @@ -422,7 +445,7 @@ public: explicit SwitchableSetting(Linkage& linkage, const Type& default_val, const std::string& name, Category category) requires(!ranged) - : Setting{linkage, default_val, name, category} { + : Setting{linkage, default_val, name, category} { linkage.restore_functions.emplace_back([this]() { this->SetGlobal(true); }); } virtual ~SwitchableSetting() = default; @@ -440,7 +463,8 @@ public: explicit SwitchableSetting(Linkage& linkage, const Type& default_val, const Type& min_val, const Type& max_val, const std::string& name, Category category) requires(ranged) - : Setting{linkage, default_val, min_val, max_val, name, category} { + : Setting{linkage, default_val, min_val, + max_val, name, category} { linkage.restore_functions.emplace_back([this]() { this->SetGlobal(true); }); } @@ -502,6 +526,10 @@ public: return true; } + [[nodiscard]] virtual std::string ToStringGlobal() const override { + return this->ToString(this->value); + } + /** * Assigns the current setting value depending on the global state. * @@ -667,15 +695,16 @@ struct Values { "fullscreen_mode", Category::Renderer}; SwitchableSetting aspect_ratio{linkage, 0, 0, 4, "aspect_ratio", Category::Renderer}; - SwitchableSetting max_anisotropy{ - linkage, 0, 0, 5, "max_anisotropy", Category::AdvancedGraphics}; + SwitchableSetting max_anisotropy{ + linkage, AnisotropyMode::Automatic, AnisotropyMode::Automatic, AnisotropyMode::X16, + "max_anisotropy", Category::AdvancedGraphics}; SwitchableSetting use_speed_limit{linkage, true, "use_speed_limit", Category::Renderer}; SwitchableSetting speed_limit{linkage, 100, 0, 9999, "speed_limit", Category::Renderer}; SwitchableSetting use_disk_shader_cache{linkage, true, "use_disk_shader_cache", Category::Renderer}; - SwitchableSetting gpu_accuracy{ + SwitchableSetting gpu_accuracy{ linkage, GPUAccuracy::High, GPUAccuracy::Normal, GPUAccuracy::Extreme, "gpu_accuracy", Category::AdvancedGraphics}; SwitchableSetting use_asynchronous_gpu_emulation{ @@ -698,9 +727,9 @@ struct Values { "shader_backend", Category::Renderer}; SwitchableSetting use_asynchronous_shaders{linkage, false, "use_asynchronous_shaders", Category::Renderer}; - SwitchableSetting use_fast_gpu_time{linkage, true, "use_fast_gpu_time", - Category::AdvancedGraphics}; - SwitchableSetting use_vulkan_driver_pipeline_cache{ + SwitchableSetting use_fast_gpu_time{linkage, true, "use_fast_gpu_time", + Category::AdvancedGraphics}; + SwitchableSetting use_vulkan_driver_pipeline_cache{ linkage, true, "use_vulkan_driver_pipeline_cache", Category::AdvancedGraphics}; SwitchableSetting enable_compute_pipelines{linkage, false, "enable_compute_pipelines", Category::AdvancedGraphics}; diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp index 665ffe3a29..a3505a505f 100644 --- a/src/core/telemetry_session.cpp +++ b/src/core/telemetry_session.cpp @@ -69,6 +69,8 @@ static const char* TranslateGPUAccuracyLevel(Settings::GPUAccuracy backend) { return "High"; case Settings::GPUAccuracy::Extreme: return "Extreme"; + case Settings::GPUAccuracy::MaxEnum: + break; } return "Unknown"; } diff --git a/src/video_core/textures/texture.cpp b/src/video_core/textures/texture.cpp index d8b88d9bc2..39c08b5ae1 100644 --- a/src/video_core/textures/texture.cpp +++ b/src/video_core/textures/texture.cpp @@ -72,12 +72,12 @@ float TSCEntry::MaxAnisotropy() const noexcept { } const auto anisotropic_settings = Settings::values.max_anisotropy.GetValue(); s32 added_anisotropic{}; - if (anisotropic_settings == 0) { + if (anisotropic_settings == Settings::AnisotropyMode::Automatic) { added_anisotropic = Settings::values.resolution_info.up_scale >> Settings::values.resolution_info.down_shift; added_anisotropic = std::max(added_anisotropic - 1, 0); } else { - added_anisotropic = Settings::values.max_anisotropy.GetValue() - 1U; + added_anisotropic = static_cast(Settings::values.max_anisotropy.GetValue()) - 1U; } return static_cast(1U << (max_anisotropy + added_anisotropic)); } diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index fe98e3605e..8b54e12689 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -143,6 +143,8 @@ add_executable(yuzu configuration/configure_web.ui configuration/input_profiles.cpp configuration/input_profiles.h + configuration/shared_translation.cpp + configuration/shared_translation.h debugger/console.cpp debugger/console.h debugger/controller.cpp diff --git a/src/yuzu/configuration/configuration_shared.cpp b/src/yuzu/configuration/configuration_shared.cpp index 72b7957e07..44222718cc 100644 --- a/src/yuzu/configuration/configuration_shared.cpp +++ b/src/yuzu/configuration/configuration_shared.cpp @@ -3,14 +3,167 @@ #include #include +#include +#include #include #include #include +#include #include "common/settings.h" #include "yuzu/configuration/configuration_shared.h" #include "yuzu/configuration/configure_per_game.h" +#include "yuzu/configuration/shared_translation.h" namespace ConfigurationShared { +static std::pair> CreateCheckBox(Settings::BasicSetting* setting, + const QString& label, + QWidget* parent, + std::list& trackers) { + QCheckBox* checkbox = new QCheckBox(label, parent); + checkbox->setObjectName(QString::fromStdString(setting->GetLabel())); + checkbox->setCheckState(setting->ToString() == "true" ? Qt::CheckState::Checked + : Qt::CheckState::Unchecked); + + CheckState* tracker{}; + + // Per-game config highlight + if (setting->Switchable() && !Settings::IsConfiguringGlobal()) { + bool global_state = setting->ToStringGlobal() == "true"; + bool state = setting->ToString() == "true"; + bool global = setting->UsingGlobal(); + tracker = &trackers.emplace_front(CheckState{}); + SetColoredTristate(checkbox, global, state, global_state, *tracker); + } + + auto load_func = [checkbox, setting, tracker]() { + if (Settings::IsConfiguringGlobal()) { + setting->LoadString(checkbox->checkState() == Qt::Checked ? "true" : "false"); + } + + if (Settings::IsConfiguringGlobal() || !setting->Switchable()) { + return; + } + + if (*tracker != CheckState::Global) { + setting->SetGlobal(false); + setting->LoadString(checkbox->checkState() == Qt::Checked ? "true" : "false"); + } else { + setting->SetGlobal(true); + } + }; + + return {checkbox, load_func}; +} + +static std::pair> CreateCombobox(Settings::BasicSetting* setting, + const QString& label, + QWidget* parent) { + const auto type = setting->TypeId(); + + QWidget* group = new QWidget(parent); + group->setObjectName(QString::fromStdString(setting->GetLabel())); + QLayout* combobox_layout = new QHBoxLayout(group); + + QLabel* qt_label = new QLabel(label, parent); + QComboBox* combobox = new QComboBox(parent); + + std::forward_list combobox_enumerations = ComboboxEnumeration(type, parent); + for (const auto& item : combobox_enumerations) { + combobox->addItem(item); + } + + combobox_layout->addWidget(qt_label); + combobox_layout->addWidget(combobox); + + combobox_layout->setSpacing(6); + combobox_layout->setContentsMargins(0, 0, 0, 0); + + if (setting->Switchable() && !Settings::IsConfiguringGlobal()) { + int current = std::stoi(setting->ToString()); + int global_value = std::stoi(setting->ToStringGlobal()); + SetColoredComboBox(combobox, group, global_value); + if (setting->UsingGlobal()) { + combobox->setCurrentIndex(USE_GLOBAL_INDEX); + } else { + SetHighlight(group, true); + combobox->setCurrentIndex(current + USE_GLOBAL_OFFSET); + } + } else { + combobox->setCurrentIndex(std::stoi(setting->ToString())); + } + + const auto load_func = [combobox, setting]() { + if (Settings::IsConfiguringGlobal()) { + setting->LoadString(std::to_string(combobox->currentIndex())); + } + + if (Settings::IsConfiguringGlobal() || !setting->Switchable()) { + return; + } + + bool using_global = combobox->currentIndex() == USE_GLOBAL_INDEX; + int index = combobox->currentIndex() - USE_GLOBAL_OFFSET; + + setting->SetGlobal(using_global); + if (!using_global) { + setting->LoadString(std::to_string(index)); + } + }; + + return {group, load_func}; +} + +QWidget* CreateWidget(Settings::BasicSetting* setting, const TranslationMap& translations, + QWidget* parent, bool runtime_lock, + std::forward_list>& apply_funcs, + std::list& trackers) { + const auto type = setting->TypeId(); + QWidget* widget{nullptr}; + + std::function load_func; + + const auto [label, tooltip] = [&]() { + const auto& setting_label = setting->GetLabel(); + if (translations.contains(setting_label)) { + return std::pair{translations.at(setting_label).first, + translations.at(setting_label).second}; + } + LOG_ERROR(Frontend, "Translation map lacks entry for \"{}\"", setting_label); + return std::pair{QString::fromStdString(setting_label), QStringLiteral("")}; + }(); + + if (type == typeid(bool)) { + auto pair = CreateCheckBox(setting, label, parent, trackers); + widget = pair.first; + load_func = pair.second; + } else if (setting->IsEnum()) { + auto pair = CreateCombobox(setting, label, parent); + widget = pair.first; + load_func = pair.second; + } + + if (widget == nullptr) { + LOG_ERROR(Frontend, "No widget was created for \"{}\"", setting->GetLabel()); + return widget; + } + + apply_funcs.push_front([load_func, setting](bool powered_on) { + if (setting->RuntimeModfiable() || !powered_on) { + load_func(); + } + }); + + bool enable = runtime_lock || setting->RuntimeModfiable(); + enable &= + setting->Switchable() && !(Settings::IsConfiguringGlobal() && !setting->UsingGlobal()); + + widget->setEnabled(enable); + widget->setVisible(Settings::IsConfiguringGlobal() || setting->Switchable()); + + widget->setToolTip(tooltip); + + return widget; +} Tab::Tab(std::shared_ptr> group_, QWidget* parent) : QWidget(parent), group{group_} { diff --git a/src/yuzu/configuration/configuration_shared.h b/src/yuzu/configuration/configuration_shared.h index 1a3a2a9850..7040673ea5 100644 --- a/src/yuzu/configuration/configuration_shared.h +++ b/src/yuzu/configuration/configuration_shared.h @@ -11,6 +11,7 @@ #include #include #include "common/settings.h" +#include "yuzu/configuration/shared_translation.h" namespace ConfigurationShared { @@ -40,6 +41,11 @@ enum class CheckState { Count, // Simply the number of states, not a valid checkbox state }; +QWidget* CreateWidget(Settings::BasicSetting* setting, const TranslationMap& translations, + QWidget* parent, bool runtime_lock, + std::forward_list>& apply_funcs, + std::list& trackers); + // Global-aware apply and set functions // ApplyPerGameSetting, given a Settings::Setting and a Qt UI element, properly applies a Setting diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp index 2cc9f36212..b3f4764c70 100644 --- a/src/yuzu/configuration/configure_dialog.cpp +++ b/src/yuzu/configuration/configure_dialog.cpp @@ -32,13 +32,15 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry_, std::vector& vk_device_records, Core::System& system_, bool enable_web_config) : QDialog(parent), ui{std::make_unique()}, - registry(registry_), system{system_}, audio_tab{std::make_unique( - system_, nullptr, this)}, + registry(registry_), system{system_}, + translations{ConfigurationShared::InitializeTranslations(this)}, + audio_tab{std::make_unique(system_, nullptr, this)}, cpu_tab{std::make_unique(system_, nullptr, this)}, debug_tab_tab{std::make_unique(system_, this)}, filesystem_tab{std::make_unique(this)}, general_tab{std::make_unique(system_, nullptr, this)}, - graphics_advanced_tab{std::make_unique(system_, nullptr, this)}, + graphics_advanced_tab{ + std::make_unique(system_, nullptr, *translations, this)}, graphics_tab{std::make_unique( system_, vk_device_records, [&]() { graphics_advanced_tab->ExposeComputeOption(); }, nullptr, this)}, diff --git a/src/yuzu/configuration/configure_dialog.h b/src/yuzu/configuration/configure_dialog.h index 8ee89a192c..0416b01d99 100644 --- a/src/yuzu/configuration/configure_dialog.h +++ b/src/yuzu/configuration/configure_dialog.h @@ -71,6 +71,7 @@ private: HotkeyRegistry& registry; Core::System& system; + std::unique_ptr translations; std::forward_list tab_group; std::unique_ptr audio_tab; diff --git a/src/yuzu/configuration/configure_graphics_advanced.cpp b/src/yuzu/configuration/configure_graphics_advanced.cpp index d332c9b7bb..6d387b5c32 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.cpp +++ b/src/yuzu/configuration/configure_graphics_advanced.cpp @@ -1,6 +1,8 @@ // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include +#include #include "common/settings.h" #include "core/core.h" #include "ui_configure_graphics_advanced.h" @@ -9,94 +11,54 @@ ConfigureGraphicsAdvanced::ConfigureGraphicsAdvanced( const Core::System& system_, - std::shared_ptr> group, QWidget* parent) - : Tab(group, parent), ui{std::make_unique()}, system{system_} { + std::shared_ptr> group, + const ConfigurationShared::TranslationMap& translations_, QWidget* parent) + : Tab(group, parent), ui{std::make_unique()}, system{system_}, + translations{translations_} { ui->setupUi(this); - SetupPerGameUI(); - SetConfiguration(); - ui->enable_compute_pipelines_checkbox->setVisible(false); + checkbox_enable_compute_pipelines->setVisible(false); } ConfigureGraphicsAdvanced::~ConfigureGraphicsAdvanced() = default; void ConfigureGraphicsAdvanced::SetConfiguration() { const bool runtime_lock = !system.IsPoweredOn(); - ui->use_reactive_flushing->setEnabled(runtime_lock); - ui->async_present->setEnabled(runtime_lock); - ui->renderer_force_max_clock->setEnabled(runtime_lock); - ui->astc_recompression_combobox->setEnabled(runtime_lock); - ui->use_asynchronous_shaders->setEnabled(runtime_lock); - ui->anisotropic_filtering_combobox->setEnabled(runtime_lock); - ui->enable_compute_pipelines_checkbox->setEnabled(runtime_lock); + auto& layout = *ui->populate_target->layout(); + std::map hold{}; // A map will sort the data for us - ui->async_present->setChecked(Settings::values.async_presentation.GetValue()); - ui->renderer_force_max_clock->setChecked(Settings::values.renderer_force_max_clock.GetValue()); - ui->use_reactive_flushing->setChecked(Settings::values.use_reactive_flushing.GetValue()); - ui->use_asynchronous_shaders->setChecked(Settings::values.use_asynchronous_shaders.GetValue()); - ui->use_fast_gpu_time->setChecked(Settings::values.use_fast_gpu_time.GetValue()); - ui->use_vulkan_driver_pipeline_cache->setChecked( - Settings::values.use_vulkan_driver_pipeline_cache.GetValue()); - ui->enable_compute_pipelines_checkbox->setChecked( - Settings::values.enable_compute_pipelines.GetValue()); - ui->use_video_framerate_checkbox->setChecked(Settings::values.use_video_framerate.GetValue()); - ui->barrier_feedback_loops_checkbox->setChecked( - Settings::values.barrier_feedback_loops.GetValue()); + for (auto setting : + Settings::values.linkage.by_category[Settings::Category::AdvancedGraphics]) { + QWidget* widget = ConfigurationShared::CreateWidget(setting, translations, this, + runtime_lock, apply_funcs, trackers); - if (Settings::IsConfiguringGlobal()) { - ui->gpu_accuracy->setCurrentIndex( - static_cast(Settings::values.gpu_accuracy.GetValue())); - ui->anisotropic_filtering_combobox->setCurrentIndex( - Settings::values.max_anisotropy.GetValue()); - ui->astc_recompression_combobox->setCurrentIndex( - static_cast(Settings::values.astc_recompression.GetValue())); - } else { - ConfigurationShared::SetPerGameSetting(ui->gpu_accuracy, &Settings::values.gpu_accuracy); - ConfigurationShared::SetPerGameSetting(ui->anisotropic_filtering_combobox, - &Settings::values.max_anisotropy); - ConfigurationShared::SetPerGameSetting(ui->astc_recompression_combobox, - &Settings::values.astc_recompression); - ConfigurationShared::SetHighlight(ui->label_gpu_accuracy, - !Settings::values.gpu_accuracy.UsingGlobal()); - ConfigurationShared::SetHighlight(ui->af_label, - !Settings::values.max_anisotropy.UsingGlobal()); - ConfigurationShared::SetHighlight(ui->label_astc_recompression, - !Settings::values.astc_recompression.UsingGlobal()); + if (widget == nullptr) { + continue; + } + + if (!setting->IsEnum()) { + hold.emplace(setting->GetLabel(), widget); + } else { + layout.addWidget(widget); + } + + if (setting->GetLabel() == "enable_compute_pipelines") { + checkbox_enable_compute_pipelines = widget; + } + } + for (const auto& [label, widget] : hold) { + layout.addWidget(widget); } } void ConfigureGraphicsAdvanced::ApplyConfiguration() { - ConfigurationShared::ApplyPerGameSetting(&Settings::values.gpu_accuracy, ui->gpu_accuracy); - ConfigurationShared::ApplyPerGameSetting(&Settings::values.async_presentation, - ui->async_present, async_present); - ConfigurationShared::ApplyPerGameSetting(&Settings::values.renderer_force_max_clock, - ui->renderer_force_max_clock, - renderer_force_max_clock); - ConfigurationShared::ApplyPerGameSetting(&Settings::values.max_anisotropy, - ui->anisotropic_filtering_combobox); - ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_reactive_flushing, - ui->use_reactive_flushing, use_reactive_flushing); - ConfigurationShared::ApplyPerGameSetting(&Settings::values.astc_recompression, - ui->astc_recompression_combobox); - ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_asynchronous_shaders, - ui->use_asynchronous_shaders, - use_asynchronous_shaders); - ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_fast_gpu_time, - ui->use_fast_gpu_time, use_fast_gpu_time); - ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vulkan_driver_pipeline_cache, - ui->use_vulkan_driver_pipeline_cache, - use_vulkan_driver_pipeline_cache); - ConfigurationShared::ApplyPerGameSetting(&Settings::values.enable_compute_pipelines, - ui->enable_compute_pipelines_checkbox, - enable_compute_pipelines); - ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_video_framerate, - ui->use_video_framerate_checkbox, use_video_framerate); - ConfigurationShared::ApplyPerGameSetting(&Settings::values.barrier_feedback_loops, - ui->barrier_feedback_loops_checkbox, - barrier_feedback_loops); + const bool is_powered_on = system.IsPoweredOn(); + for (const auto& func : apply_funcs) { + func(is_powered_on); + } } void ConfigureGraphicsAdvanced::changeEvent(QEvent* event) { @@ -111,68 +73,6 @@ void ConfigureGraphicsAdvanced::RetranslateUI() { ui->retranslateUi(this); } -void ConfigureGraphicsAdvanced::SetupPerGameUI() { - // Disable if not global (only happens during game) - if (Settings::IsConfiguringGlobal()) { - ui->gpu_accuracy->setEnabled(Settings::values.gpu_accuracy.UsingGlobal()); - ui->async_present->setEnabled(Settings::values.async_presentation.UsingGlobal()); - ui->renderer_force_max_clock->setEnabled( - Settings::values.renderer_force_max_clock.UsingGlobal()); - ui->use_reactive_flushing->setEnabled(Settings::values.use_reactive_flushing.UsingGlobal()); - ui->astc_recompression_combobox->setEnabled( - Settings::values.astc_recompression.UsingGlobal()); - ui->use_asynchronous_shaders->setEnabled( - Settings::values.use_asynchronous_shaders.UsingGlobal()); - ui->use_fast_gpu_time->setEnabled(Settings::values.use_fast_gpu_time.UsingGlobal()); - ui->use_vulkan_driver_pipeline_cache->setEnabled( - Settings::values.use_vulkan_driver_pipeline_cache.UsingGlobal()); - ui->anisotropic_filtering_combobox->setEnabled( - Settings::values.max_anisotropy.UsingGlobal()); - ui->enable_compute_pipelines_checkbox->setEnabled( - Settings::values.enable_compute_pipelines.UsingGlobal()); - ui->use_video_framerate_checkbox->setEnabled( - Settings::values.use_video_framerate.UsingGlobal()); - ui->barrier_feedback_loops_checkbox->setEnabled( - Settings::values.barrier_feedback_loops.UsingGlobal()); - - return; - } - - ConfigurationShared::SetColoredTristate(ui->async_present, Settings::values.async_presentation, - async_present); - ConfigurationShared::SetColoredTristate(ui->renderer_force_max_clock, - Settings::values.renderer_force_max_clock, - renderer_force_max_clock); - ConfigurationShared::SetColoredTristate( - ui->use_reactive_flushing, Settings::values.use_reactive_flushing, use_reactive_flushing); - ConfigurationShared::SetColoredTristate(ui->use_asynchronous_shaders, - Settings::values.use_asynchronous_shaders, - use_asynchronous_shaders); - ConfigurationShared::SetColoredTristate(ui->use_fast_gpu_time, - Settings::values.use_fast_gpu_time, use_fast_gpu_time); - ConfigurationShared::SetColoredTristate(ui->use_vulkan_driver_pipeline_cache, - Settings::values.use_vulkan_driver_pipeline_cache, - use_vulkan_driver_pipeline_cache); - ConfigurationShared::SetColoredTristate(ui->enable_compute_pipelines_checkbox, - Settings::values.enable_compute_pipelines, - enable_compute_pipelines); - ConfigurationShared::SetColoredTristate(ui->use_video_framerate_checkbox, - Settings::values.use_video_framerate, - use_video_framerate); - ConfigurationShared::SetColoredTristate(ui->barrier_feedback_loops_checkbox, - Settings::values.barrier_feedback_loops, - barrier_feedback_loops); - ConfigurationShared::SetColoredComboBox( - ui->gpu_accuracy, ui->label_gpu_accuracy, - static_cast(Settings::values.gpu_accuracy.GetValue(true))); - ConfigurationShared::SetColoredComboBox( - ui->anisotropic_filtering_combobox, ui->af_label, - static_cast(Settings::values.max_anisotropy.GetValue(true))); - ConfigurationShared::SetColoredComboBox( - ui->astc_recompression_combobox, ui->label_astc_recompression, - static_cast(Settings::values.astc_recompression.GetValue(true))); -} - void ConfigureGraphicsAdvanced::ExposeComputeOption() { - ui->enable_compute_pipelines_checkbox->setVisible(true); + checkbox_enable_compute_pipelines->setVisible(true); } diff --git a/src/yuzu/configuration/configure_graphics_advanced.h b/src/yuzu/configuration/configure_graphics_advanced.h index 585b9cb505..3ac6b4bce5 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.h +++ b/src/yuzu/configuration/configure_graphics_advanced.h @@ -20,7 +20,7 @@ public: explicit ConfigureGraphicsAdvanced( const Core::System& system_, std::shared_ptr> group, - QWidget* parent = nullptr); + const ConfigurationShared::TranslationMap& translations_, QWidget* parent = nullptr); ~ConfigureGraphicsAdvanced() override; void ApplyConfiguration() override; @@ -32,21 +32,13 @@ private: void changeEvent(QEvent* event) override; void RetranslateUI(); - void SetupPerGameUI(); - std::unique_ptr ui; - ConfigurationShared::CheckState async_present; - ConfigurationShared::CheckState renderer_force_max_clock; - ConfigurationShared::CheckState use_vsync; - ConfigurationShared::CheckState async_astc; - ConfigurationShared::CheckState use_reactive_flushing; - ConfigurationShared::CheckState use_asynchronous_shaders; - ConfigurationShared::CheckState use_fast_gpu_time; - ConfigurationShared::CheckState use_vulkan_driver_pipeline_cache; - ConfigurationShared::CheckState enable_compute_pipelines; - ConfigurationShared::CheckState use_video_framerate; - ConfigurationShared::CheckState barrier_feedback_loops; + std::list trackers{}; const Core::System& system; + const ConfigurationShared::TranslationMap& translations; + std::forward_list> apply_funcs; + + QWidget* checkbox_enable_compute_pipelines{}; }; diff --git a/src/yuzu/configuration/configure_graphics_advanced.ui b/src/yuzu/configuration/configure_graphics_advanced.ui index 859ab93665..113fbc010d 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.ui +++ b/src/yuzu/configuration/configure_graphics_advanced.ui @@ -26,238 +26,8 @@ - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Accuracy Level: - - - - - - - - Normal - - - - - High - - - - - Extreme(very slow) - - - - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - ASTC recompression: - - - - - - - - Uncompressed (Best quality) - - - - - BC1 (Low quality) - - - - - BC3 (Medium quality) - - - - - - - - - - - Enable asynchronous presentation (Vulkan only) - - - - - - - Runs work in the background while waiting for graphics commands to keep the GPU from lowering its clock speed. - - - Force maximum clocks (Vulkan only) - - - - - - - Uses reactive flushing instead of predictive flushing. Allowing a more accurate syncing of memory. - - - Enable Reactive Flushing - - - - - - - Enables asynchronous shader compilation, which may reduce shader stutter. This feature is experimental. - - - Use asynchronous shader building (Hack) - - - - - - - Enables Fast GPU Time. This option will force most games to run at their highest native resolution. - - - Use Fast GPU Time (Hack) - - - - - - - Enables GPU vendor-specific pipeline cache. This option can improve shader loading time significantly in cases where the Vulkan driver does not store pipeline cache files internally. - - - Use Vulkan pipeline cache - - - - - - - Enable compute pipelines, required by some games. This setting only exists for Intel proprietary drivers, and may crash if enabled. -Compute pipelines are always enabled on all other drivers. - - - Enable Compute Pipelines (Intel Vulkan only) - - - - - - - Run the game at normal speed during video playback, even when the framerate is unlocked. - - - Sync to framerate of video playback - - - - - - - Improves rendering of transparency effects in specific games. - - - Barrier feedback loops - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Anisotropic Filtering: - - - - - - - - Automatic - - - - - Default - - - - - 2x - - - - - 4x - - - - - 8x - - - - - 16x - - - - - + + diff --git a/src/yuzu/configuration/configure_per_game.cpp b/src/yuzu/configuration/configure_per_game.cpp index 7ec0bf9d36..339768017d 100644 --- a/src/yuzu/configuration/configure_per_game.cpp +++ b/src/yuzu/configuration/configure_per_game.cpp @@ -41,8 +41,10 @@ ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id_, const std::string& file_name, std::vector& vk_device_records, Core::System& system_) - : QDialog(parent), ui(std::make_unique()), title_id{title_id_}, - system{system_}, tab_group{std::make_shared>()} { + : QDialog(parent), + ui(std::make_unique()), title_id{title_id_}, system{system_}, + translations{ConfigurationShared::InitializeTranslations(this)}, + tab_group{std::make_shared>()} { const auto file_path = std::filesystem::path(Common::FS::ToU8String(file_name)); const auto config_file_name = title_id == 0 ? Common::FS::PathToUTF8String(file_path.filename()) : fmt::format("{:016X}", title_id); @@ -52,7 +54,8 @@ ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id_, const std::st audio_tab = std::make_unique(system_, tab_group, this); cpu_tab = std::make_unique(system_, tab_group, this); general_tab = std::make_unique(system_, tab_group, this); - graphics_advanced_tab = std::make_unique(system_, tab_group, this); + graphics_advanced_tab = + std::make_unique(system_, tab_group, *translations, this); graphics_tab = std::make_unique( system_, vk_device_records, [&]() { graphics_advanced_tab->ExposeComputeOption(); }, tab_group, this); diff --git a/src/yuzu/configuration/configure_per_game.h b/src/yuzu/configuration/configure_per_game.h index 9fceff414b..1e222c2f9c 100644 --- a/src/yuzu/configuration/configure_per_game.h +++ b/src/yuzu/configuration/configure_per_game.h @@ -75,6 +75,7 @@ private: std::unique_ptr game_config; Core::System& system; + std::unique_ptr translations; std::shared_ptr> tab_group; std::unique_ptr addons_tab; diff --git a/src/yuzu/configuration/shared_translation.cpp b/src/yuzu/configuration/shared_translation.cpp new file mode 100644 index 0000000000..974203f758 --- /dev/null +++ b/src/yuzu/configuration/shared_translation.cpp @@ -0,0 +1,170 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "common/settings.h" +#include "yuzu/configuration/shared_translation.h" + +namespace ConfigurationShared { + +std::unique_ptr InitializeTranslations(QWidget* parent) { + std::unique_ptr translations = std::make_unique(); + const auto& tr = [parent](const char* text) -> QString { return parent->tr(text); }; + +#define INSERT(LABEL, NAME, TOOLTIP) \ + translations->insert(std::pair{(LABEL), std::pair{tr((NAME)), tr((TOOLTIP))}}) + + // Audio + INSERT("output_engine", "Output Engine:", ""); + INSERT("output_device", "Output Device:", ""); + INSERT("input_device", "Input Device:", ""); + INSERT("audio_muted", "Mute audio when in background", ""); + INSERT("volume", "Volume:", ""); + + // Core + INSERT("use_multi_core", "Multicore CPU Emulation", ""); + INSERT("use_unsafe_extended_memory_layout", "Unsafe extended memory layout (8GB DRAM)", ""); + + // Cpu + INSERT("cpu_accuracy", "Accuracy:", ""); + INSERT("cpu_debug_mode", "Enable CPU Debugging", ""); + INSERT("cpuopt_page_tables", "Enable inline page tables", ""); + INSERT("cpuopt_block_linking", "Enable block linking", ""); + INSERT("cpuopt_return_stack_buffer", "Enable return stack buffer", ""); + INSERT("cpuopt_fast_dispatcher", "Enable fast dispatcher", ""); + INSERT("cpuopt_context_elimination", "Enable context elimination", ""); + INSERT("cpuopt_const_prop", "Enable constant propagation", ""); + INSERT("cpuopt_misc_ir", "Enable miscellaneous optimizations", ""); + INSERT("cpuopt_reduce_misalign_checks", "Enable misalignment check reduction", ""); + INSERT("cpuopt_fastmem", "Enable Host MMU Emulation (general memory instructions)", ""); + INSERT("cpuopt_fastmem_exclusives", "Enable Host MMU Emulation (exclusive memory instructions)", + ""); + INSERT("cpuopt_recompile_exclusives", "Enable recompilation of exlucsive memory instructions", + ""); + INSERT("cpuopt_ignore_memory_aborts", "Enable fallbacks for invalid memory accesses", ""); + + INSERT("cpuopt_unsafe_unfuse_fma", "Unfuse FMA (improve performance on CPUs without FMA)", ""); + INSERT("cpuopt_unsafe_reduce_fp_error", "Faster FRSQRTE and FRECPE", ""); + INSERT("cpuopt_unsafe_ignore_standard_fpcr", "Faster ASIMD instructions (32 bits only)", ""); + INSERT("cpuopt_unsafe_inaccurate_nan", "Inaccurate NaN handling", ""); + INSERT("cpuopt_unsafe_fastmem_check", "Disable address space checks", ""); + INSERT("cpuopt_unsafe_ignore_global_monitor", "Ignore global monitor", ""); + + // Renderer + INSERT("backend", "API:", ""); + INSERT("vulkan_device", "Device:", ""); + INSERT("shader_backend", "Shader Backend:", ""); + INSERT("resolution_setup", "Resolution:", ""); + INSERT("scaling_filter", "Window Adapting Filter:", ""); + INSERT("fsr_sharpening_slider", "AMD FidelityFX™ Super Resolution Sharpness:", ""); + INSERT("anti_aliasing", "Anti-Aliasing Method:", ""); + INSERT("fullscreen_mode", "Fullscreen Mode:", ""); + INSERT("aspect_ratio", "Aspect Ratio:", ""); + INSERT("use_disk_shader_cache", "Use disk pipeline cache", ""); + INSERT("use_asynchronous_gpu_emulation", "Use asynchronous GPU emulation", ""); + INSERT("nvdec_emulation", "NVDEC emulation:", ""); + INSERT("acclerate_astc", "ASTC Decoding Method:", ""); + INSERT( + "use_vsync", "VSync Mode:", + "FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen refresh " + "rate. FIFO Relaxed is similar to FIFO but allows tearing as it recovers from a slow down. " + "Mailbox can have lower latency than FIFO and does not tear but may drop frames. Immediate " + "(no synchronization) just presents whatever is available and can exhibit tearing."); + + // Renderer (Advanced Graphics) + INSERT("async_presentation", "Enable asynchronous presentation (Vulkan only)", ""); + INSERT("force_max_clock", "Force maximum clocks (Vulkan only)", + "Runs work in the background while waiting for graphics commands to keep the GPU from " + "lowering its clock speed."); + INSERT("max_anisotropy", "Anisotropic Filtering:", ""); + INSERT("gpu_accuracy", "Accuracy Level:", ""); + INSERT("use_asynchronous_shaders", "Use asynchronous shader building (Hack)", + "Enables asynchronous shader compilation, which may reduce shader stutter. This feature " + "is experimental."); + INSERT("use_fast_gpu_time", "Use Fast GPU Time (Hack)", + "Enables Fast GPU Time. This option will force most games to run at their highest " + "native resolution."); + INSERT("use_vulkan_driver_pipeline_cache", "Use Vulkan pipeline cache", + "Enables GPU vendor-specific pipeline cache. This option can improve shader loading " + "time significantly in cases where the Vulkan driver does not store pipeline cache " + "files internally."); + INSERT("enable_compute_pipelines", "Enable Compute Pipelines (Intel Vulkan Only)", + "Enable compute pipelines, required by some games.\nThis setting only exists for Intel " + "proprietary drivers, and may crash if enabled.\nCompute pipelines are always enabled " + "on all other drivers."); + INSERT("bg_red", "Background Color:", ""); + INSERT("bg_green", "Background Color:", ""); + INSERT("bg_blue", "Background Color:", ""); + + // Renderer (Debug) + INSERT("debug", "Enable Graphics Debugging", + "When checked, the graphics API enters a slower debugging mode"); + INSERT("shader_feedback", "Enable Shader Feedback", + "When checked, yuzu will log statistics about the compiled pipeline cache"); + INSERT("nsight_aftermath", "Enable Nsight Aftermath", + "When checked, it enables Nsight Aftermath crash dumps"); + INSERT("disable_shader_loop_safety_checks", "Disable Loop safety checks", + "When checked, it executes shaders without loop logic changes"); + + // Renderer (General) + INSERT("use_speed_limit", "Limit Speed Percent", ""); + INSERT("speed_limit", "Limit Speed Percent", ""); + + // System + INSERT("rng_seed_enabled", "RNG Seed", ""); + INSERT("rng_seed", "RNG Seed", ""); + INSERT("device_name", "Device Name", ""); + INSERT("custom_rtc_enabled", "Custom RTC", ""); + INSERT("custom_rtc", "Custom RTC", ""); + INSERT("language_index", "Language:", ""); + INSERT("region_index", "Region:", ""); + INSERT("time_zone_index", "Time Zone:", ""); + INSERT("sound_index", "Sound Output Mode:", ""); + INSERT("use_docked_mode", "Docked", ""); + +#undef INSERT + + return translations; +} + +std::forward_list ComboboxEnumeration(std::type_index type, QWidget* parent) { + const auto& tr = [&](const char* text) { return parent->tr(text); }; + + if (type == typeid(Settings::AstcDecodeMode)) { + return { + tr("CPU"), + tr("GPU"), + tr("CPU Asynchronous"), + }; + } else if (type == typeid(Settings::RendererBackend)) { + return { + tr("OpenGL"), + tr("Vulkan"), + tr("Null"), + }; + } else if (type == typeid(Settings::ShaderBackend)) { + return { + tr("GLSL"), + tr("GLASM (Assembly Shaders, NVIDIA Only)"), + tr("SPIR-V (Experimental, Mesa Only)"), + }; + } else if (type == typeid(Settings::GPUAccuracy)) { + return { + tr("Normal"), + tr("High"), + tr("Extreme"), + }; + } else if (type == typeid(Settings::AnisotropyMode)) { + return { + tr("Automatic"), tr("Default"), tr("2x"), tr("4x"), tr("8x"), tr("16x"), + }; + } + + return {}; +} + +} // namespace ConfigurationShared diff --git a/src/yuzu/configuration/shared_translation.h b/src/yuzu/configuration/shared_translation.h new file mode 100644 index 0000000000..a81ae9c877 --- /dev/null +++ b/src/yuzu/configuration/shared_translation.h @@ -0,0 +1,18 @@ +#include +#include +#include +#include +#include +#include +#include + +class QWidget; + +namespace ConfigurationShared { +using TranslationMap = std::map>; + +std::unique_ptr InitializeTranslations(QWidget* parent); + +std::forward_list ComboboxEnumeration(std::type_index type, QWidget* parent); + +} // namespace ConfigurationShared