diff options
Diffstat (limited to 'src/yuzu')
24 files changed, 538 insertions, 127 deletions
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 0f8c1e6a6..2d7b9ab65 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -189,6 +189,8 @@ add_executable(yuzu multiplayer/state.h multiplayer/validation.h precompiled_headers.h + qt_common.cpp + qt_common.h startup_checks.cpp startup_checks.h uisettings.cpp diff --git a/src/yuzu/applets/qt_profile_select.cpp b/src/yuzu/applets/qt_profile_select.cpp index 2448e46b6..1f3f23038 100644 --- a/src/yuzu/applets/qt_profile_select.cpp +++ b/src/yuzu/applets/qt_profile_select.cpp @@ -95,6 +95,7 @@ QtProfileSelectionDialog::QtProfileSelectionDialog( scroll_area->setLayout(layout); connect(tree_view, &QTreeView::clicked, this, &QtProfileSelectionDialog::SelectUser); + connect(tree_view, &QTreeView::doubleClicked, this, &QtProfileSelectionDialog::accept); connect(controller_navigation, &ControllerNavigation::TriggerKeyboardEvent, [this](Qt::Key key) { if (!this->isActiveWindow()) { diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 4c7bf28d8..59d226113 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -1,36 +1,48 @@ // SPDX-FileCopyrightText: 2014 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include <algorithm> +#include <array> +#include <cmath> +#include <cstring> +#include <string> +#include <tuple> +#include <type_traits> #include <glad/glad.h> -#include <QApplication> +#include <QtCore/qglobal.h> #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) && YUZU_USE_QT_MULTIMEDIA +#include <QCamera> #include <QCameraImageCapture> #include <QCameraInfo> #endif +#include <QCursor> +#include <QEvent> +#include <QGuiApplication> #include <QHBoxLayout> +#include <QKeyEvent> +#include <QLayout> +#include <QList> #include <QMessageBox> -#include <QPainter> #include <QScreen> -#include <QString> -#include <QStringList> +#include <QSize> +#include <QStringLiteral> +#include <QSurfaceFormat> +#include <QTimer> #include <QWindow> +#include <QtCore/qobjectdefs.h> #ifdef HAS_OPENGL #include <QOffscreenSurface> #include <QOpenGLContext> #endif -#if !defined(WIN32) -#include <qpa/qplatformnativeinterface.h> -#endif - -#include <fmt/format.h> - -#include "common/assert.h" #include "common/microprofile.h" +#include "common/polyfill_thread.h" #include "common/scm_rev.h" #include "common/settings.h" +#include "common/settings_input.h" +#include "common/thread.h" #include "core/core.h" #include "core/cpu_manager.h" #include "core/frontend/framebuffer_layout.h" @@ -40,11 +52,16 @@ #include "input_common/drivers/tas_input.h" #include "input_common/drivers/touch_screen.h" #include "input_common/main.h" +#include "video_core/gpu.h" +#include "video_core/rasterizer_interface.h" #include "video_core/renderer_base.h" #include "yuzu/bootmanager.h" #include "yuzu/main.h" +#include "yuzu/qt_common.h" -static Core::Frontend::WindowSystemType GetWindowSystemType(); +class QObject; +class QPaintEngine; +class QSurface; EmuThread::EmuThread(Core::System& system) : m_system{system} {} @@ -154,7 +171,10 @@ public: // disable vsync for any shared contexts auto format = share_context->format(); - format.setSwapInterval(main_surface ? Settings::values.use_vsync.GetValue() : 0); + const int swap_interval = + Settings::values.vsync_mode.GetValue() == Settings::VSyncMode::Immediate ? 0 : 1; + + format.setSwapInterval(main_surface ? swap_interval : 0); context = std::make_unique<QOpenGLContext>(); context->setShareContext(share_context); @@ -221,7 +241,7 @@ public: explicit RenderWidget(GRenderWindow* parent) : QWidget(parent), render_window(parent) { setAttribute(Qt::WA_NativeWindow); setAttribute(Qt::WA_PaintOnScreen); - if (GetWindowSystemType() == Core::Frontend::WindowSystemType::Wayland) { + if (QtCommon::GetWindowSystemType() == Core::Frontend::WindowSystemType::Wayland) { setAttribute(Qt::WA_DontCreateNativeAncestors); } } @@ -259,46 +279,6 @@ struct NullRenderWidget : public RenderWidget { explicit NullRenderWidget(GRenderWindow* parent) : RenderWidget(parent) {} }; -static Core::Frontend::WindowSystemType GetWindowSystemType() { - // Determine WSI type based on Qt platform. - QString platform_name = QGuiApplication::platformName(); - if (platform_name == QStringLiteral("windows")) - return Core::Frontend::WindowSystemType::Windows; - else if (platform_name == QStringLiteral("xcb")) - return Core::Frontend::WindowSystemType::X11; - else if (platform_name == QStringLiteral("wayland")) - return Core::Frontend::WindowSystemType::Wayland; - else if (platform_name == QStringLiteral("wayland-egl")) - return Core::Frontend::WindowSystemType::Wayland; - else if (platform_name == QStringLiteral("cocoa")) - return Core::Frontend::WindowSystemType::Cocoa; - else if (platform_name == QStringLiteral("android")) - return Core::Frontend::WindowSystemType::Android; - - LOG_CRITICAL(Frontend, "Unknown Qt platform {}!", platform_name.toStdString()); - return Core::Frontend::WindowSystemType::Windows; -} - -static Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window) { - Core::Frontend::EmuWindow::WindowSystemInfo wsi; - wsi.type = GetWindowSystemType(); - - // Our Win32 Qt external doesn't have the private API. -#if defined(WIN32) || defined(__APPLE__) - wsi.render_surface = window ? reinterpret_cast<void*>(window->winId()) : nullptr; -#else - QPlatformNativeInterface* pni = QGuiApplication::platformNativeInterface(); - wsi.display_connection = pni->nativeResourceForWindow("display", window); - if (wsi.type == Core::Frontend::WindowSystemType::Wayland) - wsi.render_surface = window ? pni->nativeResourceForWindow("surface", window) : nullptr; - else - wsi.render_surface = window ? reinterpret_cast<void*>(window->winId()) : nullptr; -#endif - wsi.render_surface_scale = window ? static_cast<float>(window->devicePixelRatio()) : 1.0f; - - return wsi; -} - GRenderWindow::GRenderWindow(GMainWindow* parent, EmuThread* emu_thread_, std::shared_ptr<InputCommon::InputSubsystem> input_subsystem_, Core::System& system_) @@ -904,7 +884,7 @@ bool GRenderWindow::InitRenderTarget() { } // Update the Window System information with the new render target - window_info = GetWindowSystemInfo(child_widget->windowHandle()); + window_info = QtCommon::GetWindowSystemInfo(child_widget->windowHandle()); child_widget->resize(Layout::ScreenUndocked::Width, Layout::ScreenUndocked::Height); layout()->addWidget(child_widget); diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index bb4eca07f..4276be82b 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h @@ -5,27 +5,46 @@ #include <atomic> #include <condition_variable> +#include <cstddef> #include <memory> #include <mutex> +#include <stop_token> +#include <utility> +#include <vector> +#include <QByteArray> #include <QImage> +#include <QObject> +#include <QPoint> +#include <QString> #include <QStringList> #include <QThread> -#include <QTouchEvent> #include <QWidget> +#include <qglobal.h> +#include <qnamespace.h> +#include <qobjectdefs.h> +#include "common/common_types.h" +#include "common/logging/log.h" #include "common/polyfill_thread.h" #include "common/thread.h" #include "core/frontend/emu_window.h" -class GRenderWindow; class GMainWindow; class QCamera; class QCameraImageCapture; +class QCloseEvent; +class QFocusEvent; class QKeyEvent; +class QMouseEvent; +class QObject; +class QResizeEvent; +class QShowEvent; +class QTimer; +class QTouchEvent; +class QWheelEvent; namespace Core { -enum class SystemResultStatus : u32; class System; } // namespace Core @@ -40,7 +59,6 @@ enum class TasState; namespace VideoCore { enum class LoadCallbackStage; -class RendererBase; } // namespace VideoCore class EmuThread final : public QThread { diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index bb731276e..a85eb4687 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -6,6 +6,7 @@ #include <QSettings> #include "common/fs/fs.h" #include "common/fs/path_util.h" +#include "common/settings.h" #include "core/core.h" #include "core/hle/service/acc/profile_manager.h" #include "core/hle/service/hid/controllers/npad.h" @@ -497,7 +498,7 @@ void Config::ReadCoreValues() { qt_config->beginGroup(QStringLiteral("Core")); ReadGlobalSetting(Settings::values.use_multi_core); - ReadGlobalSetting(Settings::values.use_extended_memory_layout); + ReadGlobalSetting(Settings::values.use_unsafe_extended_memory_layout); qt_config->endGroup(); } @@ -692,6 +693,7 @@ void Config::ReadRendererValues() { qt_config->beginGroup(QStringLiteral("Renderer")); ReadGlobalSetting(Settings::values.renderer_backend); + ReadGlobalSetting(Settings::values.async_presentation); ReadGlobalSetting(Settings::values.renderer_force_max_clock); ReadGlobalSetting(Settings::values.vulkan_device); ReadGlobalSetting(Settings::values.fullscreen_mode); @@ -708,17 +710,19 @@ void Config::ReadRendererValues() { ReadGlobalSetting(Settings::values.nvdec_emulation); ReadGlobalSetting(Settings::values.accelerate_astc); ReadGlobalSetting(Settings::values.async_astc); - ReadGlobalSetting(Settings::values.use_vsync); ReadGlobalSetting(Settings::values.shader_backend); ReadGlobalSetting(Settings::values.use_asynchronous_shaders); ReadGlobalSetting(Settings::values.use_fast_gpu_time); - ReadGlobalSetting(Settings::values.use_pessimistic_flushes); ReadGlobalSetting(Settings::values.use_vulkan_driver_pipeline_cache); ReadGlobalSetting(Settings::values.bg_red); ReadGlobalSetting(Settings::values.bg_green); ReadGlobalSetting(Settings::values.bg_blue); if (global) { + Settings::values.vsync_mode.SetValue(static_cast<Settings::VSyncMode>( + ReadSetting(QString::fromStdString(Settings::values.vsync_mode.GetLabel()), + static_cast<u32>(Settings::values.vsync_mode.GetDefault())) + .value<u32>())); ReadBasicSetting(Settings::values.renderer_debug); ReadBasicSetting(Settings::values.renderer_shader_feedback); ReadBasicSetting(Settings::values.enable_nsight_aftermath); @@ -1161,7 +1165,7 @@ void Config::SaveCoreValues() { qt_config->beginGroup(QStringLiteral("Core")); WriteGlobalSetting(Settings::values.use_multi_core); - WriteGlobalSetting(Settings::values.use_extended_memory_layout); + WriteGlobalSetting(Settings::values.use_unsafe_extended_memory_layout); qt_config->endGroup(); } @@ -1313,6 +1317,7 @@ 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()); + WriteGlobalSetting(Settings::values.async_presentation); WriteGlobalSetting(Settings::values.renderer_force_max_clock); WriteGlobalSetting(Settings::values.vulkan_device); WriteSetting(QString::fromStdString(Settings::values.fullscreen_mode.GetLabel()), @@ -1350,20 +1355,21 @@ void Config::SaveRendererValues() { Settings::values.nvdec_emulation.UsingGlobal()); WriteGlobalSetting(Settings::values.accelerate_astc); WriteGlobalSetting(Settings::values.async_astc); - WriteGlobalSetting(Settings::values.use_vsync); 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_pessimistic_flushes); WriteGlobalSetting(Settings::values.use_vulkan_driver_pipeline_cache); WriteGlobalSetting(Settings::values.bg_red); WriteGlobalSetting(Settings::values.bg_green); WriteGlobalSetting(Settings::values.bg_blue); if (global) { + WriteSetting(QString::fromStdString(Settings::values.vsync_mode.GetLabel()), + static_cast<u32>(Settings::values.vsync_mode.GetValue()), + static_cast<u32>(Settings::values.vsync_mode.GetDefault())); WriteBasicSetting(Settings::values.renderer_debug); WriteBasicSetting(Settings::values.renderer_shader_feedback); WriteBasicSetting(Settings::values.enable_nsight_aftermath); diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp index 207bcdc4d..26258d744 100644 --- a/src/yuzu/configuration/configure_general.cpp +++ b/src/yuzu/configuration/configure_general.cpp @@ -35,9 +35,6 @@ void ConfigureGeneral::SetConfiguration() { ui->use_multi_core->setEnabled(runtime_lock); ui->use_multi_core->setChecked(Settings::values.use_multi_core.GetValue()); - ui->use_extended_memory_layout->setEnabled(runtime_lock); - ui->use_extended_memory_layout->setChecked( - Settings::values.use_extended_memory_layout.GetValue()); ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing.GetValue()); ui->toggle_user_on_boot->setChecked(UISettings::values.select_user_on_boot.GetValue()); @@ -79,9 +76,6 @@ void ConfigureGeneral::ResetDefaults() { void ConfigureGeneral::ApplyConfiguration() { ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_multi_core, ui->use_multi_core, use_multi_core); - ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_extended_memory_layout, - ui->use_extended_memory_layout, - use_extended_memory_layout); if (Settings::IsConfiguringGlobal()) { UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked(); @@ -141,9 +135,6 @@ void ConfigureGeneral::SetupPerGameUI() { Settings::values.use_speed_limit, use_speed_limit); ConfigurationShared::SetColoredTristate(ui->use_multi_core, Settings::values.use_multi_core, use_multi_core); - ConfigurationShared::SetColoredTristate(ui->use_extended_memory_layout, - Settings::values.use_extended_memory_layout, - use_extended_memory_layout); connect(ui->toggle_speed_limit, &QCheckBox::clicked, ui->speed_limit, [this]() { ui->speed_limit->setEnabled(ui->toggle_speed_limit->isChecked() && diff --git a/src/yuzu/configuration/configure_general.h b/src/yuzu/configuration/configure_general.h index a090c1a3f..7ff63f425 100644 --- a/src/yuzu/configuration/configure_general.h +++ b/src/yuzu/configuration/configure_general.h @@ -47,7 +47,6 @@ private: ConfigurationShared::CheckState use_speed_limit; ConfigurationShared::CheckState use_multi_core; - ConfigurationShared::CheckState use_extended_memory_layout; const Core::System& system; }; diff --git a/src/yuzu/configuration/configure_general.ui b/src/yuzu/configuration/configure_general.ui index add110bb0..986a1625b 100644 --- a/src/yuzu/configuration/configure_general.ui +++ b/src/yuzu/configuration/configure_general.ui @@ -62,13 +62,6 @@ </widget> </item> <item> - <widget class="QCheckBox" name="use_extended_memory_layout"> - <property name="text"> - <string>Extended memory layout (8GB DRAM)</string> - </property> - </widget> - </item> - <item> <widget class="QCheckBox" name="toggle_check_exit"> <property name="text"> <string>Confirm exit while emulation is running</string> diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp index e9388daad..76e5b7499 100644 --- a/src/yuzu/configuration/configure_graphics.cpp +++ b/src/yuzu/configuration/configure_graphics.cpp @@ -4,20 +4,76 @@ // Include this early to include Vulkan headers how we want to #include "video_core/vulkan_common/vulkan_wrapper.h" +#include <algorithm> +#include <iosfwd> +#include <iterator> +#include <string> +#include <tuple> +#include <utility> +#include <vector> +#include <QBoxLayout> +#include <QCheckBox> #include <QColorDialog> -#include <QVulkanInstance> +#include <QComboBox> +#include <QIcon> +#include <QLabel> +#include <QPixmap> +#include <QPushButton> +#include <QSlider> +#include <QStringLiteral> +#include <QtCore/qobjectdefs.h> +#include <qcoreevent.h> +#include <qglobal.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 "core/core.h" #include "ui_configure_graphics.h" #include "video_core/vulkan_common/vulkan_instance.h" #include "video_core/vulkan_common/vulkan_library.h" +#include "video_core/vulkan_common/vulkan_surface.h" #include "yuzu/configuration/configuration_shared.h" #include "yuzu/configuration/configure_graphics.h" +#include "yuzu/qt_common.h" #include "yuzu/uisettings.h" +static const std::vector<VkPresentModeKHR> default_present_modes{VK_PRESENT_MODE_IMMEDIATE_KHR, + VK_PRESENT_MODE_FIFO_KHR}; + +// Converts a setting to a present mode (or vice versa) +static constexpr VkPresentModeKHR VSyncSettingToMode(Settings::VSyncMode mode) { + switch (mode) { + case Settings::VSyncMode::Immediate: + return VK_PRESENT_MODE_IMMEDIATE_KHR; + case Settings::VSyncMode::Mailbox: + return VK_PRESENT_MODE_MAILBOX_KHR; + case Settings::VSyncMode::FIFO: + return VK_PRESENT_MODE_FIFO_KHR; + case Settings::VSyncMode::FIFORelaxed: + return VK_PRESENT_MODE_FIFO_RELAXED_KHR; + default: + return VK_PRESENT_MODE_FIFO_KHR; + } +} + +static constexpr Settings::VSyncMode PresentModeToSetting(VkPresentModeKHR mode) { + switch (mode) { + case VK_PRESENT_MODE_IMMEDIATE_KHR: + return Settings::VSyncMode::Immediate; + case VK_PRESENT_MODE_MAILBOX_KHR: + return Settings::VSyncMode::Mailbox; + case VK_PRESENT_MODE_FIFO_KHR: + return Settings::VSyncMode::FIFO; + case VK_PRESENT_MODE_FIFO_RELAXED_KHR: + return Settings::VSyncMode::FIFORelaxed; + default: + return Settings::VSyncMode::FIFO; + } +} + ConfigureGraphics::ConfigureGraphics(const Core::System& system_, QWidget* parent) : QWidget(parent), ui{std::make_unique<Ui::ConfigureGraphics>()}, system{system_} { vulkan_device = Settings::values.vulkan_device.GetValue(); @@ -39,13 +95,16 @@ ConfigureGraphics::ConfigureGraphics(const Core::System& system_, QWidget* paren connect(ui->api, qOverload<int>(&QComboBox::currentIndexChanged), 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); }); + connect(ui->device, qOverload<int>(&QComboBox::activated), this, [this](int device) { + UpdateDeviceSelection(device); + PopulateVSyncModeSelection(); + }); connect(ui->backend, qOverload<int>(&QComboBox::activated), this, [this](int backend) { UpdateShaderBackendSelection(backend); }); @@ -70,6 +129,43 @@ ConfigureGraphics::ConfigureGraphics(const Core::System& system_, QWidget* paren ui->fsr_sharpening_label->setVisible(Settings::IsConfiguringGlobal()); } +void ConfigureGraphics::PopulateVSyncModeSelection() { + const Settings::RendererBackend backend{GetCurrentGraphicsBackend()}; + if (backend == Settings::RendererBackend::Null) { + ui->vsync_mode_combobox->setEnabled(false); + return; + } + ui->vsync_mode_combobox->setEnabled(true); + + const int current_index = //< current selected vsync mode from combobox + ui->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 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_enum_map.clear(); + vsync_mode_combobox_enum_map.reserve(present_modes.size()); + for (const auto present_mode : present_modes) { + const auto mode_name = TranslateVSyncMode(present_mode, backend); + if (mode_name.isEmpty()) { + continue; + } + + ui->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); + } + index++; + } +} + void ConfigureGraphics::UpdateDeviceSelection(int device) { if (device == -1) { return; @@ -99,6 +195,9 @@ void ConfigureGraphics::SetConfiguration() { 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()); @@ -170,7 +269,24 @@ void ConfigureGraphics::SetConfiguration() { 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; + } + index++; + } + if (static_cast<unsigned long>(index) < vsync_mode_combobox_enum_map.size()) { + ui->vsync_mode_combobox->setCurrentIndex(index); + } + } } void ConfigureGraphics::SetFSRIndicatorText(int percentage) { @@ -178,6 +294,27 @@ void ConfigureGraphics::SetFSRIndicatorText(int percentage) { tr("%1%", "FSR sharpening percentage (e.g. 50%)").arg(100 - (percentage / 2))); } +const QString ConfigureGraphics::TranslateVSyncMode(VkPresentModeKHR mode, + Settings::RendererBackend backend) const { + switch (mode) { + case VK_PRESENT_MODE_IMMEDIATE_KHR: + return backend == Settings::RendererBackend::OpenGL + ? tr("Off") + : QStringLiteral("Immediate (%1)").arg(tr("VSync Off")); + case VK_PRESENT_MODE_MAILBOX_KHR: + return QStringLiteral("Mailbox (%1)").arg(tr("Recommended")); + case VK_PRESENT_MODE_FIFO_KHR: + return backend == Settings::RendererBackend::OpenGL + ? tr("On") + : QStringLiteral("FIFO (%1)").arg(tr("VSync On")); + case VK_PRESENT_MODE_FIFO_RELAXED_KHR: + return QStringLiteral("FIFO Relaxed"); + default: + return {}; + break; + } +} + void ConfigureGraphics::ApplyConfiguration() { const auto resolution_setup = static_cast<Settings::ResolutionSetup>( ui->resolution_combobox->currentIndex() - @@ -232,6 +369,10 @@ void ConfigureGraphics::ApplyConfiguration() { 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 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); @@ -345,7 +486,9 @@ void ConfigureGraphics::UpdateAPILayout() { ui->backend_widget->setVisible(true); break; case Settings::RendererBackend::Vulkan: - ui->device->setCurrentIndex(vulkan_device); + 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; @@ -363,16 +506,27 @@ void ConfigureGraphics::RetrieveVulkanDevices() try { using namespace Vulkan; + auto* window = this->window()->windowHandle(); + auto wsi = QtCommon::GetWindowSystemInfo(window); + vk::InstanceDispatch dld; const Common::DynamicLibrary library = OpenLibrary(); - const vk::Instance instance = CreateInstance(library, dld, VK_API_VERSION_1_1); + const vk::Instance instance = CreateInstance(library, dld, VK_API_VERSION_1_1, wsi.type); const std::vector<VkPhysicalDevice> physical_devices = instance.EnumeratePhysicalDevices(); + vk::SurfaceKHR surface = //< needed to view present modes for a device + CreateSurface(instance, wsi); vulkan_devices.clear(); vulkan_devices.reserve(physical_devices.size()); + device_present_modes.clear(); + device_present_modes.reserve(physical_devices.size()); for (const VkPhysicalDevice device : physical_devices) { - const std::string name = vk::PhysicalDevice(device, dld).GetProperties().deviceName; + const auto physical_device = vk::PhysicalDevice(device, dld); + const std::string name = physical_device.GetProperties().deviceName; + const std::vector<VkPresentModeKHR> present_modes = + physical_device.GetSurfacePresentModesKHR(*surface); vulkan_devices.push_back(QString::fromStdString(name)); + device_present_modes.push_back(present_modes); } } catch (const Vulkan::vk::Exception& exception) { LOG_ERROR(Frontend, "Failed to enumerate devices with error: {}", exception.what()); @@ -465,4 +619,6 @@ void ConfigureGraphics::SetupPerGameUI() { 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); } diff --git a/src/yuzu/configuration/configure_graphics.h b/src/yuzu/configuration/configure_graphics.h index d98d6624e..901f604a5 100644 --- a/src/yuzu/configuration/configure_graphics.h +++ b/src/yuzu/configuration/configure_graphics.h @@ -5,9 +5,21 @@ #include <memory> #include <vector> +#include <QColor> #include <QString> #include <QWidget> -#include "common/settings.h" +#include <qobjectdefs.h> +#include <vulkan/vulkan_core.h> +#include "common/common_types.h" + +class QEvent; +class QObject; + +namespace Settings { +enum class NvdecEmulation : u32; +enum class RendererBackend : u32; +enum class ShaderBackend : u32; +} // namespace Settings namespace Core { class System; @@ -35,6 +47,7 @@ private: void changeEvent(QEvent* event) override; void RetranslateUI(); + void PopulateVSyncModeSelection(); void UpdateBackgroundColorButton(QColor color); void UpdateAPILayout(); void UpdateDeviceSelection(int device); @@ -43,6 +56,10 @@ 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(); @@ -58,6 +75,10 @@ private: ConfigurationShared::CheckState use_asynchronous_gpu_emulation; 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 u32 vulkan_device{}; Settings::ShaderBackend shader_backend{}; diff --git a/src/yuzu/configuration/configure_graphics.ui b/src/yuzu/configuration/configure_graphics.ui index a45ec69ec..39f70e406 100644 --- a/src/yuzu/configuration/configure_graphics.ui +++ b/src/yuzu/configuration/configure_graphics.ui @@ -189,6 +189,44 @@ </widget> </item> <item> + <widget class="QWidget" name="vsync_mode_layout" native="true"> + <layout class="QHBoxLayout" name="horizontalLayout_4"> + <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="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"> <property name="leftMargin"> @@ -366,7 +404,7 @@ </item> <item> <property name="text"> - <string>1.5X (1080p/1620p) [EXPERIMENTAL]</string> + <string>1.5X (1080p/1620p) [EXPERIMENTAL]</string> </property> </item> <item> diff --git a/src/yuzu/configuration/configure_graphics_advanced.cpp b/src/yuzu/configuration/configure_graphics_advanced.cpp index 59fb1b334..005b022ca 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.cpp +++ b/src/yuzu/configuration/configure_graphics_advanced.cpp @@ -21,18 +21,17 @@ ConfigureGraphicsAdvanced::~ConfigureGraphicsAdvanced() = default; void ConfigureGraphicsAdvanced::SetConfiguration() { const bool runtime_lock = !system.IsPoweredOn(); - ui->use_vsync->setEnabled(runtime_lock); + ui->async_present->setEnabled(runtime_lock); ui->renderer_force_max_clock->setEnabled(runtime_lock); ui->async_astc->setEnabled(runtime_lock); ui->use_asynchronous_shaders->setEnabled(runtime_lock); ui->anisotropic_filtering_combobox->setEnabled(runtime_lock); + ui->async_present->setChecked(Settings::values.async_presentation.GetValue()); ui->renderer_force_max_clock->setChecked(Settings::values.renderer_force_max_clock.GetValue()); - ui->use_vsync->setChecked(Settings::values.use_vsync.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_pessimistic_flushes->setChecked(Settings::values.use_pessimistic_flushes.GetValue()); ui->use_vulkan_driver_pipeline_cache->setChecked( Settings::values.use_vulkan_driver_pipeline_cache.GetValue()); @@ -54,12 +53,13 @@ void ConfigureGraphicsAdvanced::SetConfiguration() { 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_vsync, ui->use_vsync, use_vsync); ConfigurationShared::ApplyPerGameSetting(&Settings::values.async_astc, ui->async_astc, async_astc); ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_asynchronous_shaders, @@ -67,8 +67,6 @@ void ConfigureGraphicsAdvanced::ApplyConfiguration() { 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_pessimistic_flushes, - ui->use_pessimistic_flushes, use_pessimistic_flushes); ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vulkan_driver_pipeline_cache, ui->use_vulkan_driver_pipeline_cache, use_vulkan_driver_pipeline_cache); @@ -90,15 +88,13 @@ 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_vsync->setEnabled(Settings::values.use_vsync.UsingGlobal()); ui->async_astc->setEnabled(Settings::values.async_astc.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_pessimistic_flushes->setEnabled( - Settings::values.use_pessimistic_flushes.UsingGlobal()); ui->use_vulkan_driver_pipeline_cache->setEnabled( Settings::values.use_vulkan_driver_pipeline_cache.UsingGlobal()); ui->anisotropic_filtering_combobox->setEnabled( @@ -107,10 +103,11 @@ void ConfigureGraphicsAdvanced::SetupPerGameUI() { 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_vsync, Settings::values.use_vsync, use_vsync); ConfigurationShared::SetColoredTristate(ui->async_astc, Settings::values.async_astc, async_astc); ConfigurationShared::SetColoredTristate(ui->use_asynchronous_shaders, @@ -118,9 +115,6 @@ void ConfigureGraphicsAdvanced::SetupPerGameUI() { use_asynchronous_shaders); ConfigurationShared::SetColoredTristate(ui->use_fast_gpu_time, Settings::values.use_fast_gpu_time, use_fast_gpu_time); - ConfigurationShared::SetColoredTristate(ui->use_pessimistic_flushes, - Settings::values.use_pessimistic_flushes, - use_pessimistic_flushes); ConfigurationShared::SetColoredTristate(ui->use_vulkan_driver_pipeline_cache, Settings::values.use_vulkan_driver_pipeline_cache, use_vulkan_driver_pipeline_cache); diff --git a/src/yuzu/configuration/configure_graphics_advanced.h b/src/yuzu/configuration/configure_graphics_advanced.h index bf1b04749..ff5060957 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.h +++ b/src/yuzu/configuration/configure_graphics_advanced.h @@ -36,12 +36,12 @@ private: 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_asynchronous_shaders; ConfigurationShared::CheckState use_fast_gpu_time; - ConfigurationShared::CheckState use_pessimistic_flushes; ConfigurationShared::CheckState use_vulkan_driver_pipeline_cache; const Core::System& system; diff --git a/src/yuzu/configuration/configure_graphics_advanced.ui b/src/yuzu/configuration/configure_graphics_advanced.ui index a7dbdc18c..d073fe9b1 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.ui +++ b/src/yuzu/configuration/configure_graphics_advanced.ui @@ -7,7 +7,7 @@ <x>0</x> <y>0</y> <width>404</width> - <height>321</height> + <height>376</height> </rect> </property> <property name="windowTitle"> @@ -70,22 +70,19 @@ </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> + <widget class="QCheckBox" name="async_present"> <property name="text"> - <string>Force maximum clocks (Vulkan only)</string> + <string>Enable asynchronous presentation (Vulkan only)</string> </property> </widget> </item> <item> - <widget class="QCheckBox" name="use_vsync"> + <widget class="QCheckBox" name="renderer_force_max_clock"> <property name="toolTip"> - <string>VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference.</string> + <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>Use VSync</string> + <string>Force maximum clocks (Vulkan only)</string> </property> </widget> </item> @@ -112,7 +109,7 @@ <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> + <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> @@ -120,19 +117,9 @@ </widget> </item> <item> - <widget class="QCheckBox" name="use_pessimistic_flushes"> - <property name="toolTip"> - <string>Enables pessimistic buffer flushes. This option will force unmodified buffers to be flushed, which can cost performance.</string> - </property> - <property name="text"> - <string>Use pessimistic buffer flushes (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> + <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> diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index 50b62293e..561a08dc5 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp @@ -8,6 +8,7 @@ #include <QInputDialog> #include <QMenu> #include <QMessageBox> +#include <QMouseEvent> #include <QTimer> #include "common/assert.h" #include "common/param_package.h" @@ -206,7 +207,7 @@ QString ConfigureInputPlayer::ButtonToText(const Common::ParamPackage& param) { } if (param.Has("axis")) { const QString axis = QString::fromStdString(param.Get("axis", "")); - return QObject::tr("%1%2Axis %3").arg(toggle, invert, axis); + return QObject::tr("%1%2%3Axis %4").arg(toggle, inverted, invert, axis); } if (param.Has("axis_x") && param.Has("axis_y") && param.Has("axis_z")) { const QString axis_x = QString::fromStdString(param.Get("axis_x", "")); @@ -229,7 +230,7 @@ QString ConfigureInputPlayer::ButtonToText(const Common::ParamPackage& param) { return QObject::tr("%1%2%3Hat %4").arg(turbo, toggle, inverted, button_name); } if (param.Has("axis")) { - return QObject::tr("%1%2Axis %3").arg(toggle, inverted, button_name); + return QObject::tr("%1%2%3Axis %4").arg(toggle, inverted, invert, button_name); } if (param.Has("motion")) { return QObject::tr("%1%2Axis %3").arg(toggle, inverted, button_name); @@ -410,6 +411,12 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i button_map[button_id]->setText(ButtonToText(param)); emulated_controller->SetButtonParam(button_id, param); }); + context_menu.addAction(tr("Invert button"), [&] { + const bool invert_value = !param.Get("inverted", false); + param.Set("inverted", invert_value); + button_map[button_id]->setText(ButtonToText(param)); + emulated_controller->SetButtonParam(button_id, param); + }); context_menu.addAction(tr("Set threshold"), [&] { const int button_threshold = static_cast<int>(param.Get("threshold", 0.5f) * 100.0f); diff --git a/src/yuzu/configuration/configure_input_player_widget.cpp b/src/yuzu/configuration/configure_input_player_widget.cpp index c287220fc..fe1ee2289 100644 --- a/src/yuzu/configuration/configure_input_player_widget.cpp +++ b/src/yuzu/configuration/configure_input_player_widget.cpp @@ -180,6 +180,10 @@ void PlayerControlPreview::ControllerUpdate(Core::HID::ControllerTriggerType typ battery_values = controller->GetBatteryValues(); needs_redraw = true; break; + case Core::HID::ControllerTriggerType::Motion: + motion_values = controller->GetMotions(); + needs_redraw = true; + break; default: break; } @@ -313,6 +317,15 @@ void PlayerControlPreview::DrawLeftController(QPainter& p, const QPointF center) DrawRawJoystick(p, center + QPointF(-140, 90), QPointF(0, 0)); } + { + // Draw motion cubes + using namespace Settings::NativeMotion; + p.setPen(colors.outline); + p.setBrush(colors.transparent); + Draw3dCube(p, center + QPointF(-140, 90), + motion_values[Settings::NativeMotion::MotionLeft].euler, 20.0f); + } + using namespace Settings::NativeButton; // D-pad constants @@ -435,6 +448,15 @@ void PlayerControlPreview::DrawRightController(QPainter& p, const QPointF center DrawRawJoystick(p, QPointF(0, 0), center + QPointF(140, 90)); } + { + // Draw motion cubes + using namespace Settings::NativeMotion; + p.setPen(colors.outline); + p.setBrush(colors.transparent); + Draw3dCube(p, center + QPointF(140, 90), + motion_values[Settings::NativeMotion::MotionRight].euler, 20.0f); + } + using namespace Settings::NativeButton; // Face buttons constants @@ -555,6 +577,17 @@ void PlayerControlPreview::DrawDualController(QPainter& p, const QPointF center) DrawRawJoystick(p, center + QPointF(-180, 90), center + QPointF(180, 90)); } + { + // Draw motion cubes + using namespace Settings::NativeMotion; + p.setPen(colors.outline); + p.setBrush(colors.transparent); + Draw3dCube(p, center + QPointF(-180, -5), + motion_values[Settings::NativeMotion::MotionLeft].euler, 20.0f); + Draw3dCube(p, center + QPointF(180, -5), + motion_values[Settings::NativeMotion::MotionRight].euler, 20.0f); + } + using namespace Settings::NativeButton; // Face buttons constants @@ -647,6 +680,15 @@ void PlayerControlPreview::DrawHandheldController(QPainter& p, const QPointF cen DrawRawJoystick(p, center + QPointF(-50, 0), center + QPointF(50, 0)); } + { + // Draw motion cubes + using namespace Settings::NativeMotion; + p.setPen(colors.outline); + p.setBrush(colors.transparent); + Draw3dCube(p, center + QPointF(0, -115), + motion_values[Settings::NativeMotion::MotionLeft].euler, 15.0f); + } + using namespace Settings::NativeButton; // Face buttons constants @@ -750,6 +792,15 @@ void PlayerControlPreview::DrawProController(QPainter& p, const QPointF center) DrawRawJoystick(p, center + QPointF(-50, 105), center + QPointF(50, 105)); } + { + // Draw motion cubes + using namespace Settings::NativeMotion; + p.setPen(colors.button); + p.setBrush(colors.transparent); + Draw3dCube(p, center + QPointF(0, -100), + motion_values[Settings::NativeMotion::MotionLeft].euler, 15.0f); + } + using namespace Settings::NativeButton; // Face buttons constants @@ -2871,6 +2922,46 @@ void PlayerControlPreview::DrawArrow(QPainter& p, const QPointF center, const Di DrawPolygon(p, arrow_symbol); } +// Draw motion functions +void PlayerControlPreview::Draw3dCube(QPainter& p, QPointF center, const Common::Vec3f& euler, + float size) { + std::array<Common::Vec3f, 8> cube{ + Common::Vec3f{-1, -1, -1}, + {-1, 1, -1}, + {1, 1, -1}, + {1, -1, -1}, + {-1, -1, 1}, + {-1, 1, 1}, + {1, 1, 1}, + {1, -1, 1}, + }; + + for (Common::Vec3f& point : cube) { + point.RotateFromOrigin(euler.x, euler.y, euler.z); + point *= size; + } + + const std::array<QPointF, 4> front_face{ + center + QPointF{cube[0].x, cube[0].y}, + center + QPointF{cube[1].x, cube[1].y}, + center + QPointF{cube[2].x, cube[2].y}, + center + QPointF{cube[3].x, cube[3].y}, + }; + const std::array<QPointF, 4> back_face{ + center + QPointF{cube[4].x, cube[4].y}, + center + QPointF{cube[5].x, cube[5].y}, + center + QPointF{cube[6].x, cube[6].y}, + center + QPointF{cube[7].x, cube[7].y}, + }; + + DrawPolygon(p, front_face); + DrawPolygon(p, back_face); + p.drawLine(center + QPointF{cube[0].x, cube[0].y}, center + QPointF{cube[4].x, cube[4].y}); + p.drawLine(center + QPointF{cube[1].x, cube[1].y}, center + QPointF{cube[5].x, cube[5].y}); + p.drawLine(center + QPointF{cube[2].x, cube[2].y}, center + QPointF{cube[6].x, cube[6].y}); + p.drawLine(center + QPointF{cube[3].x, cube[3].y}, center + QPointF{cube[7].x, cube[7].y}); +} + template <size_t N> void PlayerControlPreview::DrawPolygon(QPainter& p, const std::array<QPointF, N>& polygon) { p.drawPolygon(polygon.data(), static_cast<int>(polygon.size())); diff --git a/src/yuzu/configuration/configure_input_player_widget.h b/src/yuzu/configuration/configure_input_player_widget.h index 267d134de..a16943c3c 100644 --- a/src/yuzu/configuration/configure_input_player_widget.h +++ b/src/yuzu/configuration/configure_input_player_widget.h @@ -9,6 +9,7 @@ #include "common/input.h" #include "common/settings_input.h" +#include "common/vector_math.h" #include "core/hid/emulated_controller.h" #include "core/hid/hid_types.h" @@ -193,6 +194,9 @@ private: void DrawSymbol(QPainter& p, QPointF center, Symbol symbol, float icon_size); void DrawArrow(QPainter& p, QPointF center, Direction direction, float size); + // Draw motion functions + void Draw3dCube(QPainter& p, QPointF center, const Common::Vec3f& euler, float size); + // Draw primitive types template <size_t N> void DrawPolygon(QPainter& p, const std::array<QPointF, N>& polygon); @@ -222,4 +226,5 @@ private: Core::HID::SticksValues stick_values{}; Core::HID::TriggerValues trigger_values{}; Core::HID::BatteryValues battery_values{}; + Core::HID::MotionState motion_values{}; }; diff --git a/src/yuzu/configuration/configure_system.cpp b/src/yuzu/configuration/configure_system.cpp index 6af34f793..286ccc5cd 100644 --- a/src/yuzu/configuration/configure_system.cpp +++ b/src/yuzu/configuration/configure_system.cpp @@ -111,6 +111,9 @@ void ConfigureSystem::SetConfiguration() { 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()); if (Settings::IsConfiguringGlobal()) { ui->combo_language->setCurrentIndex(Settings::values.language_index.GetValue()); @@ -160,6 +163,9 @@ void ConfigureSystem::ApplyConfiguration() { 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 @@ -215,6 +221,10 @@ void ConfigureSystem::SetupPerGameUI() { 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); } diff --git a/src/yuzu/configuration/configure_system.h b/src/yuzu/configuration/configure_system.h index ec28724a1..ce1a91601 100644 --- a/src/yuzu/configuration/configure_system.h +++ b/src/yuzu/configuration/configure_system.h @@ -41,6 +41,7 @@ private: bool enabled = false; ConfigurationShared::CheckState use_rng_seed; + ConfigurationShared::CheckState use_unsafe_extended_memory_layout; Core::System& system; }; diff --git a/src/yuzu/configuration/configure_system.ui b/src/yuzu/configuration/configure_system.ui index 9e7bc3b93..e0caecd5e 100644 --- a/src/yuzu/configuration/configure_system.ui +++ b/src/yuzu/configuration/configure_system.ui @@ -478,6 +478,13 @@ </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> </item> </layout> diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index b79409a68..ba9eece1d 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -27,6 +27,7 @@ #include "configuration/configure_input.h" #include "configuration/configure_per_game.h" #include "configuration/configure_tas.h" +#include "core/file_sys/romfs_factory.h" #include "core/file_sys/vfs.h" #include "core/file_sys/vfs_real.h" #include "core/frontend/applets/cabinet.h" @@ -4171,6 +4172,8 @@ void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) { } Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::Instance(); + bool all_keys_present{true}; + if (keys.BaseDeriveNecessary()) { Core::Crypto::PartitionDataManager pdm{vfs->OpenDirectory("", FileSys::Mode::Read)}; @@ -4195,6 +4198,7 @@ void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) { errors += tr(" - Missing PRODINFO"); } if (!errors.isEmpty()) { + all_keys_present = false; QMessageBox::warning( this, tr("Derivation Components Missing"), tr("Encryption keys are missing. " @@ -4222,11 +4226,40 @@ void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) { system->GetFileSystemController().CreateFactories(*vfs); + if (all_keys_present && !this->CheckSystemArchiveDecryption()) { + LOG_WARNING(Frontend, "Mii model decryption failed"); + QMessageBox::warning( + this, tr("System Archive Decryption Failed"), + tr("Encryption keys failed to decrypt firmware. " + "<br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu " + "quickstart guide</a> to get all your keys, firmware and " + "games.")); + } + if (behavior == ReinitializeKeyBehavior::Warning) { game_list->PopulateAsync(UISettings::values.game_dirs); } } +bool GMainWindow::CheckSystemArchiveDecryption() { + constexpr u64 MiiModelId = 0x0100000000000802; + + auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); + if (!bis_system) { + // Not having system BIS files is not an error. + return true; + } + + auto mii_nca = bis_system->GetEntry(MiiModelId, FileSys::ContentRecordType::Data); + if (!mii_nca) { + // Not having the Mii model is not an error. + return true; + } + + // Return whether we are able to decrypt the RomFS of the Mii model. + return mii_nca->GetRomFS().get() != nullptr; +} + std::optional<u64> GMainWindow::SelectRomFSDumpTarget(const FileSys::ContentProvider& installed, u64 program_id) { const auto dlc_entries = diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 8b5c1d747..3bbc31ada 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -392,6 +392,7 @@ private: void LoadTranslation(); void OpenPerGameConfiguration(u64 title_id, const std::string& file_name); bool CheckDarkMode(); + bool CheckSystemArchiveDecryption(); QString GetTasStateDescription() const; bool CreateShortcut(const std::string& shortcut_path, const std::string& title, diff --git a/src/yuzu/qt_common.cpp b/src/yuzu/qt_common.cpp new file mode 100644 index 000000000..5ac9fe310 --- /dev/null +++ b/src/yuzu/qt_common.cpp @@ -0,0 +1,55 @@ +// SPDX-FileCopyrightText: 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include <QGuiApplication> +#include <QStringLiteral> +#include <QWindow> +#include "common/logging/log.h" +#include "core/frontend/emu_window.h" +#include "yuzu/qt_common.h" + +#ifdef __linux__ +#include <qpa/qplatformnativeinterface.h> +#endif + +namespace QtCommon { +Core::Frontend::WindowSystemType GetWindowSystemType() { + // Determine WSI type based on Qt platform. + QString platform_name = QGuiApplication::platformName(); + if (platform_name == QStringLiteral("windows")) + return Core::Frontend::WindowSystemType::Windows; + else if (platform_name == QStringLiteral("xcb")) + return Core::Frontend::WindowSystemType::X11; + else if (platform_name == QStringLiteral("wayland")) + return Core::Frontend::WindowSystemType::Wayland; + else if (platform_name == QStringLiteral("wayland-egl")) + return Core::Frontend::WindowSystemType::Wayland; + else if (platform_name == QStringLiteral("cocoa")) + return Core::Frontend::WindowSystemType::Cocoa; + else if (platform_name == QStringLiteral("android")) + return Core::Frontend::WindowSystemType::Android; + + LOG_CRITICAL(Frontend, "Unknown Qt platform {}!", platform_name.toStdString()); + return Core::Frontend::WindowSystemType::Windows; +} // namespace Core::Frontend::WindowSystemType + +Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window) { + Core::Frontend::EmuWindow::WindowSystemInfo wsi; + wsi.type = GetWindowSystemType(); + + // Our Win32 Qt external doesn't have the private API. +#if defined(WIN32) || defined(__APPLE__) + wsi.render_surface = window ? reinterpret_cast<void*>(window->winId()) : nullptr; +#else + QPlatformNativeInterface* pni = QGuiApplication::platformNativeInterface(); + wsi.display_connection = pni->nativeResourceForWindow("display", window); + if (wsi.type == Core::Frontend::WindowSystemType::Wayland) + wsi.render_surface = window ? pni->nativeResourceForWindow("surface", window) : nullptr; + else + wsi.render_surface = window ? reinterpret_cast<void*>(window->winId()) : nullptr; +#endif + wsi.render_surface_scale = window ? static_cast<float>(window->devicePixelRatio()) : 1.0f; + + return wsi; +} +} // namespace QtCommon diff --git a/src/yuzu/qt_common.h b/src/yuzu/qt_common.h new file mode 100644 index 000000000..9c63f08f3 --- /dev/null +++ b/src/yuzu/qt_common.h @@ -0,0 +1,15 @@ +// SPDX-FileCopyrightText: 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <QWindow> +#include "core/frontend/emu_window.h" + +namespace QtCommon { + +Core::Frontend::WindowSystemType GetWindowSystemType(); + +Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window); + +} // namespace QtCommon |