diff options
Diffstat (limited to 'src/yuzu')
44 files changed, 761 insertions, 395 deletions
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 634fe66a5..cb4bdcc7e 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -15,18 +15,19 @@ add_executable(yuzu about_dialog.cpp about_dialog.h aboutdialog.ui - applets/controller.cpp - applets/controller.h - applets/controller.ui - applets/error.cpp - applets/error.h - applets/profile_select.cpp - applets/profile_select.h - applets/software_keyboard.cpp - applets/software_keyboard.h - applets/software_keyboard.ui - applets/web_browser.cpp - applets/web_browser.h + applets/qt_controller.cpp + applets/qt_controller.h + applets/qt_controller.ui + applets/qt_error.cpp + applets/qt_error.h + applets/qt_profile_select.cpp + applets/qt_profile_select.h + applets/qt_software_keyboard.cpp + applets/qt_software_keyboard.h + applets/qt_software_keyboard.ui + applets/qt_web_browser.cpp + applets/qt_web_browser.h + applets/qt_web_browser_scripts.h bootmanager.cpp bootmanager.h compatdb.ui @@ -52,6 +53,9 @@ add_executable(yuzu configuration/configure_debug_controller.cpp configuration/configure_debug_controller.h configuration/configure_debug_controller.ui + configuration/configure_debug_tab.cpp + configuration/configure_debug_tab.h + configuration/configure_debug_tab.ui configuration/configure_dialog.cpp configuration/configure_dialog.h configuration/configure_filesystem.cpp diff --git a/src/yuzu/applets/controller.cpp b/src/yuzu/applets/qt_controller.cpp index 836d90fda..97106d2cc 100644 --- a/src/yuzu/applets/controller.cpp +++ b/src/yuzu/applets/qt_controller.cpp @@ -12,8 +12,8 @@ #include "core/hle/service/hid/controllers/npad.h" #include "core/hle/service/hid/hid.h" #include "core/hle/service/sm/sm.h" -#include "ui_controller.h" -#include "yuzu/applets/controller.h" +#include "ui_qt_controller.h" +#include "yuzu/applets/qt_controller.h" #include "yuzu/configuration/configure_input.h" #include "yuzu/configuration/configure_input_profile_dialog.h" #include "yuzu/configuration/configure_motion_touch.h" diff --git a/src/yuzu/applets/controller.h b/src/yuzu/applets/qt_controller.h index 9b57aea1a..9b57aea1a 100644 --- a/src/yuzu/applets/controller.h +++ b/src/yuzu/applets/qt_controller.h diff --git a/src/yuzu/applets/controller.ui b/src/yuzu/applets/qt_controller.ui index c8cb6bcf3..c8cb6bcf3 100644 --- a/src/yuzu/applets/controller.ui +++ b/src/yuzu/applets/qt_controller.ui diff --git a/src/yuzu/applets/error.cpp b/src/yuzu/applets/qt_error.cpp index 085688cd4..45cf64603 100644 --- a/src/yuzu/applets/error.cpp +++ b/src/yuzu/applets/qt_error.cpp @@ -4,7 +4,7 @@ #include <QDateTime> #include "core/hle/lock.h" -#include "yuzu/applets/error.h" +#include "yuzu/applets/qt_error.h" #include "yuzu/main.h" QtErrorDisplay::QtErrorDisplay(GMainWindow& parent) { diff --git a/src/yuzu/applets/error.h b/src/yuzu/applets/qt_error.h index 8bd895a32..8bd895a32 100644 --- a/src/yuzu/applets/error.h +++ b/src/yuzu/applets/qt_error.h diff --git a/src/yuzu/applets/profile_select.cpp b/src/yuzu/applets/qt_profile_select.cpp index 62fd1141c..a56638e21 100644 --- a/src/yuzu/applets/profile_select.cpp +++ b/src/yuzu/applets/qt_profile_select.cpp @@ -14,7 +14,7 @@ #include "common/string_util.h" #include "core/constants.h" #include "core/hle/lock.h" -#include "yuzu/applets/profile_select.h" +#include "yuzu/applets/qt_profile_select.h" #include "yuzu/main.h" namespace { diff --git a/src/yuzu/applets/profile_select.h b/src/yuzu/applets/qt_profile_select.h index 4e9037488..4e9037488 100644 --- a/src/yuzu/applets/profile_select.h +++ b/src/yuzu/applets/qt_profile_select.h diff --git a/src/yuzu/applets/software_keyboard.cpp b/src/yuzu/applets/qt_software_keyboard.cpp index aa453a79f..848801cec 100644 --- a/src/yuzu/applets/software_keyboard.cpp +++ b/src/yuzu/applets/qt_software_keyboard.cpp @@ -11,8 +11,8 @@ #include "common/string_util.h" #include "core/core.h" #include "core/frontend/input_interpreter.h" -#include "ui_software_keyboard.h" -#include "yuzu/applets/software_keyboard.h" +#include "ui_qt_software_keyboard.h" +#include "yuzu/applets/qt_software_keyboard.h" #include "yuzu/main.h" #include "yuzu/util/overlay_dialog.h" diff --git a/src/yuzu/applets/software_keyboard.h b/src/yuzu/applets/qt_software_keyboard.h index 1a03c098c..1a03c098c 100644 --- a/src/yuzu/applets/software_keyboard.h +++ b/src/yuzu/applets/qt_software_keyboard.h diff --git a/src/yuzu/applets/software_keyboard.ui b/src/yuzu/applets/qt_software_keyboard.ui index b0a1fcde9..b0a1fcde9 100644 --- a/src/yuzu/applets/software_keyboard.ui +++ b/src/yuzu/applets/qt_software_keyboard.ui diff --git a/src/yuzu/applets/web_browser.cpp b/src/yuzu/applets/qt_web_browser.cpp index 34d3feb55..b112dd7b0 100644 --- a/src/yuzu/applets/web_browser.cpp +++ b/src/yuzu/applets/qt_web_browser.cpp @@ -17,8 +17,8 @@ #include "core/frontend/input_interpreter.h" #include "input_common/keyboard.h" #include "input_common/main.h" -#include "yuzu/applets/web_browser.h" -#include "yuzu/applets/web_browser_scripts.h" +#include "yuzu/applets/qt_web_browser.h" +#include "yuzu/applets/qt_web_browser_scripts.h" #include "yuzu/main.h" #include "yuzu/util/url_request_interceptor.h" diff --git a/src/yuzu/applets/web_browser.h b/src/yuzu/applets/qt_web_browser.h index 7ad07409f..7ad07409f 100644 --- a/src/yuzu/applets/web_browser.h +++ b/src/yuzu/applets/qt_web_browser.h diff --git a/src/yuzu/applets/web_browser_scripts.h b/src/yuzu/applets/qt_web_browser_scripts.h index 992837a85..992837a85 100644 --- a/src/yuzu/applets/web_browser_scripts.h +++ b/src/yuzu/applets/qt_web_browser_scripts.h diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 7524e3c40..25b658b2a 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -64,12 +64,13 @@ void EmuThread::run() { emit LoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0); - system.Renderer().ReadRasterizer()->LoadDiskResources( - system.CurrentProcess()->GetTitleID(), stop_token, - [this](VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total) { - emit LoadProgress(stage, value, total); - }); - + if (Settings::values.use_disk_shader_cache.GetValue()) { + system.Renderer().ReadRasterizer()->LoadDiskResources( + system.CurrentProcess()->GetTitleID(), stop_token, + [this](VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total) { + emit LoadProgress(stage, value, total); + }); + } emit LoadProgress(VideoCore::LoadCallbackStage::Complete, 0, 0); gpu.ReleaseContext(); @@ -411,8 +412,9 @@ void GRenderWindow::mousePressEvent(QMouseEvent* event) { if (event->source() == Qt::MouseEventSynthesizedBySystem) { return; } - - auto pos = event->pos(); + // Qt sometimes returns the parent coordinates. To avoid this we read the global mouse + // coordinates and map them to the current render area + const auto pos = mapFromGlobal(QCursor::pos()); const auto [x, y] = ScaleTouch(pos); const auto button = QtButtonToMouseButton(event->button()); input_subsystem->GetMouse()->PressButton(x, y, button); @@ -429,7 +431,9 @@ void GRenderWindow::mouseMoveEvent(QMouseEvent* event) { if (event->source() == Qt::MouseEventSynthesizedBySystem) { return; } - auto pos = event->pos(); + // Qt sometimes returns the parent coordinates. To avoid this we read the global mouse + // coordinates and map them to the current render area + const auto pos = mapFromGlobal(QCursor::pos()); const auto [x, y] = ScaleTouch(pos); const int center_x = width() / 2; const int center_y = height() / 2; @@ -564,6 +568,12 @@ std::unique_ptr<Core::Frontend::GraphicsContext> GRenderWindow::CreateSharedCont bool GRenderWindow::InitRenderTarget() { ReleaseRenderTarget(); + { + // Create a dummy render widget so that Qt + // places the render window at the correct position. + const RenderWidget dummy_widget{this}; + } + first_frame = false; switch (Settings::values.renderer_backend.GetValue()) { diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 1a0f75373..52b3ed02e 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -311,16 +311,6 @@ void Config::WriteBasicSetting(const Settings::BasicSetting<std::string>& settin qt_config->setValue(name, QString::fromStdString(value)); } -// Explicit float definition: use a double as Qt doesn't write legible floats to config files -template <> -void Config::WriteBasicSetting(const Settings::BasicSetting<float>& setting) { - const QString name = QString::fromStdString(setting.GetLabel()); - const double value = setting.GetValue(); - qt_config->setValue(name + QStringLiteral("/default"), - setting.GetValue() == setting.GetDefault()); - qt_config->setValue(name, value); -} - template <typename Type> void Config::WriteBasicSetting(const Settings::BasicSetting<Type>& setting) { const QString name = QString::fromStdString(setting.GetLabel()); @@ -329,21 +319,6 @@ void Config::WriteBasicSetting(const Settings::BasicSetting<Type>& setting) { qt_config->setValue(name, value); } -// Explicit float definition: use a double as Qt doesn't write legible floats to config files -template <> -void Config::WriteGlobalSetting(const Settings::Setting<float>& setting) { - const QString name = QString::fromStdString(setting.GetLabel()); - const double value = setting.GetValue(global); - if (!global) { - qt_config->setValue(name + QStringLiteral("/use_global"), setting.UsingGlobal()); - } - if (global || !setting.UsingGlobal()) { - qt_config->setValue(name + QStringLiteral("/default"), - setting.GetValue(global) == setting.GetDefault()); - qt_config->setValue(name, value); - } -} - template <typename Type> void Config::WriteGlobalSetting(const Settings::Setting<Type>& setting) { const QString name = QString::fromStdString(setting.GetLabel()); @@ -793,7 +768,13 @@ void Config::ReadPathValues() { void Config::ReadCpuValues() { qt_config->beginGroup(QStringLiteral("Cpu")); - ReadGlobalSetting(Settings::values.cpu_accuracy); + ReadBasicSetting(Settings::values.cpu_accuracy_first_time); + if (Settings::values.cpu_accuracy_first_time) { + Settings::values.cpu_accuracy.SetValue(Settings::values.cpu_accuracy.GetDefault()); + Settings::values.cpu_accuracy_first_time.SetValue(false); + } else { + ReadGlobalSetting(Settings::values.cpu_accuracy); + } ReadGlobalSetting(Settings::values.cpuopt_unsafe_unfuse_fma); ReadGlobalSetting(Settings::values.cpuopt_unsafe_reduce_fp_error); @@ -802,6 +783,7 @@ void Config::ReadCpuValues() { ReadGlobalSetting(Settings::values.cpuopt_unsafe_fastmem_check); if (global) { + ReadBasicSetting(Settings::values.cpu_debug_mode); ReadBasicSetting(Settings::values.cpuopt_page_tables); ReadBasicSetting(Settings::values.cpuopt_block_linking); ReadBasicSetting(Settings::values.cpuopt_return_stack_buffer); @@ -820,7 +802,6 @@ void Config::ReadRendererValues() { qt_config->beginGroup(QStringLiteral("Renderer")); ReadGlobalSetting(Settings::values.renderer_backend); - ReadBasicSetting(Settings::values.renderer_debug); ReadGlobalSetting(Settings::values.vulkan_device); ReadGlobalSetting(Settings::values.fullscreen_mode); ReadGlobalSetting(Settings::values.aspect_ratio); @@ -833,8 +814,7 @@ void Config::ReadRendererValues() { ReadGlobalSetting(Settings::values.use_nvdec_emulation); ReadGlobalSetting(Settings::values.accelerate_astc); ReadGlobalSetting(Settings::values.use_vsync); - ReadGlobalSetting(Settings::values.disable_fps_limit); - ReadGlobalSetting(Settings::values.use_assembly_shaders); + ReadGlobalSetting(Settings::values.shader_backend); ReadGlobalSetting(Settings::values.use_asynchronous_shaders); ReadGlobalSetting(Settings::values.use_fast_gpu_time); ReadGlobalSetting(Settings::values.use_caches_gc); @@ -842,6 +822,12 @@ void Config::ReadRendererValues() { ReadGlobalSetting(Settings::values.bg_green); ReadGlobalSetting(Settings::values.bg_blue); + if (global) { + ReadBasicSetting(Settings::values.renderer_debug); + ReadBasicSetting(Settings::values.enable_nsight_aftermath); + ReadBasicSetting(Settings::values.disable_shader_loop_safety_checks); + } + qt_config->endGroup(); } @@ -1309,6 +1295,7 @@ void Config::SavePathValues() { void Config::SaveCpuValues() { qt_config->beginGroup(QStringLiteral("Cpu")); + WriteBasicSetting(Settings::values.cpu_accuracy_first_time); WriteSetting(QStringLiteral("cpu_accuracy"), static_cast<u32>(Settings::values.cpu_accuracy.GetValue(global)), static_cast<u32>(Settings::values.cpu_accuracy.GetDefault()), @@ -1321,6 +1308,7 @@ void Config::SaveCpuValues() { WriteGlobalSetting(Settings::values.cpuopt_unsafe_fastmem_check); if (global) { + WriteBasicSetting(Settings::values.cpu_debug_mode); WriteBasicSetting(Settings::values.cpuopt_page_tables); WriteBasicSetting(Settings::values.cpuopt_block_linking); WriteBasicSetting(Settings::values.cpuopt_return_stack_buffer); @@ -1342,7 +1330,6 @@ void Config::SaveRendererValues() { static_cast<u32>(Settings::values.renderer_backend.GetValue(global)), static_cast<u32>(Settings::values.renderer_backend.GetDefault()), Settings::values.renderer_backend.UsingGlobal()); - WriteBasicSetting(Settings::values.renderer_debug); WriteGlobalSetting(Settings::values.vulkan_device); WriteGlobalSetting(Settings::values.fullscreen_mode); WriteGlobalSetting(Settings::values.aspect_ratio); @@ -1358,8 +1345,10 @@ void Config::SaveRendererValues() { WriteGlobalSetting(Settings::values.use_nvdec_emulation); WriteGlobalSetting(Settings::values.accelerate_astc); WriteGlobalSetting(Settings::values.use_vsync); - WriteGlobalSetting(Settings::values.disable_fps_limit); - WriteGlobalSetting(Settings::values.use_assembly_shaders); + WriteSetting(QString::fromStdString(Settings::values.shader_backend.GetLabel()), + static_cast<u32>(Settings::values.shader_backend.GetValue(global)), + static_cast<u32>(Settings::values.shader_backend.GetDefault()), + Settings::values.shader_backend.UsingGlobal()); WriteGlobalSetting(Settings::values.use_asynchronous_shaders); WriteGlobalSetting(Settings::values.use_fast_gpu_time); WriteGlobalSetting(Settings::values.use_caches_gc); @@ -1367,6 +1356,12 @@ void Config::SaveRendererValues() { WriteGlobalSetting(Settings::values.bg_green); WriteGlobalSetting(Settings::values.bg_blue); + if (global) { + WriteBasicSetting(Settings::values.renderer_debug); + WriteBasicSetting(Settings::values.enable_nsight_aftermath); + WriteBasicSetting(Settings::values.disable_shader_loop_safety_checks); + } + qt_config->endGroup(); } diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h index 96f9b6de1..4bbb9f1cd 100644 --- a/src/yuzu/configuration/config.h +++ b/src/yuzu/configuration/config.h @@ -180,5 +180,6 @@ private: // These metatype declarations cannot be in common/settings.h because core is devoid of QT Q_DECLARE_METATYPE(Settings::CPUAccuracy); -Q_DECLARE_METATYPE(Settings::RendererBackend); Q_DECLARE_METATYPE(Settings::GPUAccuracy); +Q_DECLARE_METATYPE(Settings::RendererBackend); +Q_DECLARE_METATYPE(Settings::ShaderBackend); diff --git a/src/yuzu/configuration/configure.ui b/src/yuzu/configuration/configure.ui index f92c3aff3..fca9aed5f 100644 --- a/src/yuzu/configuration/configure.ui +++ b/src/yuzu/configuration/configure.ui @@ -41,7 +41,7 @@ <item> <widget class="QTabWidget" name="tabWidget"> <property name="currentIndex"> - <number>0</number> + <number>11</number> </property> <widget class="ConfigureGeneral" name="generalTab"> <property name="accessibleName"> @@ -107,14 +107,6 @@ <string>CPU</string> </attribute> </widget> - <widget class="ConfigureCpuDebug" name="cpuDebugTab"> - <property name="accessibleName"> - <string>Debug</string> - </property> - <attribute name="title"> - <string>Debug</string> - </attribute> - </widget> <widget class="ConfigureGraphics" name="graphicsTab"> <property name="accessibleName"> <string>Graphics</string> @@ -139,7 +131,7 @@ <string>Audio</string> </attribute> </widget> - <widget class="ConfigureDebug" name="debugTab"> + <widget class="ConfigureDebugTab" name="debugTab"> <property name="accessibleName"> <string>Debug</string> </property> @@ -208,24 +200,12 @@ <container>1</container> </customwidget> <customwidget> - <class>ConfigureDebug</class> - <extends>QWidget</extends> - <header>configuration/configure_debug.h</header> - <container>1</container> - </customwidget> - <customwidget> <class>ConfigureCpu</class> <extends>QWidget</extends> <header>configuration/configure_cpu.h</header> <container>1</container> </customwidget> <customwidget> - <class>ConfigureCpuDebug</class> - <extends>QWidget</extends> - <header>configuration/configure_cpu_debug.h</header> - <container>1</container> - </customwidget> - <customwidget> <class>ConfigureGraphics</class> <extends>QWidget</extends> <header>configuration/configure_graphics.h</header> @@ -267,6 +247,12 @@ <header>configuration/configure_service.h</header> <container>1</container> </customwidget> + <customwidget> + <class>ConfigureDebugTab</class> + <extends>QWidget</extends> + <header>configuration/configure_debug_tab.h</header> + <container>1</container> + </customwidget> </customwidgets> <resources/> <connections> @@ -275,12 +261,32 @@ <signal>accepted()</signal> <receiver>ConfigureDialog</receiver> <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>20</x> + <y>20</y> + </hint> + <hint type="destinationlabel"> + <x>20</x> + <y>20</y> + </hint> + </hints> </connection> <connection> <sender>buttonBox</sender> <signal>rejected()</signal> <receiver>ConfigureDialog</receiver> <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>20</x> + <y>20</y> + </hint> + <hint type="destinationlabel"> + <x>20</x> + <y>20</y> + </hint> + </hints> </connection> </connections> </ui> diff --git a/src/yuzu/configuration/configure_audio.cpp b/src/yuzu/configuration/configure_audio.cpp index 5aba1a3b2..1d84bf4ed 100644 --- a/src/yuzu/configuration/configure_audio.cpp +++ b/src/yuzu/configuration/configure_audio.cpp @@ -47,7 +47,8 @@ void ConfigureAudio::SetConfiguration() { SetAudioDeviceFromDeviceID(); - ui->volume_slider->setValue(Settings::values.volume.GetValue() * ui->volume_slider->maximum()); + const auto volume_value = static_cast<int>(Settings::values.volume.GetValue()); + ui->volume_slider->setValue(volume_value); ui->toggle_audio_stretching->setChecked(Settings::values.enable_audio_stretching.GetValue()); @@ -112,18 +113,16 @@ void ConfigureAudio::ApplyConfiguration() { // Guard if during game and set to game-specific value if (Settings::values.volume.UsingGlobal()) { - Settings::values.volume.SetValue( - static_cast<float>(ui->volume_slider->sliderPosition()) / - ui->volume_slider->maximum()); + 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); - Settings::values.volume.SetValue( - static_cast<float>(ui->volume_slider->sliderPosition()) / - ui->volume_slider->maximum()); + const auto volume = static_cast<u8>(ui->volume_slider->value()); + Settings::values.volume.SetValue(volume); } } } diff --git a/src/yuzu/configuration/configure_cpu.cpp b/src/yuzu/configuration/configure_cpu.cpp index 13db2ba98..8d7171487 100644 --- a/src/yuzu/configuration/configure_cpu.cpp +++ b/src/yuzu/configuration/configure_cpu.cpp @@ -20,8 +20,6 @@ ConfigureCpu::ConfigureCpu(QWidget* parent) : QWidget(parent), ui(new Ui::Config SetConfiguration(); - connect(ui->accuracy, qOverload<int>(&QComboBox::activated), this, - &ConfigureCpu::AccuracyUpdated); connect(ui->accuracy, qOverload<int>(&QComboBox::currentIndexChanged), this, &ConfigureCpu::UpdateGroup); } @@ -58,20 +56,6 @@ void ConfigureCpu::SetConfiguration() { UpdateGroup(ui->accuracy->currentIndex()); } -void ConfigureCpu::AccuracyUpdated(int index) { - if (Settings::IsConfiguringGlobal() && - static_cast<Settings::CPUAccuracy>(index) == Settings::CPUAccuracy::DebugMode) { - const auto result = QMessageBox::warning(this, tr("Setting CPU to Debug Mode"), - tr("CPU Debug Mode is only intended for developer " - "use. Are you sure you want to enable this?"), - QMessageBox::Yes | QMessageBox::No); - if (result == QMessageBox::No) { - ui->accuracy->setCurrentIndex(static_cast<int>(Settings::CPUAccuracy::Accurate)); - UpdateGroup(static_cast<int>(Settings::CPUAccuracy::Accurate)); - } - } -} - void ConfigureCpu::UpdateGroup(int index) { if (!Settings::IsConfiguringGlobal()) { index -= ConfigurationShared::USE_GLOBAL_OFFSET; @@ -134,8 +118,6 @@ void ConfigureCpu::SetupPerGameUI() { ConfigurationShared::SetColoredComboBox( ui->accuracy, ui->widget_accuracy, static_cast<u32>(Settings::values.cpu_accuracy.GetValue(true))); - ui->accuracy->removeItem(static_cast<u32>(Settings::CPUAccuracy::DebugMode) + - ConfigurationShared::USE_GLOBAL_OFFSET); ConfigurationShared::SetColoredTristate(ui->cpuopt_unsafe_unfuse_fma, Settings::values.cpuopt_unsafe_unfuse_fma, diff --git a/src/yuzu/configuration/configure_cpu.h b/src/yuzu/configuration/configure_cpu.h index b2b5f1671..154931482 100644 --- a/src/yuzu/configuration/configure_cpu.h +++ b/src/yuzu/configuration/configure_cpu.h @@ -29,7 +29,6 @@ private: void changeEvent(QEvent* event) override; void RetranslateUI(); - void AccuracyUpdated(int index); void UpdateGroup(int index); void SetConfiguration(); diff --git a/src/yuzu/configuration/configure_cpu.ui b/src/yuzu/configuration/configure_cpu.ui index 0e296d4e5..5b9457faf 100644 --- a/src/yuzu/configuration/configure_cpu.ui +++ b/src/yuzu/configuration/configure_cpu.ui @@ -6,8 +6,8 @@ <rect> <x>0</x> <y>0</y> - <width>400</width> - <height>321</height> + <width>448</width> + <height>433</height> </rect> </property> <property name="windowTitle"> @@ -17,7 +17,7 @@ <item> <layout class="QVBoxLayout"> <item> - <widget class="QGroupBox"> + <widget class="QGroupBox" name="groupBox"> <property name="title"> <string>General</string> </property> @@ -36,17 +36,17 @@ <widget class="QComboBox" name="accuracy"> <item> <property name="text"> - <string>Accurate</string> + <string>Auto</string> </property> </item> <item> <property name="text"> - <string>Unsafe</string> + <string>Accurate</string> </property> </item> <item> <property name="text"> - <string>Enable Debug Mode</string> + <string>Unsafe</string> </property> </item> </widget> @@ -57,7 +57,7 @@ <item> <widget class="QLabel" name="label_recommended_accuracy"> <property name="text"> - <string>We recommend setting accuracy to "Accurate".</string> + <string>We recommend setting accuracy to "Auto".</string> </property> <property name="wordWrap"> <bool>false</bool> diff --git a/src/yuzu/configuration/configure_cpu_debug.h b/src/yuzu/configuration/configure_cpu_debug.h index 10de55099..1b0d8050c 100644 --- a/src/yuzu/configuration/configure_cpu_debug.h +++ b/src/yuzu/configuration/configure_cpu_debug.h @@ -6,7 +6,6 @@ #include <memory> #include <QWidget> -#include "common/settings.h" namespace Ui { class ConfigureCpuDebug; diff --git a/src/yuzu/configuration/configure_cpu_debug.ui b/src/yuzu/configuration/configure_cpu_debug.ui index c43f89a5a..abf469b55 100644 --- a/src/yuzu/configuration/configure_cpu_debug.ui +++ b/src/yuzu/configuration/configure_cpu_debug.ui @@ -6,8 +6,8 @@ <rect> <x>0</x> <y>0</y> - <width>400</width> - <height>321</height> + <width>592</width> + <height>503</height> </rect> </property> <property name="windowTitle"> @@ -17,140 +17,132 @@ <item> <layout class="QVBoxLayout"> <item> - <widget class="QGroupBox"> + <widget class="QGroupBox" name="groupBox"> <property name="title"> <string>Toggle CPU Optimizations</string> </property> <layout class="QVBoxLayout"> <item> - <widget class="QLabel"> - <property name="wordWrap"> - <bool>1</bool> - </property> + <widget class="QLabel" name="label"> <property name="text"> - <string> - <div> - <b>For debugging only.</b> - <br> - If you're not sure what these do, keep all of these enabled. - <br> - These settings, when disabled, only take effect when CPU Accuracy is "Debug Mode". - </div> - </string> + <string><html><head/><body><p><span style=" font-weight:600;">For debugging only.</span><br/>If you're not sure what these do, keep all of these enabled. <br/>These settings, when disabled, only take effect when CPU Debugging is enabled. </p></body></html></string> + </property> + <property name="wordWrap"> + <bool>false</bool> </property> </widget> </item> <item> <widget class="QCheckBox" name="cpuopt_page_tables"> - <property name="text"> - <string>Enable inline page tables</string> - </property> <property name="toolTip"> <string> - <div style="white-space: nowrap">This optimization speeds up memory accesses by the guest program.</div> - <div style="white-space: nowrap">Enabling it inlines accesses to PageTable::pointers into emitted code.</div> - <div style="white-space: nowrap">Disabling this forces all memory accesses to go through the Memory::Read/Memory::Write functions.</div> + <div style="white-space: nowrap">This optimization speeds up memory accesses by the guest program.</div> + <div style="white-space: nowrap">Enabling it inlines accesses to PageTable::pointers into emitted code.</div> + <div style="white-space: nowrap">Disabling this forces all memory accesses to go through the Memory::Read/Memory::Write functions.</div> </string> </property> + <property name="text"> + <string>Enable inline page tables</string> + </property> </widget> </item> <item> <widget class="QCheckBox" name="cpuopt_block_linking"> - <property name="text"> - <string>Enable block linking</string> - </property> <property name="toolTip"> <string> <div>This optimization avoids dispatcher lookups by allowing emitted basic blocks to jump directly to other basic blocks if the destination PC is static.</div> </string> </property> + <property name="text"> + <string>Enable block linking</string> + </property> </widget> </item> <item> <widget class="QCheckBox" name="cpuopt_return_stack_buffer"> - <property name="text"> - <string>Enable return stack buffer</string> - </property> <property name="toolTip"> <string> <div>This optimization avoids dispatcher lookups by keeping track potential return addresses of BL instructions. This approximates what happens with a return stack buffer on a real CPU.</div> </string> </property> + <property name="text"> + <string>Enable return stack buffer</string> + </property> </widget> </item> <item> <widget class="QCheckBox" name="cpuopt_fast_dispatcher"> - <property name="text"> - <string>Enable fast dispatcher</string> - </property> <property name="toolTip"> <string> <div>Enable a two-tiered dispatch system. A faster dispatcher written in assembly has a small MRU cache of jump destinations is used first. If that fails, dispatch falls back to the slower C++ dispatcher.</div> </string> </property> + <property name="text"> + <string>Enable fast dispatcher</string> + </property> </widget> </item> <item> <widget class="QCheckBox" name="cpuopt_context_elimination"> - <property name="text"> - <string>Enable context elimination</string> - </property> <property name="toolTip"> <string> <div>Enables an IR optimization that reduces unnecessary accesses to the CPU context structure.</div> </string> </property> + <property name="text"> + <string>Enable context elimination</string> + </property> </widget> </item> <item> <widget class="QCheckBox" name="cpuopt_const_prop"> - <property name="text"> - <string>Enable constant propagation</string> - </property> <property name="toolTip"> <string> <div>Enables IR optimizations that involve constant propagation.</div> </string> </property> + <property name="text"> + <string>Enable constant propagation</string> + </property> </widget> </item> <item> <widget class="QCheckBox" name="cpuopt_misc_ir"> - <property name="text"> - <string>Enable miscellaneous optimizations</string> - </property> <property name="toolTip"> <string> <div>Enables miscellaneous IR optimizations.</div> </string> </property> + <property name="text"> + <string>Enable miscellaneous optimizations</string> + </property> </widget> </item> <item> <widget class="QCheckBox" name="cpuopt_reduce_misalign_checks"> - <property name="text"> - <string>Enable misalignment check reduction</string> - </property> <property name="toolTip"> <string> - <div style="white-space: nowrap">When enabled, a misalignment is only triggered when an access crosses a page boundary.</div> - <div style="white-space: nowrap">When disabled, a misalignment is triggered on all misaligned accesses.</div> + <div style="white-space: nowrap">When enabled, a misalignment is only triggered when an access crosses a page boundary.</div> + <div style="white-space: nowrap">When disabled, a misalignment is triggered on all misaligned accesses.</div> </string> </property> + <property name="text"> + <string>Enable misalignment check reduction</string> + </property> </widget> </item> <item> <widget class="QCheckBox" name="cpuopt_fastmem"> - <property name="text"> - <string>Enable Host MMU Emulation</string> - </property> <property name="toolTip"> <string> - <div style="white-space: nowrap">This optimization speeds up memory accesses by the guest program.</div> - <div style="white-space: nowrap">Enabling it causes guest memory reads/writes to be done directly into memory and make use of Host's MMU.</div> - <div style="white-space: nowrap">Disabling this forces all memory accesses to use Software MMU Emulation.</div> + <div style="white-space: nowrap">This optimization speeds up memory accesses by the guest program.</div> + <div style="white-space: nowrap">Enabling it causes guest memory reads/writes to be done directly into memory and make use of Host's MMU.</div> + <div style="white-space: nowrap">Disabling this forces all memory accesses to use Software MMU Emulation.</div> </string> </property> + <property name="text"> + <string>Enable Host MMU Emulation</string> + </property> </widget> </item> </layout> diff --git a/src/yuzu/configuration/configure_debug.cpp b/src/yuzu/configuration/configure_debug.cpp index cbe45a305..f7e29dbd7 100644 --- a/src/yuzu/configuration/configure_debug.cpp +++ b/src/yuzu/configuration/configure_debug.cpp @@ -43,8 +43,15 @@ void ConfigureDebug::SetConfiguration() { ui->use_auto_stub->setChecked(Settings::values.use_auto_stub.GetValue()); ui->enable_graphics_debugging->setEnabled(runtime_lock); ui->enable_graphics_debugging->setChecked(Settings::values.renderer_debug.GetValue()); + ui->enable_cpu_debugging->setEnabled(runtime_lock); + ui->enable_cpu_debugging->setChecked(Settings::values.cpu_debug_mode.GetValue()); + ui->enable_nsight_aftermath->setEnabled(runtime_lock); + ui->enable_nsight_aftermath->setChecked(Settings::values.enable_nsight_aftermath.GetValue()); ui->disable_macro_jit->setEnabled(runtime_lock); ui->disable_macro_jit->setChecked(Settings::values.disable_macro_jit.GetValue()); + ui->disable_loop_safety_checks->setEnabled(runtime_lock); + ui->disable_loop_safety_checks->setChecked( + Settings::values.disable_shader_loop_safety_checks.GetValue()); ui->extended_logging->setChecked(Settings::values.extended_logging.GetValue()); } @@ -58,6 +65,10 @@ void ConfigureDebug::ApplyConfiguration() { Settings::values.use_debug_asserts = ui->use_debug_asserts->isChecked(); Settings::values.use_auto_stub = ui->use_auto_stub->isChecked(); Settings::values.renderer_debug = ui->enable_graphics_debugging->isChecked(); + Settings::values.cpu_debug_mode = ui->enable_cpu_debugging->isChecked(); + Settings::values.enable_nsight_aftermath = ui->enable_nsight_aftermath->isChecked(); + Settings::values.disable_shader_loop_safety_checks = + ui->disable_loop_safety_checks->isChecked(); Settings::values.disable_macro_jit = ui->disable_macro_jit->isChecked(); Settings::values.extended_logging = ui->extended_logging->isChecked(); Debugger::ToggleConsole(); diff --git a/src/yuzu/configuration/configure_debug.ui b/src/yuzu/configuration/configure_debug.ui index c8087542f..c8baf2921 100644 --- a/src/yuzu/configuration/configure_debug.ui +++ b/src/yuzu/configuration/configure_debug.ui @@ -7,7 +7,7 @@ <x>0</x> <y>0</y> <width>400</width> - <height>486</height> + <height>777</height> </rect> </property> <property name="windowTitle"> @@ -126,6 +126,16 @@ </widget> </item> <item> + <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> <widget class="QCheckBox" name="disable_macro_jit"> <property name="enabled"> <bool>true</bool> @@ -138,6 +148,16 @@ </property> </widget> </item> + <item> + <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> </layout> </widget> </item> @@ -192,34 +212,41 @@ </property> </widget> </item> - <item> - <widget class="QCheckBox" name="use_debug_asserts"> - <property name="text"> - <string>Enable Debug Asserts</string> - </property> - </widget> - </item> - <item> - <widget class="QCheckBox" name="use_auto_stub"> - <property name="text"> - <string>Enable Auto-Stub</string> - </property> - </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> + <widget class="QCheckBox" name="enable_cpu_debugging"> + <property name="text"> + <string>Enable CPU Debugging</string> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="use_debug_asserts"> + <property name="text"> + <string>Enable Debug Asserts</string> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="use_auto_stub"> + <property name="text"> + <string>Enable Auto-Stub</string> + </property> + </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> @@ -245,11 +272,17 @@ <tabstops> <tabstop>log_filter_edit</tabstop> <tabstop>toggle_console</tabstop> + <tabstop>extended_logging</tabstop> <tabstop>open_log_button</tabstop> <tabstop>homebrew_args_edit</tabstop> <tabstop>enable_graphics_debugging</tabstop> + <tabstop>enable_nsight_aftermath</tabstop> + <tabstop>disable_macro_jit</tabstop> + <tabstop>disable_loop_safety_checks</tabstop> <tabstop>reporting_services</tabstop> <tabstop>quest_flag</tabstop> + <tabstop>use_debug_asserts</tabstop> + <tabstop>use_auto_stub</tabstop> </tabstops> <resources/> <connections/> diff --git a/src/yuzu/configuration/configure_debug_tab.cpp b/src/yuzu/configuration/configure_debug_tab.cpp new file mode 100644 index 000000000..67d369249 --- /dev/null +++ b/src/yuzu/configuration/configure_debug_tab.cpp @@ -0,0 +1,38 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "ui_configure_debug_tab.h" +#include "yuzu/configuration/configure_debug_tab.h" + +ConfigureDebugTab::ConfigureDebugTab(QWidget* parent) + : QWidget(parent), ui(new Ui::ConfigureDebugTab) { + ui->setupUi(this); + + SetConfiguration(); +} + +ConfigureDebugTab::~ConfigureDebugTab() = default; + +void ConfigureDebugTab::ApplyConfiguration() { + ui->debugTab->ApplyConfiguration(); + ui->cpuDebugTab->ApplyConfiguration(); +} + +void ConfigureDebugTab::SetCurrentIndex(int index) { + ui->tabWidget->setCurrentIndex(index); +} + +void ConfigureDebugTab::changeEvent(QEvent* event) { + if (event->type() == QEvent::LanguageChange) { + RetranslateUI(); + } + + QWidget::changeEvent(event); +} + +void ConfigureDebugTab::RetranslateUI() { + ui->retranslateUi(this); +} + +void ConfigureDebugTab::SetConfiguration() {} diff --git a/src/yuzu/configuration/configure_debug_tab.h b/src/yuzu/configuration/configure_debug_tab.h new file mode 100644 index 000000000..0a96d43d0 --- /dev/null +++ b/src/yuzu/configuration/configure_debug_tab.h @@ -0,0 +1,32 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <memory> +#include <QWidget> + +namespace Ui { +class ConfigureDebugTab; +} + +class ConfigureDebugTab : public QWidget { + Q_OBJECT + +public: + explicit ConfigureDebugTab(QWidget* parent = nullptr); + ~ConfigureDebugTab() override; + + void ApplyConfiguration(); + + void SetCurrentIndex(int index); + +private: + void changeEvent(QEvent* event) override; + void RetranslateUI(); + + void SetConfiguration(); + + std::unique_ptr<Ui::ConfigureDebugTab> ui; +}; diff --git a/src/yuzu/configuration/configure_debug_tab.ui b/src/yuzu/configuration/configure_debug_tab.ui new file mode 100644 index 000000000..7dc6dd704 --- /dev/null +++ b/src/yuzu/configuration/configure_debug_tab.ui @@ -0,0 +1,52 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ConfigureDebugTab</class> + <widget class="QWidget" name="ConfigureDebugTab"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>320</width> + <height>240</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QTabWidget" name="tabWidget"> + <property name="currentIndex"> + <number>1</number> + </property> + <widget class="ConfigureDebug" name="debugTab"> + <attribute name="title"> + <string>General</string> + </attribute> + </widget> + <widget class="ConfigureCpuDebug" name="cpuDebugTab"> + <attribute name="title"> + <string>CPU</string> + </attribute> + </widget> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>ConfigureDebug</class> + <extends>QWidget</extends> + <header>configuration/configure_debug.h</header> + <container>1</container> + </customwidget> + <customwidget> + <class>ConfigureCpuDebug</class> + <extends>QWidget</extends> + <header>configuration/configure_cpu_debug.h</header> + <container>1</container> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp index 371bc01b1..bc009b6b3 100644 --- a/src/yuzu/configuration/configure_dialog.cpp +++ b/src/yuzu/configuration/configure_dialog.cpp @@ -8,6 +8,7 @@ #include <QListWidgetItem> #include <QPushButton> #include <QSignalBlocker> +#include <QTabWidget> #include "common/settings.h" #include "core/core.h" #include "ui_configure.h" @@ -32,6 +33,8 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry, SetConfiguration(); PopulateSelectionList(); + connect(ui->tabWidget, &QTabWidget::currentChanged, this, + [this]() { ui->debugTab->SetCurrentIndex(0); }); connect(ui->uiTab, &ConfigureUi::LanguageChanged, this, &ConfigureDialog::OnLanguageChanged); connect(ui->selectorList, &QListWidget::itemSelectionChanged, this, &ConfigureDialog::UpdateVisibleTabs); @@ -59,7 +62,6 @@ void ConfigureDialog::ApplyConfiguration() { ui->inputTab->ApplyConfiguration(); ui->hotkeysTab->ApplyConfiguration(registry); ui->cpuTab->ApplyConfiguration(); - ui->cpuDebugTab->ApplyConfiguration(); ui->graphicsTab->ApplyConfiguration(); ui->graphicsAdvancedTab->ApplyConfiguration(); ui->audioTab->ApplyConfiguration(); @@ -102,7 +104,7 @@ void ConfigureDialog::PopulateSelectionList() { const std::array<std::pair<QString, QList<QWidget*>>, 6> items{ {{tr("General"), {ui->generalTab, ui->hotkeysTab, ui->uiTab, ui->webTab, ui->debugTab}}, {tr("System"), {ui->systemTab, ui->profileManagerTab, ui->serviceTab, ui->filesystemTab}}, - {tr("CPU"), {ui->cpuTab, ui->cpuDebugTab}}, + {tr("CPU"), {ui->cpuTab}}, {tr("Graphics"), {ui->graphicsTab, ui->graphicsAdvancedTab}}, {tr("Audio"), {ui->audioTab}}, {tr("Controls"), ui->inputTab->GetSubTabs()}}, diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp index 41a69d9b8..fef211707 100644 --- a/src/yuzu/configuration/configure_graphics.cpp +++ b/src/yuzu/configuration/configure_graphics.cpp @@ -26,19 +26,29 @@ ConfigureGraphics::ConfigureGraphics(QWidget* parent) ui->setupUi(this); + for (const auto& device : vulkan_devices) { + ui->device->addItem(device); + } + + ui->backend->addItem(QStringLiteral("GLSL")); + ui->backend->addItem(tr("GLASM (NVIDIA Only)")); + ui->backend->addItem(QStringLiteral("SPIR-V (Experimental, Mesa Only)")); + SetupPerGameUI(); SetConfiguration(); connect(ui->api, qOverload<int>(&QComboBox::currentIndexChanged), this, [this] { - UpdateDeviceComboBox(); + UpdateAPILayout(); if (!Settings::IsConfiguringGlobal()) { ConfigurationShared::SetHighlight( - ui->api_layout, ui->api->currentIndex() != ConfigurationShared::USE_GLOBAL_INDEX); + ui->api_widget, ui->api->currentIndex() != ConfigurationShared::USE_GLOBAL_INDEX); } }); connect(ui->device, qOverload<int>(&QComboBox::activated), this, [this](int device) { UpdateDeviceSelection(device); }); + connect(ui->backend, qOverload<int>(&QComboBox::activated), this, + [this](int backend) { UpdateShaderBackendSelection(backend); }); connect(ui->bg_button, &QPushButton::clicked, this, [this] { const QColor new_bg_color = QColorDialog::getColor(bg_color); @@ -61,12 +71,21 @@ void ConfigureGraphics::UpdateDeviceSelection(int device) { } } +void ConfigureGraphics::UpdateShaderBackendSelection(int backend) { + if (backend == -1) { + return; + } + if (GetCurrentGraphicsBackend() == Settings::RendererBackend::OpenGL) { + shader_backend = static_cast<Settings::ShaderBackend>(backend); + } +} + ConfigureGraphics::~ConfigureGraphics() = default; void ConfigureGraphics::SetConfiguration() { const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn(); - ui->api->setEnabled(runtime_lock); + ui->api_widget->setEnabled(runtime_lock); ui->use_asynchronous_gpu_emulation->setEnabled(runtime_lock); ui->use_disk_shader_cache->setEnabled(runtime_lock); ui->use_nvdec_emulation->setEnabled(runtime_lock); @@ -83,7 +102,7 @@ void ConfigureGraphics::SetConfiguration() { ui->aspect_ratio_combobox->setCurrentIndex(Settings::values.aspect_ratio.GetValue()); } else { ConfigurationShared::SetPerGameSetting(ui->api, &Settings::values.renderer_backend); - ConfigurationShared::SetHighlight(ui->api_layout, + ConfigurationShared::SetHighlight(ui->api_widget, !Settings::values.renderer_backend.UsingGlobal()); ConfigurationShared::SetPerGameSetting(ui->fullscreen_mode_combobox, @@ -100,11 +119,10 @@ void ConfigureGraphics::SetConfiguration() { ui->bg_button->setEnabled(!Settings::values.bg_red.UsingGlobal()); ConfigurationShared::SetHighlight(ui->bg_layout, !Settings::values.bg_red.UsingGlobal()); } - - UpdateBackgroundColorButton(QColor::fromRgbF(Settings::values.bg_red.GetValue(), - Settings::values.bg_green.GetValue(), - Settings::values.bg_blue.GetValue())); - UpdateDeviceComboBox(); + UpdateBackgroundColorButton(QColor::fromRgb(Settings::values.bg_red.GetValue(), + Settings::values.bg_green.GetValue(), + Settings::values.bg_blue.GetValue())); + UpdateAPILayout(); } void ConfigureGraphics::ApplyConfiguration() { @@ -128,26 +146,36 @@ void ConfigureGraphics::ApplyConfiguration() { if (Settings::values.renderer_backend.UsingGlobal()) { Settings::values.renderer_backend.SetValue(GetCurrentGraphicsBackend()); } + 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<float>(bg_color.redF())); - Settings::values.bg_green.SetValue(static_cast<float>(bg_color.greenF())); - Settings::values.bg_blue.SetValue(static_cast<float>(bg_color.blueF())); + 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 { 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()); - if (GetCurrentGraphicsBackend() == Settings::RendererBackend::Vulkan) { + switch (GetCurrentGraphicsBackend()) { + case Settings::RendererBackend::OpenGL: + 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); - } else { - Settings::values.vulkan_device.SetGlobal(true); + break; } } @@ -159,9 +187,9 @@ void ConfigureGraphics::ApplyConfiguration() { 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<float>(bg_color.redF())); - Settings::values.bg_green.SetValue(static_cast<float>(bg_color.greenF())); - Settings::values.bg_blue.SetValue(static_cast<float>(bg_color.blueF())); + 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())); } } } @@ -188,32 +216,32 @@ void ConfigureGraphics::UpdateBackgroundColorButton(QColor color) { ui->bg_button->setIcon(color_icon); } -void ConfigureGraphics::UpdateDeviceComboBox() { - ui->device->clear(); - - bool enabled = false; - +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); } + switch (GetCurrentGraphicsBackend()) { case Settings::RendererBackend::OpenGL: - ui->device->addItem(tr("OpenGL Graphics Device")); - enabled = false; + ui->backend->setCurrentIndex(static_cast<u32>(shader_backend)); + ui->device_widget->setVisible(false); + ui->backend_widget->setVisible(true); break; case Settings::RendererBackend::Vulkan: - for (const auto& device : vulkan_devices) { - ui->device->addItem(device); - } ui->device->setCurrentIndex(vulkan_device); - enabled = !vulkan_devices.empty(); + ui->device_widget->setVisible(true); + ui->backend_widget->setVisible(false); break; } - // If in per-game config and use global is selected, don't enable. - enabled &= !(!Settings::IsConfiguringGlobal() && - ui->api->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX); - ui->device->setEnabled(enabled && !Core::System::GetInstance().IsPoweredOn()); } void ConfigureGraphics::RetrieveVulkanDevices() try { diff --git a/src/yuzu/configuration/configure_graphics.h b/src/yuzu/configuration/configure_graphics.h index 6418115cf..c866b911b 100644 --- a/src/yuzu/configuration/configure_graphics.h +++ b/src/yuzu/configuration/configure_graphics.h @@ -34,8 +34,9 @@ private: void SetConfiguration(); void UpdateBackgroundColorButton(QColor color); - void UpdateDeviceComboBox(); + void UpdateAPILayout(); void UpdateDeviceSelection(int device); + void UpdateShaderBackendSelection(int backend); void RetrieveVulkanDevices(); @@ -53,4 +54,5 @@ private: std::vector<QString> vulkan_devices; u32 vulkan_device{}; + Settings::ShaderBackend shader_backend{}; }; diff --git a/src/yuzu/configuration/configure_graphics.ui b/src/yuzu/configuration/configure_graphics.ui index 5b999d84d..099ddbb7c 100644 --- a/src/yuzu/configuration/configure_graphics.ui +++ b/src/yuzu/configuration/configure_graphics.ui @@ -23,7 +23,7 @@ </property> <layout class="QVBoxLayout" name="verticalLayout_3"> <item> - <widget class="QWidget" name="api_layout" native="true"> + <widget class="QWidget" name="api_widget" native="true"> <layout class="QGridLayout" name="gridLayout"> <property name="leftMargin"> <number>0</number> @@ -40,37 +40,107 @@ <property name="horizontalSpacing"> <number>6</number> </property> - <item row="0" column="0"> - <widget class="QLabel" name="api_label"> - <property name="text"> - <string>API:</string> - </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="0" column="1"> - <widget class="QComboBox" name="api"> - <item> - <property name="text"> - <string notr="true">OpenGL</string> + <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> - </item> - <item> - <property name="text"> - <string notr="true">Vulkan</string> + <property name="topMargin"> + <number>0</number> </property> - </item> + <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="1" column="0"> - <widget class="QLabel" name="device_label"> - <property name="text"> - <string>Device:</string> - </property> + <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> + </widget> + </item> + </layout> </widget> </item> - <item row="1" column="1"> - <widget class="QComboBox" name="device"/> - </item> </layout> </widget> </item> diff --git a/src/yuzu/configuration/configure_graphics_advanced.cpp b/src/yuzu/configuration/configure_graphics_advanced.cpp index 8d13c9857..38276feb1 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.cpp +++ b/src/yuzu/configuration/configure_graphics_advanced.cpp @@ -23,13 +23,10 @@ ConfigureGraphicsAdvanced::~ConfigureGraphicsAdvanced() = default; void ConfigureGraphicsAdvanced::SetConfiguration() { const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn(); ui->use_vsync->setEnabled(runtime_lock); - ui->use_assembly_shaders->setEnabled(runtime_lock); ui->use_asynchronous_shaders->setEnabled(runtime_lock); ui->anisotropic_filtering_combobox->setEnabled(runtime_lock); ui->use_vsync->setChecked(Settings::values.use_vsync.GetValue()); - ui->disable_fps_limit->setChecked(Settings::values.disable_fps_limit.GetValue()); - ui->use_assembly_shaders->setChecked(Settings::values.use_assembly_shaders.GetValue()); ui->use_asynchronous_shaders->setChecked(Settings::values.use_asynchronous_shaders.GetValue()); ui->use_caches_gc->setChecked(Settings::values.use_caches_gc.GetValue()); ui->use_fast_gpu_time->setChecked(Settings::values.use_fast_gpu_time.GetValue()); @@ -59,10 +56,6 @@ void ConfigureGraphicsAdvanced::ApplyConfiguration() { ConfigurationShared::ApplyPerGameSetting(&Settings::values.max_anisotropy, ui->anisotropic_filtering_combobox); ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vsync, ui->use_vsync, use_vsync); - ConfigurationShared::ApplyPerGameSetting(&Settings::values.disable_fps_limit, - ui->disable_fps_limit, disable_fps_limit); - ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_assembly_shaders, - ui->use_assembly_shaders, use_assembly_shaders); ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_asynchronous_shaders, ui->use_asynchronous_shaders, use_asynchronous_shaders); @@ -103,8 +96,6 @@ void ConfigureGraphicsAdvanced::SetupPerGameUI() { if (Settings::IsConfiguringGlobal()) { ui->gpu_accuracy->setEnabled(Settings::values.gpu_accuracy.UsingGlobal()); ui->use_vsync->setEnabled(Settings::values.use_vsync.UsingGlobal()); - ui->disable_fps_limit->setEnabled(Settings::values.disable_fps_limit.UsingGlobal()); - ui->use_assembly_shaders->setEnabled(Settings::values.use_assembly_shaders.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()); @@ -116,10 +107,6 @@ void ConfigureGraphicsAdvanced::SetupPerGameUI() { } ConfigurationShared::SetColoredTristate(ui->use_vsync, Settings::values.use_vsync, use_vsync); - ConfigurationShared::SetColoredTristate(ui->disable_fps_limit, - Settings::values.disable_fps_limit, disable_fps_limit); - ConfigurationShared::SetColoredTristate( - ui->use_assembly_shaders, Settings::values.use_assembly_shaders, use_assembly_shaders); ConfigurationShared::SetColoredTristate(ui->use_asynchronous_shaders, Settings::values.use_asynchronous_shaders, use_asynchronous_shaders); diff --git a/src/yuzu/configuration/configure_graphics_advanced.h b/src/yuzu/configuration/configure_graphics_advanced.h index 6ac5f20ec..7356e6916 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.h +++ b/src/yuzu/configuration/configure_graphics_advanced.h @@ -35,8 +35,6 @@ private: std::unique_ptr<Ui::ConfigureGraphicsAdvanced> ui; ConfigurationShared::CheckState use_vsync; - ConfigurationShared::CheckState disable_fps_limit; - ConfigurationShared::CheckState use_assembly_shaders; ConfigurationShared::CheckState use_asynchronous_shaders; ConfigurationShared::CheckState use_fast_gpu_time; ConfigurationShared::CheckState use_caches_gc; diff --git a/src/yuzu/configuration/configure_graphics_advanced.ui b/src/yuzu/configuration/configure_graphics_advanced.ui index 18c43629e..379dc5d2e 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.ui +++ b/src/yuzu/configuration/configure_graphics_advanced.ui @@ -77,40 +77,12 @@ </widget> </item> <item> - <widget class="QCheckBox" name="disable_fps_limit"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="toolTip"> - <string> - <html><head/><body> - <p>Presents guest frames as they become available, disabling the FPS limit in most titles.</p> - <p>NOTE: Will cause instabilities.</p> - </body></html> - </string> - </property> - <property name="text"> - <string>Disable framerate limit (experimental)</string> - </property> - </widget> - </item> - <item> - <widget class="QCheckBox" name="use_assembly_shaders"> - <property name="toolTip"> - <string>Enabling this reduces shader stutter. Enables OpenGL assembly shaders on supported Nvidia devices (NV_gpu_program5 is required). This feature is experimental.</string> - </property> - <property name="text"> - <string>Use assembly shaders (experimental, Nvidia OpenGL only)</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 (experimental)</string> + <string>Use asynchronous shader building</string> </property> </widget> </item> @@ -162,22 +134,22 @@ </item> <item> <property name="text"> - <string>2x</string> + <string>2x (WILL BREAK THINGS)</string> </property> </item> <item> <property name="text"> - <string>4x</string> + <string>4x (WILL BREAK THINGS)</string> </property> </item> <item> <property name="text"> - <string>8x</string> + <string>8x (WILL BREAK THINGS)</string> </property> </item> <item> <property name="text"> - <string>16x</string> + <string>16x (WILL BREAK THINGS)</string> </property> </item> </widget> diff --git a/src/yuzu/configuration/configure_input_advanced.ui b/src/yuzu/configuration/configure_input_advanced.ui index 173130d8d..d3ef5bd06 100644 --- a/src/yuzu/configuration/configure_input_advanced.ui +++ b/src/yuzu/configuration/configure_input_advanced.ui @@ -2573,27 +2573,24 @@ </widget> </item> <item row="2" column="2"> - <widget class="QDoubleSpinBox" name="mouse_panning_sensitivity"> + <widget class="QSpinBox" name="mouse_panning_sensitivity"> <property name="toolTip"> <string>Mouse sensitivity</string> </property> <property name="alignment"> <set>Qt::AlignCenter</set> </property> - <property name="decimals"> - <number>2</number> + <property name="suffix"> + <string>%</string> </property> <property name="minimum"> - <double>0.100000000000000</double> + <number>1</number> </property> <property name="maximum"> - <double>16.000000000000000</double> - </property> - <property name="singleStep"> - <double>0.010000000000000</double> + <number>100</number> </property> <property name="value"> - <double>1.000000000000000</double> + <number>100</number> </property> </widget> </item> diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index d5d624b96..6b9bd05f1 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp @@ -149,8 +149,9 @@ QString ButtonToText(const Common::ParamPackage& param) { if (param.Has("button")) { const QString button_str = QString::fromStdString(param.Get("button", "")); + const QString toggle = QString::fromStdString(param.Get("toggle", false) ? "~" : ""); - return QObject::tr("Button %1").arg(button_str); + return QObject::tr("%1Button %2").arg(toggle, button_str); } if (param.Has("motion")) { @@ -313,6 +314,24 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i buttons_param[button_id].Set("toggle", toggle_value); button_map[button_id]->setText(ButtonToText(buttons_param[button_id])); }); + if (buttons_param[button_id].Has("threshold")) { + context_menu.addAction(tr("Set threshold"), [&] { + const int button_threshold = static_cast<int>( + buttons_param[button_id].Get("threshold", 0.5f) * 100.0f); + const int new_threshold = QInputDialog::getInt( + this, tr("Set threshold"), tr("Choose a value between 0% and 100%"), + button_threshold, 0, 100); + buttons_param[button_id].Set("threshold", new_threshold / 100.0f); + + if (button_id == Settings::NativeButton::ZL) { + ui->sliderZLThreshold->setValue(new_threshold); + } + if (button_id == Settings::NativeButton::ZR) { + ui->sliderZRThreshold->setValue(new_threshold); + } + }); + } + context_menu.exec(button_map[button_id]->mapToGlobal(menu_location)); ui->controllerFrame->SetPlayerInput(player_index, buttons_param, analogs_param); }); @@ -341,6 +360,20 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i }); } + connect(ui->sliderZLThreshold, &QSlider::valueChanged, [=, this] { + if (buttons_param[Settings::NativeButton::ZL].Has("threshold")) { + const auto slider_value = ui->sliderZLThreshold->value(); + buttons_param[Settings::NativeButton::ZL].Set("threshold", slider_value / 100.0f); + } + }); + + connect(ui->sliderZRThreshold, &QSlider::valueChanged, [=, this] { + if (buttons_param[Settings::NativeButton::ZR].Has("threshold")) { + const auto slider_value = ui->sliderZRThreshold->value(); + buttons_param[Settings::NativeButton::ZR].Set("threshold", slider_value / 100.0f); + } + }); + for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; ++analog_id) { for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; ++sub_button_id) { auto* const analog_button = analog_map_buttons[analog_id][sub_button_id]; @@ -849,6 +882,18 @@ void ConfigureInputPlayer::UpdateUI() { button_map[button]->setText(ButtonToText(buttons_param[button])); } + if (buttons_param[Settings::NativeButton::ZL].Has("threshold")) { + const int button_threshold = static_cast<int>( + buttons_param[Settings::NativeButton::ZL].Get("threshold", 0.5f) * 100.0f); + ui->sliderZLThreshold->setValue(button_threshold); + } + + if (buttons_param[Settings::NativeButton::ZR].Has("threshold")) { + const int button_threshold = static_cast<int>( + buttons_param[Settings::NativeButton::ZR].Get("threshold", 0.5f) * 100.0f); + ui->sliderZRThreshold->setValue(button_threshold); + } + for (int motion_id = 0; motion_id < Settings::NativeMotion::NumMotions; ++motion_id) { motion_map[motion_id]->setText(ButtonToText(motions_param[motion_id])); } diff --git a/src/yuzu/configuration/configure_input_player.ui b/src/yuzu/configuration/configure_input_player.ui index e76aa484f..e7433912b 100644 --- a/src/yuzu/configuration/configure_input_player.ui +++ b/src/yuzu/configuration/configure_input_player.ui @@ -1334,6 +1334,12 @@ </item> <item> <widget class="QGroupBox" name="buttonShoulderButtonsButtonZLGroup"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> <property name="title"> <string>ZL</string> </property> @@ -1378,6 +1384,22 @@ </property> </widget> </item> + <item> + <widget class="QSlider" name="sliderZLThreshold"> + <property name="maximumSize"> + <size> + <width>70</width> + <height>15</height> + </size> + </property> + <property name="maximum"> + <number>100</number> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> </layout> </widget> </item> @@ -1759,6 +1781,12 @@ </item> <item> <widget class="QGroupBox" name="buttonShoulderButtonsZRGroup"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> <property name="title"> <string>ZR</string> </property> @@ -1803,6 +1831,22 @@ </property> </widget> </item> + <item> + <widget class="QSlider" name="sliderZRThreshold"> + <property name="maximumSize"> + <size> + <width>70</width> + <height>15</height> + </size> + </property> + <property name="maximum"> + <number>100</number> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> </layout> </widget> </item> diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index 218b4782b..f746bd85d 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp @@ -404,9 +404,11 @@ void GameList::ValidateEntry(const QModelIndex& item) { return; } + const auto title_id = selected.data(GameListItemPath::ProgramIdRole).toULongLong(); + // Users usually want to run a different game after closing one search_field->clear(); - emit GameChosen(file_path); + emit GameChosen(file_path, title_id); break; } case GameListItemType::AddDir: @@ -518,9 +520,11 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri QMenu* remove_menu = context_menu.addMenu(tr("Remove")); QAction* remove_update = remove_menu->addAction(tr("Remove Installed Update")); QAction* remove_dlc = remove_menu->addAction(tr("Remove All Installed DLC")); - QAction* remove_shader_cache = remove_menu->addAction(tr("Remove Shader Cache")); QAction* remove_custom_config = remove_menu->addAction(tr("Remove Custom Configuration")); + QAction* remove_gl_shader_cache = remove_menu->addAction(tr("Remove OpenGL Shader Cache")); + QAction* remove_vk_shader_cache = remove_menu->addAction(tr("Remove Vulkan Shader Cache")); remove_menu->addSeparator(); + QAction* remove_shader_cache = remove_menu->addAction(tr("Remove All Shader Caches")); QAction* remove_all_content = remove_menu->addAction(tr("Remove All Installed Contents")); QMenu* dump_romfs_menu = context_menu.addMenu(tr("Dump RomFS")); QAction* dump_romfs = dump_romfs_menu->addAction(tr("Dump RomFS")); @@ -538,6 +542,8 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri open_transferable_shader_cache->setVisible(program_id != 0); remove_update->setVisible(program_id != 0); remove_dlc->setVisible(program_id != 0); + remove_gl_shader_cache->setVisible(program_id != 0); + remove_vk_shader_cache->setVisible(program_id != 0); remove_shader_cache->setVisible(program_id != 0); remove_all_content->setVisible(program_id != 0); auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id); @@ -548,10 +554,10 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri emit OpenFolderRequested(program_id, GameListOpenTarget::SaveData, path); }); connect(start_game, &QAction::triggered, [this, path]() { - emit BootGame(QString::fromStdString(path), 0, StartGameType::Normal); + emit BootGame(QString::fromStdString(path), 0, 0, StartGameType::Normal); }); connect(start_game_global, &QAction::triggered, [this, path]() { - emit BootGame(QString::fromStdString(path), 0, StartGameType::Global); + emit BootGame(QString::fromStdString(path), 0, 0, StartGameType::Global); }); connect(open_mod_location, &QAction::triggered, [this, program_id, path]() { emit OpenFolderRequested(program_id, GameListOpenTarget::ModData, path); @@ -567,8 +573,14 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri connect(remove_dlc, &QAction::triggered, [this, program_id]() { emit RemoveInstalledEntryRequested(program_id, InstalledEntryType::AddOnContent); }); + connect(remove_gl_shader_cache, &QAction::triggered, [this, program_id, path]() { + emit RemoveFileRequested(program_id, GameListRemoveTarget::GlShaderCache, path); + }); + connect(remove_vk_shader_cache, &QAction::triggered, [this, program_id, path]() { + emit RemoveFileRequested(program_id, GameListRemoveTarget::VkShaderCache, path); + }); connect(remove_shader_cache, &QAction::triggered, [this, program_id, path]() { - emit RemoveFileRequested(program_id, GameListRemoveTarget::ShaderCache, path); + emit RemoveFileRequested(program_id, GameListRemoveTarget::AllShaderCache, path); }); connect(remove_custom_config, &QAction::triggered, [this, program_id, path]() { emit RemoveFileRequested(program_id, GameListRemoveTarget::CustomConfiguration, path); diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h index 50402da51..10339dcca 100644 --- a/src/yuzu/game_list.h +++ b/src/yuzu/game_list.h @@ -41,7 +41,9 @@ enum class GameListOpenTarget { }; enum class GameListRemoveTarget { - ShaderCache, + GlShaderCache, + VkShaderCache, + AllShaderCache, CustomConfiguration, }; @@ -88,8 +90,9 @@ public: static const QStringList supported_file_extensions; signals: - void BootGame(const QString& game_path, std::size_t program_index, StartGameType type); - void GameChosen(const QString& game_path); + void BootGame(const QString& game_path, u64 program_id, std::size_t program_index, + StartGameType type); + void GameChosen(const QString& game_path, const u64 title_id = 0); void ShouldCancelWorker(); void OpenFolderRequested(u64 program_id, GameListOpenTarget target, const std::string& game_path); diff --git a/src/yuzu/game_list_worker.cpp b/src/yuzu/game_list_worker.cpp index 33cc90d5a..2d5492157 100644 --- a/src/yuzu/game_list_worker.cpp +++ b/src/yuzu/game_list_worker.cpp @@ -336,18 +336,44 @@ void GameListWorker::ScanFileSystem(ScanTarget target, const std::string& dir_pa } } } else { - std::vector<u8> icon; - [[maybe_unused]] const auto res1 = loader->ReadIcon(icon); + std::vector<u64> program_ids; + loader->ReadProgramIds(program_ids); + + if (res2 == Loader::ResultStatus::Success && program_ids.size() > 1 && + (file_type == Loader::FileType::XCI || file_type == Loader::FileType::NSP)) { + for (const auto id : program_ids) { + loader = Loader::GetLoader(system, file, id); + if (!loader) { + continue; + } + + std::vector<u8> icon; + [[maybe_unused]] const auto res1 = loader->ReadIcon(icon); - std::string name = " "; - [[maybe_unused]] const auto res3 = loader->ReadTitle(name); + std::string name = " "; + [[maybe_unused]] const auto res3 = loader->ReadTitle(name); - const FileSys::PatchManager patch{program_id, system.GetFileSystemController(), - system.GetContentProvider()}; + const FileSys::PatchManager patch{id, system.GetFileSystemController(), + system.GetContentProvider()}; + + emit EntryReady(MakeGameListEntry(physical_name, name, icon, *loader, id, + compatibility_list, patch), + parent_dir); + } + } else { + std::vector<u8> icon; + [[maybe_unused]] const auto res1 = loader->ReadIcon(icon); - emit EntryReady(MakeGameListEntry(physical_name, name, icon, *loader, program_id, - compatibility_list, patch), - parent_dir); + std::string name = " "; + [[maybe_unused]] const auto res3 = loader->ReadTitle(name); + + const FileSys::PatchManager patch{program_id, system.GetFileSystemController(), + system.GetContentProvider()}; + + emit EntryReady(MakeGameListEntry(physical_name, name, icon, *loader, + program_id, compatibility_list, patch), + parent_dir); + } } } else if (is_dir) { watch_list.append(QString::fromStdString(physical_name)); diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index d94c660b3..2f84ada73 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -11,11 +11,11 @@ #endif // VFS includes must be before glad as they will conflict with Windows file api, which uses defines. -#include "applets/controller.h" -#include "applets/error.h" -#include "applets/profile_select.h" -#include "applets/software_keyboard.h" -#include "applets/web_browser.h" +#include "applets/qt_controller.h" +#include "applets/qt_error.h" +#include "applets/qt_profile_select.h" +#include "applets/qt_software_keyboard.h" +#include "applets/qt_web_browser.h" #include "common/nvidia_flags.h" #include "configuration/configure_input.h" #include "configuration/configure_per_game.h" @@ -1208,7 +1208,7 @@ void GMainWindow::AllowOSSleep() { #endif } -bool GMainWindow::LoadROM(const QString& filename, std::size_t program_index) { +bool GMainWindow::LoadROM(const QString& filename, u64 program_id, std::size_t program_index) { // Shutdown previous session if the emu thread is still active... if (emu_thread != nullptr) ShutdownGame(); @@ -1231,7 +1231,7 @@ bool GMainWindow::LoadROM(const QString& filename, std::size_t program_index) { }); const Core::System::ResultStatus result{ - system.Load(*render_window, filename.toStdString(), program_index)}; + system.Load(*render_window, filename.toStdString(), program_id, program_index)}; const auto drd_callout = (UISettings::values.callout_flags.GetValue() & static_cast<u32>(CalloutFlag::DRDDeprecation)) == 0; @@ -1318,7 +1318,8 @@ void GMainWindow::SelectAndSetCurrentUser() { Settings::values.current_user = dialog.GetIndex(); } -void GMainWindow::BootGame(const QString& filename, std::size_t program_index, StartGameType type) { +void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t program_index, + StartGameType type) { LOG_INFO(Frontend, "yuzu starting..."); StoreRecentFile(filename); // Put the filename on top of the list @@ -1328,7 +1329,7 @@ void GMainWindow::BootGame(const QString& filename, std::size_t program_index, S auto& system = Core::System::GetInstance(); const auto v_file = Core::GetGameFileFromPath(vfs, filename.toUtf8().constData()); - const auto loader = Loader::GetLoader(system, v_file, program_index); + const auto loader = Loader::GetLoader(system, v_file, program_id, program_index); if (loader != nullptr && loader->ReadProgramId(title_id) == Loader::ResultStatus::Success && type == StartGameType::Normal) { @@ -1342,6 +1343,9 @@ void GMainWindow::BootGame(const QString& filename, std::size_t program_index, S ConfigureVibration::SetAllVibrationDevices(); + // Disable fps limit toggle when booting a new title + Settings::values.disable_fps_limit.SetValue(false); + // Save configurations UpdateUISettings(); game_list->SaveInterfaceLayout(); @@ -1353,7 +1357,7 @@ void GMainWindow::BootGame(const QString& filename, std::size_t program_index, S SelectAndSetCurrentUser(); } - if (!LoadROM(filename, program_index)) + if (!LoadROM(filename, program_id, program_index)) return; // Create and start the emulation thread @@ -1413,8 +1417,10 @@ void GMainWindow::BootGame(const QString& filename, std::size_t program_index, S std::filesystem::path{filename.toStdU16String()}.filename()); } const bool is_64bit = system.Kernel().CurrentProcess()->Is64BitProcess(); - const auto instruction_set_suffix = is_64bit ? " (64-bit)" : " (32-bit)"; - title_name += instruction_set_suffix; + const auto instruction_set_suffix = is_64bit ? tr("(64-bit)") : tr("(32-bit)"); + title_name = tr("%1 %2", "%1 is the title name. %2 indicates if the title is 64-bit or 32-bit") + .arg(QString::fromStdString(title_name), instruction_set_suffix) + .toStdString(); LOG_INFO(Frontend, "Booting game: {:016X} | {} | {}", title_id, title_name, title_version); const auto gpu_vendor = system.GPU().Renderer().GetDeviceVendor(); UpdateWindowTitle(title_name, title_version, gpu_vendor); @@ -1526,8 +1532,8 @@ void GMainWindow::UpdateRecentFiles() { ui.menu_recent_files->setEnabled(num_recent_files != 0); } -void GMainWindow::OnGameListLoadFile(QString game_path) { - BootGame(game_path); +void GMainWindow::OnGameListLoadFile(QString game_path, u64 program_id) { + BootGame(game_path, program_id); } void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target, @@ -1631,35 +1637,15 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target void GMainWindow::OnTransferableShaderCacheOpenFile(u64 program_id) { const auto shader_cache_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::ShaderDir); - const auto transferable_shader_cache_folder_path = shader_cache_dir / "opengl" / "transferable"; - const auto transferable_shader_cache_file_path = - transferable_shader_cache_folder_path / fmt::format("{:016X}.bin", program_id); - - if (!Common::FS::Exists(transferable_shader_cache_file_path)) { + const auto shader_cache_folder_path{shader_cache_dir / fmt::format("{:016x}", program_id)}; + if (!Common::FS::CreateDirs(shader_cache_folder_path)) { QMessageBox::warning(this, tr("Error Opening Transferable Shader Cache"), - tr("A shader cache for this title does not exist.")); + tr("Filed to create the shader cache directory for this title.")); return; } - - const auto qt_shader_cache_folder_path = - QString::fromStdString(Common::FS::PathToUTF8String(transferable_shader_cache_folder_path)); - const auto qt_shader_cache_file_path = - QString::fromStdString(Common::FS::PathToUTF8String(transferable_shader_cache_file_path)); - - // Windows supports opening a folder with selecting a specified file in explorer. On every other - // OS we just open the transferable shader cache folder without preselecting the transferable - // shader cache file for the selected game. -#if defined(Q_OS_WIN) - const QString explorer = QStringLiteral("explorer"); - QStringList param; - if (!QFileInfo(qt_shader_cache_file_path).isDir()) { - param << QStringLiteral("/select,"); - } - param << QDir::toNativeSeparators(qt_shader_cache_file_path); - QProcess::startDetached(explorer, param); -#else - QDesktopServices::openUrl(QUrl::fromLocalFile(qt_shader_cache_folder_path)); -#endif + const auto shader_path_string{Common::FS::PathToUTF8String(shader_cache_folder_path)}; + const auto qt_shader_cache_path = QString::fromStdString(shader_path_string); + QDesktopServices::openUrl(QUrl::fromLocalFile(qt_shader_cache_path)); } static std::size_t CalculateRomFSEntrySize(const FileSys::VirtualDir& dir, bool full) { @@ -1802,8 +1788,12 @@ void GMainWindow::OnGameListRemoveFile(u64 program_id, GameListRemoveTarget targ const std::string& game_path) { const QString question = [this, target] { switch (target) { - case GameListRemoveTarget::ShaderCache: - return tr("Delete Transferable Shader Cache?"); + case GameListRemoveTarget::GlShaderCache: + return tr("Delete OpenGL Transferable Shader Cache?"); + case GameListRemoveTarget::VkShaderCache: + return tr("Delete Vulkan Transferable Shader Cache?"); + case GameListRemoveTarget::AllShaderCache: + return tr("Delete All Transferable Shader Caches?"); case GameListRemoveTarget::CustomConfiguration: return tr("Remove Custom Game Configuration?"); default: @@ -1817,8 +1807,12 @@ void GMainWindow::OnGameListRemoveFile(u64 program_id, GameListRemoveTarget targ } switch (target) { - case GameListRemoveTarget::ShaderCache: - RemoveTransferableShaderCache(program_id); + case GameListRemoveTarget::GlShaderCache: + case GameListRemoveTarget::VkShaderCache: + RemoveTransferableShaderCache(program_id, target); + break; + case GameListRemoveTarget::AllShaderCache: + RemoveAllTransferableShaderCaches(program_id); break; case GameListRemoveTarget::CustomConfiguration: RemoveCustomConfiguration(program_id, game_path); @@ -1826,18 +1820,27 @@ void GMainWindow::OnGameListRemoveFile(u64 program_id, GameListRemoveTarget targ } } -void GMainWindow::RemoveTransferableShaderCache(u64 program_id) { +void GMainWindow::RemoveTransferableShaderCache(u64 program_id, GameListRemoveTarget target) { + const auto target_file_name = [target] { + switch (target) { + case GameListRemoveTarget::GlShaderCache: + return "opengl.bin"; + case GameListRemoveTarget::VkShaderCache: + return "vulkan.bin"; + default: + return ""; + } + }(); const auto shader_cache_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::ShaderDir); - const auto transferable_shader_cache_file_path = - shader_cache_dir / "opengl" / "transferable" / fmt::format("{:016X}.bin", program_id); + const auto shader_cache_folder_path = shader_cache_dir / fmt::format("{:016x}", program_id); + const auto target_file = shader_cache_folder_path / target_file_name; - if (!Common::FS::Exists(transferable_shader_cache_file_path)) { + if (!Common::FS::Exists(target_file)) { QMessageBox::warning(this, tr("Error Removing Transferable Shader Cache"), tr("A shader cache for this title does not exist.")); return; } - - if (Common::FS::RemoveFile(transferable_shader_cache_file_path)) { + if (Common::FS::RemoveFile(target_file)) { QMessageBox::information(this, tr("Successfully Removed"), tr("Successfully removed the transferable shader cache.")); } else { @@ -1846,6 +1849,24 @@ void GMainWindow::RemoveTransferableShaderCache(u64 program_id) { } } +void GMainWindow::RemoveAllTransferableShaderCaches(u64 program_id) { + const auto shader_cache_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::ShaderDir); + const auto program_shader_cache_dir = shader_cache_dir / fmt::format("{:016x}", program_id); + + if (!Common::FS::Exists(program_shader_cache_dir)) { + QMessageBox::warning(this, tr("Error Removing Transferable Shader Caches"), + tr("A shader cache for this title does not exist.")); + return; + } + if (Common::FS::RemoveDirRecursively(program_shader_cache_dir)) { + QMessageBox::information(this, tr("Successfully Removed"), + tr("Successfully removed the transferable shader caches.")); + } else { + QMessageBox::warning(this, tr("Error Removing Transferable Shader Caches"), + tr("Failed to remove the transferable shader cache directory.")); + } +} + void GMainWindow::RemoveCustomConfiguration(u64 program_id, const std::string& game_path) { const auto file_path = std::filesystem::path(Common::FS::ToU8String(game_path)); const auto config_file_name = @@ -2428,7 +2449,7 @@ void GMainWindow::OnLoadComplete() { void GMainWindow::OnExecuteProgram(std::size_t program_index) { ShutdownGame(); - BootGame(last_filename_booted, program_index); + BootGame(last_filename_booted, 0, program_index); } void GMainWindow::ErrorDisplayDisplayError(QString error_code, QString error_text) { @@ -2800,7 +2821,7 @@ void GMainWindow::OnCaptureScreenshot() { QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::ScreenshotsDir)); const auto date = QDateTime::currentDateTime().toString(QStringLiteral("yyyy-MM-dd_hh-mm-ss-zzz")); - QString filename = QStringLiteral("%1%2_%3.png") + QString filename = QStringLiteral("%1/%2_%3.png") .arg(screenshot_path) .arg(title_id, 16, 16, QLatin1Char{'0'}) .arg(date); @@ -2877,13 +2898,13 @@ void GMainWindow::UpdateStatusBar() { return; } - auto results = Core::System::GetInstance().GetAndResetPerfStats(); - auto& shader_notify = Core::System::GetInstance().GPU().ShaderNotify(); - const auto shaders_building = shader_notify.GetShadersBuilding(); + auto& system = Core::System::GetInstance(); + auto results = system.GetAndResetPerfStats(); + auto& shader_notify = system.GPU().ShaderNotify(); + const int shaders_building = shader_notify.ShadersBuilding(); - if (shaders_building != 0) { - shader_building_label->setText( - tr("Building: %n shader(s)", "", static_cast<int>(shaders_building))); + if (shaders_building > 0) { + shader_building_label->setText(tr("Building: %n shader(s)", "", shaders_building)); shader_building_label->setVisible(true); } else { shader_building_label->setVisible(false); @@ -2896,7 +2917,12 @@ void GMainWindow::UpdateStatusBar() { } else { emu_speed_label->setText(tr("Speed: %1%").arg(results.emulation_speed * 100.0, 0, 'f', 0)); } - game_fps_label->setText(tr("Game: %1 FPS").arg(results.average_game_fps, 0, 'f', 0)); + if (Settings::values.disable_fps_limit) { + game_fps_label->setText( + tr("Game: %1 FPS (Limit off)").arg(results.average_game_fps, 0, 'f', 0)); + } else { + game_fps_label->setText(tr("Game: %1 FPS").arg(results.average_game_fps, 0, 'f', 0)); + } emu_frametime_label->setText(tr("Frame: %1 ms").arg(results.frametime * 1000.0, 0, 'f', 2)); emu_speed_label->setVisible(!Settings::values.use_multi_core.GetValue()); diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 15e4deab9..38e66ccd0 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -186,8 +186,8 @@ private: void PreventOSSleep(); void AllowOSSleep(); - bool LoadROM(const QString& filename, std::size_t program_index); - void BootGame(const QString& filename, std::size_t program_index = 0, + bool LoadROM(const QString& filename, u64 program_id, std::size_t program_index); + void BootGame(const QString& filename, u64 program_id = 0, std::size_t program_index = 0, StartGameType with_config = StartGameType::Normal); void ShutdownGame(); @@ -238,7 +238,7 @@ private slots: void OnOpenQuickstartGuide(); void OnOpenFAQ(); /// Called whenever a user selects a game in the game list widget. - void OnGameListLoadFile(QString game_path); + void OnGameListLoadFile(QString game_path, u64 program_id); void OnGameListOpenFolder(u64 program_id, GameListOpenTarget target, const std::string& game_path); void OnTransferableShaderCacheOpenFile(u64 program_id); @@ -282,7 +282,8 @@ private: void RemoveBaseContent(u64 program_id, const QString& entry_type); void RemoveUpdateContent(u64 program_id, const QString& entry_type); void RemoveAddOnContent(u64 program_id, const QString& entry_type); - void RemoveTransferableShaderCache(u64 program_id); + void RemoveTransferableShaderCache(u64 program_id, GameListRemoveTarget target); + void RemoveAllTransferableShaderCaches(u64 program_id); void RemoveCustomConfiguration(u64 program_id, const std::string& game_path); std::optional<u64> SelectRomFSDumpTarget(const FileSys::ContentProvider&, u64 program_id); InstallResult InstallNSPXCI(const QString& filename); |