Merge pull request #10839 from lat9nq/pgc-plus

general: Reimplement per-game configurations
This commit is contained in:
liamwhite
2023-08-02 14:25:52 -04:00
committed by GitHub
78 changed files with 4614 additions and 4820 deletions

View File

@ -143,6 +143,10 @@ add_executable(yuzu
configuration/configure_web.ui
configuration/input_profiles.cpp
configuration/input_profiles.h
configuration/shared_translation.cpp
configuration/shared_translation.h
configuration/shared_widget.cpp
configuration/shared_widget.h
debugger/console.cpp
debugger/console.h
debugger/controller.cpp
@ -231,6 +235,12 @@ if (WIN32 AND YUZU_CRASH_DUMPS)
target_compile_definitions(yuzu PRIVATE -DYUZU_DBGHELP)
endif()
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
target_compile_definitions(yuzu PRIVATE
$<$<VERSION_LESS:$<CXX_COMPILER_VERSION>,15>:CANNOT_EXPLICITLY_INSTANTIATE>
)
endif()
file(GLOB COMPAT_LIST
${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.qrc
${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.json)

File diff suppressed because it is too large Load Diff

View File

@ -52,7 +52,7 @@ public:
static const std::map<Settings::AntiAliasing, QString> anti_aliasing_texts_map;
static const std::map<Settings::ScalingFilter, QString> scaling_filter_texts_map;
static const std::map<bool, QString> use_docked_mode_texts_map;
static const std::map<Settings::GPUAccuracy, QString> gpu_accuracy_texts_map;
static const std::map<Settings::GpuAccuracy, QString> gpu_accuracy_texts_map;
static const std::map<Settings::RendererBackend, QString> renderer_backend_texts_map;
static const std::map<Settings::ShaderBackend, QString> shader_backend_texts_map;
@ -74,7 +74,6 @@ private:
void ReadKeyboardValues();
void ReadMouseValues();
void ReadTouchscreenValues();
void ReadMousePanningValues();
void ReadMotionTouchValues();
void ReadHidbusValues();
void ReadIrCameraValues();
@ -99,13 +98,13 @@ private:
void ReadUILayoutValues();
void ReadWebServiceValues();
void ReadMultiplayerValues();
void ReadNetworkValues();
void SaveValues();
void SavePlayerValue(std::size_t player_index);
void SaveDebugValues();
void SaveMouseValues();
void SaveTouchscreenValues();
void SaveMousePanningValues();
void SaveMotionTouchValues();
void SaveHidbusValues();
void SaveIrCameraValues();
@ -140,18 +139,6 @@ private:
QVariant ReadSetting(const QString& name) const;
QVariant ReadSetting(const QString& name, const QVariant& default_value) const;
/**
* Only reads a setting from the qt_config if the current config is a global config, or if the
* current config is a custom config and the setting is overriding the global setting. Otherwise
* it does nothing.
*
* @param setting The variable to be modified
* @param name The setting's identifier
* @param default_value The value to use when the setting is not already present in the config
*/
template <typename Type>
void ReadSettingGlobal(Type& setting, const QString& name, const QVariant& default_value) const;
/**
* Writes a setting to the qt_config.
*
@ -166,50 +153,20 @@ private:
void WriteSetting(const QString& name, const QVariant& value, const QVariant& default_value,
bool use_global);
/**
* Reads a value from the qt_config and applies it to the setting, using its label and default
* value. If the config is a custom config, this will also read the global state of the setting
* and apply that information to it.
*
* @param The setting
*/
template <typename Type, bool ranged>
void ReadGlobalSetting(Settings::SwitchableSetting<Type, ranged>& setting);
void ReadCategory(Settings::Category category);
void WriteCategory(Settings::Category category);
void ReadSettingGeneric(Settings::BasicSetting* const setting);
void WriteSettingGeneric(Settings::BasicSetting* const setting) const;
/**
* Sets a value to the qt_config using the setting's label and default value. If the config is a
* custom config, it will apply the global state, and the custom value if needed.
*
* @param The setting
*/
template <typename Type, bool ranged>
void WriteGlobalSetting(const Settings::SwitchableSetting<Type, ranged>& setting);
/**
* Reads a value from the qt_config using the setting's label and default value and applies the
* value to the setting.
*
* @param The setting
*/
template <typename Type, bool ranged>
void ReadBasicSetting(Settings::Setting<Type, ranged>& setting);
/** Sets a value from the setting in the qt_config using the setting's label and default value.
*
* @param The setting
*/
template <typename Type, bool ranged>
void WriteBasicSetting(const Settings::Setting<Type, ranged>& setting);
ConfigType type;
const ConfigType type;
std::unique_ptr<QSettings> qt_config;
std::string qt_config_loc;
bool global;
const bool global;
};
// These metatype declarations cannot be in common/settings.h because core is devoid of QT
Q_DECLARE_METATYPE(Settings::CPUAccuracy);
Q_DECLARE_METATYPE(Settings::GPUAccuracy);
Q_DECLARE_METATYPE(Settings::CpuAccuracy);
Q_DECLARE_METATYPE(Settings::GpuAccuracy);
Q_DECLARE_METATYPE(Settings::FullscreenMode);
Q_DECLARE_METATYPE(Settings::NvdecEmulation);
Q_DECLARE_METATYPE(Settings::ResolutionSetup);
@ -218,3 +175,4 @@ Q_DECLARE_METATYPE(Settings::AntiAliasing);
Q_DECLARE_METATYPE(Settings::RendererBackend);
Q_DECLARE_METATYPE(Settings::ShaderBackend);
Q_DECLARE_METATYPE(Settings::AstcRecompression);
Q_DECLARE_METATYPE(Settings::AstcDecodeMode);

View File

@ -1,104 +1,19 @@
// SPDX-FileCopyrightText: 2016 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <QCheckBox>
#include <QObject>
#include <QString>
#include "common/settings.h"
#include <memory>
#include <type_traits>
#include <vector>
#include "yuzu/configuration/configuration_shared.h"
#include "yuzu/configuration/configure_per_game.h"
void ConfigurationShared::ApplyPerGameSetting(Settings::SwitchableSetting<bool>* setting,
const QCheckBox* checkbox,
const CheckState& tracker) {
if (Settings::IsConfiguringGlobal() && setting->UsingGlobal()) {
setting->SetValue(checkbox->checkState());
} else if (!Settings::IsConfiguringGlobal()) {
if (tracker == CheckState::Global) {
setting->SetGlobal(true);
} else {
setting->SetGlobal(false);
setting->SetValue(checkbox->checkState());
}
namespace ConfigurationShared {
Tab::Tab(std::shared_ptr<std::vector<Tab*>> group, QWidget* parent) : QWidget(parent) {
if (group != nullptr) {
group->push_back(this);
}
}
void ConfigurationShared::SetPerGameSetting(QCheckBox* checkbox,
const Settings::SwitchableSetting<bool>* setting) {
if (setting->UsingGlobal()) {
checkbox->setCheckState(Qt::PartiallyChecked);
} else {
checkbox->setCheckState(setting->GetValue() ? Qt::Checked : Qt::Unchecked);
}
}
Tab::~Tab() = default;
void ConfigurationShared::SetHighlight(QWidget* widget, bool highlighted) {
if (highlighted) {
widget->setStyleSheet(QStringLiteral("QWidget#%1 { background-color:rgba(0,203,255,0.5) }")
.arg(widget->objectName()));
} else {
widget->setStyleSheet(QStringLiteral("QWidget#%1 { background-color:rgba(0,0,0,0) }")
.arg(widget->objectName()));
}
widget->show();
}
void ConfigurationShared::SetColoredTristate(QCheckBox* checkbox,
const Settings::SwitchableSetting<bool>& setting,
CheckState& tracker) {
if (setting.UsingGlobal()) {
tracker = CheckState::Global;
} else {
tracker = (setting.GetValue() == setting.GetValue(true)) ? CheckState::On : CheckState::Off;
}
SetHighlight(checkbox, tracker != CheckState::Global);
QObject::connect(checkbox, &QCheckBox::clicked, checkbox, [checkbox, setting, &tracker] {
tracker = static_cast<CheckState>((static_cast<int>(tracker) + 1) %
static_cast<int>(CheckState::Count));
if (tracker == CheckState::Global) {
checkbox->setChecked(setting.GetValue(true));
}
SetHighlight(checkbox, tracker != CheckState::Global);
});
}
void ConfigurationShared::SetColoredTristate(QCheckBox* checkbox, bool global, bool state,
bool global_state, CheckState& tracker) {
if (global) {
tracker = CheckState::Global;
} else {
tracker = (state == global_state) ? CheckState::On : CheckState::Off;
}
SetHighlight(checkbox, tracker != CheckState::Global);
QObject::connect(checkbox, &QCheckBox::clicked, checkbox, [checkbox, global_state, &tracker] {
tracker = static_cast<CheckState>((static_cast<int>(tracker) + 1) %
static_cast<int>(CheckState::Count));
if (tracker == CheckState::Global) {
checkbox->setChecked(global_state);
}
SetHighlight(checkbox, tracker != CheckState::Global);
});
}
void ConfigurationShared::SetColoredComboBox(QComboBox* combobox, QWidget* target, int global) {
InsertGlobalItem(combobox, global);
QObject::connect(combobox, qOverload<int>(&QComboBox::activated), target,
[target](int index) { SetHighlight(target, index != 0); });
}
void ConfigurationShared::InsertGlobalItem(QComboBox* combobox, int global_index) {
const QString use_global_text =
ConfigurePerGame::tr("Use global configuration (%1)").arg(combobox->itemText(global_index));
combobox->insertItem(ConfigurationShared::USE_GLOBAL_INDEX, use_global_text);
combobox->insertSeparator(ConfigurationShared::USE_GLOBAL_SEPARATOR_INDEX);
}
int ConfigurationShared::GetComboboxIndex(int global_setting_index, const QComboBox* combobox) {
if (Settings::IsConfiguringGlobal()) {
return combobox->currentIndex();
}
if (combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
return global_setting_index;
}
return combobox->currentIndex() - ConfigurationShared::USE_GLOBAL_OFFSET;
}
} // namespace ConfigurationShared

View File

@ -3,73 +3,25 @@
#pragma once
#include <QCheckBox>
#include <QComboBox>
#include "common/settings.h"
#include <memory>
#include <vector>
#include <QString>
#include <QWidget>
#include <qobjectdefs.h>
class QObject;
namespace ConfigurationShared {
constexpr int USE_GLOBAL_INDEX = 0;
constexpr int USE_GLOBAL_SEPARATOR_INDEX = 1;
constexpr int USE_GLOBAL_OFFSET = 2;
class Tab : public QWidget {
Q_OBJECT
// CheckBoxes require a tracker for their state since we emulate a tristate CheckBox
enum class CheckState {
Off, // Checkbox overrides to off/false
On, // Checkbox overrides to on/true
Global, // Checkbox defers to the global state
Count, // Simply the number of states, not a valid checkbox state
public:
explicit Tab(std::shared_ptr<std::vector<Tab*>> group, QWidget* parent = nullptr);
~Tab();
virtual void ApplyConfiguration() = 0;
virtual void SetConfiguration() = 0;
};
// Global-aware apply and set functions
// ApplyPerGameSetting, given a Settings::Setting and a Qt UI element, properly applies a Setting
void ApplyPerGameSetting(Settings::SwitchableSetting<bool>* setting, const QCheckBox* checkbox,
const CheckState& tracker);
template <typename Type, bool ranged>
void ApplyPerGameSetting(Settings::SwitchableSetting<Type, ranged>* setting,
const QComboBox* combobox) {
if (Settings::IsConfiguringGlobal() && setting->UsingGlobal()) {
setting->SetValue(static_cast<Type>(combobox->currentIndex()));
} else if (!Settings::IsConfiguringGlobal()) {
if (combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
setting->SetGlobal(true);
} else {
setting->SetGlobal(false);
setting->SetValue(static_cast<Type>(combobox->currentIndex() -
ConfigurationShared::USE_GLOBAL_OFFSET));
}
}
}
// Sets a Qt UI element given a Settings::Setting
void SetPerGameSetting(QCheckBox* checkbox, const Settings::SwitchableSetting<bool>* setting);
template <typename Type, bool ranged>
void SetPerGameSetting(QComboBox* combobox,
const Settings::SwitchableSetting<Type, ranged>* setting) {
combobox->setCurrentIndex(setting->UsingGlobal() ? ConfigurationShared::USE_GLOBAL_INDEX
: static_cast<int>(setting->GetValue()) +
ConfigurationShared::USE_GLOBAL_OFFSET);
}
// (Un)highlights a Qt UI element
void SetHighlight(QWidget* widget, bool highlighted);
// Sets up a QCheckBox like a tristate one, given a Setting
void SetColoredTristate(QCheckBox* checkbox, const Settings::SwitchableSetting<bool>& setting,
CheckState& tracker);
void SetColoredTristate(QCheckBox* checkbox, bool global, bool state, bool global_state,
CheckState& tracker);
// Sets up coloring of a QWidget `target` based on the state of a QComboBox, and calls
// InsertGlobalItem
void SetColoredComboBox(QComboBox* combobox, QWidget* target, int global);
// Adds the "Use Global Configuration" selection and separator to the beginning of a QComboBox
void InsertGlobalItem(QComboBox* combobox, int global_index);
// Returns the correct index of a QComboBox taking into account global configuration
int GetComboboxIndex(int global_setting_index, const QComboBox* combobox);
} // namespace ConfigurationShared

View File

@ -48,11 +48,34 @@
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="leftMargin">
<number>0</number>
</property>
</widget>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Some settings are only available when a game is not running.</string>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>

View File

@ -1,87 +1,112 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <map>
#include <memory>
#include <vector>
#include <QComboBox>
#include "audio_core/sink/sink.h"
#include "audio_core/sink/sink_details.h"
#include "common/common_types.h"
#include "common/settings.h"
#include "common/settings_common.h"
#include "core/core.h"
#include "ui_configure_audio.h"
#include "yuzu/configuration/configuration_shared.h"
#include "yuzu/configuration/configure_audio.h"
#include "yuzu/configuration/shared_translation.h"
#include "yuzu/configuration/shared_widget.h"
#include "yuzu/uisettings.h"
ConfigureAudio::ConfigureAudio(const Core::System& system_, QWidget* parent)
: QWidget(parent), ui(std::make_unique<Ui::ConfigureAudio>()), system{system_} {
ConfigureAudio::ConfigureAudio(const Core::System& system_,
std::shared_ptr<std::vector<ConfigurationShared::Tab*>> group_,
const ConfigurationShared::Builder& builder, QWidget* parent)
: Tab(group_, parent), ui(std::make_unique<Ui::ConfigureAudio>()), system{system_} {
ui->setupUi(this);
InitializeAudioSinkComboBox();
connect(ui->volume_slider, &QSlider::valueChanged, this,
&ConfigureAudio::SetVolumeIndicatorText);
connect(ui->sink_combo_box, qOverload<int>(&QComboBox::currentIndexChanged), this,
&ConfigureAudio::UpdateAudioDevices);
ui->volume_label->setVisible(Settings::IsConfiguringGlobal());
ui->volume_combo_box->setVisible(!Settings::IsConfiguringGlobal());
SetupPerGameUI();
Setup(builder);
SetConfiguration();
const bool is_powered_on = system_.IsPoweredOn();
ui->sink_combo_box->setEnabled(!is_powered_on);
ui->output_combo_box->setEnabled(!is_powered_on);
ui->input_combo_box->setEnabled(!is_powered_on);
}
ConfigureAudio::~ConfigureAudio() = default;
void ConfigureAudio::Setup(const ConfigurationShared::Builder& builder) {
auto& layout = *ui->audio_widget->layout();
std::vector<Settings::BasicSetting*> settings;
std::map<u32, QWidget*> hold;
auto push = [&](Settings::Category category) {
for (auto* setting : Settings::values.linkage.by_category[category]) {
settings.push_back(setting);
}
};
push(Settings::Category::Audio);
push(Settings::Category::SystemAudio);
for (auto* setting : settings) {
auto* widget = builder.BuildWidget(setting, apply_funcs);
if (widget == nullptr) {
continue;
}
if (!widget->Valid()) {
widget->deleteLater();
continue;
}
hold.emplace(std::pair{setting->Id(), widget});
if (setting->Id() == Settings::values.sink_id.Id()) {
// TODO (lat9nq): Let the system manage sink_id
sink_combo_box = widget->combobox;
InitializeAudioSinkComboBox();
connect(sink_combo_box, qOverload<int>(&QComboBox::currentIndexChanged), this,
&ConfigureAudio::UpdateAudioDevices);
} else if (setting->Id() == Settings::values.audio_output_device_id.Id()) {
// Keep track of output (and input) device comboboxes to populate them with system
// devices, which are determined at run time
output_device_combo_box = widget->combobox;
} else if (setting->Id() == Settings::values.audio_input_device_id.Id()) {
input_device_combo_box = widget->combobox;
}
}
for (const auto& [id, widget] : hold) {
layout.addWidget(widget);
}
}
void ConfigureAudio::SetConfiguration() {
if (!Settings::IsConfiguringGlobal()) {
return;
}
SetOutputSinkFromSinkID();
// The device list cannot be pre-populated (nor listed) until the output sink is known.
UpdateAudioDevices(ui->sink_combo_box->currentIndex());
UpdateAudioDevices(sink_combo_box->currentIndex());
SetAudioDevicesFromDeviceID();
const auto volume_value = static_cast<int>(Settings::values.volume.GetValue());
ui->volume_slider->setValue(volume_value);
ui->toggle_background_mute->setChecked(UISettings::values.mute_when_in_background.GetValue());
if (!Settings::IsConfiguringGlobal()) {
if (Settings::values.volume.UsingGlobal()) {
ui->volume_combo_box->setCurrentIndex(0);
ui->volume_slider->setEnabled(false);
} else {
ui->volume_combo_box->setCurrentIndex(1);
ui->volume_slider->setEnabled(true);
}
ConfigurationShared::SetPerGameSetting(ui->combo_sound, &Settings::values.sound_index);
ConfigurationShared::SetHighlight(ui->mode_label,
!Settings::values.sound_index.UsingGlobal());
ConfigurationShared::SetHighlight(ui->volume_layout,
!Settings::values.volume.UsingGlobal());
} else {
ui->combo_sound->setCurrentIndex(Settings::values.sound_index.GetValue());
}
SetVolumeIndicatorText(ui->volume_slider->sliderPosition());
}
void ConfigureAudio::SetOutputSinkFromSinkID() {
[[maybe_unused]] const QSignalBlocker blocker(ui->sink_combo_box);
[[maybe_unused]] const QSignalBlocker blocker(sink_combo_box);
int new_sink_index = 0;
const QString sink_id = QString::fromStdString(Settings::values.sink_id.GetValue());
for (int index = 0; index < ui->sink_combo_box->count(); index++) {
if (ui->sink_combo_box->itemText(index) == sink_id) {
const QString sink_id = QString::fromStdString(Settings::values.sink_id.ToString());
for (int index = 0; index < sink_combo_box->count(); index++) {
if (sink_combo_box->itemText(index) == sink_id) {
new_sink_index = index;
break;
}
}
ui->sink_combo_box->setCurrentIndex(new_sink_index);
sink_combo_box->setCurrentIndex(new_sink_index);
}
void ConfigureAudio::SetAudioDevicesFromDeviceID() {
@ -89,57 +114,42 @@ void ConfigureAudio::SetAudioDevicesFromDeviceID() {
const QString output_device_id =
QString::fromStdString(Settings::values.audio_output_device_id.GetValue());
for (int index = 0; index < ui->output_combo_box->count(); index++) {
if (ui->output_combo_box->itemText(index) == output_device_id) {
for (int index = 0; index < output_device_combo_box->count(); index++) {
if (output_device_combo_box->itemText(index) == output_device_id) {
new_device_index = index;
break;
}
}
ui->output_combo_box->setCurrentIndex(new_device_index);
output_device_combo_box->setCurrentIndex(new_device_index);
new_device_index = -1;
const QString input_device_id =
QString::fromStdString(Settings::values.audio_input_device_id.GetValue());
for (int index = 0; index < ui->input_combo_box->count(); index++) {
if (ui->input_combo_box->itemText(index) == input_device_id) {
for (int index = 0; index < input_device_combo_box->count(); index++) {
if (input_device_combo_box->itemText(index) == input_device_id) {
new_device_index = index;
break;
}
}
ui->input_combo_box->setCurrentIndex(new_device_index);
}
void ConfigureAudio::SetVolumeIndicatorText(int percentage) {
ui->volume_indicator->setText(tr("%1%", "Volume percentage (e.g. 50%)").arg(percentage));
input_device_combo_box->setCurrentIndex(new_device_index);
}
void ConfigureAudio::ApplyConfiguration() {
ConfigurationShared::ApplyPerGameSetting(&Settings::values.sound_index, ui->combo_sound);
const bool is_powered_on = system.IsPoweredOn();
for (const auto& apply_func : apply_funcs) {
apply_func(is_powered_on);
}
if (Settings::IsConfiguringGlobal()) {
Settings::values.sink_id =
ui->sink_combo_box->itemText(ui->sink_combo_box->currentIndex()).toStdString();
Settings::values.sink_id.LoadString(
sink_combo_box->itemText(sink_combo_box->currentIndex()).toStdString());
Settings::values.audio_output_device_id.SetValue(
ui->output_combo_box->itemText(ui->output_combo_box->currentIndex()).toStdString());
output_device_combo_box->itemText(output_device_combo_box->currentIndex())
.toStdString());
Settings::values.audio_input_device_id.SetValue(
ui->input_combo_box->itemText(ui->input_combo_box->currentIndex()).toStdString());
UISettings::values.mute_when_in_background = ui->toggle_background_mute->isChecked();
// Guard if during game and set to game-specific value
if (Settings::values.volume.UsingGlobal()) {
const auto volume = static_cast<u8>(ui->volume_slider->value());
Settings::values.volume.SetValue(volume);
}
} else {
if (ui->volume_combo_box->currentIndex() == 0) {
Settings::values.volume.SetGlobal(true);
} else {
Settings::values.volume.SetGlobal(false);
const auto volume = static_cast<u8>(ui->volume_slider->value());
Settings::values.volume.SetValue(volume);
}
input_device_combo_box->itemText(input_device_combo_box->currentIndex()).toStdString());
}
}
@ -152,54 +162,31 @@ void ConfigureAudio::changeEvent(QEvent* event) {
}
void ConfigureAudio::UpdateAudioDevices(int sink_index) {
ui->output_combo_box->clear();
ui->output_combo_box->addItem(QString::fromUtf8(AudioCore::Sink::auto_device_name));
output_device_combo_box->clear();
output_device_combo_box->addItem(QString::fromUtf8(AudioCore::Sink::auto_device_name));
const std::string sink_id = ui->sink_combo_box->itemText(sink_index).toStdString();
const auto sink_id =
Settings::ToEnum<Settings::AudioEngine>(sink_combo_box->itemText(sink_index).toStdString());
for (const auto& device : AudioCore::Sink::GetDeviceListForSink(sink_id, false)) {
ui->output_combo_box->addItem(QString::fromStdString(device));
output_device_combo_box->addItem(QString::fromStdString(device));
}
ui->input_combo_box->clear();
ui->input_combo_box->addItem(QString::fromUtf8(AudioCore::Sink::auto_device_name));
input_device_combo_box->clear();
input_device_combo_box->addItem(QString::fromUtf8(AudioCore::Sink::auto_device_name));
for (const auto& device : AudioCore::Sink::GetDeviceListForSink(sink_id, true)) {
ui->input_combo_box->addItem(QString::fromStdString(device));
input_device_combo_box->addItem(QString::fromStdString(device));
}
}
void ConfigureAudio::InitializeAudioSinkComboBox() {
ui->sink_combo_box->clear();
ui->sink_combo_box->addItem(QString::fromUtf8(AudioCore::Sink::auto_device_name));
sink_combo_box->clear();
sink_combo_box->addItem(QString::fromUtf8(AudioCore::Sink::auto_device_name));
for (const auto& id : AudioCore::Sink::GetSinkIDs()) {
ui->sink_combo_box->addItem(QString::fromUtf8(id.data(), static_cast<s32>(id.length())));
sink_combo_box->addItem(QString::fromStdString(Settings::CanonicalizeEnum(id)));
}
}
void ConfigureAudio::RetranslateUI() {
ui->retranslateUi(this);
SetVolumeIndicatorText(ui->volume_slider->sliderPosition());
}
void ConfigureAudio::SetupPerGameUI() {
if (Settings::IsConfiguringGlobal()) {
ui->combo_sound->setEnabled(Settings::values.sound_index.UsingGlobal());
ui->volume_slider->setEnabled(Settings::values.volume.UsingGlobal());
return;
}
ConfigurationShared::SetColoredComboBox(ui->combo_sound, ui->mode_label,
Settings::values.sound_index.GetValue(true));
connect(ui->volume_combo_box, qOverload<int>(&QComboBox::activated), this, [this](int index) {
ui->volume_slider->setEnabled(index == 1);
ConfigurationShared::SetHighlight(ui->volume_layout, index == 1);
});
ui->sink_combo_box->setVisible(false);
ui->sink_label->setVisible(false);
ui->output_combo_box->setVisible(false);
ui->output_label->setVisible(false);
ui->input_combo_box->setVisible(false);
ui->input_label->setVisible(false);
}

View File

@ -3,30 +3,35 @@
#pragma once
#include <functional>
#include <memory>
#include <vector>
#include <QWidget>
#include "yuzu/configuration/configuration_shared.h"
class QComboBox;
namespace Core {
class System;
}
namespace ConfigurationShared {
enum class CheckState;
}
namespace Ui {
class ConfigureAudio;
}
class ConfigureAudio : public QWidget {
Q_OBJECT
namespace ConfigurationShared {
class Builder;
}
class ConfigureAudio : public ConfigurationShared::Tab {
public:
explicit ConfigureAudio(const Core::System& system_, QWidget* parent = nullptr);
explicit ConfigureAudio(const Core::System& system_,
std::shared_ptr<std::vector<ConfigurationShared::Tab*>> group,
const ConfigurationShared::Builder& builder, QWidget* parent = nullptr);
~ConfigureAudio() override;
void ApplyConfiguration();
void SetConfiguration();
void ApplyConfiguration() override;
void SetConfiguration() override;
private:
void changeEvent(QEvent* event) override;
@ -39,11 +44,16 @@ private:
void SetOutputSinkFromSinkID();
void SetAudioDevicesFromDeviceID();
void SetVolumeIndicatorText(int percentage);
void SetupPerGameUI();
void Setup(const ConfigurationShared::Builder& builder);
std::unique_ptr<Ui::ConfigureAudio> ui;
const Core::System& system;
std::vector<std::function<void(bool)>> apply_funcs{};
QComboBox* sink_combo_box;
QComboBox* output_device_combo_box;
QComboBox* input_device_combo_box;
};

View File

@ -21,80 +21,14 @@
</property>
<layout class="QVBoxLayout">
<item>
<layout class="QHBoxLayout" name="engine_layout">
<item>
<widget class="QLabel" name="sink_label">
<property name="text">
<string>Output Engine:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="sink_combo_box"/>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="output_layout">
<item>
<widget class="QLabel" name="output_label">
<property name="text">
<string>Output Device:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="output_combo_box"/>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="input_layout">
<item>
<widget class="QLabel" name="input_label">
<property name="text">
<string>Input Device:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="input_combo_box"/>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="mode_layout">
<item>
<widget class="QLabel" name="mode_label">
<property name="text">
<string>Sound Output Mode:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="combo_sound">
<item>
<property name="text">
<string>Mono</string>
</property>
</item>
<item>
<property name="text">
<string>Stereo</string>
</property>
</item>
<item>
<property name="text">
<string>Surround</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QWidget" name="volume_layout" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<widget class="QWidget" name="audio_widget" native="true">
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777213</height>
</size>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>0</number>
</property>
@ -107,89 +41,9 @@
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QComboBox" name="volume_combo_box">
<item>
<property name="text">
<string>Use global volume</string>
</property>
</item>
<item>
<property name="text">
<string>Set volume:</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QLabel" name="volume_label">
<property name="text">
<string>Volume:</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>30</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QSlider" name="volume_slider">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximum">
<number>200</number>
</property>
<property name="pageStep">
<number>5</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="volume_indicator">
<property name="minimumSize">
<size>
<width>32</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>0 %</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="mute_layout">
<item>
<widget class="QCheckBox" name="toggle_background_mute">
<property name="text">
<string>Mute audio when in background</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>

View File

@ -1,88 +1,92 @@
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <memory>
#include <typeinfo>
#include <vector>
#include <QComboBox>
#include "common/common_types.h"
#include "common/settings.h"
#include "common/settings_enums.h"
#include "configuration/shared_widget.h"
#include "core/core.h"
#include "ui_configure_cpu.h"
#include "yuzu/configuration/configuration_shared.h"
#include "yuzu/configuration/configure_cpu.h"
ConfigureCpu::ConfigureCpu(const Core::System& system_, QWidget* parent)
: QWidget(parent), ui{std::make_unique<Ui::ConfigureCpu>()}, system{system_} {
ConfigureCpu::ConfigureCpu(const Core::System& system_,
std::shared_ptr<std::vector<ConfigurationShared::Tab*>> group_,
const ConfigurationShared::Builder& builder, QWidget* parent)
: Tab(group_, parent), ui{std::make_unique<Ui::ConfigureCpu>()}, system{system_},
combobox_translations(builder.ComboboxTranslations()) {
ui->setupUi(this);
SetupPerGameUI();
Setup(builder);
SetConfiguration();
connect(ui->accuracy, qOverload<int>(&QComboBox::currentIndexChanged), this,
connect(accuracy_combobox, qOverload<int>(&QComboBox::currentIndexChanged), this,
&ConfigureCpu::UpdateGroup);
}
ConfigureCpu::~ConfigureCpu() = default;
void ConfigureCpu::SetConfiguration() {
const bool runtime_lock = !system.IsPoweredOn();
void ConfigureCpu::SetConfiguration() {}
void ConfigureCpu::Setup(const ConfigurationShared::Builder& builder) {
auto* accuracy_layout = ui->widget_accuracy->layout();
auto* unsafe_layout = ui->unsafe_widget->layout();
std::map<u32, QWidget*> unsafe_hold{};
ui->accuracy->setEnabled(runtime_lock);
ui->cpuopt_unsafe_unfuse_fma->setEnabled(runtime_lock);
ui->cpuopt_unsafe_reduce_fp_error->setEnabled(runtime_lock);
ui->cpuopt_unsafe_ignore_standard_fpcr->setEnabled(runtime_lock);
ui->cpuopt_unsafe_inaccurate_nan->setEnabled(runtime_lock);
ui->cpuopt_unsafe_fastmem_check->setEnabled(runtime_lock);
ui->cpuopt_unsafe_ignore_global_monitor->setEnabled(runtime_lock);
std::vector<Settings::BasicSetting*> settings;
const auto push = [&](Settings::Category category) {
for (const auto setting : Settings::values.linkage.by_category[category]) {
settings.push_back(setting);
}
};
ui->cpuopt_unsafe_unfuse_fma->setChecked(Settings::values.cpuopt_unsafe_unfuse_fma.GetValue());
ui->cpuopt_unsafe_reduce_fp_error->setChecked(
Settings::values.cpuopt_unsafe_reduce_fp_error.GetValue());
ui->cpuopt_unsafe_ignore_standard_fpcr->setChecked(
Settings::values.cpuopt_unsafe_ignore_standard_fpcr.GetValue());
ui->cpuopt_unsafe_inaccurate_nan->setChecked(
Settings::values.cpuopt_unsafe_inaccurate_nan.GetValue());
ui->cpuopt_unsafe_fastmem_check->setChecked(
Settings::values.cpuopt_unsafe_fastmem_check.GetValue());
ui->cpuopt_unsafe_ignore_global_monitor->setChecked(
Settings::values.cpuopt_unsafe_ignore_global_monitor.GetValue());
push(Settings::Category::Cpu);
push(Settings::Category::CpuUnsafe);
if (Settings::IsConfiguringGlobal()) {
ui->accuracy->setCurrentIndex(static_cast<int>(Settings::values.cpu_accuracy.GetValue()));
} else {
ConfigurationShared::SetPerGameSetting(ui->accuracy, &Settings::values.cpu_accuracy);
ConfigurationShared::SetHighlight(ui->widget_accuracy,
!Settings::values.cpu_accuracy.UsingGlobal());
for (const auto setting : settings) {
auto* widget = builder.BuildWidget(setting, apply_funcs);
if (widget == nullptr) {
continue;
}
if (!widget->Valid()) {
widget->deleteLater();
continue;
}
if (setting->Id() == Settings::values.cpu_accuracy.Id()) {
// Keep track of cpu_accuracy combobox to display/hide the unsafe settings
accuracy_layout->addWidget(widget);
accuracy_combobox = widget->combobox;
} else {
// Presently, all other settings here are unsafe checkboxes
unsafe_hold.insert({setting->Id(), widget});
}
}
UpdateGroup(ui->accuracy->currentIndex());
for (const auto& [label, widget] : unsafe_hold) {
unsafe_layout->addWidget(widget);
}
UpdateGroup(accuracy_combobox->currentIndex());
}
void ConfigureCpu::UpdateGroup(int index) {
if (!Settings::IsConfiguringGlobal()) {
index -= ConfigurationShared::USE_GLOBAL_OFFSET;
}
const auto accuracy = static_cast<Settings::CPUAccuracy>(index);
ui->unsafe_group->setVisible(accuracy == Settings::CPUAccuracy::Unsafe);
const auto accuracy = static_cast<Settings::CpuAccuracy>(
combobox_translations.at(Settings::EnumMetadata<Settings::CpuAccuracy>::Index())[index]
.first);
ui->unsafe_group->setVisible(accuracy == Settings::CpuAccuracy::Unsafe);
}
void ConfigureCpu::ApplyConfiguration() {
ConfigurationShared::ApplyPerGameSetting(&Settings::values.cpu_accuracy, ui->accuracy);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.cpuopt_unsafe_unfuse_fma,
ui->cpuopt_unsafe_unfuse_fma,
cpuopt_unsafe_unfuse_fma);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.cpuopt_unsafe_reduce_fp_error,
ui->cpuopt_unsafe_reduce_fp_error,
cpuopt_unsafe_reduce_fp_error);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.cpuopt_unsafe_ignore_standard_fpcr,
ui->cpuopt_unsafe_ignore_standard_fpcr,
cpuopt_unsafe_ignore_standard_fpcr);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.cpuopt_unsafe_inaccurate_nan,
ui->cpuopt_unsafe_inaccurate_nan,
cpuopt_unsafe_inaccurate_nan);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.cpuopt_unsafe_fastmem_check,
ui->cpuopt_unsafe_fastmem_check,
cpuopt_unsafe_fastmem_check);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.cpuopt_unsafe_ignore_global_monitor,
ui->cpuopt_unsafe_ignore_global_monitor,
cpuopt_unsafe_ignore_global_monitor);
const bool is_powered_on = system.IsPoweredOn();
for (const auto& apply_func : apply_funcs) {
apply_func(is_powered_on);
}
}
void ConfigureCpu::changeEvent(QEvent* event) {
@ -96,32 +100,3 @@ void ConfigureCpu::changeEvent(QEvent* event) {
void ConfigureCpu::RetranslateUI() {
ui->retranslateUi(this);
}
void ConfigureCpu::SetupPerGameUI() {
if (Settings::IsConfiguringGlobal()) {
return;
}
ConfigurationShared::SetColoredComboBox(
ui->accuracy, ui->widget_accuracy,
static_cast<u32>(Settings::values.cpu_accuracy.GetValue(true)));
ConfigurationShared::SetColoredTristate(ui->cpuopt_unsafe_unfuse_fma,
Settings::values.cpuopt_unsafe_unfuse_fma,
cpuopt_unsafe_unfuse_fma);
ConfigurationShared::SetColoredTristate(ui->cpuopt_unsafe_reduce_fp_error,
Settings::values.cpuopt_unsafe_reduce_fp_error,
cpuopt_unsafe_reduce_fp_error);
ConfigurationShared::SetColoredTristate(ui->cpuopt_unsafe_ignore_standard_fpcr,
Settings::values.cpuopt_unsafe_ignore_standard_fpcr,
cpuopt_unsafe_ignore_standard_fpcr);
ConfigurationShared::SetColoredTristate(ui->cpuopt_unsafe_inaccurate_nan,
Settings::values.cpuopt_unsafe_inaccurate_nan,
cpuopt_unsafe_inaccurate_nan);
ConfigurationShared::SetColoredTristate(ui->cpuopt_unsafe_fastmem_check,
Settings::values.cpuopt_unsafe_fastmem_check,
cpuopt_unsafe_fastmem_check);
ConfigurationShared::SetColoredTristate(ui->cpuopt_unsafe_ignore_global_monitor,
Settings::values.cpuopt_unsafe_ignore_global_monitor,
cpuopt_unsafe_ignore_global_monitor);
}

View File

@ -4,29 +4,34 @@
#pragma once
#include <memory>
#include <vector>
#include <QWidget>
#include "yuzu/configuration/configuration_shared.h"
#include "yuzu/configuration/shared_translation.h"
class QComboBox;
namespace Core {
class System;
}
namespace ConfigurationShared {
enum class CheckState;
}
namespace Ui {
class ConfigureCpu;
}
class ConfigureCpu : public QWidget {
Q_OBJECT
namespace ConfigurationShared {
class Builder;
}
class ConfigureCpu : public ConfigurationShared::Tab {
public:
explicit ConfigureCpu(const Core::System& system_, QWidget* parent = nullptr);
explicit ConfigureCpu(const Core::System& system_,
std::shared_ptr<std::vector<ConfigurationShared::Tab*>> group,
const ConfigurationShared::Builder& builder, QWidget* parent = nullptr);
~ConfigureCpu() override;
void ApplyConfiguration();
void SetConfiguration();
void ApplyConfiguration() override;
void SetConfiguration() override;
private:
void changeEvent(QEvent* event) override;
@ -34,16 +39,14 @@ private:
void UpdateGroup(int index);
void SetupPerGameUI();
void Setup(const ConfigurationShared::Builder& builder);
std::unique_ptr<Ui::ConfigureCpu> ui;
ConfigurationShared::CheckState cpuopt_unsafe_unfuse_fma;
ConfigurationShared::CheckState cpuopt_unsafe_reduce_fp_error;
ConfigurationShared::CheckState cpuopt_unsafe_ignore_standard_fpcr;
ConfigurationShared::CheckState cpuopt_unsafe_inaccurate_nan;
ConfigurationShared::CheckState cpuopt_unsafe_fastmem_check;
ConfigurationShared::CheckState cpuopt_unsafe_ignore_global_monitor;
const Core::System& system;
const ConfigurationShared::ComboboxTranslationMap& combobox_translations;
std::vector<std::function<void(bool)>> apply_funcs{};
QComboBox* accuracy_combobox;
};

View File

@ -16,9 +16,12 @@
<property name="accessibleName">
<string>CPU</string>
</property>
<layout class="QVBoxLayout">
<layout class="QVBoxLayout" name="vboxlayout_2" stretch="0">
<item>
<layout class="QVBoxLayout">
<layout class="QVBoxLayout" name="vboxlayout">
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
@ -27,38 +30,19 @@
<layout class="QVBoxLayout">
<item>
<widget class="QWidget" name="widget_accuracy" native="true">
<layout class="QHBoxLayout" name="layout_accuracy">
<item>
<widget class="QLabel" name="label_accuracy">
<property name="text">
<string>Accuracy:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="accuracy">
<item>
<property name="text">
<string>Auto</string>
</property>
</item>
<item>
<property name="text">
<string>Accurate</string>
</property>
</item>
<item>
<property name="text">
<string>Unsafe</string>
</property>
</item>
<item>
<property name="text">
<string>Paranoid (disables most optimizations)</string>
</property>
</item>
</widget>
</item>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
</layout>
</widget>
</item>
@ -75,10 +59,6 @@
</layout>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout">
<item>
<widget class="QGroupBox" name="unsafe_group">
<property name="title">
@ -96,105 +76,44 @@
</widget>
</item>
<item>
<widget class="QCheckBox" name="cpuopt_unsafe_unfuse_fma">
<property name="toolTip">
<string>
&lt;div&gt;This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support.&lt;/div&gt;
</string>
</property>
<property name="text">
<string>Unfuse FMA (improve performance on CPUs without FMA)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cpuopt_unsafe_reduce_fp_error">
<property name="toolTip">
<string>
&lt;div&gt;This option improves the speed of some approximate floating-point functions by using less accurate native approximations.&lt;/div&gt;
</string>
</property>
<property name="text">
<string>Faster FRSQRTE and FRECPE</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cpuopt_unsafe_ignore_standard_fpcr">
<property name="toolTip">
<string>
&lt;div&gt;This option improves the speed of 32 bits ASIMD floating-point functions by running with incorrect rounding modes.&lt;/div&gt;
</string>
</property>
<property name="text">
<string>Faster ASIMD instructions (32 bits only)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cpuopt_unsafe_inaccurate_nan">
<property name="toolTip">
<string>
&lt;div&gt;This option improves speed by removing NaN checking. Please note this also reduces accuracy of certain floating-point instructions.&lt;/div&gt;
</string>
</property>
<property name="text">
<string>Inaccurate NaN handling</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cpuopt_unsafe_fastmem_check">
<property name="toolTip">
<string>
&lt;div&gt;This option improves speed by eliminating a safety check before every memory read/write in guest. Disabling it may allow a game to read/write the emulator's memory.&lt;/div&gt;
</string>
</property>
<property name="text">
<string>Disable address space checks</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cpuopt_unsafe_ignore_global_monitor">
<property name="toolTip">
<string>
&lt;div&gt;This option improves speed by relying only on the semantics of cmpxchg to ensure safety of exclusive access instructions. Please note this may result in deadlocks and other race conditions.&lt;/div&gt;
</string>
</property>
<property name="text">
<string>Ignore global monitor</string>
</property>
<widget class="QWidget" name="unsafe_widget" native="true">
<layout class="QVBoxLayout" name="unsafe_layout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_disable_info">
<property name="text">
<string>CPU settings are available only when game is not running.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>

View File

@ -2,360 +2,549 @@
<ui version="4.0">
<class>ConfigureDebug</class>
<widget class="QScrollArea" name="ConfigureDebug">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>831</width>
<height>760</height>
</rect>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget">
<layout class="QVBoxLayout" name="verticalLayout_1">
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Debugger</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_11">
<item>
<widget class="QCheckBox" name="toggle_gdbstub">
<property name="text">
<string>Enable GDB Stub</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_11">
<property name="text">
<string>Port:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="gdbport_spinbox">
<property name="minimum">
<number>1024</number>
</property>
<property name="maximum">
<number>65535</number>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Logging</string>
</property>
<layout class="QGridLayout" name="gridLayout_1">
<item row="0" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout_1">
<item>
<widget class="QLabel" name="label_1">
<property name="text">
<string>Global Log Filter</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="log_filter_edit"/>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="toggle_console">
<property name="text">
<string>Show Log in Console</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="open_log_button">
<property name="text">
<string>Open Log Location</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="extended_logging">
<property name="enabled">
<bool>true</bool>
</property>
<property name="toolTip">
<string>When checked, the max size of the log increases from 100 MB to 1 GB</string>
</property>
<property name="text">
<string>Enable Extended Logging**</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>Homebrew</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
<widget class="QWidget" name="widget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>829</width>
<height>758</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_1">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="topMargin">
<number>0</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Arguments String</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="homebrew_args_edit"/>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_4">
<property name="title">
<string>Graphics</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QCheckBox" name="enable_graphics_debugging">
<property name="enabled">
<bool>true</bool>
<widget class="QGroupBox" name="groupBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>When checked, the graphics API enters a slower debugging mode</string>
<property name="title">
<string>Debugger</string>
</property>
<property name="text">
<string>Enable Graphics Debugging</string>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<property name="flat">
<bool>false</bool>
</property>
<property name="checkable">
<bool>false</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QWidget" name="debug_widget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QCheckBox" name="toggle_gdbstub">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Enable GDB Stub</string>
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="horizontalWidget_3" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_11">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Port:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="gdbport_spinbox">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimum">
<number>1024</number>
</property>
<property name="maximum">
<number>65535</number>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="enable_nsight_aftermath">
<property name="toolTip">
<string>When checked, it enables Nsight Aftermath crash dumps</string>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Enable Nsight Aftermath</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="dump_shaders">
<property name="enabled">
<bool>true</bool>
</property>
<property name="toolTip">
<string>When checked, it will dump all the original assembler shaders from the disk shader cache or game as found</string>
</property>
<property name="text">
<string>Dump Game Shaders</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QCheckBox" name="dump_macros">
<property name="enabled">
<bool>true</bool>
</property>
<property name="toolTip">
<string>When checked, it will dump all the macro programs of the GPU</string>
</property>
<property name="text">
<string>Dump Maxwell Macros</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="disable_macro_jit">
<property name="enabled">
<bool>true</bool>
</property>
<property name="toolTip">
<string>When checked, it disables the macro Just In Time compiler. Enabling this makes games run slower</string>
</property>
<property name="text">
<string>Disable Macro JIT</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QCheckBox" name="disable_macro_hle">
<property name="enabled">
<bool>true</bool>
</property>
<property name="toolTip">
<string>When checked, it disables the macro HLE functions. Enabling this makes games run slower</string>
</property>
<property name="text">
<string>Disable Macro HLE</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="enable_shader_feedback">
<property name="toolTip">
<string>When checked, yuzu will log statistics about the compiled pipeline cache</string>
</property>
<property name="text">
<string>Enable Shader Feedback</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="disable_loop_safety_checks">
<property name="toolTip">
<string>When checked, it executes shaders without loop logic changes</string>
</property>
<property name="text">
<string>Disable Loop safety checks</string>
<property name="title">
<string>Logging</string>
</property>
<layout class="QGridLayout" name="gridLayout_1">
<item row="1" column="1">
<widget class="QPushButton" name="open_log_button">
<property name="text">
<string>Open Log Location</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QWidget" name="logging_widget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_1">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_1">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Global Log Filter</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="log_filter_edit"/>
</item>
</layout>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="extended_logging">
<property name="enabled">
<bool>true</bool>
</property>
<property name="toolTip">
<string>When checked, the max size of the log increases from 100 MB to 1 GB</string>
</property>
<property name="text">
<string>Enable Extended Logging**</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="toggle_console">
<property name="text">
<string>Show Log in Console</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_5">
<property name="title">
<string>Debugging</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="2" column="0">
<widget class="QCheckBox" name="reporting_services">
<property name="text">
<string>Enable Verbose Reporting Services**</string>
</item>
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>Homebrew</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Arguments String</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="homebrew_args_edit"/>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QGroupBox" name="groupBox_4">
<property name="title">
<string>Graphics</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="3" column="0">
<widget class="QCheckBox" name="disable_loop_safety_checks">
<property name="toolTip">
<string>When checked, it executes shaders without loop logic changes</string>
</property>
<property name="text">
<string>Disable Loop safety checks</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="dump_shaders">
<property name="enabled">
<bool>true</bool>
</property>
<property name="toolTip">
<string>When checked, it will dump all the original assembler shaders from the disk shader cache or game as found</string>
</property>
<property name="text">
<string>Dump Game Shaders</string>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QCheckBox" name="disable_macro_hle">
<property name="enabled">
<bool>true</bool>
</property>
<property name="toolTip">
<string>When checked, it disables the macro HLE functions. Enabling this makes games run slower</string>
</property>
<property name="text">
<string>Disable Macro HLE</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QCheckBox" name="disable_macro_jit">
<property name="enabled">
<bool>true</bool>
</property>
<property name="toolTip">
<string>When checked, it disables the macro Just In Time compiler. Enabling this makes games run slower</string>
</property>
<property name="text">
<string>Disable Macro JIT</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="enable_graphics_debugging">
<property name="enabled">
<bool>true</bool>
</property>
<property name="toolTip">
<string>When checked, the graphics API enters a slower debugging mode</string>
</property>
<property name="text">
<string>Enable Graphics Debugging</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QCheckBox" name="dump_macros">
<property name="enabled">
<bool>true</bool>
</property>
<property name="toolTip">
<string>When checked, it will dump all the macro programs of the GPU</string>
</property>
<property name="text">
<string>Dump Maxwell Macros</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="enable_shader_feedback">
<property name="toolTip">
<string>When checked, yuzu will log statistics about the compiled pipeline cache</string>
</property>
<property name="text">
<string>Enable Shader Feedback</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="enable_nsight_aftermath">
<property name="toolTip">
<string>When checked, it enables Nsight Aftermath crash dumps</string>
</property>
<property name="text">
<string>Enable Nsight Aftermath</string>
</property>
</widget>
</item>
<item row="8" column="0">
<spacer name="verticalSpacer_5">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Preferred</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="fs_access_log">
<property name="text">
<string>Enable FS Access Log</string>
<item>
<widget class="QGroupBox" name="groupBox_6">
<property name="title">
<string>Advanced</string>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<item row="3" column="0">
<widget class="QCheckBox" name="perform_vulkan_check">
<property name="toolTip">
<string>Enables yuzu to check for a working Vulkan environment when the program starts up. Disable this if this is causing issues with external programs seeing yuzu.</string>
</property>
<property name="text">
<string>Perform Startup Vulkan Check</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="disable_web_applet">
<property name="text">
<string>Disable Web Applet</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QCheckBox" name="enable_all_controllers">
<property name="text">
<string>Enable All Controller Types</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QCheckBox" name="use_auto_stub">
<property name="text">
<string>Enable Auto-Stub**</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="quest_flag">
<property name="text">
<string>Kiosk (Quest) Mode</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="enable_cpu_debugging">
<property name="text">
<string>Enable CPU Debugging</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="use_debug_asserts">
<property name="text">
<string>Enable Debug Asserts</string>
</property>
</widget>
</item>
<item row="7" column="0">
<spacer name="verticalSpacer_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="dump_audio_commands">
<property name="toolTip">
<string>Enable this to output the latest generated audio command list to the console. Only affects games using the audio renderer.</string>
</property>
<property name="text">
<string>Dump Audio Commands To Console**</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="create_crash_dumps">
<property name="text">
<string>Create Minidump After Crash</string>
<item>
<widget class="QGroupBox" name="groupBox_5">
<property name="title">
<string>Debugging</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QCheckBox" name="fs_access_log">
<property name="text">
<string>Enable FS Access Log</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="create_crash_dumps">
<property name="text">
<string>Create Minidump After Crash</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="dump_audio_commands">
<property name="toolTip">
<string>Enable this to output the latest generated audio command list to the console. Only affects games using the audio renderer.</string>
</property>
<property name="text">
<string>Dump Audio Commands To Console**</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="reporting_services">
<property name="text">
<string>Enable Verbose Reporting Services**</string>
</property>
</widget>
</item>
<item row="5" column="0">
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_6">
<property name="title">
<string>Advanced</string>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0">
<widget class="QCheckBox" name="quest_flag">
<property name="text">
<string>Kiosk (Quest) Mode</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="enable_cpu_debugging">
<property name="text">
<string>Enable CPU Debugging</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="use_debug_asserts">
<property name="text">
<string>Enable Debug Asserts</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="use_auto_stub">
<property name="text">
<string>Enable Auto-Stub**</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="enable_all_controllers">
<property name="text">
<string>Enable All Controller Types</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="disable_web_applet">
<property name="text">
<string>Disable Web Applet</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="perform_vulkan_check">
<property name="toolTip">
<string>Enables yuzu to check for a working Vulkan environment when the program starts up. Disable this if this is causing issues with external programs seeing yuzu.</string>
</property>
<property name="text">
<string>Perform Startup Vulkan Check</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QLabel" name="label_5">
<property name="font">
<font>
<italic>true</italic>
</font>
</property>
<property name="text">
<string>**This will be reset automatically when yuzu closes.</string>
</property>
<property name="indent">
<number>20</number>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_5">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<italic>true</italic>
</font>
</property>
<property name="text">
<string>**This will be reset automatically when yuzu closes.</string>
</property>
<property name="indent">
<number>20</number>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<tabstops>
<tabstop>log_filter_edit</tabstop>
@ -366,14 +555,11 @@
<tabstop>enable_graphics_debugging</tabstop>
<tabstop>enable_shader_feedback</tabstop>
<tabstop>enable_nsight_aftermath</tabstop>
<tabstop>disable_macro_jit</tabstop>
<tabstop>disable_loop_safety_checks</tabstop>
<tabstop>fs_access_log</tabstop>
<tabstop>reporting_services</tabstop>
<tabstop>quest_flag</tabstop>
<tabstop>enable_cpu_debugging</tabstop>
<tabstop>use_debug_asserts</tabstop>
<tabstop>use_auto_stub</tabstop>
</tabstops>
<resources/>
<connections/>

View File

@ -32,21 +32,23 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry_,
std::vector<VkDeviceInfo::Record>& vk_device_records,
Core::System& system_, bool enable_web_config)
: QDialog(parent), ui{std::make_unique<Ui::ConfigureDialog>()},
registry(registry_), system{system_}, audio_tab{std::make_unique<ConfigureAudio>(system_,
this)},
cpu_tab{std::make_unique<ConfigureCpu>(system_, this)},
registry(registry_), system{system_}, builder{std::make_unique<ConfigurationShared::Builder>(
this, !system_.IsPoweredOn())},
audio_tab{std::make_unique<ConfigureAudio>(system_, nullptr, *builder, this)},
cpu_tab{std::make_unique<ConfigureCpu>(system_, nullptr, *builder, this)},
debug_tab_tab{std::make_unique<ConfigureDebugTab>(system_, this)},
filesystem_tab{std::make_unique<ConfigureFilesystem>(this)},
general_tab{std::make_unique<ConfigureGeneral>(system_, this)},
graphics_advanced_tab{std::make_unique<ConfigureGraphicsAdvanced>(system_, this)},
general_tab{std::make_unique<ConfigureGeneral>(system_, nullptr, *builder, this)},
graphics_advanced_tab{
std::make_unique<ConfigureGraphicsAdvanced>(system_, nullptr, *builder, this)},
graphics_tab{std::make_unique<ConfigureGraphics>(
system_, vk_device_records, [&]() { graphics_advanced_tab->ExposeComputeOption(); },
this)},
nullptr, *builder, this)},
hotkeys_tab{std::make_unique<ConfigureHotkeys>(system_.HIDCore(), this)},
input_tab{std::make_unique<ConfigureInput>(system_, this)},
network_tab{std::make_unique<ConfigureNetwork>(system_, this)},
profile_tab{std::make_unique<ConfigureProfileManager>(system_, this)},
system_tab{std::make_unique<ConfigureSystem>(system_, this)},
system_tab{std::make_unique<ConfigureSystem>(system_, nullptr, *builder, this)},
ui_tab{std::make_unique<ConfigureUi>(system_, this)}, web_tab{std::make_unique<ConfigureWeb>(
this)} {
Settings::SetConfiguringGlobal(true);
@ -95,6 +97,9 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry_,
adjustSize();
ui->selectorList->setCurrentRow(0);
// Selects the leftmost button on the bottom bar (Cancel as of writing)
ui->buttonBox->setFocus();
}
ConfigureDialog::~ConfigureDialog() = default;

View File

@ -6,6 +6,9 @@
#include <memory>
#include <vector>
#include <QDialog>
#include "configuration/shared_widget.h"
#include "yuzu/configuration/configuration_shared.h"
#include "yuzu/configuration/shared_translation.h"
#include "yuzu/vk_device_info.h"
namespace Core {
@ -69,6 +72,8 @@ private:
HotkeyRegistry& registry;
Core::System& system;
std::unique_ptr<ConfigurationShared::Builder> builder;
std::vector<ConfigurationShared::Tab*> tab_group;
std::unique_ptr<ConfigureAudio> audio_tab;
std::unique_ptr<ConfigureCpu> cpu_tab;

View File

@ -3,57 +3,60 @@
#include <functional>
#include <utility>
#include <vector>
#include <QMessageBox>
#include "common/settings.h"
#include "core/core.h"
#include "ui_configure_general.h"
#include "yuzu/configuration/configuration_shared.h"
#include "yuzu/configuration/configure_general.h"
#include "yuzu/configuration/shared_widget.h"
#include "yuzu/uisettings.h"
ConfigureGeneral::ConfigureGeneral(const Core::System& system_, QWidget* parent)
: QWidget(parent), ui{std::make_unique<Ui::ConfigureGeneral>()}, system{system_} {
ConfigureGeneral::ConfigureGeneral(const Core::System& system_,
std::shared_ptr<std::vector<ConfigurationShared::Tab*>> group_,
const ConfigurationShared::Builder& builder, QWidget* parent)
: Tab(group_, parent), ui{std::make_unique<Ui::ConfigureGeneral>()}, system{system_} {
ui->setupUi(this);
SetupPerGameUI();
Setup(builder);
SetConfiguration();
if (Settings::IsConfiguringGlobal()) {
connect(ui->toggle_speed_limit, &QCheckBox::clicked, ui->speed_limit,
[this]() { ui->speed_limit->setEnabled(ui->toggle_speed_limit->isChecked()); });
}
connect(ui->button_reset_defaults, &QPushButton::clicked, this,
&ConfigureGeneral::ResetDefaults);
if (!Settings::IsConfiguringGlobal()) {
ui->button_reset_defaults->setVisible(false);
}
}
ConfigureGeneral::~ConfigureGeneral() = default;
void ConfigureGeneral::SetConfiguration() {
const bool runtime_lock = !system.IsPoweredOn();
void ConfigureGeneral::SetConfiguration() {}
ui->use_multi_core->setEnabled(runtime_lock);
ui->use_multi_core->setChecked(Settings::values.use_multi_core.GetValue());
void ConfigureGeneral::Setup(const ConfigurationShared::Builder& builder) {
QLayout& layout = *ui->general_widget->layout();
ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing.GetValue());
ui->toggle_user_on_boot->setChecked(UISettings::values.select_user_on_boot.GetValue());
ui->toggle_background_pause->setChecked(UISettings::values.pause_when_in_background.GetValue());
ui->toggle_hide_mouse->setChecked(UISettings::values.hide_mouse.GetValue());
ui->toggle_controller_applet_disabled->setEnabled(runtime_lock);
ui->toggle_controller_applet_disabled->setChecked(
UISettings::values.controller_applet_disabled.GetValue());
std::map<u32, QWidget*> hold{};
ui->toggle_speed_limit->setChecked(Settings::values.use_speed_limit.GetValue());
ui->speed_limit->setValue(Settings::values.speed_limit.GetValue());
for (const auto setting :
UISettings::values.linkage.by_category[Settings::Category::UiGeneral]) {
auto* widget = builder.BuildWidget(setting, apply_funcs);
ui->button_reset_defaults->setEnabled(runtime_lock);
if (widget == nullptr) {
continue;
}
if (!widget->Valid()) {
widget->deleteLater();
continue;
}
if (Settings::IsConfiguringGlobal()) {
ui->speed_limit->setEnabled(Settings::values.use_speed_limit.GetValue());
} else {
ui->speed_limit->setEnabled(Settings::values.use_speed_limit.GetValue() &&
use_speed_limit != ConfigurationShared::CheckState::Global);
hold.emplace(setting->Id(), widget);
}
for (const auto& [id, widget] : hold) {
layout.addWidget(widget);
}
}
@ -77,32 +80,9 @@ void ConfigureGeneral::ResetDefaults() {
}
void ConfigureGeneral::ApplyConfiguration() {
ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_multi_core, ui->use_multi_core,
use_multi_core);
if (Settings::IsConfiguringGlobal()) {
UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked();
UISettings::values.select_user_on_boot = ui->toggle_user_on_boot->isChecked();
UISettings::values.pause_when_in_background = ui->toggle_background_pause->isChecked();
UISettings::values.hide_mouse = ui->toggle_hide_mouse->isChecked();
UISettings::values.controller_applet_disabled =
ui->toggle_controller_applet_disabled->isChecked();
// Guard if during game and set to game-specific value
if (Settings::values.use_speed_limit.UsingGlobal()) {
Settings::values.use_speed_limit.SetValue(ui->toggle_speed_limit->checkState() ==
Qt::Checked);
Settings::values.speed_limit.SetValue(ui->speed_limit->value());
}
} else {
bool global_speed_limit = use_speed_limit == ConfigurationShared::CheckState::Global;
Settings::values.use_speed_limit.SetGlobal(global_speed_limit);
Settings::values.speed_limit.SetGlobal(global_speed_limit);
if (!global_speed_limit) {
Settings::values.use_speed_limit.SetValue(ui->toggle_speed_limit->checkState() ==
Qt::Checked);
Settings::values.speed_limit.SetValue(ui->speed_limit->value());
}
bool powered_on = system.IsPoweredOn();
for (const auto& func : apply_funcs) {
func(powered_on);
}
}
@ -117,33 +97,3 @@ void ConfigureGeneral::changeEvent(QEvent* event) {
void ConfigureGeneral::RetranslateUI() {
ui->retranslateUi(this);
}
void ConfigureGeneral::SetupPerGameUI() {
if (Settings::IsConfiguringGlobal()) {
// Disables each setting if:
// - A game is running (thus settings in use), and
// - A non-global setting is applied.
ui->toggle_speed_limit->setEnabled(Settings::values.use_speed_limit.UsingGlobal());
ui->speed_limit->setEnabled(Settings::values.speed_limit.UsingGlobal());
return;
}
ui->toggle_check_exit->setVisible(false);
ui->toggle_user_on_boot->setVisible(false);
ui->toggle_background_pause->setVisible(false);
ui->toggle_hide_mouse->setVisible(false);
ui->toggle_controller_applet_disabled->setVisible(false);
ui->button_reset_defaults->setVisible(false);
ConfigurationShared::SetColoredTristate(ui->toggle_speed_limit,
Settings::values.use_speed_limit, use_speed_limit);
ConfigurationShared::SetColoredTristate(ui->use_multi_core, Settings::values.use_multi_core,
use_multi_core);
connect(ui->toggle_speed_limit, &QCheckBox::clicked, ui->speed_limit, [this]() {
ui->speed_limit->setEnabled(ui->toggle_speed_limit->isChecked() &&
(use_speed_limit != ConfigurationShared::CheckState::Global));
});
}

View File

@ -5,48 +5,49 @@
#include <functional>
#include <memory>
#include <vector>
#include <QWidget>
#include "yuzu/configuration/configuration_shared.h"
namespace Core {
class System;
}
class ConfigureDialog;
namespace ConfigurationShared {
enum class CheckState;
}
class HotkeyRegistry;
namespace Ui {
class ConfigureGeneral;
}
class ConfigureGeneral : public QWidget {
Q_OBJECT
namespace ConfigurationShared {
class Builder;
}
class ConfigureGeneral : public ConfigurationShared::Tab {
public:
explicit ConfigureGeneral(const Core::System& system_, QWidget* parent = nullptr);
explicit ConfigureGeneral(const Core::System& system_,
std::shared_ptr<std::vector<ConfigurationShared::Tab*>> group,
const ConfigurationShared::Builder& builder,
QWidget* parent = nullptr);
~ConfigureGeneral() override;
void SetResetCallback(std::function<void()> callback);
void ResetDefaults();
void ApplyConfiguration();
void SetConfiguration();
void ApplyConfiguration() override;
void SetConfiguration() override;
private:
void Setup(const ConfigurationShared::Builder& builder);
void changeEvent(QEvent* event) override;
void RetranslateUI();
void SetupPerGameUI();
std::function<void()> reset_callback;
std::unique_ptr<Ui::ConfigureGeneral> ui;
ConfigurationShared::CheckState use_speed_limit;
ConfigurationShared::CheckState use_multi_core;
std::vector<std::function<void(bool)>> apply_funcs{};
const Core::System& system;
};

View File

@ -26,77 +26,22 @@
</property>
<layout class="QHBoxLayout" name="GeneralHorizontalLayout">
<item>
<layout class="QVBoxLayout" name="GeneralVerticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QCheckBox" name="toggle_speed_limit">
<property name="text">
<string>Limit Speed Percent</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="speed_limit">
<property name="suffix">
<string>%</string>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>9999</number>
</property>
<property name="value">
<number>100</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="use_multi_core">
<property name="text">
<string>Multicore CPU Emulation</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="toggle_check_exit">
<property name="text">
<string>Confirm exit while emulation is running</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="toggle_user_on_boot">
<property name="text">
<string>Prompt for user on game boot</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="toggle_background_pause">
<property name="text">
<string>Pause emulation when in background</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="toggle_hide_mouse">
<property name="text">
<string>Hide mouse on inactivity</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="toggle_controller_applet_disabled">
<property name="text">
<string>Disable controller applet</string>
</property>
</widget>
</item>
</layout>
<widget class="QWidget" name="general_widget" native="true">
<layout class="QVBoxLayout" name="GeneralVerticalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
</layout>
</widget>
</item>
</layout>
</widget>

View File

@ -7,6 +7,7 @@
#include <iterator>
#include <string>
#include <tuple>
#include <typeinfo>
#include <utility>
#include <vector>
#include <QBoxLayout>
@ -15,23 +16,29 @@
#include <QComboBox>
#include <QIcon>
#include <QLabel>
#include <QLineEdit>
#include <QPixmap>
#include <QPushButton>
#include <QSlider>
#include <QStringLiteral>
#include <QtCore/qobjectdefs.h>
#include <qabstractbutton.h>
#include <qboxlayout.h>
#include <qcoreevent.h>
#include <qglobal.h>
#include <qgridlayout.h>
#include <vulkan/vulkan_core.h>
#include "common/common_types.h"
#include "common/dynamic_library.h"
#include "common/logging/log.h"
#include "common/settings.h"
#include "common/settings_enums.h"
#include "core/core.h"
#include "ui_configure_graphics.h"
#include "yuzu/configuration/configuration_shared.h"
#include "yuzu/configuration/configure_graphics.h"
#include "yuzu/configuration/shared_widget.h"
#include "yuzu/qt_common.h"
#include "yuzu/uisettings.h"
#include "yuzu/vk_device_info.h"
@ -46,9 +53,9 @@ static constexpr VkPresentModeKHR VSyncSettingToMode(Settings::VSyncMode mode) {
return VK_PRESENT_MODE_IMMEDIATE_KHR;
case Settings::VSyncMode::Mailbox:
return VK_PRESENT_MODE_MAILBOX_KHR;
case Settings::VSyncMode::FIFO:
case Settings::VSyncMode::Fifo:
return VK_PRESENT_MODE_FIFO_KHR;
case Settings::VSyncMode::FIFORelaxed:
case Settings::VSyncMode::FifoRelaxed:
return VK_PRESENT_MODE_FIFO_RELAXED_KHR;
default:
return VK_PRESENT_MODE_FIFO_KHR;
@ -62,50 +69,67 @@ static constexpr Settings::VSyncMode PresentModeToSetting(VkPresentModeKHR mode)
case VK_PRESENT_MODE_MAILBOX_KHR:
return Settings::VSyncMode::Mailbox;
case VK_PRESENT_MODE_FIFO_KHR:
return Settings::VSyncMode::FIFO;
return Settings::VSyncMode::Fifo;
case VK_PRESENT_MODE_FIFO_RELAXED_KHR:
return Settings::VSyncMode::FIFORelaxed;
return Settings::VSyncMode::FifoRelaxed;
default:
return Settings::VSyncMode::FIFO;
return Settings::VSyncMode::Fifo;
}
}
ConfigureGraphics::ConfigureGraphics(const Core::System& system_,
std::vector<VkDeviceInfo::Record>& records_,
const std::function<void()>& expose_compute_option_,
QWidget* parent)
: QWidget(parent), ui{std::make_unique<Ui::ConfigureGraphics>()}, records{records_},
expose_compute_option{expose_compute_option_}, system{system_} {
std::shared_ptr<std::vector<ConfigurationShared::Tab*>> group_,
const ConfigurationShared::Builder& builder, QWidget* parent)
: ConfigurationShared::Tab(group_, parent), ui{std::make_unique<Ui::ConfigureGraphics>()},
records{records_}, expose_compute_option{expose_compute_option_}, system{system_},
combobox_translations{builder.ComboboxTranslations()},
shader_mapping{
combobox_translations.at(Settings::EnumMetadata<Settings::ShaderBackend>::Index())} {
vulkan_device = Settings::values.vulkan_device.GetValue();
RetrieveVulkanDevices();
ui->setupUi(this);
Setup(builder);
for (const auto& device : vulkan_devices) {
ui->device->addItem(device);
vulkan_device_combobox->addItem(device);
}
ui->backend->addItem(QStringLiteral("GLSL"));
ui->backend->addItem(tr("GLASM (Assembly Shaders, NVIDIA Only)"));
ui->backend->addItem(tr("SPIR-V (Experimental, Mesa Only)"));
UpdateBackgroundColorButton(QColor::fromRgb(Settings::values.bg_red.GetValue(),
Settings::values.bg_green.GetValue(),
Settings::values.bg_blue.GetValue()));
UpdateAPILayout();
PopulateVSyncModeSelection(); //< must happen after UpdateAPILayout
SetupPerGameUI();
// VSync setting needs to be determined after populating the VSync combobox
if (Settings::IsConfiguringGlobal()) {
const auto vsync_mode_setting = Settings::values.vsync_mode.GetValue();
const auto vsync_mode = VSyncSettingToMode(vsync_mode_setting);
int index{};
for (const auto mode : vsync_mode_combobox_enum_map) {
if (mode == vsync_mode) {
break;
}
index++;
}
if (static_cast<unsigned long>(index) < vsync_mode_combobox_enum_map.size()) {
vsync_mode_combobox->setCurrentIndex(index);
}
}
SetConfiguration();
connect(ui->api, qOverload<int>(&QComboBox::currentIndexChanged), this, [this] {
connect(api_combobox, qOverload<int>(&QComboBox::activated), this, [this] {
UpdateAPILayout();
PopulateVSyncModeSelection();
if (!Settings::IsConfiguringGlobal()) {
ConfigurationShared::SetHighlight(
ui->api_widget, ui->api->currentIndex() != ConfigurationShared::USE_GLOBAL_INDEX);
}
});
connect(ui->device, qOverload<int>(&QComboBox::activated), this, [this](int device) {
UpdateDeviceSelection(device);
PopulateVSyncModeSelection();
});
connect(ui->backend, qOverload<int>(&QComboBox::activated), this,
connect(vulkan_device_combobox, qOverload<int>(&QComboBox::activated), this,
[this](int device) {
UpdateDeviceSelection(device);
PopulateVSyncModeSelection();
});
connect(shader_backend_combobox, qOverload<int>(&QComboBox::activated), this,
[this](int backend) { UpdateShaderBackendSelection(backend); });
connect(ui->bg_button, &QPushButton::clicked, this, [this] {
@ -116,39 +140,45 @@ ConfigureGraphics::ConfigureGraphics(const Core::System& system_,
UpdateBackgroundColorButton(new_bg_color);
});
ui->api->setEnabled(!UISettings::values.has_broken_vulkan && ui->api->isEnabled());
api_combobox->setEnabled(!UISettings::values.has_broken_vulkan && api_combobox->isEnabled());
ui->api_widget->setEnabled(
(!UISettings::values.has_broken_vulkan || Settings::IsConfiguringGlobal()) &&
ui->api_widget->isEnabled());
ui->bg_label->setVisible(Settings::IsConfiguringGlobal());
ui->bg_combobox->setVisible(!Settings::IsConfiguringGlobal());
connect(ui->fsr_sharpening_slider, &QSlider::valueChanged, this,
&ConfigureGraphics::SetFSRIndicatorText);
ui->fsr_sharpening_combobox->setVisible(!Settings::IsConfiguringGlobal());
ui->fsr_sharpening_label->setVisible(Settings::IsConfiguringGlobal());
if (Settings::IsConfiguringGlobal()) {
ui->bg_widget->setEnabled(Settings::values.bg_red.UsingGlobal());
}
}
void ConfigureGraphics::PopulateVSyncModeSelection() {
const Settings::RendererBackend backend{GetCurrentGraphicsBackend()};
if (backend == Settings::RendererBackend::Null) {
ui->vsync_mode_combobox->setEnabled(false);
if (!Settings::IsConfiguringGlobal()) {
return;
}
ui->vsync_mode_combobox->setEnabled(true);
const Settings::RendererBackend backend{GetCurrentGraphicsBackend()};
if (backend == Settings::RendererBackend::Null) {
vsync_mode_combobox->setEnabled(false);
return;
}
vsync_mode_combobox->setEnabled(true);
const int current_index = //< current selected vsync mode from combobox
ui->vsync_mode_combobox->currentIndex();
vsync_mode_combobox->currentIndex();
const auto current_mode = //< current selected vsync mode as a VkPresentModeKHR
current_index == -1 ? VSyncSettingToMode(Settings::values.vsync_mode.GetValue())
: vsync_mode_combobox_enum_map[current_index];
int index{};
const int device{ui->device->currentIndex()}; //< current selected Vulkan device
const int device{vulkan_device_combobox->currentIndex()}; //< current selected Vulkan device
if (device == -1) {
// Invalid device
return;
}
const auto& present_modes = //< relevant vector of present modes for the selected device or API
backend == Settings::RendererBackend::Vulkan ? device_present_modes[device]
: default_present_modes;
ui->vsync_mode_combobox->clear();
vsync_mode_combobox->clear();
vsync_mode_combobox_enum_map.clear();
vsync_mode_combobox_enum_map.reserve(present_modes.size());
for (const auto present_mode : present_modes) {
@ -157,10 +187,10 @@ void ConfigureGraphics::PopulateVSyncModeSelection() {
continue;
}
ui->vsync_mode_combobox->insertItem(index, mode_name);
vsync_mode_combobox->insertItem(index, mode_name);
vsync_mode_combobox_enum_map.push_back(present_mode);
if (present_mode == current_mode) {
ui->vsync_mode_combobox->setCurrentIndex(index);
vsync_mode_combobox->setCurrentIndex(index);
}
index++;
}
@ -186,112 +216,124 @@ void ConfigureGraphics::UpdateShaderBackendSelection(int backend) {
ConfigureGraphics::~ConfigureGraphics() = default;
void ConfigureGraphics::SetConfiguration() {
const bool runtime_lock = !system.IsPoweredOn();
void ConfigureGraphics::SetConfiguration() {}
ui->api_widget->setEnabled(runtime_lock);
ui->use_asynchronous_gpu_emulation->setEnabled(runtime_lock);
ui->use_disk_shader_cache->setEnabled(runtime_lock);
ui->nvdec_emulation_widget->setEnabled(runtime_lock);
ui->resolution_combobox->setEnabled(runtime_lock);
ui->accelerate_astc->setEnabled(runtime_lock);
ui->vsync_mode_layout->setEnabled(runtime_lock ||
Settings::values.renderer_backend.GetValue() ==
Settings::RendererBackend::Vulkan);
ui->use_disk_shader_cache->setChecked(Settings::values.use_disk_shader_cache.GetValue());
ui->use_asynchronous_gpu_emulation->setChecked(
Settings::values.use_asynchronous_gpu_emulation.GetValue());
ui->accelerate_astc->setChecked(Settings::values.accelerate_astc.GetValue());
void ConfigureGraphics::Setup(const ConfigurationShared::Builder& builder) {
QLayout* api_layout = ui->api_widget->layout();
QWidget* api_grid_widget = new QWidget(this);
QVBoxLayout* api_grid_layout = new QVBoxLayout(api_grid_widget);
api_grid_layout->setContentsMargins(0, 0, 0, 0);
api_layout->addWidget(api_grid_widget);
if (Settings::IsConfiguringGlobal()) {
ui->api->setCurrentIndex(static_cast<int>(Settings::values.renderer_backend.GetValue()));
ui->fullscreen_mode_combobox->setCurrentIndex(
static_cast<int>(Settings::values.fullscreen_mode.GetValue()));
ui->nvdec_emulation->setCurrentIndex(
static_cast<int>(Settings::values.nvdec_emulation.GetValue()));
ui->aspect_ratio_combobox->setCurrentIndex(Settings::values.aspect_ratio.GetValue());
ui->resolution_combobox->setCurrentIndex(
static_cast<int>(Settings::values.resolution_setup.GetValue()));
ui->scaling_filter_combobox->setCurrentIndex(
static_cast<int>(Settings::values.scaling_filter.GetValue()));
ui->fsr_sharpening_slider->setValue(Settings::values.fsr_sharpening_slider.GetValue());
ui->anti_aliasing_combobox->setCurrentIndex(
static_cast<int>(Settings::values.anti_aliasing.GetValue()));
} else {
ConfigurationShared::SetPerGameSetting(ui->api, &Settings::values.renderer_backend);
ConfigurationShared::SetHighlight(ui->api_widget,
!Settings::values.renderer_backend.UsingGlobal());
QLayout& graphics_layout = *ui->graphics_widget->layout();
ConfigurationShared::SetPerGameSetting(ui->nvdec_emulation,
&Settings::values.nvdec_emulation);
ConfigurationShared::SetHighlight(ui->nvdec_emulation_widget,
!Settings::values.nvdec_emulation.UsingGlobal());
std::map<u32, QWidget*> hold_graphics;
std::vector<QWidget*> hold_api;
ConfigurationShared::SetPerGameSetting(ui->fullscreen_mode_combobox,
&Settings::values.fullscreen_mode);
ConfigurationShared::SetHighlight(ui->fullscreen_mode_label,
!Settings::values.fullscreen_mode.UsingGlobal());
ConfigurationShared::SetPerGameSetting(ui->aspect_ratio_combobox,
&Settings::values.aspect_ratio);
ConfigurationShared::SetHighlight(ui->ar_label,
!Settings::values.aspect_ratio.UsingGlobal());
ConfigurationShared::SetPerGameSetting(ui->resolution_combobox,
&Settings::values.resolution_setup);
ConfigurationShared::SetHighlight(ui->resolution_label,
!Settings::values.resolution_setup.UsingGlobal());
ConfigurationShared::SetPerGameSetting(ui->scaling_filter_combobox,
&Settings::values.scaling_filter);
ConfigurationShared::SetHighlight(ui->scaling_filter_label,
!Settings::values.scaling_filter.UsingGlobal());
ConfigurationShared::SetPerGameSetting(ui->anti_aliasing_combobox,
&Settings::values.anti_aliasing);
ConfigurationShared::SetHighlight(ui->anti_aliasing_label,
!Settings::values.anti_aliasing.UsingGlobal());
ui->fsr_sharpening_combobox->setCurrentIndex(
Settings::values.fsr_sharpening_slider.UsingGlobal() ? 0 : 1);
ui->fsr_sharpening_slider->setEnabled(
!Settings::values.fsr_sharpening_slider.UsingGlobal());
ui->fsr_sharpening_value->setEnabled(!Settings::values.fsr_sharpening_slider.UsingGlobal());
ConfigurationShared::SetHighlight(ui->fsr_sharpening_layout,
!Settings::values.fsr_sharpening_slider.UsingGlobal());
ui->fsr_sharpening_slider->setValue(Settings::values.fsr_sharpening_slider.GetValue());
ui->bg_combobox->setCurrentIndex(Settings::values.bg_red.UsingGlobal() ? 0 : 1);
ui->bg_button->setEnabled(!Settings::values.bg_red.UsingGlobal());
ConfigurationShared::SetHighlight(ui->bg_layout, !Settings::values.bg_red.UsingGlobal());
}
UpdateBackgroundColorButton(QColor::fromRgb(Settings::values.bg_red.GetValue(),
Settings::values.bg_green.GetValue(),
Settings::values.bg_blue.GetValue()));
UpdateAPILayout();
PopulateVSyncModeSelection(); //< must happen after UpdateAPILayout
SetFSRIndicatorText(ui->fsr_sharpening_slider->sliderPosition());
// VSync setting needs to be determined after populating the VSync combobox
if (Settings::IsConfiguringGlobal()) {
const auto vsync_mode_setting = Settings::values.vsync_mode.GetValue();
const auto vsync_mode = VSyncSettingToMode(vsync_mode_setting);
int index{};
for (const auto mode : vsync_mode_combobox_enum_map) {
if (mode == vsync_mode) {
break;
for (const auto setting : Settings::values.linkage.by_category[Settings::Category::Renderer]) {
ConfigurationShared::Widget* widget = [&]() {
if (setting->Id() == Settings::values.fsr_sharpening_slider.Id()) {
// FSR needs a reversed slider and a 0.5 multiplier
return builder.BuildWidget(
setting, apply_funcs, ConfigurationShared::RequestType::ReverseSlider, true,
0.5f, nullptr, tr("%", "FSR sharpening percentage (e.g. 50%)"));
} else {
return builder.BuildWidget(setting, apply_funcs);
}
index++;
}();
if (widget == nullptr) {
continue;
}
if (static_cast<unsigned long>(index) < vsync_mode_combobox_enum_map.size()) {
ui->vsync_mode_combobox->setCurrentIndex(index);
if (!widget->Valid()) {
widget->deleteLater();
continue;
}
if (setting->Id() == Settings::values.renderer_backend.Id()) {
// Add the renderer combobox now so it's at the top
api_grid_layout->addWidget(widget);
api_combobox = widget->combobox;
api_restore_global_button = widget->restore_button;
if (!Settings::IsConfiguringGlobal()) {
QObject::connect(api_restore_global_button, &QAbstractButton::clicked,
[this](bool) { UpdateAPILayout(); });
// Detach API's restore button and place it where we want
// Lets us put it on the side, and it will automatically scale if there's a
// second combobox (shader_backend, vulkan_device)
widget->layout()->removeWidget(api_restore_global_button);
api_layout->addWidget(api_restore_global_button);
}
} else if (setting->Id() == Settings::values.vulkan_device.Id()) {
// Keep track of vulkan_device's combobox so we can populate it
hold_api.push_back(widget);
vulkan_device_combobox = widget->combobox;
vulkan_device_widget = widget;
} else if (setting->Id() == Settings::values.shader_backend.Id()) {
// Keep track of shader_backend's combobox so we can populate it
hold_api.push_back(widget);
shader_backend_combobox = widget->combobox;
shader_backend_widget = widget;
} else if (setting->Id() == Settings::values.vsync_mode.Id()) {
// Keep track of vsync_mode's combobox so we can populate it
vsync_mode_combobox = widget->combobox;
hold_graphics.emplace(setting->Id(), widget);
} else {
hold_graphics.emplace(setting->Id(), widget);
}
}
}
void ConfigureGraphics::SetFSRIndicatorText(int percentage) {
ui->fsr_sharpening_value->setText(
tr("%1%", "FSR sharpening percentage (e.g. 50%)").arg(100 - (percentage / 2)));
for (const auto& [id, widget] : hold_graphics) {
graphics_layout.addWidget(widget);
}
for (auto widget : hold_api) {
api_grid_layout->addWidget(widget);
}
// Background color is too specific to build into the new system, so we manage it here
// (3 settings, all collected into a single widget with a QColor to manage on top)
if (Settings::IsConfiguringGlobal()) {
apply_funcs.push_back([this](bool powered_on) {
Settings::values.bg_red.SetValue(static_cast<u8>(bg_color.red()));
Settings::values.bg_green.SetValue(static_cast<u8>(bg_color.green()));
Settings::values.bg_blue.SetValue(static_cast<u8>(bg_color.blue()));
});
} else {
QPushButton* bg_restore_button = ConfigurationShared::Widget::CreateRestoreGlobalButton(
Settings::values.bg_red.UsingGlobal(), ui->bg_widget);
ui->bg_widget->layout()->addWidget(bg_restore_button);
QObject::connect(bg_restore_button, &QAbstractButton::clicked,
[bg_restore_button, this](bool) {
const int r = Settings::values.bg_red.GetValue(true);
const int g = Settings::values.bg_green.GetValue(true);
const int b = Settings::values.bg_blue.GetValue(true);
UpdateBackgroundColorButton(QColor::fromRgb(r, g, b));
bg_restore_button->setVisible(false);
bg_restore_button->setEnabled(false);
});
QObject::connect(ui->bg_button, &QAbstractButton::clicked, [bg_restore_button](bool) {
bg_restore_button->setVisible(true);
bg_restore_button->setEnabled(true);
});
apply_funcs.push_back([bg_restore_button, this](bool powered_on) {
const bool using_global = !bg_restore_button->isEnabled();
Settings::values.bg_red.SetGlobal(using_global);
Settings::values.bg_green.SetGlobal(using_global);
Settings::values.bg_blue.SetGlobal(using_global);
if (!using_global) {
Settings::values.bg_red.SetValue(static_cast<u8>(bg_color.red()));
Settings::values.bg_green.SetValue(static_cast<u8>(bg_color.green()));
Settings::values.bg_blue.SetValue(static_cast<u8>(bg_color.blue()));
}
});
}
}
const QString ConfigureGraphics::TranslateVSyncMode(VkPresentModeKHR mode,
@ -315,130 +357,48 @@ const QString ConfigureGraphics::TranslateVSyncMode(VkPresentModeKHR mode,
}
}
int ConfigureGraphics::FindIndex(u32 enumeration, int value) const {
for (u32 i = 0; i < combobox_translations.at(enumeration).size(); i++) {
if (combobox_translations.at(enumeration)[i].first == static_cast<u32>(value)) {
return i;
}
}
return -1;
}
void ConfigureGraphics::ApplyConfiguration() {
const auto resolution_setup = static_cast<Settings::ResolutionSetup>(
ui->resolution_combobox->currentIndex() -
((Settings::IsConfiguringGlobal()) ? 0 : ConfigurationShared::USE_GLOBAL_OFFSET));
const auto scaling_filter = static_cast<Settings::ScalingFilter>(
ui->scaling_filter_combobox->currentIndex() -
((Settings::IsConfiguringGlobal()) ? 0 : ConfigurationShared::USE_GLOBAL_OFFSET));
const auto anti_aliasing = static_cast<Settings::AntiAliasing>(
ui->anti_aliasing_combobox->currentIndex() -
((Settings::IsConfiguringGlobal()) ? 0 : ConfigurationShared::USE_GLOBAL_OFFSET));
ConfigurationShared::ApplyPerGameSetting(&Settings::values.fullscreen_mode,
ui->fullscreen_mode_combobox);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.aspect_ratio,
ui->aspect_ratio_combobox);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_disk_shader_cache,
ui->use_disk_shader_cache, use_disk_shader_cache);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_asynchronous_gpu_emulation,
ui->use_asynchronous_gpu_emulation,
use_asynchronous_gpu_emulation);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.accelerate_astc, ui->accelerate_astc,
accelerate_astc);
const bool powered_on = system.IsPoweredOn();
for (const auto& func : apply_funcs) {
func(powered_on);
}
if (Settings::IsConfiguringGlobal()) {
// Guard if during game and set to game-specific value
if (Settings::values.renderer_backend.UsingGlobal()) {
Settings::values.renderer_backend.SetValue(GetCurrentGraphicsBackend());
}
if (Settings::values.nvdec_emulation.UsingGlobal()) {
Settings::values.nvdec_emulation.SetValue(GetCurrentNvdecEmulation());
}
if (Settings::values.shader_backend.UsingGlobal()) {
Settings::values.shader_backend.SetValue(shader_backend);
}
if (Settings::values.vulkan_device.UsingGlobal()) {
Settings::values.vulkan_device.SetValue(vulkan_device);
}
if (Settings::values.bg_red.UsingGlobal()) {
Settings::values.bg_red.SetValue(static_cast<u8>(bg_color.red()));
Settings::values.bg_green.SetValue(static_cast<u8>(bg_color.green()));
Settings::values.bg_blue.SetValue(static_cast<u8>(bg_color.blue()));
}
if (Settings::values.resolution_setup.UsingGlobal()) {
Settings::values.resolution_setup.SetValue(resolution_setup);
}
if (Settings::values.scaling_filter.UsingGlobal()) {
Settings::values.scaling_filter.SetValue(scaling_filter);
}
if (Settings::values.anti_aliasing.UsingGlobal()) {
Settings::values.anti_aliasing.SetValue(anti_aliasing);
}
Settings::values.fsr_sharpening_slider.SetValue(ui->fsr_sharpening_slider->value());
const auto mode = vsync_mode_combobox_enum_map[ui->vsync_mode_combobox->currentIndex()];
const auto mode = vsync_mode_combobox_enum_map[vsync_mode_combobox->currentIndex()];
const auto vsync_mode = PresentModeToSetting(mode);
Settings::values.vsync_mode.SetValue(vsync_mode);
} else {
if (ui->resolution_combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
Settings::values.resolution_setup.SetGlobal(true);
} else {
Settings::values.resolution_setup.SetGlobal(false);
Settings::values.resolution_setup.SetValue(resolution_setup);
}
if (ui->scaling_filter_combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
Settings::values.scaling_filter.SetGlobal(true);
} else {
Settings::values.scaling_filter.SetGlobal(false);
Settings::values.scaling_filter.SetValue(scaling_filter);
}
if (ui->anti_aliasing_combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
Settings::values.anti_aliasing.SetGlobal(true);
} else {
Settings::values.anti_aliasing.SetGlobal(false);
Settings::values.anti_aliasing.SetValue(anti_aliasing);
}
if (ui->api->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
Settings::values.renderer_backend.SetGlobal(true);
Settings::values.shader_backend.SetGlobal(true);
Settings::values.vulkan_device.SetGlobal(true);
} else {
Settings::values.renderer_backend.SetGlobal(false);
Settings::values.renderer_backend.SetValue(GetCurrentGraphicsBackend());
switch (GetCurrentGraphicsBackend()) {
case Settings::RendererBackend::OpenGL:
case Settings::RendererBackend::Null:
Settings::values.shader_backend.SetGlobal(false);
Settings::values.vulkan_device.SetGlobal(true);
Settings::values.shader_backend.SetValue(shader_backend);
break;
case Settings::RendererBackend::Vulkan:
Settings::values.shader_backend.SetGlobal(true);
Settings::values.vulkan_device.SetGlobal(false);
Settings::values.vulkan_device.SetValue(vulkan_device);
break;
}
}
}
if (ui->nvdec_emulation->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
Settings::values.nvdec_emulation.SetGlobal(true);
} else {
Settings::values.nvdec_emulation.SetGlobal(false);
Settings::values.nvdec_emulation.SetValue(GetCurrentNvdecEmulation());
}
if (ui->bg_combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
Settings::values.bg_red.SetGlobal(true);
Settings::values.bg_green.SetGlobal(true);
Settings::values.bg_blue.SetGlobal(true);
} else {
Settings::values.bg_red.SetGlobal(false);
Settings::values.bg_green.SetGlobal(false);
Settings::values.bg_blue.SetGlobal(false);
Settings::values.bg_red.SetValue(static_cast<u8>(bg_color.red()));
Settings::values.bg_green.SetValue(static_cast<u8>(bg_color.green()));
Settings::values.bg_blue.SetValue(static_cast<u8>(bg_color.blue()));
}
if (ui->fsr_sharpening_combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
Settings::values.fsr_sharpening_slider.SetGlobal(true);
} else {
Settings::values.fsr_sharpening_slider.SetGlobal(false);
Settings::values.fsr_sharpening_slider.SetValue(ui->fsr_sharpening_slider->value());
Settings::values.vulkan_device.SetGlobal(true);
Settings::values.shader_backend.SetGlobal(true);
if (Settings::IsConfiguringGlobal() ||
(!Settings::IsConfiguringGlobal() && api_restore_global_button->isEnabled())) {
auto backend = static_cast<Settings::RendererBackend>(
combobox_translations
.at(Settings::EnumMetadata<
Settings::RendererBackend>::Index())[api_combobox->currentIndex()]
.first);
switch (backend) {
case Settings::RendererBackend::OpenGL:
Settings::values.shader_backend.SetGlobal(Settings::IsConfiguringGlobal());
Settings::values.shader_backend.SetValue(static_cast<Settings::ShaderBackend>(
shader_mapping[shader_backend_combobox->currentIndex()].first));
break;
case Settings::RendererBackend::Vulkan:
Settings::values.vulkan_device.SetGlobal(Settings::IsConfiguringGlobal());
Settings::values.vulkan_device.SetValue(vulkan_device_combobox->currentIndex());
break;
case Settings::RendererBackend::Null:
break;
}
}
}
@ -466,36 +426,26 @@ void ConfigureGraphics::UpdateBackgroundColorButton(QColor color) {
}
void ConfigureGraphics::UpdateAPILayout() {
if (!Settings::IsConfiguringGlobal() &&
ui->api->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
vulkan_device = Settings::values.vulkan_device.GetValue(true);
shader_backend = Settings::values.shader_backend.GetValue(true);
ui->device_widget->setEnabled(false);
ui->backend_widget->setEnabled(false);
} else {
vulkan_device = Settings::values.vulkan_device.GetValue();
shader_backend = Settings::values.shader_backend.GetValue();
ui->device_widget->setEnabled(true);
ui->backend_widget->setEnabled(true);
}
bool runtime_lock = !system.IsPoweredOn();
bool need_global = !(Settings::IsConfiguringGlobal() || api_restore_global_button->isEnabled());
vulkan_device = Settings::values.vulkan_device.GetValue(need_global);
shader_backend = Settings::values.shader_backend.GetValue(need_global);
vulkan_device_widget->setEnabled(!need_global && runtime_lock);
shader_backend_widget->setEnabled(!need_global && runtime_lock);
switch (GetCurrentGraphicsBackend()) {
case Settings::RendererBackend::OpenGL:
ui->backend->setCurrentIndex(static_cast<u32>(shader_backend));
ui->device_widget->setVisible(false);
ui->backend_widget->setVisible(true);
break;
case Settings::RendererBackend::Vulkan:
if (static_cast<int>(vulkan_device) < ui->device->count()) {
ui->device->setCurrentIndex(vulkan_device);
}
ui->device_widget->setVisible(true);
ui->backend_widget->setVisible(false);
break;
case Settings::RendererBackend::Null:
ui->device_widget->setVisible(false);
ui->backend_widget->setVisible(false);
break;
const auto current_backend = GetCurrentGraphicsBackend();
const bool is_opengl = current_backend == Settings::RendererBackend::OpenGL;
const bool is_vulkan = current_backend == Settings::RendererBackend::Vulkan;
vulkan_device_widget->setVisible(is_vulkan);
shader_backend_widget->setVisible(is_opengl);
if (is_opengl) {
shader_backend_combobox->setCurrentIndex(
FindIndex(Settings::EnumMetadata<Settings::ShaderBackend>::Index(),
static_cast<int>(shader_backend)));
} else if (is_vulkan && static_cast<int>(vulkan_device) < vulkan_device_combobox->count()) {
vulkan_device_combobox->setCurrentIndex(vulkan_device);
}
}
@ -515,92 +465,11 @@ void ConfigureGraphics::RetrieveVulkanDevices() {
}
Settings::RendererBackend ConfigureGraphics::GetCurrentGraphicsBackend() const {
if (Settings::IsConfiguringGlobal()) {
return static_cast<Settings::RendererBackend>(ui->api->currentIndex());
if (!Settings::IsConfiguringGlobal() && !api_restore_global_button->isEnabled()) {
return Settings::values.renderer_backend.GetValue(true);
}
if (ui->api->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
Settings::values.renderer_backend.SetGlobal(true);
return Settings::values.renderer_backend.GetValue();
}
Settings::values.renderer_backend.SetGlobal(false);
return static_cast<Settings::RendererBackend>(ui->api->currentIndex() -
ConfigurationShared::USE_GLOBAL_OFFSET);
}
Settings::NvdecEmulation ConfigureGraphics::GetCurrentNvdecEmulation() const {
if (Settings::IsConfiguringGlobal()) {
return static_cast<Settings::NvdecEmulation>(ui->nvdec_emulation->currentIndex());
}
if (ui->nvdec_emulation->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
Settings::values.nvdec_emulation.SetGlobal(true);
return Settings::values.nvdec_emulation.GetValue();
}
Settings::values.nvdec_emulation.SetGlobal(false);
return static_cast<Settings::NvdecEmulation>(ui->nvdec_emulation->currentIndex() -
ConfigurationShared::USE_GLOBAL_OFFSET);
}
void ConfigureGraphics::SetupPerGameUI() {
if (Settings::IsConfiguringGlobal()) {
ui->api->setEnabled(Settings::values.renderer_backend.UsingGlobal());
ui->device->setEnabled(Settings::values.renderer_backend.UsingGlobal());
ui->fullscreen_mode_combobox->setEnabled(Settings::values.fullscreen_mode.UsingGlobal());
ui->aspect_ratio_combobox->setEnabled(Settings::values.aspect_ratio.UsingGlobal());
ui->resolution_combobox->setEnabled(Settings::values.resolution_setup.UsingGlobal());
ui->scaling_filter_combobox->setEnabled(Settings::values.scaling_filter.UsingGlobal());
ui->fsr_sharpening_slider->setEnabled(Settings::values.fsr_sharpening_slider.UsingGlobal());
ui->anti_aliasing_combobox->setEnabled(Settings::values.anti_aliasing.UsingGlobal());
ui->use_asynchronous_gpu_emulation->setEnabled(
Settings::values.use_asynchronous_gpu_emulation.UsingGlobal());
ui->nvdec_emulation->setEnabled(Settings::values.nvdec_emulation.UsingGlobal());
ui->accelerate_astc->setEnabled(Settings::values.accelerate_astc.UsingGlobal());
ui->use_disk_shader_cache->setEnabled(Settings::values.use_disk_shader_cache.UsingGlobal());
ui->bg_button->setEnabled(Settings::values.bg_red.UsingGlobal());
ui->fsr_slider_layout->setEnabled(Settings::values.fsr_sharpening_slider.UsingGlobal());
return;
}
connect(ui->bg_combobox, qOverload<int>(&QComboBox::activated), this, [this](int index) {
ui->bg_button->setEnabled(index == 1);
ConfigurationShared::SetHighlight(ui->bg_layout, index == 1);
});
connect(ui->fsr_sharpening_combobox, qOverload<int>(&QComboBox::activated), this,
[this](int index) {
ui->fsr_sharpening_slider->setEnabled(index == 1);
ui->fsr_sharpening_value->setEnabled(index == 1);
ConfigurationShared::SetHighlight(ui->fsr_sharpening_layout, index == 1);
});
ConfigurationShared::SetColoredTristate(
ui->use_disk_shader_cache, Settings::values.use_disk_shader_cache, use_disk_shader_cache);
ConfigurationShared::SetColoredTristate(ui->accelerate_astc, Settings::values.accelerate_astc,
accelerate_astc);
ConfigurationShared::SetColoredTristate(ui->use_asynchronous_gpu_emulation,
Settings::values.use_asynchronous_gpu_emulation,
use_asynchronous_gpu_emulation);
ConfigurationShared::SetColoredComboBox(ui->aspect_ratio_combobox, ui->ar_label,
Settings::values.aspect_ratio.GetValue(true));
ConfigurationShared::SetColoredComboBox(
ui->fullscreen_mode_combobox, ui->fullscreen_mode_label,
static_cast<int>(Settings::values.fullscreen_mode.GetValue(true)));
ConfigurationShared::SetColoredComboBox(
ui->resolution_combobox, ui->resolution_label,
static_cast<int>(Settings::values.resolution_setup.GetValue(true)));
ConfigurationShared::SetColoredComboBox(
ui->scaling_filter_combobox, ui->scaling_filter_label,
static_cast<int>(Settings::values.scaling_filter.GetValue(true)));
ConfigurationShared::SetColoredComboBox(
ui->anti_aliasing_combobox, ui->anti_aliasing_label,
static_cast<int>(Settings::values.anti_aliasing.GetValue(true)));
ConfigurationShared::InsertGlobalItem(
ui->api, static_cast<int>(Settings::values.renderer_backend.GetValue(true)));
ConfigurationShared::InsertGlobalItem(
ui->nvdec_emulation, static_cast<int>(Settings::values.nvdec_emulation.GetValue(true)));
ui->vsync_mode_layout->setVisible(false);
return static_cast<Settings::RendererBackend>(
combobox_translations.at(Settings::EnumMetadata<Settings::RendererBackend>::Index())
.at(api_combobox->currentIndex())
.first);
}

View File

@ -5,6 +5,8 @@
#include <functional>
#include <memory>
#include <type_traits>
#include <typeindex>
#include <vector>
#include <QColor>
#include <QString>
@ -12,10 +14,14 @@
#include <qobjectdefs.h>
#include <vulkan/vulkan_core.h>
#include "common/common_types.h"
#include "configuration/shared_translation.h"
#include "vk_device_info.h"
#include "yuzu/configuration/configuration_shared.h"
class QPushButton;
class QEvent;
class QObject;
class QComboBox;
namespace Settings {
enum class NvdecEmulation : u32;
@ -27,31 +33,33 @@ namespace Core {
class System;
}
namespace ConfigurationShared {
enum class CheckState;
}
namespace Ui {
class ConfigureGraphics;
}
class ConfigureGraphics : public QWidget {
Q_OBJECT
namespace ConfigurationShared {
class Builder;
}
class ConfigureGraphics : public ConfigurationShared::Tab {
public:
explicit ConfigureGraphics(const Core::System& system_,
std::vector<VkDeviceInfo::Record>& records,
const std::function<void()>& expose_compute_option_,
std::shared_ptr<std::vector<ConfigurationShared::Tab*>> group,
const ConfigurationShared::Builder& builder,
QWidget* parent = nullptr);
~ConfigureGraphics() override;
void ApplyConfiguration();
void SetConfiguration();
void ApplyConfiguration() override;
void SetConfiguration() override;
private:
void changeEvent(QEvent* event) override;
void RetranslateUI();
void Setup(const ConfigurationShared::Builder& builder);
void PopulateVSyncModeSelection();
void UpdateBackgroundColorButton(QColor color);
void UpdateAPILayout();
@ -60,34 +68,40 @@ private:
void RetrieveVulkanDevices();
void SetFSRIndicatorText(int percentage);
/* Turns a Vulkan present mode into a textual string for a UI
* (and eventually for a human to read) */
const QString TranslateVSyncMode(VkPresentModeKHR mode,
Settings::RendererBackend backend) const;
void SetupPerGameUI();
Settings::RendererBackend GetCurrentGraphicsBackend() const;
Settings::NvdecEmulation GetCurrentNvdecEmulation() const;
int FindIndex(u32 enumeration, int value) const;
std::unique_ptr<Ui::ConfigureGraphics> ui;
QColor bg_color;
ConfigurationShared::CheckState use_nvdec_emulation;
ConfigurationShared::CheckState accelerate_astc;
ConfigurationShared::CheckState use_disk_shader_cache;
ConfigurationShared::CheckState use_asynchronous_gpu_emulation;
std::vector<std::function<void(bool)>> apply_funcs{};
std::vector<VkDeviceInfo::Record>& records;
std::vector<QString> vulkan_devices;
std::vector<std::vector<VkPresentModeKHR>> device_present_modes;
std::vector<VkPresentModeKHR>
vsync_mode_combobox_enum_map; //< Keeps track of which present mode corresponds to which
// selection in the combobox
vsync_mode_combobox_enum_map{}; //< Keeps track of which present mode corresponds to which
// selection in the combobox
u32 vulkan_device{};
Settings::ShaderBackend shader_backend{};
const std::function<void()>& expose_compute_option;
const Core::System& system;
const ConfigurationShared::ComboboxTranslationMap& combobox_translations;
const std::vector<std::pair<u32, QString>>& shader_mapping;
QPushButton* api_restore_global_button;
QComboBox* vulkan_device_combobox;
QComboBox* api_combobox;
QComboBox* shader_backend_combobox;
QComboBox* vsync_mode_combobox;
QWidget* vulkan_device_widget;
QWidget* api_widget;
QWidget* shader_backend_widget;
};

View File

@ -27,7 +27,7 @@
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QWidget" name="api_widget" native="true">
<layout class="QGridLayout" name="gridLayout">
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="leftMargin">
<number>0</number>
</property>
@ -40,115 +40,6 @@
<property name="bottomMargin">
<number>0</number>
</property>
<property name="horizontalSpacing">
<number>6</number>
</property>
<item row="4" column="0">
<widget class="QWidget" name="backend_widget" native="true">
<layout class="QHBoxLayout" name="backend_layout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="backend_label">
<property name="text">
<string>Shader Backend:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="backend"/>
</item>
</layout>
</widget>
</item>
<item row="2" column="0">
<widget class="QWidget" name="device_widget" native="true">
<layout class="QHBoxLayout" name="device_layout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="device_label">
<property name="text">
<string>Device:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="device"/>
</item>
</layout>
</widget>
</item>
<item row="0" column="0">
<widget class="QWidget" name="api_layout_2" native="true">
<layout class="QHBoxLayout" name="api_layout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="api_label">
<property name="text">
<string>API:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="api">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<item>
<property name="text">
<string notr="true">OpenGL</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">Vulkan</string>
</property>
</item>
<item>
<property name="text">
<string>None</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
@ -168,29 +59,8 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QCheckBox" name="use_disk_shader_cache">
<property name="text">
<string>Use disk pipeline cache</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="use_asynchronous_gpu_emulation">
<property name="text">
<string>Use asynchronous GPU emulation</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="accelerate_astc">
<property name="text">
<string>Accelerate ASTC texture decoding</string>
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="vsync_mode_layout" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<widget class="QWidget" name="graphics_widget" native="true">
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>0</number>
</property>
@ -203,32 +73,12 @@
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="vsync_mode_label">
<property name="text">
<string>VSync Mode:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="vsync_mode_combobox">
<property name="toolTip">
<string>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.</string>
</property>
<property name="currentText">
<string/>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="nvdec_emulation_widget" native="true">
<layout class="QHBoxLayout" name="nvdec_emulation_layout">
<widget class="QWidget" name="bg_widget" native="true">
<layout class="QHBoxLayout" name="bg_layout">
<property name="leftMargin">
<number>0</number>
</property>
@ -242,535 +92,35 @@ Immediate (no synchronization) just presents whatever is available and can exhib
<number>0</number>
</property>
<item>
<widget class="QLabel" name="nvdec_emulation_label">
<property name="text">
<string>NVDEC emulation:</string>
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="nvdec_emulation">
<item>
<property name="text">
<string>No Video Output</string>
</property>
</item>
<item>
<property name="text">
<string>CPU Video Decoding</string>
</property>
</item>
<item>
<property name="text">
<string>GPU Video Decoding (Default)</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="fullscreen_mode_layout" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_1">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="fullscreen_mode_label">
<property name="text">
<string>Fullscreen Mode:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="fullscreen_mode_combobox">
<item>
<property name="text">
<string>Borderless Windowed</string>
</property>
</item>
<item>
<property name="text">
<string>Exclusive Fullscreen</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="aspect_ratio_layout" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="ar_label">
<property name="text">
<string>Aspect Ratio:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="aspect_ratio_combobox">
<item>
<property name="text">
<string>Default (16:9)</string>
</property>
</item>
<item>
<property name="text">
<string>Force 4:3</string>
</property>
</item>
<item>
<property name="text">
<string>Force 21:9</string>
</property>
</item>
<item>
<property name="text">
<string>Force 16:10</string>
</property>
</item>
<item>
<property name="text">
<string>Stretch to Window</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="resolution_layout" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_5">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="resolution_label">
<property name="text">
<string>Resolution:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="resolution_combobox">
<item>
<property name="text">
<string>0.5X (360p/540p) [EXPERIMENTAL]</string>
</property>
</item>
<item>
<property name="text">
<string>0.75X (540p/810p) [EXPERIMENTAL]</string>
</property>
</item>
<item>
<property name="text">
<string>1X (720p/1080p)</string>
</property>
</item>
<item>
<property name="text">
<string>1.5X (1080p/1620p) [EXPERIMENTAL]</string>
</property>
</item>
<item>
<property name="text">
<string>2X (1440p/2160p)</string>
</property>
</item>
<item>
<property name="text">
<string>3X (2160p/3240p)</string>
</property>
</item>
<item>
<property name="text">
<string>4X (2880p/4320p)</string>
</property>
</item>
<item>
<property name="text">
<string>5X (3600p/5400p)</string>
</property>
</item>
<item>
<property name="text">
<string>6X (4320p/6480p)</string>
</property>
</item>
<item>
<property name="text">
<string>7X (5040p/7560p)</string>
</property>
</item>
<item>
<property name="text">
<string>8X (5760p/8640p)</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="scaling_filter_layout" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_6">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="scaling_filter_label">
<property name="text">
<string>Window Adapting Filter:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="scaling_filter_combobox">
<item>
<property name="text">
<string>Nearest Neighbor</string>
</property>
</item>
<item>
<property name="text">
<string>Bilinear</string>
</property>
</item>
<item>
<property name="text">
<string>Bicubic</string>
</property>
</item>
<item>
<property name="text">
<string>Gaussian</string>
</property>
</item>
<item>
<property name="text">
<string>ScaleForce</string>
</property>
</item>
<item>
<property name="text">
<string>AMD FidelityFX™ Super Resolution</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="anti_aliasing_layout" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_7">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="anti_aliasing_label">
<property name="text">
<string>Anti-Aliasing Method:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="anti_aliasing_combobox">
<item>
<property name="text">
<string>None</string>
</property>
</item>
<item>
<property name="text">
<string>FXAA</string>
</property>
</item>
<item>
<property name="text">
<string>SMAA</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="fsr_sharpening_layout" native="true">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<layout class="QHBoxLayout" name="fsr_sharpening_label_group">
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QComboBox" name="fsr_sharpening_combobox">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<item>
<property name="text">
<string>Use global FSR Sharpness</string>
</property>
</item>
<item>
<property name="text">
<string>Set FSR Sharpness</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QLabel" name="fsr_sharpening_label">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>FSR Sharpness:</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="fsr_slider_layout">
<property name="spacing">
<number>6</number>
</property>
<item>
<widget class="QSlider" name="fsr_sharpening_slider">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="baseSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="maximum">
<number>200</number>
</property>
<property name="sliderPosition">
<number>25</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="invertedAppearance">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="fsr_sharpening_value">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>32</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>100%</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="bg_layout" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QComboBox" name="bg_combobox">
<property name="currentText">
<string>Use global background color</string>
</property>
<property name="currentIndex">
<number>0</number>
</property>
<property name="maxVisibleItems">
<number>10</number>
</property>
<item>
<property name="text">
<string>Use global background color</string>
</property>
</item>
<item>
<property name="text">
<string>Set background color:</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QLabel" name="bg_label">
<property name="text">
<string>Background Color:</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="bg_button">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>40</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>

View File

@ -1,104 +1,68 @@
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <vector>
#include <QLabel>
#include <qnamespace.h>
#include "common/settings.h"
#include "core/core.h"
#include "ui_configure_graphics_advanced.h"
#include "yuzu/configuration/configuration_shared.h"
#include "yuzu/configuration/configure_graphics_advanced.h"
#include "yuzu/configuration/shared_translation.h"
#include "yuzu/configuration/shared_widget.h"
ConfigureGraphicsAdvanced::ConfigureGraphicsAdvanced(const Core::System& system_, QWidget* parent)
: QWidget(parent), ui{std::make_unique<Ui::ConfigureGraphicsAdvanced>()}, system{system_} {
ConfigureGraphicsAdvanced::ConfigureGraphicsAdvanced(
const Core::System& system_, std::shared_ptr<std::vector<ConfigurationShared::Tab*>> group_,
const ConfigurationShared::Builder& builder, QWidget* parent)
: Tab(group_, parent), ui{std::make_unique<Ui::ConfigureGraphicsAdvanced>()}, system{system_} {
ui->setupUi(this);
SetupPerGameUI();
Setup(builder);
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->async_astc->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);
void ConfigureGraphicsAdvanced::SetConfiguration() {}
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->async_astc->setChecked(Settings::values.async_astc.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());
void ConfigureGraphicsAdvanced::Setup(const ConfigurationShared::Builder& builder) {
auto& layout = *ui->populate_target->layout();
std::map<u32, QWidget*> hold{}; // A map will sort the data for us
if (Settings::IsConfiguringGlobal()) {
ui->gpu_accuracy->setCurrentIndex(
static_cast<int>(Settings::values.gpu_accuracy.GetValue()));
ui->anisotropic_filtering_combobox->setCurrentIndex(
Settings::values.max_anisotropy.GetValue());
ui->astc_recompression_combobox->setCurrentIndex(
static_cast<int>(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());
for (auto setting :
Settings::values.linkage.by_category[Settings::Category::RendererAdvanced]) {
ConfigurationShared::Widget* widget = builder.BuildWidget(setting, apply_funcs);
if (widget == nullptr) {
continue;
}
if (!widget->Valid()) {
widget->deleteLater();
continue;
}
hold.emplace(setting->Id(), widget);
// Keep track of enable_compute_pipelines so we can display it when needed
if (setting->Id() == Settings::values.enable_compute_pipelines.Id()) {
checkbox_enable_compute_pipelines = widget;
}
}
for (const auto& [id, 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.async_astc, ui->async_astc,
async_astc);
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) {
@ -113,71 +77,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->async_astc->setEnabled(Settings::values.async_astc.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->async_astc, Settings::values.async_astc,
async_astc);
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<int>(Settings::values.gpu_accuracy.GetValue(true)));
ConfigurationShared::SetColoredComboBox(
ui->anisotropic_filtering_combobox, ui->af_label,
static_cast<int>(Settings::values.max_anisotropy.GetValue(true)));
ConfigurationShared::SetColoredComboBox(
ui->astc_recompression_combobox, ui->label_astc_recompression,
static_cast<int>(Settings::values.astc_recompression.GetValue(true)));
}
void ConfigureGraphicsAdvanced::ExposeComputeOption() {
ui->enable_compute_pipelines_checkbox->setVisible(true);
checkbox_enable_compute_pipelines->setVisible(true);
}

View File

@ -4,51 +4,44 @@
#pragma once
#include <memory>
#include <vector>
#include <QWidget>
#include "yuzu/configuration/configuration_shared.h"
namespace Core {
class System;
}
namespace ConfigurationShared {
enum class CheckState;
}
namespace Ui {
class ConfigureGraphicsAdvanced;
}
class ConfigureGraphicsAdvanced : public QWidget {
Q_OBJECT
namespace ConfigurationShared {
class Builder;
}
class ConfigureGraphicsAdvanced : public ConfigurationShared::Tab {
public:
explicit ConfigureGraphicsAdvanced(const Core::System& system_, QWidget* parent = nullptr);
explicit ConfigureGraphicsAdvanced(
const Core::System& system_, std::shared_ptr<std::vector<ConfigurationShared::Tab*>> group,
const ConfigurationShared::Builder& builder, QWidget* parent = nullptr);
~ConfigureGraphicsAdvanced() override;
void ApplyConfiguration();
void SetConfiguration();
void ApplyConfiguration() override;
void SetConfiguration() override;
void ExposeComputeOption();
private:
void Setup(const ConfigurationShared::Builder& builder);
void changeEvent(QEvent* event) override;
void RetranslateUI();
void SetupPerGameUI();
std::unique_ptr<Ui::ConfigureGraphicsAdvanced> 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;
const Core::System& system;
std::vector<std::function<void(bool)>> apply_funcs;
QWidget* checkbox_enable_compute_pipelines{};
};

View File

@ -26,8 +26,8 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QWidget" name="gpu_accuracy_layout" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<widget class="QWidget" name="populate_target" native="true">
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>0</number>
</property>
@ -40,233 +40,6 @@
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_gpu_accuracy">
<property name="text">
<string>Accuracy Level:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="gpu_accuracy">
<item>
<property name="text">
<string notr="true">Normal</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">High</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">Extreme(very slow)</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="astc_recompression_layout" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_astc_recompression">
<property name="text">
<string>ASTC recompression:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="astc_recompression_combobox">
<item>
<property name="text">
<string>Uncompressed (Best quality)</string>
</property>
</item>
<item>
<property name="text">
<string>BC1 (Low quality)</string>
</property>
</item>
<item>
<property name="text">
<string>BC3 (Medium quality)</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QCheckBox" name="async_present">
<property name="text">
<string>Enable asynchronous presentation (Vulkan only)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="renderer_force_max_clock">
<property name="toolTip">
<string>Runs work in the background while waiting for graphics commands to keep the GPU from lowering its clock speed.</string>
</property>
<property name="text">
<string>Force maximum clocks (Vulkan only)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="async_astc">
<property name="toolTip">
<string>Enables asynchronous ASTC texture decoding, which may reduce load time stutter. This feature is experimental.</string>
</property>
<property name="text">
<string>Decode ASTC textures asynchronously (Hack)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="use_reactive_flushing">
<property name="toolTip">
<string>Uses reactive flushing instead of predictive flushing. Allowing a more accurate syncing of memory.</string>
</property>
<property name="text">
<string>Enable Reactive Flushing</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="use_asynchronous_shaders">
<property name="toolTip">
<string>Enables asynchronous shader compilation, which may reduce shader stutter. This feature is experimental.</string>
</property>
<property name="text">
<string>Use asynchronous shader building (Hack)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="use_fast_gpu_time">
<property name="toolTip">
<string>Enables Fast GPU Time. This option will force most games to run at their highest native resolution.</string>
</property>
<property name="text">
<string>Use Fast GPU Time (Hack)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="use_vulkan_driver_pipeline_cache">
<property name="toolTip">
<string>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.</string>
</property>
<property name="text">
<string>Use Vulkan pipeline cache</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="enable_compute_pipelines_checkbox">
<property name="toolTip">
<string>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.</string>
</property>
<property name="text">
<string>Enable Compute Pipelines (Intel Vulkan only)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="use_video_framerate_checkbox">
<property name="toolTip">
<string>Run the game at normal speed during video playback, even when the framerate is unlocked.</string>
</property>
<property name="text">
<string>Sync to framerate of video playback</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="barrier_feedback_loops_checkbox">
<property name="toolTip">
<string>Improves rendering of transparency effects in specific games.</string>
</property>
<property name="text">
<string>Barrier feedback loops</string>
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="af_layout" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_1">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="af_label">
<property name="text">
<string>Anisotropic Filtering:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="anisotropic_filtering_combobox">
<item>
<property name="text">
<string>Automatic</string>
</property>
</item>
<item>
<property name="text">
<string>Default</string>
</property>
</item>
<item>
<property name="text">
<string>2x</string>
</property>
</item>
<item>
<property name="text">
<string>4x</string>
</property>
</item>
<item>
<property name="text">
<string>8x</string>
</property>
</item>
<item>
<property name="text">
<string>16x</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>

View File

@ -17,6 +17,7 @@
#include <QTimer>
#include "common/fs/fs_util.h"
#include "configuration/shared_widget.h"
#include "core/core.h"
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/patch_manager.h"
@ -24,9 +25,9 @@
#include "core/loader/loader.h"
#include "ui_configure_per_game.h"
#include "yuzu/configuration/config.h"
#include "yuzu/configuration/configuration_shared.h"
#include "yuzu/configuration/configure_audio.h"
#include "yuzu/configuration/configure_cpu.h"
#include "yuzu/configuration/configure_general.h"
#include "yuzu/configuration/configure_graphics.h"
#include "yuzu/configuration/configure_graphics_advanced.h"
#include "yuzu/configuration/configure_input_per_game.h"
@ -41,26 +42,28 @@ ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id_, const std::st
std::vector<VkDeviceInfo::Record>& vk_device_records,
Core::System& system_)
: QDialog(parent),
ui(std::make_unique<Ui::ConfigurePerGame>()), title_id{title_id_}, system{system_} {
ui(std::make_unique<Ui::ConfigurePerGame>()), title_id{title_id_}, system{system_},
builder{std::make_unique<ConfigurationShared::Builder>(this, !system_.IsPoweredOn())},
tab_group{std::make_shared<std::vector<ConfigurationShared::Tab*>>()} {
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);
game_config = std::make_unique<Config>(config_file_name, Config::ConfigType::PerGameConfig);
addons_tab = std::make_unique<ConfigurePerGameAddons>(system_, this);
audio_tab = std::make_unique<ConfigureAudio>(system_, this);
cpu_tab = std::make_unique<ConfigureCpu>(system_, this);
general_tab = std::make_unique<ConfigureGeneral>(system_, this);
graphics_advanced_tab = std::make_unique<ConfigureGraphicsAdvanced>(system_, this);
audio_tab = std::make_unique<ConfigureAudio>(system_, tab_group, *builder, this);
cpu_tab = std::make_unique<ConfigureCpu>(system_, tab_group, *builder, this);
graphics_advanced_tab =
std::make_unique<ConfigureGraphicsAdvanced>(system_, tab_group, *builder, this);
graphics_tab = std::make_unique<ConfigureGraphics>(
system_, vk_device_records, [&]() { graphics_advanced_tab->ExposeComputeOption(); }, this);
system_, vk_device_records, [&]() { graphics_advanced_tab->ExposeComputeOption(); },
tab_group, *builder, this);
input_tab = std::make_unique<ConfigureInputPerGame>(system_, game_config.get(), this);
system_tab = std::make_unique<ConfigureSystem>(system_, this);
system_tab = std::make_unique<ConfigureSystem>(system_, tab_group, *builder, this);
ui->setupUi(this);
ui->tabWidget->addTab(addons_tab.get(), tr("Add-Ons"));
ui->tabWidget->addTab(general_tab.get(), tr("General"));
ui->tabWidget->addTab(system_tab.get(), tr("System"));
ui->tabWidget->addTab(cpu_tab.get(), tr("CPU"));
ui->tabWidget->addTab(graphics_tab.get(), tr("Graphics"));
@ -88,13 +91,10 @@ ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id_, const std::st
ConfigurePerGame::~ConfigurePerGame() = default;
void ConfigurePerGame::ApplyConfiguration() {
for (const auto tab : *tab_group) {
tab->ApplyConfiguration();
}
addons_tab->ApplyConfiguration();
general_tab->ApplyConfiguration();
cpu_tab->ApplyConfiguration();
system_tab->ApplyConfiguration();
graphics_tab->ApplyConfiguration();
graphics_advanced_tab->ApplyConfiguration();
audio_tab->ApplyConfiguration();
input_tab->ApplyConfiguration();
system.ApplySettings();

View File

@ -10,9 +10,12 @@
#include <QDialog>
#include <QList>
#include "configuration/shared_widget.h"
#include "core/file_sys/vfs_types.h"
#include "vk_device_info.h"
#include "yuzu/configuration/config.h"
#include "yuzu/configuration/configuration_shared.h"
#include "yuzu/configuration/shared_translation.h"
namespace Core {
class System;
@ -25,7 +28,6 @@ class InputSubsystem;
class ConfigurePerGameAddons;
class ConfigureAudio;
class ConfigureCpu;
class ConfigureGeneral;
class ConfigureGraphics;
class ConfigureGraphicsAdvanced;
class ConfigureInputPerGame;
@ -73,11 +75,12 @@ private:
std::unique_ptr<Config> game_config;
Core::System& system;
std::unique_ptr<ConfigurationShared::Builder> builder;
std::shared_ptr<std::vector<ConfigurationShared::Tab*>> tab_group;
std::unique_ptr<ConfigurePerGameAddons> addons_tab;
std::unique_ptr<ConfigureAudio> audio_tab;
std::unique_ptr<ConfigureCpu> cpu_tab;
std::unique_ptr<ConfigureGeneral> general_tab;
std::unique_ptr<ConfigureGraphicsAdvanced> graphics_advanced_tab;
std::unique_ptr<ConfigureGraphics> graphics_tab;
std::unique_ptr<ConfigureInputPerGame> input_tab;

View File

@ -2,6 +2,14 @@
<ui version="4.0">
<class>ConfigurePerGame</class>
<widget class="QDialog" name="ConfigurePerGame">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>900</width>
<height>607</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>900</width>
@ -225,20 +233,31 @@
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_8">
<property name="text">
<string>Some settings are only available when a game is not running.</string>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>

View File

@ -3,16 +3,23 @@
#include <chrono>
#include <optional>
#include <vector>
#include <QCheckBox>
#include <QComboBox>
#include <QDateTimeEdit>
#include <QFileDialog>
#include <QGraphicsItem>
#include <QLineEdit>
#include <QMessageBox>
#include "common/settings.h"
#include "core/core.h"
#include "core/hle/service/time/time_manager.h"
#include "ui_configure_system.h"
#include "yuzu/configuration/config.h"
#include "yuzu/configuration/configuration_shared.h"
#include "yuzu/configuration/configure_system.h"
#include "yuzu/configuration/shared_widget.h"
constexpr std::array<u32, 7> LOCALE_BLOCKLIST{
// pzzefezrpnkzeidfej
@ -37,44 +44,32 @@ static bool IsValidLocale(u32 region_index, u32 language_index) {
return ((LOCALE_BLOCKLIST.at(region_index) >> language_index) & 1) == 0;
}
ConfigureSystem::ConfigureSystem(Core::System& system_, QWidget* parent)
: QWidget(parent), ui{std::make_unique<Ui::ConfigureSystem>()}, system{system_} {
ConfigureSystem::ConfigureSystem(Core::System& system_,
std::shared_ptr<std::vector<ConfigurationShared::Tab*>> group_,
const ConfigurationShared::Builder& builder, QWidget* parent)
: Tab(group_, parent), ui{std::make_unique<Ui::ConfigureSystem>()}, system{system_} {
ui->setupUi(this);
connect(ui->rng_seed_checkbox, &QCheckBox::stateChanged, this, [this](int state) {
ui->rng_seed_edit->setEnabled(state == Qt::Checked);
if (state != Qt::Checked) {
ui->rng_seed_edit->setText(QStringLiteral("00000000"));
}
});
Setup(builder);
connect(ui->custom_rtc_checkbox, &QCheckBox::stateChanged, this, [this](int state) {
ui->custom_rtc_edit->setEnabled(state == Qt::Checked);
if (state != Qt::Checked) {
ui->custom_rtc_edit->setDateTime(QDateTime::currentDateTime());
}
});
const auto locale_check = [this](int index) {
const auto region_index = ConfigurationShared::GetComboboxIndex(
Settings::values.region_index.GetValue(true), ui->combo_region);
const auto language_index = ConfigurationShared::GetComboboxIndex(
Settings::values.language_index.GetValue(true), ui->combo_language);
const auto locale_check = [this]() {
const auto region_index = combo_region->currentIndex();
const auto language_index = combo_language->currentIndex();
const bool valid_locale = IsValidLocale(region_index, language_index);
ui->label_warn_invalid_locale->setVisible(!valid_locale);
if (!valid_locale) {
ui->label_warn_invalid_locale->setText(
tr("Warning: \"%1\" is not a valid language for region \"%2\"")
.arg(ui->combo_language->currentText())
.arg(ui->combo_region->currentText()));
.arg(combo_language->currentText())
.arg(combo_region->currentText()));
}
};
connect(ui->combo_language, qOverload<int>(&QComboBox::currentIndexChanged), this,
locale_check);
connect(ui->combo_region, qOverload<int>(&QComboBox::currentIndexChanged), this, locale_check);
connect(combo_language, qOverload<int>(&QComboBox::currentIndexChanged), this, locale_check);
connect(combo_region, qOverload<int>(&QComboBox::currentIndexChanged), this, locale_check);
SetupPerGameUI();
ui->label_warn_invalid_locale->setVisible(false);
locale_check();
SetConfiguration();
}
@ -93,137 +88,66 @@ void ConfigureSystem::RetranslateUI() {
ui->retranslateUi(this);
}
void ConfigureSystem::SetConfiguration() {
enabled = !system.IsPoweredOn();
const auto rng_seed =
QStringLiteral("%1")
.arg(Settings::values.rng_seed.GetValue().value_or(0), 8, 16, QLatin1Char{'0'})
.toUpper();
const auto rtc_time = Settings::values.custom_rtc.value_or(QDateTime::currentSecsSinceEpoch());
void ConfigureSystem::Setup(const ConfigurationShared::Builder& builder) {
auto& core_layout = *ui->core_widget->layout();
auto& system_layout = *ui->system_widget->layout();
ui->rng_seed_checkbox->setChecked(Settings::values.rng_seed.GetValue().has_value());
ui->rng_seed_edit->setEnabled(Settings::values.rng_seed.GetValue().has_value() &&
Settings::values.rng_seed.UsingGlobal());
ui->rng_seed_edit->setText(rng_seed);
std::map<u32, QWidget*> core_hold{};
std::map<u32, QWidget*> system_hold{};
ui->custom_rtc_checkbox->setChecked(Settings::values.custom_rtc.has_value());
ui->custom_rtc_edit->setEnabled(Settings::values.custom_rtc.has_value());
ui->custom_rtc_edit->setDateTime(QDateTime::fromSecsSinceEpoch(rtc_time));
ui->device_name_edit->setText(
QString::fromUtf8(Settings::values.device_name.GetValue().c_str()));
ui->use_unsafe_extended_memory_layout->setEnabled(enabled);
ui->use_unsafe_extended_memory_layout->setChecked(
Settings::values.use_unsafe_extended_memory_layout.GetValue());
std::vector<Settings::BasicSetting*> settings;
auto push = [&settings](auto& list) {
for (auto setting : list) {
settings.push_back(setting);
}
};
if (Settings::IsConfiguringGlobal()) {
ui->combo_language->setCurrentIndex(Settings::values.language_index.GetValue());
ui->combo_region->setCurrentIndex(Settings::values.region_index.GetValue());
ui->combo_time_zone->setCurrentIndex(Settings::values.time_zone_index.GetValue());
} else {
ConfigurationShared::SetPerGameSetting(ui->combo_language,
&Settings::values.language_index);
ConfigurationShared::SetPerGameSetting(ui->combo_region, &Settings::values.region_index);
ConfigurationShared::SetPerGameSetting(ui->combo_time_zone,
&Settings::values.time_zone_index);
push(Settings::values.linkage.by_category[Settings::Category::Core]);
push(Settings::values.linkage.by_category[Settings::Category::System]);
ConfigurationShared::SetHighlight(ui->label_language,
!Settings::values.language_index.UsingGlobal());
ConfigurationShared::SetHighlight(ui->label_region,
!Settings::values.region_index.UsingGlobal());
ConfigurationShared::SetHighlight(ui->label_timezone,
!Settings::values.time_zone_index.UsingGlobal());
for (auto setting : settings) {
ConfigurationShared::Widget* widget = builder.BuildWidget(setting, apply_funcs);
if (widget == nullptr) {
continue;
}
if (!widget->Valid()) {
widget->deleteLater();
continue;
}
if (setting->Id() == Settings::values.region_index.Id()) {
// Keep track of the region_index (and langauge_index) combobox to validate the selected
// settings
combo_region = widget->combobox;
} else if (setting->Id() == Settings::values.language_index.Id()) {
combo_language = widget->combobox;
}
switch (setting->GetCategory()) {
case Settings::Category::Core:
core_hold.emplace(setting->Id(), widget);
break;
case Settings::Category::System:
system_hold.emplace(setting->Id(), widget);
break;
default:
widget->deleteLater();
}
}
for (const auto& [label, widget] : core_hold) {
core_layout.addWidget(widget);
}
for (const auto& [id, widget] : system_hold) {
system_layout.addWidget(widget);
}
}
void ConfigureSystem::ReadSystemSettings() {}
void ConfigureSystem::SetConfiguration() {}
void ConfigureSystem::ApplyConfiguration() {
// Allow setting custom RTC even if system is powered on,
// to allow in-game time to be fast forwarded
if (Settings::IsConfiguringGlobal()) {
if (ui->custom_rtc_checkbox->isChecked()) {
Settings::values.custom_rtc = ui->custom_rtc_edit->dateTime().toSecsSinceEpoch();
if (system.IsPoweredOn()) {
const s64 posix_time{*Settings::values.custom_rtc};
system.GetTimeManager().UpdateLocalSystemClockTime(posix_time);
}
} else {
Settings::values.custom_rtc = std::nullopt;
}
}
Settings::values.device_name = ui->device_name_edit->text().toStdString();
if (!enabled) {
return;
}
ConfigurationShared::ApplyPerGameSetting(&Settings::values.language_index, ui->combo_language);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.region_index, ui->combo_region);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.time_zone_index,
ui->combo_time_zone);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_unsafe_extended_memory_layout,
ui->use_unsafe_extended_memory_layout,
use_unsafe_extended_memory_layout);
if (Settings::IsConfiguringGlobal()) {
// Guard if during game and set to game-specific value
if (Settings::values.rng_seed.UsingGlobal()) {
if (ui->rng_seed_checkbox->isChecked()) {
Settings::values.rng_seed.SetValue(ui->rng_seed_edit->text().toUInt(nullptr, 16));
} else {
Settings::values.rng_seed.SetValue(std::nullopt);
}
}
} else {
switch (use_rng_seed) {
case ConfigurationShared::CheckState::On:
case ConfigurationShared::CheckState::Off:
Settings::values.rng_seed.SetGlobal(false);
if (ui->rng_seed_checkbox->isChecked()) {
Settings::values.rng_seed.SetValue(ui->rng_seed_edit->text().toUInt(nullptr, 16));
} else {
Settings::values.rng_seed.SetValue(std::nullopt);
}
break;
case ConfigurationShared::CheckState::Global:
Settings::values.rng_seed.SetGlobal(false);
Settings::values.rng_seed.SetValue(std::nullopt);
Settings::values.rng_seed.SetGlobal(true);
break;
case ConfigurationShared::CheckState::Count:
break;
}
const bool powered_on = system.IsPoweredOn();
for (const auto& func : apply_funcs) {
func(powered_on);
}
}
void ConfigureSystem::SetupPerGameUI() {
if (Settings::IsConfiguringGlobal()) {
ui->combo_language->setEnabled(Settings::values.language_index.UsingGlobal());
ui->combo_region->setEnabled(Settings::values.region_index.UsingGlobal());
ui->combo_time_zone->setEnabled(Settings::values.time_zone_index.UsingGlobal());
ui->rng_seed_checkbox->setEnabled(Settings::values.rng_seed.UsingGlobal());
ui->rng_seed_edit->setEnabled(Settings::values.rng_seed.UsingGlobal());
return;
}
ConfigurationShared::SetColoredComboBox(ui->combo_language, ui->label_language,
Settings::values.language_index.GetValue(true));
ConfigurationShared::SetColoredComboBox(ui->combo_region, ui->label_region,
Settings::values.region_index.GetValue(true));
ConfigurationShared::SetColoredComboBox(ui->combo_time_zone, ui->label_timezone,
Settings::values.time_zone_index.GetValue(true));
ConfigurationShared::SetColoredTristate(
ui->rng_seed_checkbox, Settings::values.rng_seed.UsingGlobal(),
Settings::values.rng_seed.GetValue().has_value(),
Settings::values.rng_seed.GetValue(true).has_value(), use_rng_seed);
ConfigurationShared::SetColoredTristate(ui->use_unsafe_extended_memory_layout,
Settings::values.use_unsafe_extended_memory_layout,
use_unsafe_extended_memory_layout);
ui->custom_rtc_checkbox->setVisible(false);
ui->custom_rtc_edit->setVisible(false);
}

View File

@ -3,45 +3,53 @@
#pragma once
#include <functional>
#include <memory>
#include <vector>
#include <QWidget>
#include "yuzu/configuration/configuration_shared.h"
class QCheckBox;
class QLineEdit;
class QComboBox;
class QDateTimeEdit;
namespace Core {
class System;
}
namespace ConfigurationShared {
enum class CheckState;
}
namespace Ui {
class ConfigureSystem;
}
class ConfigureSystem : public QWidget {
Q_OBJECT
namespace ConfigurationShared {
class Builder;
}
class ConfigureSystem : public ConfigurationShared::Tab {
public:
explicit ConfigureSystem(Core::System& system_, QWidget* parent = nullptr);
explicit ConfigureSystem(Core::System& system_,
std::shared_ptr<std::vector<ConfigurationShared::Tab*>> group,
const ConfigurationShared::Builder& builder,
QWidget* parent = nullptr);
~ConfigureSystem() override;
void ApplyConfiguration();
void SetConfiguration();
void ApplyConfiguration() override;
void SetConfiguration() override;
private:
void changeEvent(QEvent* event) override;
void RetranslateUI();
void ReadSystemSettings();
void Setup(const ConfigurationShared::Builder& builder);
void SetupPerGameUI();
std::vector<std::function<void(bool)>> apply_funcs{};
std::unique_ptr<Ui::ConfigureSystem> ui;
bool enabled = false;
ConfigurationShared::CheckState use_rng_seed;
ConfigurationShared::CheckState use_unsafe_extended_memory_layout;
Core::System& system;
QComboBox* combo_region;
QComboBox* combo_language;
};

View File

@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>366</width>
<width>605</width>
<height>483</height>
</rect>
</property>
@ -22,470 +22,63 @@
<item>
<widget class="QGroupBox" name="group_system_settings">
<property name="title">
<string>System Settings</string>
<string>System</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QGridLayout" name="gridLayout_2">
<item row="1" column="0">
<widget class="QLabel" name="label_region">
<property name="text">
<string>Region:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="combo_time_zone">
<item>
<property name="text">
<string>Auto</string>
</property>
</item>
<item>
<property name="text">
<string>Default</string>
</property>
</item>
<item>
<property name="text">
<string>CET</string>
</property>
</item>
<item>
<property name="text">
<string>CST6CDT</string>
</property>
</item>
<item>
<property name="text">
<string>Cuba</string>
</property>
</item>
<item>
<property name="text">
<string>EET</string>
</property>
</item>
<item>
<property name="text">
<string>Egypt</string>
</property>
</item>
<item>
<property name="text">
<string>Eire</string>
</property>
</item>
<item>
<property name="text">
<string>EST</string>
</property>
</item>
<item>
<property name="text">
<string>EST5EDT</string>
</property>
</item>
<item>
<property name="text">
<string>GB</string>
</property>
</item>
<item>
<property name="text">
<string>GB-Eire</string>
</property>
</item>
<item>
<property name="text">
<string>GMT</string>
</property>
</item>
<item>
<property name="text">
<string>GMT+0</string>
</property>
</item>
<item>
<property name="text">
<string>GMT-0</string>
</property>
</item>
<item>
<property name="text">
<string>GMT0</string>
</property>
</item>
<item>
<property name="text">
<string>Greenwich</string>
</property>
</item>
<item>
<property name="text">
<string>Hongkong</string>
</property>
</item>
<item>
<property name="text">
<string>HST</string>
</property>
</item>
<item>
<property name="text">
<string>Iceland</string>
</property>
</item>
<item>
<property name="text">
<string>Iran</string>
</property>
</item>
<item>
<property name="text">
<string>Israel</string>
</property>
</item>
<item>
<property name="text">
<string>Jamaica</string>
</property>
</item>
<item>
<property name="text">
<string>Japan</string>
</property>
</item>
<item>
<property name="text">
<string>Kwajalein</string>
</property>
</item>
<item>
<property name="text">
<string>Libya</string>
</property>
</item>
<item>
<property name="text">
<string>MET</string>
</property>
</item>
<item>
<property name="text">
<string>MST</string>
</property>
</item>
<item>
<property name="text">
<string>MST7MDT</string>
</property>
</item>
<item>
<property name="text">
<string>Navajo</string>
</property>
</item>
<item>
<property name="text">
<string>NZ</string>
</property>
</item>
<item>
<property name="text">
<string>NZ-CHAT</string>
</property>
</item>
<item>
<property name="text">
<string>Poland</string>
</property>
</item>
<item>
<property name="text">
<string>Portugal</string>
</property>
</item>
<item>
<property name="text">
<string>PRC</string>
</property>
</item>
<item>
<property name="text">
<string>PST8PDT</string>
</property>
</item>
<item>
<property name="text">
<string>ROC</string>
</property>
</item>
<item>
<property name="text">
<string>ROK</string>
</property>
</item>
<item>
<property name="text">
<string>Singapore</string>
</property>
</item>
<item>
<property name="text">
<string>Turkey</string>
</property>
</item>
<item>
<property name="text">
<string>UCT</string>
</property>
</item>
<item>
<property name="text">
<string>Universal</string>
</property>
</item>
<item>
<property name="text">
<string>UTC</string>
</property>
</item>
<item>
<property name="text">
<string>W-SU</string>
</property>
</item>
<item>
<property name="text">
<string>WET</string>
</property>
</item>
<item>
<property name="text">
<string>Zulu</string>
</property>
</item>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="combo_region">
<item>
<property name="text">
<string>Japan</string>
</property>
</item>
<item>
<property name="text">
<string>USA</string>
</property>
</item>
<item>
<property name="text">
<string>Europe</string>
</property>
</item>
<item>
<property name="text">
<string>Australia</string>
</property>
</item>
<item>
<property name="text">
<string>China</string>
</property>
</item>
<item>
<property name="text">
<string>Korea</string>
</property>
</item>
<item>
<property name="text">
<string>Taiwan</string>
</property>
</item>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_timezone">
<property name="text">
<string>Time Zone:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="combo_language">
<property name="toolTip">
<string>Note: this can be overridden when region setting is auto-select</string>
</property>
<item>
<property name="text">
<string>Japanese (日本語)</string>
</property>
</item>
<item>
<property name="text">
<string>American English</string>
</property>
</item>
<item>
<property name="text">
<string>French (français)</string>
</property>
</item>
<item>
<property name="text">
<string>German (Deutsch)</string>
</property>
</item>
<item>
<property name="text">
<string>Italian (italiano)</string>
</property>
</item>
<item>
<property name="text">
<string>Spanish (español)</string>
</property>
</item>
<item>
<property name="text">
<string>Chinese</string>
</property>
</item>
<item>
<property name="text">
<string>Korean (한국어)</string>
</property>
</item>
<item>
<property name="text">
<string>Dutch (Nederlands)</string>
</property>
</item>
<item>
<property name="text">
<string>Portuguese (português)</string>
</property>
</item>
<item>
<property name="text">
<string>Russian (Русский)</string>
</property>
</item>
<item>
<property name="text">
<string>Taiwanese</string>
</property>
</item>
<item>
<property name="text">
<string>British English</string>
</property>
</item>
<item>
<property name="text">
<string>Canadian French</string>
</property>
</item>
<item>
<property name="text">
<string>Latin American Spanish</string>
</property>
</item>
<item>
<property name="text">
<string>Simplified Chinese</string>
</property>
</item>
<item>
<property name="text">
<string>Traditional Chinese (正體中文)</string>
</property>
</item>
<item>
<property name="text">
<string>Brazilian Portuguese (português do Brasil)</string>
</property>
</item>
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="custom_rtc_checkbox">
<property name="text">
<string>Custom RTC</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_language">
<property name="text">
<string>Language</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QCheckBox" name="rng_seed_checkbox">
<property name="text">
<string>RNG Seed</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="device_name_label">
<property name="text">
<string>Device Name</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QDateTimeEdit" name="custom_rtc_edit">
<property name="minimumDate">
<date>
<year>1970</year>
<month>1</month>
<day>1</day>
</date>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLineEdit" name="device_name_edit">
<property name="maxLength">
<number>128</number>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLineEdit" name="rng_seed_edit">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<family>Lucida Console</family>
</font>
</property>
<property name="inputMask">
<string notr="true">HHHHHHHH</string>
</property>
<property name="maxLength">
<number>8</number>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QCheckBox" name="use_unsafe_extended_memory_layout">
<property name="text">
<string>Unsafe extended memory layout (8GB DRAM)</string>
</property>
</widget>
</item>
</layout>
<widget class="QWidget" name="system_widget" native="true">
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
</layout>
</widget>
</item>
<item>
<widget class="QLabel" name="label_warn_invalid_locale">
<property name="text">
<string/>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Core</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="QWidget" name="core_widget" native="true">
<layout class="QVBoxLayout" name="verticalLayout_5">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
</layout>
</widget>
</item>
</layout>
</widget>
@ -503,26 +96,6 @@
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_warn_invalid_locale">
<property name="text">
<string></string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_disable_info">
<property name="text">
<string>System settings are available only when game is not running.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>

View File

@ -0,0 +1,388 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/time_zone.h"
#include "yuzu/configuration/shared_translation.h"
#include <map>
#include <memory>
#include <tuple>
#include <utility>
#include <QWidget>
#include "common/settings.h"
#include "common/settings_enums.h"
#include "common/settings_setting.h"
#include "yuzu/uisettings.h"
namespace ConfigurationShared {
std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent) {
std::unique_ptr<TranslationMap> translations = std::make_unique<TranslationMap>();
const auto& tr = [parent](const char* text) -> QString { return parent->tr(text); };
#define INSERT(SETTINGS, ID, NAME, TOOLTIP) \
translations->insert(std::pair{SETTINGS::values.ID.Id(), std::pair{tr((NAME)), tr((TOOLTIP))}})
// A setting can be ignored by giving it a blank name
// Audio
INSERT(Settings, sink_id, "Output Engine:", "");
INSERT(Settings, audio_output_device_id, "Output Device:", "");
INSERT(Settings, audio_input_device_id, "Input Device:", "");
INSERT(Settings, audio_muted, "Mute audio when in background", "");
INSERT(Settings, volume, "Volume:", "");
INSERT(Settings, dump_audio_commands, "", "");
// Core
INSERT(Settings, use_multi_core, "Multicore CPU Emulation", "");
INSERT(Settings, memory_layout_mode, "Memory Layout", "");
INSERT(Settings, use_speed_limit, "", "");
INSERT(Settings, speed_limit, "Limit Speed Percent", "");
// Cpu
INSERT(Settings, cpu_accuracy, "Accuracy:", "");
// Cpu Debug
// Cpu Unsafe
INSERT(Settings, cpuopt_unsafe_unfuse_fma,
"Unfuse FMA (improve performance on CPUs without FMA)",
"This option improves speed by reducing accuracy of fused-multiply-add instructions on "
"CPUs without native FMA support.");
INSERT(Settings, cpuopt_unsafe_reduce_fp_error, "Faster FRSQRTE and FRECPE",
"This option improves the speed of some approximate floating-point functions by using "
"less accurate native approximations.");
INSERT(Settings, cpuopt_unsafe_ignore_standard_fpcr, "Faster ASIMD instructions (32 bits only)",
"This option improves the speed of 32 bits ASIMD floating-point functions by running "
"with incorrect rounding modes.");
INSERT(Settings, cpuopt_unsafe_inaccurate_nan, "Inaccurate NaN handling",
"This option improves speed by removing NaN checking. Please note this also reduces "
"accuracy of certain floating-point instructions.");
INSERT(
Settings, cpuopt_unsafe_fastmem_check, "Disable address space checks",
"This option improves speed by eliminating a safety check before every memory read/write "
"in guest. Disabling it may allow a game to read/write the emulator's memory.");
INSERT(Settings, cpuopt_unsafe_ignore_global_monitor, "Ignore global monitor",
"This option improves speed by relying only on the semantics of cmpxchg to ensure "
"safety of exclusive access instructions. Please note this may result in deadlocks and "
"other race conditions.");
// Renderer
INSERT(Settings, renderer_backend, "API:", "");
INSERT(Settings, vulkan_device, "Device:", "");
INSERT(Settings, shader_backend, "Shader Backend:", "");
INSERT(Settings, resolution_setup, "Resolution:", "");
INSERT(Settings, scaling_filter, "Window Adapting Filter:", "");
INSERT(Settings, fsr_sharpening_slider, "FSR Sharpness:", "");
INSERT(Settings, anti_aliasing, "Anti-Aliasing Method:", "");
INSERT(Settings, fullscreen_mode, "Fullscreen Mode:", "");
INSERT(Settings, aspect_ratio, "Aspect Ratio:", "");
INSERT(Settings, use_disk_shader_cache, "Use disk pipeline cache", "");
INSERT(Settings, use_asynchronous_gpu_emulation, "Use asynchronous GPU emulation", "");
INSERT(Settings, nvdec_emulation, "NVDEC emulation:", "");
INSERT(Settings, accelerate_astc, "ASTC Decoding Method:", "");
INSERT(Settings, astc_recompression, "ASTC Recompression Method:", "");
INSERT(Settings, vsync_mode, "VSync Mode:",
"FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen "
"refresh rate.\nFIFO Relaxed is similar to FIFO but allows tearing as it recovers from "
"a slow down.\nMailbox can have lower latency than FIFO and does not tear but may drop "
"frames.\nImmediate (no synchronization) just presents whatever is available and can "
"exhibit tearing.");
INSERT(Settings, bg_red, "", "");
INSERT(Settings, bg_green, "", "");
INSERT(Settings, bg_blue, "", "");
// Renderer (Advanced Graphics)
INSERT(Settings, async_presentation, "Enable asynchronous presentation (Vulkan only)", "");
INSERT(Settings, renderer_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(Settings, max_anisotropy, "Anisotropic Filtering:", "");
INSERT(Settings, gpu_accuracy, "Accuracy Level:", "");
INSERT(Settings, use_asynchronous_shaders, "Use asynchronous shader building (Hack)",
"Enables asynchronous shader compilation, which may reduce shader stutter. This feature "
"is experimental.");
INSERT(Settings, 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(Settings, 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(Settings, 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(Settings, use_reactive_flushing, "Enable Reactive Flushing",
"Uses reactive flushing instead of predictive flushing, allowing more accurate memory "
"syncing.");
INSERT(Settings, use_video_framerate, "Sync to framerate of video playback",
"Run the game at normal speed during video playback, even when the framerate is "
"unlocked.");
INSERT(Settings, barrier_feedback_loops, "Barrier feedback loops",
"Improves rendering of transparency effects in specific games.");
// Renderer (Debug)
// System
INSERT(Settings, rng_seed, "RNG Seed", "");
INSERT(Settings, rng_seed_enabled, "", "");
INSERT(Settings, device_name, "Device Name", "");
INSERT(Settings, custom_rtc, "Custom RTC", "");
INSERT(Settings, custom_rtc_enabled, "", "");
INSERT(Settings, language_index,
"Language:", "Note: this can be overridden when region setting is auto-select");
INSERT(Settings, region_index, "Region:", "");
INSERT(Settings, time_zone_index, "Time Zone:", "");
INSERT(Settings, sound_index, "Sound Output Mode:", "");
INSERT(Settings, use_docked_mode, "", "");
INSERT(Settings, current_user, "", "");
// Controls
// Data Storage
// Debugging
// Debugging Graphics
// Network
// Web Service
// Ui
// Ui General
INSERT(UISettings, select_user_on_boot, "Prompt for user on game boot", "");
INSERT(UISettings, pause_when_in_background, "Pause emulation when in background", "");
INSERT(UISettings, confirm_before_closing, "Confirm exit while emulation is running", "");
INSERT(UISettings, hide_mouse, "Hide mouse on inactivity", "");
INSERT(UISettings, controller_applet_disabled, "Disable controller applet", "");
// Ui Debugging
// Ui Multiplayer
// Ui Games list
#undef INSERT
return translations;
}
std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QWidget* parent) {
std::unique_ptr<ComboboxTranslationMap> translations =
std::make_unique<ComboboxTranslationMap>();
const auto& tr = [&](const char* text, const char* context = "") {
return parent->tr(text, context);
};
#define PAIR(ENUM, VALUE, TRANSLATION) \
{ static_cast<u32>(Settings::ENUM::VALUE), tr(TRANSLATION) }
#define CTX_PAIR(ENUM, VALUE, TRANSLATION, CONTEXT) \
{ static_cast<u32>(Settings::ENUM::VALUE), tr(TRANSLATION, CONTEXT) }
// Intentionally skipping VSyncMode to let the UI fill that one out
translations->insert({Settings::EnumMetadata<Settings::AstcDecodeMode>::Index(),
{
PAIR(AstcDecodeMode, Cpu, "CPU"),
PAIR(AstcDecodeMode, Gpu, "GPU"),
PAIR(AstcDecodeMode, CpuAsynchronous, "CPU Asynchronous"),
}});
translations->insert({Settings::EnumMetadata<Settings::AstcRecompression>::Index(),
{
PAIR(AstcRecompression, Uncompressed, "Uncompressed (Best quality)"),
PAIR(AstcRecompression, Bc1, "BC1 (Low quality)"),
PAIR(AstcRecompression, Bc3, "BC3 (Medium quality)"),
}});
translations->insert({Settings::EnumMetadata<Settings::RendererBackend>::Index(),
{
#ifdef HAS_OPENGL
PAIR(RendererBackend, OpenGL, "OpenGL"),
#endif
PAIR(RendererBackend, Vulkan, "Vulkan"),
PAIR(RendererBackend, Null, "Null"),
}});
translations->insert({Settings::EnumMetadata<Settings::ShaderBackend>::Index(),
{
PAIR(ShaderBackend, Glsl, "GLSL"),
PAIR(ShaderBackend, Glasm, "GLASM (Assembly Shaders, NVIDIA Only)"),
PAIR(ShaderBackend, SpirV, "SPIR-V (Experimental, Mesa Only)"),
}});
translations->insert({Settings::EnumMetadata<Settings::GpuAccuracy>::Index(),
{
PAIR(GpuAccuracy, Normal, "Normal"),
PAIR(GpuAccuracy, High, "High"),
PAIR(GpuAccuracy, Extreme, "Extreme"),
}});
translations->insert({Settings::EnumMetadata<Settings::CpuAccuracy>::Index(),
{
PAIR(CpuAccuracy, Auto, "Auto"),
PAIR(CpuAccuracy, Accurate, "Accurate"),
PAIR(CpuAccuracy, Unsafe, "Unsafe"),
PAIR(CpuAccuracy, Paranoid, "Paranoid (disables most optimizations)"),
}});
translations->insert({Settings::EnumMetadata<Settings::FullscreenMode>::Index(),
{
PAIR(FullscreenMode, Borderless, "Borderless Windowed"),
PAIR(FullscreenMode, Exclusive, "Exclusive Fullscreen"),
}});
translations->insert({Settings::EnumMetadata<Settings::NvdecEmulation>::Index(),
{
PAIR(NvdecEmulation, Off, "No Video Output"),
PAIR(NvdecEmulation, Cpu, "CPU Video Decoding"),
PAIR(NvdecEmulation, Gpu, "GPU Video Decoding (Default)"),
}});
translations->insert({Settings::EnumMetadata<Settings::ResolutionSetup>::Index(),
{
PAIR(ResolutionSetup, Res1_2X, "0.5X (360p/540p) [EXPERIMENTAL]"),
PAIR(ResolutionSetup, Res3_4X, "0.75X (540p/810p) [EXPERIMENTAL]"),
PAIR(ResolutionSetup, Res1X, "1X (720p/1080p)"),
PAIR(ResolutionSetup, Res3_2X, "1.5X (1080p/1620p) [EXPERIMENTAL]"),
PAIR(ResolutionSetup, Res2X, "2X (1440p/2160p)"),
PAIR(ResolutionSetup, Res3X, "3X (2160p/3240p)"),
PAIR(ResolutionSetup, Res4X, "4X (2880p/4320p)"),
PAIR(ResolutionSetup, Res5X, "5X (3600p/5400p)"),
PAIR(ResolutionSetup, Res6X, "6X (4320p/6480p)"),
PAIR(ResolutionSetup, Res7X, "7X (5040p/7560p)"),
PAIR(ResolutionSetup, Res8X, "8X (5760p/8640p)"),
}});
translations->insert({Settings::EnumMetadata<Settings::ScalingFilter>::Index(),
{
PAIR(ScalingFilter, NearestNeighbor, "Nearest Neighbor"),
PAIR(ScalingFilter, Bilinear, "Bilinear"),
PAIR(ScalingFilter, Bicubic, "Bicubic"),
PAIR(ScalingFilter, Gaussian, "Gaussian"),
PAIR(ScalingFilter, ScaleForce, "ScaleForce"),
PAIR(ScalingFilter, Fsr, "AMD FidelityFX™ Super Resolution"),
}});
translations->insert({Settings::EnumMetadata<Settings::AntiAliasing>::Index(),
{
PAIR(AntiAliasing, None, "None"),
PAIR(AntiAliasing, Fxaa, "FXAA"),
PAIR(AntiAliasing, Smaa, "SMAA"),
}});
translations->insert({Settings::EnumMetadata<Settings::AspectRatio>::Index(),
{
PAIR(AspectRatio, R16_9, "Default (16:9)"),
PAIR(AspectRatio, R4_3, "Force 4:3"),
PAIR(AspectRatio, R21_9, "Force 21:9"),
PAIR(AspectRatio, R16_10, "Force 16:10"),
PAIR(AspectRatio, Stretch, "Stretch to Window"),
}});
translations->insert({Settings::EnumMetadata<Settings::AnisotropyMode>::Index(),
{
PAIR(AnisotropyMode, Automatic, "Automatic"),
PAIR(AnisotropyMode, Default, "Default"),
PAIR(AnisotropyMode, X2, "2x"),
PAIR(AnisotropyMode, X4, "4x"),
PAIR(AnisotropyMode, X8, "8x"),
PAIR(AnisotropyMode, X16, "16x"),
}});
translations->insert(
{Settings::EnumMetadata<Settings::Language>::Index(),
{
PAIR(Language, Japanese, "Japanese (日本語)"),
PAIR(Language, EnglishAmerican, "American English"),
PAIR(Language, French, "French (français)"),
PAIR(Language, German, "German (Deutsch)"),
PAIR(Language, Italian, "Italian (italiano)"),
PAIR(Language, Spanish, "Spanish (español)"),
PAIR(Language, Chinese, "Chinese"),
PAIR(Language, Korean, "Korean (한국어)"),
PAIR(Language, Dutch, "Dutch (Nederlands)"),
PAIR(Language, Portuguese, "Portuguese (português)"),
PAIR(Language, Russian, "Russian (Русский)"),
PAIR(Language, Taiwanese, "Taiwanese"),
PAIR(Language, EnglishBritish, "British English"),
PAIR(Language, FrenchCanadian, "Canadian French"),
PAIR(Language, SpanishLatin, "Latin American Spanish"),
PAIR(Language, ChineseSimplified, "Simplified Chinese"),
PAIR(Language, ChineseTraditional, "Traditional Chinese (正體中文)"),
PAIR(Language, PortugueseBrazilian, "Brazilian Portuguese (português do Brasil)"),
}});
translations->insert({Settings::EnumMetadata<Settings::Region>::Index(),
{
PAIR(Region, Japan, "Japan"),
PAIR(Region, Usa, "USA"),
PAIR(Region, Europe, "Europe"),
PAIR(Region, Australia, "Australia"),
PAIR(Region, China, "China"),
PAIR(Region, Korea, "Korea"),
PAIR(Region, Taiwan, "Taiwan"),
}});
translations->insert(
{Settings::EnumMetadata<Settings::TimeZone>::Index(),
{
{static_cast<u32>(Settings::TimeZone::Auto),
tr("Auto (%1)", "Auto select time zone")
.arg(QString::fromStdString(
Settings::GetTimeZoneString(Settings::TimeZone::Auto)))},
{static_cast<u32>(Settings::TimeZone::Default),
tr("Default (%1)", "Default time zone")
.arg(QString::fromStdString(Common::TimeZone::GetDefaultTimeZone()))},
PAIR(TimeZone, Cet, "CET"),
PAIR(TimeZone, Cst6Cdt, "CST6CDT"),
PAIR(TimeZone, Cuba, "Cuba"),
PAIR(TimeZone, Eet, "EET"),
PAIR(TimeZone, Egypt, "Egypt"),
PAIR(TimeZone, Eire, "Eire"),
PAIR(TimeZone, Est, "EST"),
PAIR(TimeZone, Est5Edt, "EST5EDT"),
PAIR(TimeZone, Gb, "GB"),
PAIR(TimeZone, GbEire, "GB-Eire"),
PAIR(TimeZone, Gmt, "GMT"),
PAIR(TimeZone, GmtPlusZero, "GMT+0"),
PAIR(TimeZone, GmtMinusZero, "GMT-0"),
PAIR(TimeZone, GmtZero, "GMT0"),
PAIR(TimeZone, Greenwich, "Greenwich"),
PAIR(TimeZone, Hongkong, "Hongkong"),
PAIR(TimeZone, Hst, "HST"),
PAIR(TimeZone, Iceland, "Iceland"),
PAIR(TimeZone, Iran, "Iran"),
PAIR(TimeZone, Israel, "Israel"),
PAIR(TimeZone, Jamaica, "Jamaica"),
PAIR(TimeZone, Japan, "Japan"),
PAIR(TimeZone, Kwajalein, "Kwajalein"),
PAIR(TimeZone, Libya, "Libya"),
PAIR(TimeZone, Met, "MET"),
PAIR(TimeZone, Mst, "MST"),
PAIR(TimeZone, Mst7Mdt, "MST7MDT"),
PAIR(TimeZone, Navajo, "Navajo"),
PAIR(TimeZone, Nz, "NZ"),
PAIR(TimeZone, NzChat, "NZ-CHAT"),
PAIR(TimeZone, Poland, "Poland"),
PAIR(TimeZone, Portugal, "Portugal"),
PAIR(TimeZone, Prc, "PRC"),
PAIR(TimeZone, Pst8Pdt, "PST8PDT"),
PAIR(TimeZone, Roc, "ROC"),
PAIR(TimeZone, Rok, "ROK"),
PAIR(TimeZone, Singapore, "Singapore"),
PAIR(TimeZone, Turkey, "Turkey"),
PAIR(TimeZone, Uct, "UCT"),
PAIR(TimeZone, Universal, "Universal"),
PAIR(TimeZone, Utc, "UTC"),
PAIR(TimeZone, WSu, "W-SU"),
PAIR(TimeZone, Wet, "WET"),
PAIR(TimeZone, Zulu, "Zulu"),
}});
translations->insert({Settings::EnumMetadata<Settings::AudioMode>::Index(),
{
PAIR(AudioMode, Mono, "Mono"),
PAIR(AudioMode, Stereo, "Stereo"),
PAIR(AudioMode, Surround, "Surround"),
}});
translations->insert({Settings::EnumMetadata<Settings::MemoryLayout>::Index(),
{
PAIR(MemoryLayout, Memory_4Gb, "4GB DRAM (Default)"),
PAIR(MemoryLayout, Memory_6Gb, "6GB DRAM (Unsafe)"),
PAIR(MemoryLayout, Memory_8Gb, "8GB DRAM (Unsafe)"),
}});
#undef PAIR
#undef CTX_PAIR
return translations;
}
} // namespace ConfigurationShared

View File

@ -0,0 +1,25 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <map>
#include <memory>
#include <typeindex>
#include <utility>
#include <vector>
#include <QString>
#include "common/common_types.h"
class QWidget;
namespace ConfigurationShared {
using TranslationMap = std::map<u32, std::pair<QString, QString>>;
using ComboboxTranslations = std::vector<std::pair<u32, QString>>;
using ComboboxTranslationMap = std::map<u32, ComboboxTranslations>;
std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent);
std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QWidget* parent);
} // namespace ConfigurationShared

View File

@ -0,0 +1,642 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "yuzu/configuration/shared_widget.h"
#include <functional>
#include <limits>
#include <typeindex>
#include <typeinfo>
#include <utility>
#include <vector>
#include <QAbstractButton>
#include <QAbstractSlider>
#include <QBoxLayout>
#include <QCheckBox>
#include <QComboBox>
#include <QDateTime>
#include <QDateTimeEdit>
#include <QIcon>
#include <QLabel>
#include <QLayout>
#include <QLineEdit>
#include <QObject>
#include <QPushButton>
#include <QRegularExpression>
#include <QSizePolicy>
#include <QSlider>
#include <QSpinBox>
#include <QStyle>
#include <QValidator>
#include <QVariant>
#include <QtCore/qglobal.h>
#include <QtCore/qobjectdefs.h>
#include <fmt/core.h>
#include <qglobal.h>
#include <qnamespace.h>
#include "common/assert.h"
#include "common/common_types.h"
#include "common/logging/log.h"
#include "common/settings.h"
#include "common/settings_common.h"
#include "yuzu/configuration/shared_translation.h"
namespace ConfigurationShared {
static int restore_button_count = 0;
static std::string RelevantDefault(const Settings::BasicSetting& setting) {
return Settings::IsConfiguringGlobal() ? setting.DefaultToString() : setting.ToStringGlobal();
}
static QString DefaultSuffix(QWidget* parent, Settings::BasicSetting& setting) {
const auto tr = [parent](const char* text, const char* context) {
return parent->tr(text, context);
};
if ((setting.Specialization() & Settings::SpecializationAttributeMask) ==
Settings::Specialization::Percentage) {
std::string context{fmt::format("{} percentage (e.g. 50%)", setting.GetLabel())};
return tr("%", context.c_str());
}
return QStringLiteral("");
}
QPushButton* Widget::CreateRestoreGlobalButton(bool using_global, QWidget* parent) {
restore_button_count++;
QStyle* style = parent->style();
QIcon* icon = new QIcon(style->standardIcon(QStyle::SP_LineEditClearButton));
QPushButton* restore_button = new QPushButton(*icon, QStringLiteral(""), parent);
restore_button->setObjectName(QStringLiteral("RestoreButton%1").arg(restore_button_count));
restore_button->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
// Workaround for dark theme causing min-width to be much larger than 0
restore_button->setStyleSheet(
QStringLiteral("QAbstractButton#%1 { min-width: 0px }").arg(restore_button->objectName()));
QSizePolicy sp_retain = restore_button->sizePolicy();
sp_retain.setRetainSizeWhenHidden(true);
restore_button->setSizePolicy(sp_retain);
restore_button->setEnabled(!using_global);
restore_button->setVisible(!using_global);
return restore_button;
}
QLabel* Widget::CreateLabel(const QString& text) {
QLabel* qt_label = new QLabel(text, this->parent);
qt_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
return qt_label;
}
QWidget* Widget::CreateCheckBox(Settings::BasicSetting* bool_setting, const QString& label,
std::function<std::string()>& serializer,
std::function<void()>& restore_func,
const std::function<void()>& touch) {
checkbox = new QCheckBox(label, this);
checkbox->setCheckState(bool_setting->ToString() == "true" ? Qt::CheckState::Checked
: Qt::CheckState::Unchecked);
checkbox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
if (!bool_setting->Save() && !Settings::IsConfiguringGlobal() && runtime_lock) {
checkbox->setEnabled(false);
}
serializer = [this]() {
return checkbox->checkState() == Qt::CheckState::Checked ? "true" : "false";
};
restore_func = [this, bool_setting]() {
checkbox->setCheckState(RelevantDefault(*bool_setting) == "true" ? Qt::Checked
: Qt::Unchecked);
};
if (!Settings::IsConfiguringGlobal()) {
QObject::connect(checkbox, &QCheckBox::clicked, [touch]() { touch(); });
}
return checkbox;
}
QWidget* Widget::CreateCombobox(std::function<std::string()>& serializer,
std::function<void()>& restore_func,
const std::function<void()>& touch) {
const auto type = setting.EnumIndex();
combobox = new QComboBox(this);
combobox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
const ComboboxTranslations* enumeration{nullptr};
if (combobox_enumerations.contains(type)) {
enumeration = &combobox_enumerations.at(type);
for (const auto& [id, name] : *enumeration) {
combobox->addItem(name);
}
} else {
return combobox;
}
const auto find_index = [=](u32 value) -> int {
for (u32 i = 0; i < enumeration->size(); i++) {
if (enumeration->at(i).first == value) {
return i;
}
}
return -1;
};
const u32 setting_value = std::stoi(setting.ToString());
combobox->setCurrentIndex(find_index(setting_value));
serializer = [this, enumeration]() {
int current = combobox->currentIndex();
return std::to_string(enumeration->at(current).first);
};
restore_func = [this, find_index]() {
const u32 global_value = std::stoi(RelevantDefault(setting));
combobox->setCurrentIndex(find_index(global_value));
};
if (!Settings::IsConfiguringGlobal()) {
QObject::connect(combobox, QOverload<int>::of(&QComboBox::activated),
[touch]() { touch(); });
}
return combobox;
}
QWidget* Widget::CreateLineEdit(std::function<std::string()>& serializer,
std::function<void()>& restore_func,
const std::function<void()>& touch, bool managed) {
const QString text = QString::fromStdString(setting.ToString());
line_edit = new QLineEdit(this);
line_edit->setText(text);
serializer = [this]() { return line_edit->text().toStdString(); };
if (!managed) {
return line_edit;
}
restore_func = [this]() {
line_edit->setText(QString::fromStdString(RelevantDefault(setting)));
};
if (!Settings::IsConfiguringGlobal()) {
QObject::connect(line_edit, &QLineEdit::textChanged, [touch]() { touch(); });
}
return line_edit;
}
QWidget* Widget::CreateSlider(bool reversed, float multiplier, const QString& given_suffix,
std::function<std::string()>& serializer,
std::function<void()>& restore_func,
const std::function<void()>& touch) {
if (!setting.Ranged()) {
LOG_ERROR(Frontend, "\"{}\" is not a ranged setting, but a slider was requested.",
setting.GetLabel());
return nullptr;
}
QWidget* container = new QWidget(this);
QHBoxLayout* layout = new QHBoxLayout(container);
slider = new QSlider(Qt::Horizontal, this);
QLabel* feedback = new QLabel(this);
layout->addWidget(slider);
layout->addWidget(feedback);
container->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
layout->setContentsMargins(0, 0, 0, 0);
int max_val = std::stoi(setting.MaxVal());
QString suffix =
given_suffix == QStringLiteral("") ? DefaultSuffix(this, setting) : given_suffix;
const QString use_format = QStringLiteral("%1").append(suffix);
QObject::connect(slider, &QAbstractSlider::valueChanged, [=](int value) {
int present = (reversed ? max_val - value : value) * multiplier + 0.5f;
feedback->setText(use_format.arg(QVariant::fromValue(present).value<QString>()));
});
slider->setMinimum(std::stoi(setting.MinVal()));
slider->setMaximum(max_val);
slider->setValue(std::stoi(setting.ToString()));
slider->setInvertedAppearance(reversed);
serializer = [this]() { return std::to_string(slider->value()); };
restore_func = [this]() { slider->setValue(std::stoi(RelevantDefault(setting))); };
if (!Settings::IsConfiguringGlobal()) {
QObject::connect(slider, &QAbstractSlider::actionTriggered, [touch]() { touch(); });
}
return container;
}
QWidget* Widget::CreateSpinBox(const QString& given_suffix,
std::function<std::string()>& serializer,
std::function<void()>& restore_func,
const std::function<void()>& touch) {
const int min_val =
setting.Ranged() ? std::stoi(setting.MinVal()) : std::numeric_limits<int>::min();
const int max_val =
setting.Ranged() ? std::stoi(setting.MaxVal()) : std::numeric_limits<int>::max();
const int default_val = std::stoi(setting.ToString());
QString suffix =
given_suffix == QStringLiteral("") ? DefaultSuffix(this, setting) : given_suffix;
spinbox = new QSpinBox(this);
spinbox->setRange(min_val, max_val);
spinbox->setValue(default_val);
spinbox->setSuffix(suffix);
spinbox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
serializer = [this]() { return std::to_string(spinbox->value()); };
restore_func = [this]() {
auto value{std::stol(RelevantDefault(setting))};
spinbox->setValue(value);
};
if (!Settings::IsConfiguringGlobal()) {
QObject::connect(spinbox, QOverload<int>::of(&QSpinBox::valueChanged), [this, touch]() {
if (spinbox->value() != std::stoi(setting.ToStringGlobal())) {
touch();
}
});
}
return spinbox;
}
QWidget* Widget::CreateHexEdit(std::function<std::string()>& serializer,
std::function<void()>& restore_func,
const std::function<void()>& touch) {
auto* data_component = CreateLineEdit(serializer, restore_func, touch, false);
if (data_component == nullptr) {
return nullptr;
}
auto to_hex = [=](const std::string& input) {
return QString::fromStdString(fmt::format("{:08x}", std::stoul(input)));
};
QRegularExpressionValidator* regex = new QRegularExpressionValidator(
QRegularExpression{QStringLiteral("^[0-9a-fA-F]{0,8}$")}, line_edit);
const QString default_val = to_hex(setting.ToString());
line_edit->setText(default_val);
line_edit->setMaxLength(8);
line_edit->setValidator(regex);
auto hex_to_dec = [this]() -> std::string {
return std::to_string(std::stoul(line_edit->text().toStdString(), nullptr, 16));
};
serializer = [hex_to_dec]() { return hex_to_dec(); };
restore_func = [this, to_hex]() { line_edit->setText(to_hex(RelevantDefault(setting))); };
if (!Settings::IsConfiguringGlobal()) {
QObject::connect(line_edit, &QLineEdit::textChanged, [touch]() { touch(); });
}
return line_edit;
}
QWidget* Widget::CreateDateTimeEdit(bool disabled, bool restrict,
std::function<std::string()>& serializer,
std::function<void()>& restore_func,
const std::function<void()>& touch) {
const long long current_time = QDateTime::currentSecsSinceEpoch();
const s64 the_time = disabled ? current_time : std::stoll(setting.ToString());
const auto default_val = QDateTime::fromSecsSinceEpoch(the_time);
date_time_edit = new QDateTimeEdit(this);
date_time_edit->setDateTime(default_val);
date_time_edit->setMinimumDateTime(QDateTime::fromSecsSinceEpoch(0));
date_time_edit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
serializer = [this]() { return std::to_string(date_time_edit->dateTime().toSecsSinceEpoch()); };
auto get_clear_val = [this, restrict, current_time]() {
return QDateTime::fromSecsSinceEpoch([this, restrict, current_time]() {
if (restrict && checkbox->checkState() == Qt::Checked) {
return std::stoll(RelevantDefault(setting));
}
return current_time;
}());
};
restore_func = [this, get_clear_val]() { date_time_edit->setDateTime(get_clear_val()); };
if (!Settings::IsConfiguringGlobal()) {
QObject::connect(date_time_edit, &QDateTimeEdit::editingFinished,
[this, get_clear_val, touch]() {
if (date_time_edit->dateTime() != get_clear_val()) {
touch();
}
});
}
return date_time_edit;
}
void Widget::SetupComponent(const QString& label, std::function<void()>& load_func, bool managed,
RequestType request, float multiplier,
Settings::BasicSetting* other_setting, const QString& suffix) {
created = true;
const auto type = setting.TypeId();
QLayout* layout = new QHBoxLayout(this);
layout->setContentsMargins(0, 0, 0, 0);
if (other_setting == nullptr) {
other_setting = setting.PairedSetting();
}
const bool require_checkbox =
other_setting != nullptr && other_setting->TypeId() == typeid(bool);
if (other_setting != nullptr && other_setting->TypeId() != typeid(bool)) {
LOG_WARNING(
Frontend,
"Extra setting \"{}\" specified but is not bool, refusing to create checkbox for it.",
other_setting->GetLabel());
}
std::function<std::string()> checkbox_serializer = []() -> std::string { return {}; };
std::function<void()> checkbox_restore_func = []() {};
std::function<void()> touch = []() {};
std::function<std::string()> serializer = []() -> std::string { return {}; };
std::function<void()> restore_func = []() {};
QWidget* data_component{nullptr};
request = [&]() {
if (request != RequestType::Default) {
return request;
}
switch (setting.Specialization() & Settings::SpecializationTypeMask) {
case Settings::Specialization::Default:
return RequestType::Default;
case Settings::Specialization::Time:
return RequestType::DateTimeEdit;
case Settings::Specialization::Hex:
return RequestType::HexEdit;
case Settings::Specialization::RuntimeList:
managed = false;
[[fallthrough]];
case Settings::Specialization::List:
return RequestType::ComboBox;
case Settings::Specialization::Scalar:
return RequestType::Slider;
case Settings::Specialization::Countable:
return RequestType::SpinBox;
default:
break;
}
return request;
}();
if (!Settings::IsConfiguringGlobal() && managed) {
restore_button = CreateRestoreGlobalButton(setting.UsingGlobal(), this);
touch = [this]() {
LOG_DEBUG(Frontend, "Enabling custom setting for \"{}\"", setting.GetLabel());
restore_button->setEnabled(true);
restore_button->setVisible(true);
};
}
if (require_checkbox) {
QWidget* lhs =
CreateCheckBox(other_setting, label, checkbox_serializer, checkbox_restore_func, touch);
layout->addWidget(lhs);
} else if (setting.TypeId() != typeid(bool)) {
QLabel* qt_label = CreateLabel(label);
layout->addWidget(qt_label);
}
if (setting.TypeId() == typeid(bool)) {
data_component = CreateCheckBox(&setting, label, serializer, restore_func, touch);
} else if (setting.IsEnum()) {
data_component = CreateCombobox(serializer, restore_func, touch);
} else if (type == typeid(u32) || type == typeid(int) || type == typeid(u16) ||
type == typeid(s64) || type == typeid(u8)) {
switch (request) {
case RequestType::Slider:
case RequestType::ReverseSlider:
data_component = CreateSlider(request == RequestType::ReverseSlider, multiplier, suffix,
serializer, restore_func, touch);
break;
case RequestType::Default:
case RequestType::LineEdit:
data_component = CreateLineEdit(serializer, restore_func, touch);
break;
case RequestType::DateTimeEdit:
data_component = CreateDateTimeEdit(other_setting->ToString() != "true", true,
serializer, restore_func, touch);
break;
case RequestType::SpinBox:
data_component = CreateSpinBox(suffix, serializer, restore_func, touch);
break;
case RequestType::HexEdit:
data_component = CreateHexEdit(serializer, restore_func, touch);
break;
case RequestType::ComboBox:
data_component = CreateCombobox(serializer, restore_func, touch);
break;
default:
UNIMPLEMENTED();
}
} else if (type == typeid(std::string)) {
switch (request) {
case RequestType::Default:
case RequestType::LineEdit:
data_component = CreateLineEdit(serializer, restore_func, touch);
break;
case RequestType::ComboBox:
data_component = CreateCombobox(serializer, restore_func, touch);
break;
default:
UNIMPLEMENTED();
}
}
if (data_component == nullptr) {
LOG_ERROR(Frontend, "Failed to create widget for \"{}\"", setting.GetLabel());
created = false;
return;
}
layout->addWidget(data_component);
if (!managed) {
return;
}
if (Settings::IsConfiguringGlobal()) {
load_func = [this, serializer, checkbox_serializer, require_checkbox, other_setting]() {
if (require_checkbox && other_setting->UsingGlobal()) {
other_setting->LoadString(checkbox_serializer());
}
if (setting.UsingGlobal()) {
setting.LoadString(serializer());
}
};
} else {
layout->addWidget(restore_button);
QObject::connect(restore_button, &QAbstractButton::clicked,
[this, restore_func, checkbox_restore_func](bool) {
LOG_DEBUG(Frontend, "Restore global state for \"{}\"",
setting.GetLabel());
restore_button->setEnabled(false);
restore_button->setVisible(false);
checkbox_restore_func();
restore_func();
});
load_func = [this, serializer, require_checkbox, checkbox_serializer, other_setting]() {
bool using_global = !restore_button->isEnabled();
setting.SetGlobal(using_global);
if (!using_global) {
setting.LoadString(serializer());
}
if (require_checkbox) {
other_setting->SetGlobal(using_global);
if (!using_global) {
other_setting->LoadString(checkbox_serializer());
}
}
};
}
if (other_setting != nullptr) {
const auto reset = [restore_func, data_component](int state) {
data_component->setEnabled(state == Qt::Checked);
if (state != Qt::Checked) {
restore_func();
}
};
connect(checkbox, &QCheckBox::stateChanged, reset);
reset(checkbox->checkState());
}
}
bool Widget::Valid() const {
return created;
}
Widget::~Widget() = default;
Widget::Widget(Settings::BasicSetting* setting_, const TranslationMap& translations_,
const ComboboxTranslationMap& combobox_translations_, QWidget* parent_,
bool runtime_lock_, std::vector<std::function<void(bool)>>& apply_funcs_,
RequestType request, bool managed, float multiplier,
Settings::BasicSetting* other_setting, const QString& suffix)
: QWidget(parent_), parent{parent_}, translations{translations_},
combobox_enumerations{combobox_translations_}, setting{*setting_}, apply_funcs{apply_funcs_},
runtime_lock{runtime_lock_} {
if (!Settings::IsConfiguringGlobal() && !setting.Switchable()) {
LOG_DEBUG(Frontend, "\"{}\" is not switchable, skipping...", setting.GetLabel());
return;
}
const int id = setting.Id();
const auto [label, tooltip] = [&]() {
const auto& setting_label = setting.GetLabel();
if (translations.contains(id)) {
return std::pair{translations.at(id).first, translations.at(id).second};
}
LOG_WARNING(Frontend, "Translation table lacks entry for \"{}\"", setting_label);
return std::pair{QString::fromStdString(setting_label), QStringLiteral("")};
}();
if (label == QStringLiteral("")) {
LOG_DEBUG(Frontend, "Translation table has empty entry for \"{}\", skipping...",
setting.GetLabel());
return;
}
std::function<void()> load_func = []() {};
SetupComponent(label, load_func, managed, request, multiplier, other_setting, suffix);
if (!created) {
LOG_WARNING(Frontend, "No widget was created for \"{}\"", setting.GetLabel());
return;
}
apply_funcs.push_back([load_func, setting_](bool powered_on) {
if (setting_->RuntimeModfiable() || !powered_on) {
load_func();
}
});
bool enable = runtime_lock || setting.RuntimeModfiable();
if (setting.Switchable() && Settings::IsConfiguringGlobal() && !runtime_lock) {
enable &= setting.UsingGlobal();
}
this->setEnabled(enable);
this->setToolTip(tooltip);
}
Builder::Builder(QWidget* parent_, bool runtime_lock_)
: translations{InitializeTranslations(parent_)},
combobox_translations{ComboboxEnumeration(parent_)}, parent{parent_}, runtime_lock{
runtime_lock_} {}
Builder::~Builder() = default;
Widget* Builder::BuildWidget(Settings::BasicSetting* setting,
std::vector<std::function<void(bool)>>& apply_funcs,
RequestType request, bool managed, float multiplier,
Settings::BasicSetting* other_setting, const QString& suffix) const {
if (!Settings::IsConfiguringGlobal() && !setting->Switchable()) {
return nullptr;
}
if (setting->Specialization() == Settings::Specialization::Paired) {
LOG_DEBUG(Frontend, "\"{}\" has specialization Paired: ignoring", setting->GetLabel());
return nullptr;
}
return new Widget(setting, *translations, *combobox_translations, parent, runtime_lock,
apply_funcs, request, managed, multiplier, other_setting, suffix);
}
Widget* Builder::BuildWidget(Settings::BasicSetting* setting,
std::vector<std::function<void(bool)>>& apply_funcs,
Settings::BasicSetting* other_setting, RequestType request,
const QString& suffix) const {
return BuildWidget(setting, apply_funcs, request, true, 1.0f, other_setting, suffix);
}
const ComboboxTranslationMap& Builder::ComboboxTranslations() const {
return *combobox_translations;
}
} // namespace ConfigurationShared

View File

@ -0,0 +1,161 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <functional>
#include <memory>
#include <string>
#include <vector>
#include <QString>
#include <QStringLiteral>
#include <QWidget>
#include <qobjectdefs.h>
#include "yuzu/configuration/shared_translation.h"
class QCheckBox;
class QComboBox;
class QDateTimeEdit;
class QLabel;
class QLineEdit;
class QObject;
class QPushButton;
class QSlider;
class QSpinBox;
namespace Settings {
class BasicSetting;
} // namespace Settings
namespace ConfigurationShared {
enum class RequestType {
Default,
ComboBox,
SpinBox,
Slider,
ReverseSlider,
LineEdit,
HexEdit,
DateTimeEdit,
MaxEnum,
};
class Widget : public QWidget {
Q_OBJECT
public:
/**
* @param setting The primary Setting to create the Widget for
* @param translations Map of translations to display on the left side label/checkbox
* @param combobox_translations Map of translations for enumerating combo boxes
* @param parent Qt parent
* @param runtime_lock Emulated guest powered on state, for use on settings that should be
* configured during guest execution
* @param apply_funcs_ List to append, functions to run to apply the widget state to the setting
* @param request What type of data representation component to create -- not always respected
* for the Setting data type
* @param managed Set true if the caller will set up component data and handling
* @param multiplier Value to multiply the slider feedback label
* @param other_setting Second setting to modify, to replace the label with a checkbox
* @param suffix Set to specify formats for Slider feedback labels or SpinBox
*/
explicit Widget(Settings::BasicSetting* setting, const TranslationMap& translations,
const ComboboxTranslationMap& combobox_translations, QWidget* parent,
bool runtime_lock, std::vector<std::function<void(bool)>>& apply_funcs_,
RequestType request = RequestType::Default, bool managed = true,
float multiplier = 1.0f, Settings::BasicSetting* other_setting = nullptr,
const QString& suffix = QStringLiteral(""));
virtual ~Widget();
/**
* @returns True if the Widget successfully created the components for the setting
*/
bool Valid() const;
/**
* Creates a button to appear when a setting has been modified. This exists for custom
* configurations and wasn't designed to work for the global configuration. It has public access
* for settings that need to be unmanaged but can be custom.
*
* @param using_global The global state of the setting this button is for
* @param parent QWidget parent
*/
[[nodiscard]] static QPushButton* CreateRestoreGlobalButton(bool using_global, QWidget* parent);
// Direct handles to sub components created
QPushButton* restore_button{}; ///< Restore button for custom configurations
QLineEdit* line_edit{}; ///< QLineEdit, used for LineEdit and HexEdit
QSpinBox* spinbox{};
QCheckBox* checkbox{};
QSlider* slider{};
QComboBox* combobox{};
QDateTimeEdit* date_time_edit{};
private:
void SetupComponent(const QString& label, std::function<void()>& load_func, bool managed,
RequestType request, float multiplier,
Settings::BasicSetting* other_setting, const QString& suffix);
QLabel* CreateLabel(const QString& text);
QWidget* CreateCheckBox(Settings::BasicSetting* bool_setting, const QString& label,
std::function<std::string()>& serializer,
std::function<void()>& restore_func,
const std::function<void()>& touch);
QWidget* CreateCombobox(std::function<std::string()>& serializer,
std::function<void()>& restore_func,
const std::function<void()>& touch);
QWidget* CreateLineEdit(std::function<std::string()>& serializer,
std::function<void()>& restore_func, const std::function<void()>& touch,
bool managed = true);
QWidget* CreateHexEdit(std::function<std::string()>& serializer,
std::function<void()>& restore_func, const std::function<void()>& touch);
QWidget* CreateSlider(bool reversed, float multiplier, const QString& suffix,
std::function<std::string()>& serializer,
std::function<void()>& restore_func, const std::function<void()>& touch);
QWidget* CreateDateTimeEdit(bool disabled, bool restrict,
std::function<std::string()>& serializer,
std::function<void()>& restore_func,
const std::function<void()>& touch);
QWidget* CreateSpinBox(const QString& suffix, std::function<std::string()>& serializer,
std::function<void()>& restore_func, const std::function<void()>& touch);
QWidget* parent;
const TranslationMap& translations;
const ComboboxTranslationMap& combobox_enumerations;
Settings::BasicSetting& setting;
std::vector<std::function<void(bool)>>& apply_funcs;
bool created{false};
bool runtime_lock{false};
};
class Builder {
public:
explicit Builder(QWidget* parent, bool runtime_lock);
~Builder();
Widget* BuildWidget(Settings::BasicSetting* setting,
std::vector<std::function<void(bool)>>& apply_funcs,
RequestType request = RequestType::Default, bool managed = true,
float multiplier = 1.0f, Settings::BasicSetting* other_setting = nullptr,
const QString& suffix = QStringLiteral("")) const;
Widget* BuildWidget(Settings::BasicSetting* setting,
std::vector<std::function<void(bool)>>& apply_funcs,
Settings::BasicSetting* other_setting,
RequestType request = RequestType::Default,
const QString& suffix = QStringLiteral("")) const;
const ComboboxTranslationMap& ComboboxTranslations() const;
private:
std::unique_ptr<TranslationMap> translations;
std::unique_ptr<ComboboxTranslationMap> combobox_translations;
QWidget* parent;
const bool runtime_lock;
};
} // namespace ConfigurationShared

View File

@ -24,6 +24,7 @@
#include "applets/qt_software_keyboard.h"
#include "applets/qt_web_browser.h"
#include "common/nvidia_flags.h"
#include "common/settings_enums.h"
#include "configuration/configure_input.h"
#include "configuration/configure_per_game.h"
#include "configuration/configure_tas.h"
@ -1095,10 +1096,9 @@ void GMainWindow::InitializeWidgets() {
aa_status_button->setFocusPolicy(Qt::NoFocus);
connect(aa_status_button, &QPushButton::clicked, [&] {
auto aa_mode = Settings::values.anti_aliasing.GetValue();
if (aa_mode == Settings::AntiAliasing::LastAA) {
aa_mode = static_cast<Settings::AntiAliasing>(static_cast<u32>(aa_mode) + 1);
if (aa_mode == Settings::AntiAliasing::MaxEnum) {
aa_mode = Settings::AntiAliasing::None;
} else {
aa_mode = static_cast<Settings::AntiAliasing>(static_cast<u32>(aa_mode) + 1);
}
Settings::values.anti_aliasing.SetValue(aa_mode);
aa_status_button->setChecked(true);
@ -1183,7 +1183,7 @@ void GMainWindow::InitializeWidgets() {
QMenu context_menu;
for (auto const& gpu_accuracy_pair : Config::gpu_accuracy_texts_map) {
if (gpu_accuracy_pair.first == Settings::GPUAccuracy::Extreme) {
if (gpu_accuracy_pair.first == Settings::GpuAccuracy::Extreme) {
continue;
}
context_menu.addAction(gpu_accuracy_pair.second, [this, gpu_accuracy_pair] {
@ -3651,14 +3651,14 @@ void GMainWindow::OnToggleDockedMode() {
void GMainWindow::OnToggleGpuAccuracy() {
switch (Settings::values.gpu_accuracy.GetValue()) {
case Settings::GPUAccuracy::High: {
Settings::values.gpu_accuracy.SetValue(Settings::GPUAccuracy::Normal);
case Settings::GpuAccuracy::High: {
Settings::values.gpu_accuracy.SetValue(Settings::GpuAccuracy::Normal);
break;
}
case Settings::GPUAccuracy::Normal:
case Settings::GPUAccuracy::Extreme:
case Settings::GpuAccuracy::Normal:
case Settings::GpuAccuracy::Extreme:
default: {
Settings::values.gpu_accuracy.SetValue(Settings::GPUAccuracy::High);
Settings::values.gpu_accuracy.SetValue(Settings::GpuAccuracy::High);
break;
}
}
@ -3702,10 +3702,9 @@ void GMainWindow::OnIncreaseVolume() {
void GMainWindow::OnToggleAdaptingFilter() {
auto filter = Settings::values.scaling_filter.GetValue();
if (filter == Settings::ScalingFilter::LastFilter) {
filter = static_cast<Settings::ScalingFilter>(static_cast<u32>(filter) + 1);
if (filter == Settings::ScalingFilter::MaxEnum) {
filter = Settings::ScalingFilter::NearestNeighbor;
} else {
filter = static_cast<Settings::ScalingFilter>(static_cast<u32>(filter) + 1);
}
Settings::values.scaling_filter.SetValue(filter);
filter_status_button->setChecked(true);
@ -4071,7 +4070,7 @@ void GMainWindow::UpdateGPUAccuracyButton() {
const auto gpu_accuracy = Settings::values.gpu_accuracy.GetValue();
const auto gpu_accuracy_text = Config::gpu_accuracy_texts_map.find(gpu_accuracy)->second;
gpu_accuracy_button->setText(gpu_accuracy_text.toUpper());
gpu_accuracy_button->setChecked(gpu_accuracy != Settings::GPUAccuracy::Normal);
gpu_accuracy_button->setChecked(gpu_accuracy != Settings::GpuAccuracy::Normal);
}
void GMainWindow::UpdateDockedButton() {

View File

@ -34,13 +34,14 @@ DirectConnectWindow::DirectConnectWindow(Core::System& system_, QWidget* parent)
connect(watcher, &QFutureWatcher<void>::finished, this, &DirectConnectWindow::OnConnection);
ui->nickname->setValidator(validation.GetNickname());
ui->nickname->setText(UISettings::values.multiplayer_nickname.GetValue());
ui->nickname->setText(
QString::fromStdString(UISettings::values.multiplayer_nickname.GetValue()));
if (ui->nickname->text().isEmpty() && !Settings::values.yuzu_username.GetValue().empty()) {
// Use yuzu Web Service user name as nickname by default
ui->nickname->setText(QString::fromStdString(Settings::values.yuzu_username.GetValue()));
}
ui->ip->setValidator(validation.GetIP());
ui->ip->setText(UISettings::values.multiplayer_ip.GetValue());
ui->ip->setText(QString::fromStdString(UISettings::values.multiplayer_ip.GetValue()));
ui->port->setValidator(validation.GetPort());
ui->port->setText(QString::number(UISettings::values.multiplayer_port.GetValue()));
@ -91,8 +92,8 @@ void DirectConnectWindow::Connect() {
}
// Store settings
UISettings::values.multiplayer_nickname = ui->nickname->text();
UISettings::values.multiplayer_ip = ui->ip->text();
UISettings::values.multiplayer_nickname = ui->nickname->text().toStdString();
UISettings::values.multiplayer_ip = ui->ip->text().toStdString();
if (ui->port->isModified() && !ui->port->text().isEmpty()) {
UISettings::values.multiplayer_port = ui->port->text().toInt();
} else {

View File

@ -55,12 +55,14 @@ HostRoomWindow::HostRoomWindow(QWidget* parent, QStandardItemModel* list,
connect(ui->host, &QPushButton::clicked, this, &HostRoomWindow::Host);
// Restore the settings:
ui->username->setText(UISettings::values.multiplayer_room_nickname.GetValue());
ui->username->setText(
QString::fromStdString(UISettings::values.multiplayer_room_nickname.GetValue()));
if (ui->username->text().isEmpty() && !Settings::values.yuzu_username.GetValue().empty()) {
// Use yuzu Web Service user name as nickname by default
ui->username->setText(QString::fromStdString(Settings::values.yuzu_username.GetValue()));
}
ui->room_name->setText(UISettings::values.multiplayer_room_name.GetValue());
ui->room_name->setText(
QString::fromStdString(UISettings::values.multiplayer_room_name.GetValue()));
ui->port->setText(QString::number(UISettings::values.multiplayer_room_port.GetValue()));
ui->max_player->setValue(UISettings::values.multiplayer_max_player.GetValue());
int index = UISettings::values.multiplayer_host_type.GetValue();
@ -72,7 +74,8 @@ HostRoomWindow::HostRoomWindow(QWidget* parent, QStandardItemModel* list,
if (index != -1) {
ui->game_list->setCurrentIndex(index);
}
ui->room_description->setText(UISettings::values.multiplayer_room_description.GetValue());
ui->room_description->setText(
QString::fromStdString(UISettings::values.multiplayer_room_description.GetValue()));
}
HostRoomWindow::~HostRoomWindow() = default;
@ -218,8 +221,8 @@ void HostRoomWindow::Host() {
Network::NoPreferredIP, password, token);
// Store settings
UISettings::values.multiplayer_room_nickname = ui->username->text();
UISettings::values.multiplayer_room_name = ui->room_name->text();
UISettings::values.multiplayer_room_nickname = ui->username->text().toStdString();
UISettings::values.multiplayer_room_name = ui->room_name->text().toStdString();
UISettings::values.multiplayer_game_id =
ui->game_list->currentData(GameListItemPath::ProgramIdRole).toLongLong();
UISettings::values.multiplayer_max_player = ui->max_player->value();
@ -230,7 +233,8 @@ void HostRoomWindow::Host() {
} else {
UISettings::values.multiplayer_room_port = Network::DefaultRoomPort;
}
UISettings::values.multiplayer_room_description = ui->room_description->toPlainText();
UISettings::values.multiplayer_room_description =
ui->room_description->toPlainText().toStdString();
ui->host->setEnabled(true);
emit SaveConfig();
close();

View File

@ -60,7 +60,8 @@ Lobby::Lobby(QWidget* parent, QStandardItemModel* list,
ui->room_list->setContextMenuPolicy(Qt::CustomContextMenu);
ui->nickname->setValidator(validation.GetNickname());
ui->nickname->setText(UISettings::values.multiplayer_nickname.GetValue());
ui->nickname->setText(
QString::fromStdString(UISettings::values.multiplayer_nickname.GetValue()));
// Try find the best nickname by default
if (ui->nickname->text().isEmpty() || ui->nickname->text() == QStringLiteral("yuzu")) {
@ -202,9 +203,9 @@ void Lobby::OnJoinRoom(const QModelIndex& source) {
// TODO(jroweboy): disable widgets and display a connecting while we wait
// Save settings
UISettings::values.multiplayer_nickname = ui->nickname->text();
UISettings::values.multiplayer_nickname = ui->nickname->text().toStdString();
UISettings::values.multiplayer_ip =
proxy->data(connection_index, LobbyItemHost::HostIPRole).toString();
proxy->data(connection_index, LobbyItemHost::HostIPRole).value<QString>().toStdString();
UISettings::values.multiplayer_port =
proxy->data(connection_index, LobbyItemHost::HostPortRole).toInt();
emit SaveConfig();

View File

@ -3,6 +3,18 @@
#include "yuzu/uisettings.h"
#ifndef CANNOT_EXPLICITLY_INSTANTIATE
namespace Settings {
template class Setting<bool>;
template class Setting<std::string>;
template class Setting<u16, true>;
template class Setting<u32>;
template class Setting<u8, true>;
template class Setting<u8>;
template class Setting<unsigned long long>;
} // namespace Settings
#endif
namespace UISettings {
const Themes themes{{

View File

@ -14,6 +14,21 @@
#include "common/common_types.h"
#include "common/settings.h"
using Settings::Category;
using Settings::Setting;
#ifndef CANNOT_EXPLICITLY_INSTANTIATE
namespace Settings {
extern template class Setting<bool>;
extern template class Setting<std::string>;
extern template class Setting<u16, true>;
extern template class Setting<u32>;
extern template class Setting<u8, true>;
extern template class Setting<u8>;
extern template class Setting<unsigned long long>;
} // namespace Settings
#endif
namespace UISettings {
bool IsDarkTheme();
@ -56,6 +71,8 @@ struct GameDir {
};
struct Values {
Settings::Linkage linkage{1000};
QByteArray geometry;
QByteArray state;
@ -64,30 +81,54 @@ struct Values {
QByteArray gamelist_header_state;
QByteArray microprofile_geometry;
Settings::Setting<bool> microprofile_visible{false, "microProfileDialogVisible"};
Setting<bool> microprofile_visible{linkage, false, "microProfileDialogVisible",
Category::UiLayout};
Settings::Setting<bool> single_window_mode{true, "singleWindowMode"};
Settings::Setting<bool> fullscreen{false, "fullscreen"};
Settings::Setting<bool> display_titlebar{true, "displayTitleBars"};
Settings::Setting<bool> show_filter_bar{true, "showFilterBar"};
Settings::Setting<bool> show_status_bar{true, "showStatusBar"};
Settings::Setting<bool> confirm_before_closing{true, "confirmClose"};
Settings::Setting<bool> first_start{true, "firstStart"};
Settings::Setting<bool> pause_when_in_background{false, "pauseWhenInBackground"};
Settings::Setting<bool> mute_when_in_background{false, "muteWhenInBackground"};
Settings::Setting<bool> hide_mouse{true, "hideInactiveMouse"};
Settings::Setting<bool> controller_applet_disabled{false, "disableControllerApplet"};
Setting<bool> single_window_mode{linkage, true, "singleWindowMode", Category::Ui};
Setting<bool> fullscreen{linkage, false, "fullscreen", Category::Ui};
Setting<bool> display_titlebar{linkage, true, "displayTitleBars", Category::Ui};
Setting<bool> show_filter_bar{linkage, true, "showFilterBar", Category::Ui};
Setting<bool> show_status_bar{linkage, true, "showStatusBar", Category::Ui};
Setting<bool> confirm_before_closing{
linkage, true, "confirmClose", Category::UiGeneral, Settings::Specialization::Default,
true, true};
Setting<bool> first_start{linkage, true, "firstStart", Category::Ui};
Setting<bool> pause_when_in_background{linkage,
false,
"pauseWhenInBackground",
Category::UiGeneral,
Settings::Specialization::Default,
true,
true};
Setting<bool> mute_when_in_background{
linkage, false, "muteWhenInBackground", Category::Ui, Settings::Specialization::Default,
true, true};
Setting<bool> hide_mouse{
linkage, true, "hideInactiveMouse", Category::UiGeneral, Settings::Specialization::Default,
true, true};
Setting<bool> controller_applet_disabled{linkage, false, "disableControllerApplet",
Category::UiGeneral};
// Set when Vulkan is known to crash the application
bool has_broken_vulkan = false;
Settings::Setting<bool> select_user_on_boot{false, "select_user_on_boot"};
Setting<bool> select_user_on_boot{linkage,
false,
"select_user_on_boot",
Category::UiGeneral,
Settings::Specialization::Default,
true,
true};
Setting<bool> disable_web_applet{linkage, true, "disable_web_applet", Category::Ui};
// Discord RPC
Settings::Setting<bool> enable_discord_presence{true, "enable_discord_presence"};
Setting<bool> enable_discord_presence{linkage, true, "enable_discord_presence", Category::Ui};
Settings::Setting<bool> enable_screenshot_save_as{true, "enable_screenshot_save_as"};
// logging
Setting<bool> show_console{linkage, false, "showConsole", Category::Ui};
Setting<bool> enable_screenshot_save_as{linkage, true, "enable_screenshot_save_as",
Category::Screenshots};
QString roms_path;
QString symbols_path;
@ -102,47 +143,46 @@ struct Values {
// Shortcut name <Shortcut, context>
std::vector<Shortcut> shortcuts;
Settings::Setting<uint32_t> callout_flags{0, "calloutFlags"};
Setting<u32> callout_flags{linkage, 0, "calloutFlags", Category::Ui};
// multiplayer settings
Settings::Setting<QString> multiplayer_nickname{{}, "nickname"};
Settings::Setting<QString> multiplayer_ip{{}, "ip"};
Settings::SwitchableSetting<uint, true> multiplayer_port{24872, 0, UINT16_MAX, "port"};
Settings::Setting<QString> multiplayer_room_nickname{{}, "room_nickname"};
Settings::Setting<QString> multiplayer_room_name{{}, "room_name"};
Settings::SwitchableSetting<uint, true> multiplayer_max_player{8, 0, 8, "max_player"};
Settings::SwitchableSetting<uint, true> multiplayer_room_port{24872, 0, UINT16_MAX,
"room_port"};
Settings::SwitchableSetting<uint, true> multiplayer_host_type{0, 0, 1, "host_type"};
Settings::Setting<qulonglong> multiplayer_game_id{{}, "game_id"};
Settings::Setting<QString> multiplayer_room_description{{}, "room_description"};
Setting<std::string> multiplayer_nickname{linkage, {}, "nickname", Category::Multiplayer};
Setting<std::string> multiplayer_ip{linkage, {}, "ip", Category::Multiplayer};
Setting<u16, true> multiplayer_port{linkage, 24872, 0,
UINT16_MAX, "port", Category::Multiplayer};
Setting<std::string> multiplayer_room_nickname{
linkage, {}, "room_nickname", Category::Multiplayer};
Setting<std::string> multiplayer_room_name{linkage, {}, "room_name", Category::Multiplayer};
Setting<u8, true> multiplayer_max_player{linkage, 8, 0, 8, "max_player", Category::Multiplayer};
Setting<u16, true> multiplayer_room_port{linkage, 24872, 0,
UINT16_MAX, "room_port", Category::Multiplayer};
Setting<u8, true> multiplayer_host_type{linkage, 0, 0, 1, "host_type", Category::Multiplayer};
Setting<unsigned long long> multiplayer_game_id{linkage, {}, "game_id", Category::Multiplayer};
Setting<std::string> multiplayer_room_description{
linkage, {}, "room_description", Category::Multiplayer};
std::pair<std::vector<std::string>, std::vector<std::string>> multiplayer_ban_list;
// logging
Settings::Setting<bool> show_console{false, "showConsole"};
// Game List
Settings::Setting<bool> show_add_ons{true, "show_add_ons"};
Settings::Setting<uint32_t> game_icon_size{64, "game_icon_size"};
Settings::Setting<uint32_t> folder_icon_size{48, "folder_icon_size"};
Settings::Setting<uint8_t> row_1_text_id{3, "row_1_text_id"};
Settings::Setting<uint8_t> row_2_text_id{2, "row_2_text_id"};
Setting<bool> show_add_ons{linkage, true, "show_add_ons", Category::UiGameList};
Setting<u32> game_icon_size{linkage, 64, "game_icon_size", Category::UiGameList};
Setting<u32> folder_icon_size{linkage, 48, "folder_icon_size", Category::UiGameList};
Setting<u8> row_1_text_id{linkage, 3, "row_1_text_id", Category::UiGameList};
Setting<u8> row_2_text_id{linkage, 2, "row_2_text_id", Category::UiGameList};
std::atomic_bool is_game_list_reload_pending{false};
Settings::Setting<bool> cache_game_list{true, "cache_game_list"};
Settings::Setting<bool> favorites_expanded{true, "favorites_expanded"};
Setting<bool> cache_game_list{linkage, true, "cache_game_list", Category::UiGameList};
Setting<bool> favorites_expanded{linkage, true, "favorites_expanded", Category::UiGameList};
QVector<u64> favorited_ids;
// Compatibility List
Settings::Setting<bool> show_compat{false, "show_compat"};
Setting<bool> show_compat{linkage, false, "show_compat", Category::UiGameList};
// Size & File Types Column
Settings::Setting<bool> show_size{true, "show_size"};
Settings::Setting<bool> show_types{true, "show_types"};
Setting<bool> show_size{linkage, true, "show_size", Category::UiGameList};
Setting<bool> show_types{linkage, true, "show_types", Category::UiGameList};
bool configuration_applied;
bool reset_to_defaults;
bool shortcut_already_warned{false};
Settings::Setting<bool> disable_web_applet{true, "disable_web_applet"};
};
extern Values values;