summaryrefslogtreecommitdiff
path: root/src/yuzu
diff options
context:
space:
mode:
Diffstat (limited to 'src/yuzu')
-rw-r--r--src/yuzu/CMakeLists.txt40
-rw-r--r--src/yuzu/applets/qt_amiibo_settings.cpp264
-rw-r--r--src/yuzu/applets/qt_amiibo_settings.h83
-rw-r--r--src/yuzu/applets/qt_amiibo_settings.ui494
-rw-r--r--src/yuzu/bootmanager.cpp32
-rw-r--r--src/yuzu/bootmanager.h4
-rw-r--r--src/yuzu/compatdb.cpp1
-rw-r--r--src/yuzu/configuration/config.cpp5
-rw-r--r--src/yuzu/configuration/configure_camera.cpp7
-rw-r--r--src/yuzu/configuration/configure_camera.h2
-rw-r--r--src/yuzu/configuration/configure_graphics.cpp45
-rw-r--r--src/yuzu/configuration/configure_graphics.h2
-rw-r--r--src/yuzu/configuration/configure_graphics.ui151
-rw-r--r--src/yuzu/configuration/configure_input_advanced.cpp4
-rw-r--r--src/yuzu/main.cpp102
-rw-r--r--src/yuzu/main.h13
-rw-r--r--src/yuzu/main.ui9
-rw-r--r--src/yuzu/multiplayer/chat_room.h1
-rw-r--r--src/yuzu/multiplayer/direct_connect.cpp2
-rw-r--r--src/yuzu/multiplayer/validation.h16
-rw-r--r--src/yuzu/precompiled_headers.h6
-rw-r--r--src/yuzu/startup_checks.cpp84
-rw-r--r--src/yuzu/startup_checks.h4
23 files changed, 1304 insertions, 67 deletions
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index 8a252bd5d..f192d6329 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -18,6 +18,9 @@ add_executable(yuzu
about_dialog.cpp
about_dialog.h
aboutdialog.ui
+ applets/qt_amiibo_settings.cpp
+ applets/qt_amiibo_settings.h
+ applets/qt_amiibo_settings.ui
applets/qt_controller.cpp
applets/qt_controller.h
applets/qt_controller.ui
@@ -186,6 +189,7 @@ add_executable(yuzu
multiplayer/state.cpp
multiplayer/state.h
multiplayer/validation.h
+ precompiled_headers.h
startup_checks.cpp
startup_checks.h
uisettings.cpp
@@ -295,7 +299,7 @@ if (APPLE)
set_target_properties(yuzu PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist)
elseif(WIN32)
# compile as a win32 gui application instead of a console application
- if (QT_VERSION VERSION_GREATER 6)
+ if (QT_VERSION VERSION_GREATER_EQUAL 6)
target_link_libraries(yuzu PRIVATE Qt6::EntryPointPrivate)
else()
target_link_libraries(yuzu PRIVATE Qt5::WinMain)
@@ -311,15 +315,15 @@ endif()
create_target_directory_groups(yuzu)
target_link_libraries(yuzu PRIVATE common core input_common network video_core)
-target_link_libraries(yuzu PRIVATE Boost::boost glad Qt::Widgets Qt::Multimedia)
+target_link_libraries(yuzu PRIVATE Boost::boost glad Qt${QT_MAJOR_VERSION}::Widgets)
target_link_libraries(yuzu PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads)
target_include_directories(yuzu PRIVATE ../../externals/Vulkan-Headers/include)
if (NOT WIN32)
- target_include_directories(yuzu PRIVATE ${Qt5Gui_PRIVATE_INCLUDE_DIRS})
+ target_include_directories(yuzu PRIVATE ${Qt${QT_MAJOR_VERSION}Gui_PRIVATE_INCLUDE_DIRS})
endif()
if (UNIX AND NOT APPLE)
- target_link_libraries(yuzu PRIVATE Qt::DBus)
+ target_link_libraries(yuzu PRIVATE Qt${QT_MAJOR_VERSION}::DBus)
endif()
target_compile_definitions(yuzu PRIVATE
@@ -358,8 +362,13 @@ if (ENABLE_WEB_SERVICE)
target_compile_definitions(yuzu PRIVATE -DENABLE_WEB_SERVICE)
endif()
+if (YUZU_USE_QT_MULTIMEDIA)
+ target_link_libraries(yuzu PRIVATE Qt${QT_MAJOR_VERSION}::Multimedia)
+ target_compile_definitions(yuzu PRIVATE -DYUZU_USE_QT_MULTIMEDIA)
+endif ()
+
if (YUZU_USE_QT_WEB_ENGINE)
- target_link_libraries(yuzu PRIVATE Qt::WebEngineCore Qt::WebEngineWidgets)
+ target_link_libraries(yuzu PRIVATE Qt${QT_MAJOR_VERSION}::WebEngineCore Qt${QT_MAJOR_VERSION}::WebEngineWidgets)
target_compile_definitions(yuzu PRIVATE -DYUZU_USE_QT_WEB_ENGINE)
endif ()
@@ -367,13 +376,26 @@ if(UNIX AND NOT APPLE)
install(TARGETS yuzu)
endif()
-if (YUZU_USE_BUNDLED_QT)
+if (WIN32 AND QT_VERSION VERSION_GREATER_EQUAL 6)
+ if (MSVC AND NOT ${CMAKE_GENERATOR} STREQUAL "Ninja")
+ set(YUZU_EXE_DIR "${CMAKE_BINARY_DIR}/bin/$<CONFIG>")
+ else()
+ set(YUZU_EXE_DIR "${CMAKE_BINARY_DIR}/bin")
+ endif()
+ add_custom_command(TARGET yuzu POST_BUILD COMMAND ${WINDEPLOYQT_EXECUTABLE} "${YUZU_EXE_DIR}/yuzu.exe" --dir "${YUZU_EXE_DIR}" --libdir "${YUZU_EXE_DIR}" --plugindir "${YUZU_EXE_DIR}/plugins" --no-compiler-runtime --no-opengl-sw --no-system-d3d-compiler --no-translations --verbose 0)
+endif()
+
+if (YUZU_USE_BUNDLED_QT AND QT_VERSION VERSION_LESS 6)
include(CopyYuzuQt5Deps)
copy_yuzu_Qt5_deps(yuzu)
endif()
if (ENABLE_SDL2)
- target_link_libraries(yuzu PRIVATE SDL2)
+ if (YUZU_USE_EXTERNAL_SDL2)
+ target_link_libraries(yuzu PRIVATE SDL2-static)
+ else()
+ target_link_libraries(yuzu PRIVATE SDL2)
+ endif()
target_compile_definitions(yuzu PRIVATE HAVE_SDL2)
endif()
@@ -391,3 +413,7 @@ endif()
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
target_link_libraries(yuzu PRIVATE dynarmic)
endif()
+
+if (YUZU_USE_PRECOMPILED_HEADERS)
+ target_precompile_headers(yuzu PRIVATE precompiled_headers.h)
+endif()
diff --git a/src/yuzu/applets/qt_amiibo_settings.cpp b/src/yuzu/applets/qt_amiibo_settings.cpp
new file mode 100644
index 000000000..93ad4b4f9
--- /dev/null
+++ b/src/yuzu/applets/qt_amiibo_settings.cpp
@@ -0,0 +1,264 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <algorithm>
+#include <thread>
+#include <fmt/format.h>
+#include <nlohmann/json.hpp>
+
+#include "common/assert.h"
+#include "common/string_util.h"
+#include "core/hle/service/nfp/nfp_device.h"
+#include "core/hle/service/nfp/nfp_result.h"
+#include "input_common/drivers/virtual_amiibo.h"
+#include "input_common/main.h"
+#include "ui_qt_amiibo_settings.h"
+#ifdef ENABLE_WEB_SERVICE
+#include "web_service/web_backend.h"
+#endif
+#include "yuzu/applets/qt_amiibo_settings.h"
+#include "yuzu/main.h"
+
+QtAmiiboSettingsDialog::QtAmiiboSettingsDialog(QWidget* parent,
+ Core::Frontend::CabinetParameters parameters_,
+ InputCommon::InputSubsystem* input_subsystem_,
+ std::shared_ptr<Service::NFP::NfpDevice> nfp_device_)
+ : QDialog(parent), ui(std::make_unique<Ui::QtAmiiboSettingsDialog>()),
+ input_subsystem{input_subsystem_}, nfp_device{std::move(nfp_device_)},
+ parameters(std::move(parameters_)) {
+ ui->setupUi(this);
+
+ LoadInfo();
+
+ resize(0, 0);
+}
+
+QtAmiiboSettingsDialog::~QtAmiiboSettingsDialog() = default;
+
+int QtAmiiboSettingsDialog::exec() {
+ if (!is_initalized) {
+ return QDialog::Rejected;
+ }
+ return QDialog::exec();
+}
+
+std::string QtAmiiboSettingsDialog::GetName() const {
+ return ui->amiiboCustomNameValue->text().toStdString();
+}
+
+void QtAmiiboSettingsDialog::LoadInfo() {
+ if (input_subsystem->GetVirtualAmiibo()->ReloadAmiibo() !=
+ InputCommon::VirtualAmiibo::Info::Success) {
+ return;
+ }
+
+ if (nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagFound &&
+ nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagMounted) {
+ return;
+ }
+ nfp_device->Mount(Service::NFP::MountTarget::All);
+
+ LoadAmiiboInfo();
+ LoadAmiiboData();
+ LoadAmiiboGameInfo();
+
+ ui->amiiboDirectoryValue->setText(
+ QString::fromStdString(input_subsystem->GetVirtualAmiibo()->GetLastFilePath()));
+
+ SetSettingsDescription();
+ is_initalized = true;
+}
+
+void QtAmiiboSettingsDialog::LoadAmiiboInfo() {
+ Service::NFP::ModelInfo model_info{};
+ const auto model_result = nfp_device->GetModelInfo(model_info);
+
+ if (model_result.IsFailure()) {
+ ui->amiiboImageLabel->setVisible(false);
+ ui->amiiboInfoGroup->setVisible(false);
+ return;
+ }
+
+ const auto amiibo_id =
+ fmt::format("{:04x}{:02x}{:02x}{:04x}{:02x}02", Common::swap16(model_info.character_id),
+ model_info.character_variant, model_info.amiibo_type, model_info.model_number,
+ model_info.series);
+
+ LOG_DEBUG(Frontend, "Loading amiibo id {}", amiibo_id);
+ // Note: This function is not being used until we host the images on our server
+ // LoadAmiiboApiInfo(amiibo_id);
+ ui->amiiboImageLabel->setVisible(false);
+ ui->amiiboInfoGroup->setVisible(false);
+}
+
+void QtAmiiboSettingsDialog::LoadAmiiboApiInfo(std::string_view amiibo_id) {
+#ifdef ENABLE_WEB_SERVICE
+ // TODO: Host this data on our website
+ WebService::Client client{"https://amiiboapi.com", {}, {}};
+ WebService::Client image_client{"https://raw.githubusercontent.com", {}, {}};
+ const auto url_path = fmt::format("/api/amiibo/?id={}", amiibo_id);
+
+ const auto amiibo_json = client.GetJson(url_path, true).returned_data;
+ if (amiibo_json.empty()) {
+ ui->amiiboImageLabel->setVisible(false);
+ ui->amiiboInfoGroup->setVisible(false);
+ return;
+ }
+
+ std::string amiibo_series{};
+ std::string amiibo_name{};
+ std::string amiibo_image_url{};
+ std::string amiibo_type{};
+
+ const auto parsed_amiibo_json_json = nlohmann::json::parse(amiibo_json).at("amiibo");
+ parsed_amiibo_json_json.at("amiiboSeries").get_to(amiibo_series);
+ parsed_amiibo_json_json.at("name").get_to(amiibo_name);
+ parsed_amiibo_json_json.at("image").get_to(amiibo_image_url);
+ parsed_amiibo_json_json.at("type").get_to(amiibo_type);
+
+ ui->amiiboSeriesValue->setText(QString::fromStdString(amiibo_series));
+ ui->amiiboNameValue->setText(QString::fromStdString(amiibo_name));
+ ui->amiiboTypeValue->setText(QString::fromStdString(amiibo_type));
+
+ if (amiibo_image_url.size() < 34) {
+ ui->amiiboImageLabel->setVisible(false);
+ }
+
+ const auto image_url_path = amiibo_image_url.substr(34, amiibo_image_url.size() - 34);
+ const auto image_data = image_client.GetImage(image_url_path, true).returned_data;
+
+ if (image_data.empty()) {
+ ui->amiiboImageLabel->setVisible(false);
+ }
+
+ QPixmap pixmap;
+ pixmap.loadFromData(reinterpret_cast<const u8*>(image_data.data()),
+ static_cast<uint>(image_data.size()));
+ pixmap = pixmap.scaled(250, 350, Qt::AspectRatioMode::KeepAspectRatio,
+ Qt::TransformationMode::SmoothTransformation);
+ ui->amiiboImageLabel->setPixmap(pixmap);
+#endif
+}
+
+void QtAmiiboSettingsDialog::LoadAmiiboData() {
+ Service::NFP::RegisterInfo register_info{};
+ Service::NFP::CommonInfo common_info{};
+ const auto register_result = nfp_device->GetRegisterInfo(register_info);
+ const auto common_result = nfp_device->GetCommonInfo(common_info);
+
+ if (register_result.IsFailure()) {
+ ui->creationDateValue->setDisabled(true);
+ ui->modificationDateValue->setDisabled(true);
+ ui->amiiboCustomNameValue->setReadOnly(false);
+ ui->amiiboOwnerValue->setReadOnly(false);
+ return;
+ }
+
+ if (parameters.mode == Service::NFP::CabinetMode::StartNicknameAndOwnerSettings) {
+ ui->creationDateValue->setDisabled(true);
+ ui->modificationDateValue->setDisabled(true);
+ }
+
+ const auto amiibo_name = std::string(register_info.amiibo_name.data());
+ const auto owner_name = Common::UTF16ToUTF8(register_info.mii_char_info.name.data());
+ const auto creation_date =
+ QDate(register_info.creation_date.year, register_info.creation_date.month,
+ register_info.creation_date.day);
+
+ ui->amiiboCustomNameValue->setText(QString::fromStdString(amiibo_name));
+ ui->amiiboOwnerValue->setText(QString::fromStdString(owner_name));
+ ui->amiiboCustomNameValue->setReadOnly(true);
+ ui->amiiboOwnerValue->setReadOnly(true);
+ ui->creationDateValue->setDate(creation_date);
+
+ if (common_result.IsFailure()) {
+ ui->modificationDateValue->setDisabled(true);
+ return;
+ }
+
+ const auto modification_date =
+ QDate(common_info.last_write_date.year, common_info.last_write_date.month,
+ common_info.last_write_date.day);
+ ui->modificationDateValue->setDate(modification_date);
+}
+
+void QtAmiiboSettingsDialog::LoadAmiiboGameInfo() {
+ u32 application_area_id{};
+ const auto application_result = nfp_device->GetApplicationAreaId(application_area_id);
+
+ if (application_result.IsFailure()) {
+ ui->gameIdValue->setVisible(false);
+ ui->gameIdLabel->setText(tr("No game data present"));
+ return;
+ }
+
+ SetGameDataName(application_area_id);
+}
+
+void QtAmiiboSettingsDialog::SetGameDataName(u32 application_area_id) {
+ static constexpr std::array<std::pair<u32, const char*>, 12> game_name_list = {
+ // 3ds, wii u
+ std::pair<u32, const char*>{0x10110E00, "Super Smash Bros (3DS/WiiU)"},
+ {0x00132600, "Mario & Luigi: Paper Jam"},
+ {0x0014F000, "Animal Crossing: Happy Home Designer"},
+ {0x00152600, "Chibi-Robo!: Zip Lash"},
+ {0x10161f00, "Mario Party 10"},
+ {0x1019C800, "The Legend of Zelda: Twilight Princess HD"},
+ // switch
+ {0x10162B00, "Splatoon 2"},
+ {0x1016e100, "Shovel Knight: Treasure Trove"},
+ {0x1019C800, "The Legend of Zelda: Breath of the Wild"},
+ {0x34F80200, "Super Smash Bros. Ultimate"},
+ {0x38600500, "Splatoon 3"},
+ {0x3B440400, "The Legend of Zelda: Link's Awakening"},
+ };
+
+ for (const auto& [game_id, game_name] : game_name_list) {
+ if (application_area_id == game_id) {
+ ui->gameIdValue->setText(QString::fromStdString(game_name));
+ return;
+ }
+ }
+
+ const auto application_area_string = fmt::format("{:016x}", application_area_id);
+ ui->gameIdValue->setText(QString::fromStdString(application_area_string));
+}
+
+void QtAmiiboSettingsDialog::SetSettingsDescription() {
+ switch (parameters.mode) {
+ case Service::NFP::CabinetMode::StartFormatter:
+ ui->cabinetActionDescriptionLabel->setText(
+ tr("The following amiibo data will be formatted:"));
+ break;
+ case Service::NFP::CabinetMode::StartGameDataEraser:
+ ui->cabinetActionDescriptionLabel->setText(tr("The following game data will removed:"));
+ break;
+ case Service::NFP::CabinetMode::StartNicknameAndOwnerSettings:
+ ui->cabinetActionDescriptionLabel->setText(tr("Set nickname and owner:"));
+ break;
+ case Service::NFP::CabinetMode::StartRestorer:
+ ui->cabinetActionDescriptionLabel->setText(tr("Do you wish to restore this amiibo?"));
+ break;
+ }
+}
+
+QtAmiiboSettings::QtAmiiboSettings(GMainWindow& parent) {
+ connect(this, &QtAmiiboSettings::MainWindowShowAmiiboSettings, &parent,
+ &GMainWindow::AmiiboSettingsShowDialog, Qt::QueuedConnection);
+ connect(&parent, &GMainWindow::AmiiboSettingsFinished, this,
+ &QtAmiiboSettings::MainWindowFinished, Qt::QueuedConnection);
+}
+
+QtAmiiboSettings::~QtAmiiboSettings() = default;
+
+void QtAmiiboSettings::ShowCabinetApplet(
+ const Core::Frontend::CabinetCallback& callback_,
+ const Core::Frontend::CabinetParameters& parameters,
+ std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const {
+ callback = std::move(callback_);
+ emit MainWindowShowAmiiboSettings(parameters, nfp_device);
+}
+
+void QtAmiiboSettings::MainWindowFinished(bool is_success, const std::string& name) {
+ callback(is_success, name);
+}
diff --git a/src/yuzu/applets/qt_amiibo_settings.h b/src/yuzu/applets/qt_amiibo_settings.h
new file mode 100644
index 000000000..930c96739
--- /dev/null
+++ b/src/yuzu/applets/qt_amiibo_settings.h
@@ -0,0 +1,83 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <array>
+#include <memory>
+#include <QDialog>
+#include "core/frontend/applets/cabinet.h"
+
+class GMainWindow;
+class QCheckBox;
+class QComboBox;
+class QDialogButtonBox;
+class QGroupBox;
+class QLabel;
+
+namespace InputCommon {
+class InputSubsystem;
+}
+
+namespace Ui {
+class QtAmiiboSettingsDialog;
+}
+
+namespace Service::NFP {
+class NfpDevice;
+} // namespace Service::NFP
+
+class QtAmiiboSettingsDialog final : public QDialog {
+ Q_OBJECT
+
+public:
+ explicit QtAmiiboSettingsDialog(QWidget* parent, Core::Frontend::CabinetParameters parameters_,
+ InputCommon::InputSubsystem* input_subsystem_,
+ std::shared_ptr<Service::NFP::NfpDevice> nfp_device_);
+ ~QtAmiiboSettingsDialog() override;
+
+ int exec() override;
+
+ std::string GetName() const;
+
+private:
+ void LoadInfo();
+ void LoadAmiiboInfo();
+ void LoadAmiiboApiInfo(std::string_view amiibo_id);
+ void LoadAmiiboData();
+ void LoadAmiiboGameInfo();
+ void SetGameDataName(u32 application_area_id);
+ void SetSettingsDescription();
+
+ std::unique_ptr<Ui::QtAmiiboSettingsDialog> ui;
+
+ InputCommon::InputSubsystem* input_subsystem;
+ std::shared_ptr<Service::NFP::NfpDevice> nfp_device;
+
+ // Parameters sent in from the backend HLE applet.
+ Core::Frontend::CabinetParameters parameters;
+
+ // If false amiibo settings failed to load
+ bool is_initalized{};
+};
+
+class QtAmiiboSettings final : public QObject, public Core::Frontend::CabinetApplet {
+ Q_OBJECT
+
+public:
+ explicit QtAmiiboSettings(GMainWindow& parent);
+ ~QtAmiiboSettings() override;
+
+ void ShowCabinetApplet(const Core::Frontend::CabinetCallback& callback_,
+ const Core::Frontend::CabinetParameters& parameters,
+ std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const override;
+
+signals:
+ void MainWindowShowAmiiboSettings(const Core::Frontend::CabinetParameters& parameters,
+ std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const;
+
+private:
+ void MainWindowFinished(bool is_success, const std::string& name);
+
+ mutable Core::Frontend::CabinetCallback callback;
+};
diff --git a/src/yuzu/applets/qt_amiibo_settings.ui b/src/yuzu/applets/qt_amiibo_settings.ui
new file mode 100644
index 000000000..f377a6e61
--- /dev/null
+++ b/src/yuzu/applets/qt_amiibo_settings.ui
@@ -0,0 +1,494 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>QtAmiiboSettingsDialog</class>
+ <widget class="QDialog" name="QtAmiiboSettingsDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>839</width>
+ <height>500</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Amiibo Settings</string>
+ </property>
+ <property name="styleSheet">
+ <string notr="true"/>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout" stretch="0">
+ <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="QWidget" name="mainControllerApplet" native="true">
+ <layout class="QVBoxLayout" name="verticalLayout_1" stretch="0,3,0">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QWidget" name="topControllerApplet" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <property name="spacing">
+ <number>10</number>
+ </property>
+ <property name="leftMargin">
+ <number>20</number>
+ </property>
+ <property name="topMargin">
+ <number>15</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>15</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="cabinetActionDescriptionLabel">
+ <property name="font">
+ <font>
+ <pointsize>12</pointsize>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+ </property>
+ <property name="wordWrap">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="middleControllerApplet" native="true">
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <property name="spacing">
+ <number>20</number>
+ </property>
+ <property name="leftMargin">
+ <number>15</number>
+ </property>
+ <property name="rightMargin">
+ <number>15</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="amiiboImageLabel">
+ <property name="minimumSize">
+ <size>
+ <width>250</width>
+ <height>350</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>236</width>
+ <height>350</height>
+ </size>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_4">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>8</number>
+ </property>
+ <property name="bottomMargin">
+ <number>15</number>
+ </property>
+ <item>
+ <widget class="QGroupBox" name="amiiboInfoGroup">
+ <property name="title">
+ <string>Amiibo Info</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_5">
+ <item>
+ <layout class="QGridLayout" name="gridLayout_1">
+ <item row="0" column="0">
+ <widget class="QLabel" name="amiiboSeriesLabel">
+ <property name="text">
+ <string>Series</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="amiiboSeriesValue">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="amiiboTypeLabel">
+ <property name="text">
+ <string>Type</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="amiiboTypeValue">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="amiiboNameLabel">
+ <property name="text">
+ <string>Name</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLineEdit" name="amiiboNameValue">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="amiiboDataGroup">
+ <property name="title">
+ <string>Amiibo Data</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_6">
+ <item>
+ <layout class="QGridLayout" name="gridLayout_2">
+ <item row="0" column="0">
+ <widget class="QLabel" name="amiiboCustomNameLabel">
+ <property name="text">
+ <string>Custom Name</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="amiiboCustomNameValue">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maxLength">
+ <number>10</number>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="amiiboOwnerLabel">
+ <property name="text">
+ <string>Owner</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="amiiboOwnerValue">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maxLength">
+ <number>10</number>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="creationDateLabel">
+ <property name="text">
+ <string>Creation Date</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QDateTimeEdit" name="creationDateValue">
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ <property name="minimumDate">
+ <date>
+ <year>1970</year>
+ <month>1</month>
+ <day>1</day>
+ </date>
+ </property>
+ <property name="displayFormat">
+ <string>dd/MM/yyyy</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="modificationDateLabel">
+ <property name="text">
+ <string>Modification Date</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QDateTimeEdit" name="modificationDateValue">
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ <property name="minimumDate">
+ <date>
+ <year>1970</year>
+ <month>1</month>
+ <day>1</day>
+ </date>
+ </property>
+ <property name="displayFormat">
+ <string>dd/MM/yyyy </string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="gameDataGroup">
+ <property name="minimumSize">
+ <size>
+ <width>500</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="title">
+ <string>Game Data</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_3">
+ <item row="0" column="0">
+ <widget class="QLabel" name="gameIdLabel">
+ <property name="text">
+ <string>Game Id</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="gameIdValue">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="MountAmiiboGroup">
+ <property name="minimumSize">
+ <size>
+ <width>500</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="title">
+ <string>Mount Amiibo</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_4">
+ <item row="0" column="3">
+ <widget class="QToolButton" name="amiiboDirectoryButton">
+ <property name="text">
+ <string>...</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Maximum</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>60</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="amiiboDirectoryLabel">
+ <property name="text">
+ <string>File Path</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2">
+ <widget class="QLineEdit" name="amiiboDirectoryValue"/>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="bottomControllerApplet" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout_6">
+ <property name="spacing">
+ <number>15</number>
+ </property>
+ <property name="leftMargin">
+ <number>15</number>
+ </property>
+ <property name="topMargin">
+ <number>8</number>
+ </property>
+ <property name="rightMargin">
+ <number>20</number>
+ </property>
+ <property name="bottomMargin">
+ <number>8</number>
+ </property>
+ <item alignment="Qt::AlignBottom">
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>QtAmiiboSettingsDialog</receiver>
+ <slot>accept()</slot>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>QtAmiiboSettingsDialog</receiver>
+ <slot>reject()</slot>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp
index d88efacd7..5b5b6fed8 100644
--- a/src/yuzu/bootmanager.cpp
+++ b/src/yuzu/bootmanager.cpp
@@ -4,8 +4,10 @@
#include <glad/glad.h>
#include <QApplication>
+#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) && YUZU_USE_QT_MULTIMEDIA
#include <QCameraImageCapture>
#include <QCameraInfo>
+#endif
#include <QHBoxLayout>
#include <QMessageBox>
#include <QPainter>
@@ -116,7 +118,7 @@ void EmuThread::run() {
}
} else {
std::unique_lock lock{running_mutex};
- running_cv.wait(lock, stop_token, [this] { return IsRunning(); });
+ Common::CondvarWait(running_cv, lock, stop_token, [&] { return IsRunning(); });
}
}
@@ -235,8 +237,7 @@ private:
GRenderWindow* render_window;
};
-class OpenGLRenderWidget : public RenderWidget {
-public:
+struct OpenGLRenderWidget : public RenderWidget {
explicit OpenGLRenderWidget(GRenderWindow* parent) : RenderWidget(parent) {
windowHandle()->setSurfaceType(QWindow::OpenGLSurface);
}
@@ -249,13 +250,16 @@ private:
std::unique_ptr<Core::Frontend::GraphicsContext> context;
};
-class VulkanRenderWidget : public RenderWidget {
-public:
+struct VulkanRenderWidget : public RenderWidget {
explicit VulkanRenderWidget(GRenderWindow* parent) : RenderWidget(parent) {
windowHandle()->setSurfaceType(QWindow::VulkanSurface);
}
};
+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();
@@ -265,6 +269,10 @@ static Core::Frontend::WindowSystemType GetWindowSystemType() {
return Core::Frontend::WindowSystemType::X11;
else if (platform_name == QStringLiteral("wayland"))
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!");
return Core::Frontend::WindowSystemType::Windows;
@@ -707,6 +715,7 @@ void GRenderWindow::TouchEndEvent() {
}
void GRenderWindow::InitializeCamera() {
+#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) && YUZU_USE_QT_MULTIMEDIA
constexpr auto camera_update_ms = std::chrono::milliseconds{50}; // (50ms, 20Hz)
if (!Settings::values.enable_ir_sensor) {
return;
@@ -760,18 +769,22 @@ void GRenderWindow::InitializeCamera() {
connect(camera_timer.get(), &QTimer::timeout, [this] { RequestCameraCapture(); });
// This timer should be dependent of camera resolution 5ms for every 100 pixels
camera_timer->start(camera_update_ms);
+#endif
}
void GRenderWindow::FinalizeCamera() {
+#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) && YUZU_USE_QT_MULTIMEDIA
if (camera_timer) {
camera_timer->stop();
}
if (camera) {
camera->unload();
}
+#endif
}
void GRenderWindow::RequestCameraCapture() {
+#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) && YUZU_USE_QT_MULTIMEDIA
if (!Settings::values.enable_ir_sensor) {
return;
}
@@ -788,6 +801,7 @@ void GRenderWindow::RequestCameraCapture() {
pending_camera_snapshots++;
camera_capture->capture();
+#endif
}
void GRenderWindow::OnCameraCapture(int requestId, const QImage& img) {
@@ -866,6 +880,9 @@ bool GRenderWindow::InitRenderTarget() {
return false;
}
break;
+ case Settings::RendererBackend::Null:
+ InitializeNull();
+ break;
}
// Update the Window System information with the new render target
@@ -962,6 +979,11 @@ bool GRenderWindow::InitializeVulkan() {
return true;
}
+void GRenderWindow::InitializeNull() {
+ child_widget = new NullRenderWidget(this);
+ main_context = std::make_unique<DummyContext>();
+}
+
bool GRenderWindow::LoadOpenGL() {
auto context = CreateSharedContext();
auto scope = context->Acquire();
diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h
index c45ebf1a2..f4deae4ee 100644
--- a/src/yuzu/bootmanager.h
+++ b/src/yuzu/bootmanager.h
@@ -14,6 +14,7 @@
#include <QTouchEvent>
#include <QWidget>
+#include "common/polyfill_thread.h"
#include "common/thread.h"
#include "core/frontend/emu_window.h"
@@ -218,6 +219,7 @@ private:
bool InitializeOpenGL();
bool InitializeVulkan();
+ void InitializeNull();
bool LoadOpenGL();
QStringList GetUnsupportedGLExtensions() const;
@@ -241,8 +243,10 @@ private:
bool is_virtual_camera;
int pending_camera_snapshots;
+#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) && YUZU_USE_QT_MULTIMEDIA
std::unique_ptr<QCamera> camera;
std::unique_ptr<QCameraImageCapture> camera_capture;
+#endif
std::unique_ptr<QTimer> camera_timer;
Core::System& system;
diff --git a/src/yuzu/compatdb.cpp b/src/yuzu/compatdb.cpp
index b03e71248..05f49c0d2 100644
--- a/src/yuzu/compatdb.cpp
+++ b/src/yuzu/compatdb.cpp
@@ -126,6 +126,7 @@ void CompatDB::Submit() {
break;
default:
LOG_ERROR(Frontend, "Unexpected page: {}", currentId());
+ break;
}
}
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index cc1ba9f70..c11d1c8b3 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -693,6 +693,7 @@ void Config::ReadRendererValues() {
ReadGlobalSetting(Settings::values.aspect_ratio);
ReadGlobalSetting(Settings::values.resolution_setup);
ReadGlobalSetting(Settings::values.scaling_filter);
+ ReadGlobalSetting(Settings::values.fsr_sharpening_slider);
ReadGlobalSetting(Settings::values.anti_aliasing);
ReadGlobalSetting(Settings::values.max_anisotropy);
ReadGlobalSetting(Settings::values.use_speed_limit);
@@ -1316,6 +1317,10 @@ void Config::SaveRendererValues() {
static_cast<u32>(Settings::values.scaling_filter.GetValue(global)),
static_cast<u32>(Settings::values.scaling_filter.GetDefault()),
Settings::values.scaling_filter.UsingGlobal());
+ WriteSetting(QString::fromStdString(Settings::values.fsr_sharpening_slider.GetLabel()),
+ static_cast<u32>(Settings::values.fsr_sharpening_slider.GetValue(global)),
+ static_cast<u32>(Settings::values.fsr_sharpening_slider.GetDefault()),
+ Settings::values.fsr_sharpening_slider.UsingGlobal());
WriteSetting(QString::fromStdString(Settings::values.anti_aliasing.GetLabel()),
static_cast<u32>(Settings::values.anti_aliasing.GetValue(global)),
static_cast<u32>(Settings::values.anti_aliasing.GetDefault()),
diff --git a/src/yuzu/configuration/configure_camera.cpp b/src/yuzu/configuration/configure_camera.cpp
index 2a61de2a1..d95e96696 100644
--- a/src/yuzu/configuration/configure_camera.cpp
+++ b/src/yuzu/configuration/configure_camera.cpp
@@ -2,8 +2,11 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#include <memory>
+#include <QtCore>
+#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) && YUZU_USE_QT_MULTIMEDIA
#include <QCameraImageCapture>
#include <QCameraInfo>
+#endif
#include <QStandardItemModel>
#include <QTimer>
@@ -33,6 +36,7 @@ ConfigureCamera::ConfigureCamera(QWidget* parent, InputCommon::InputSubsystem* i
ConfigureCamera::~ConfigureCamera() = default;
void ConfigureCamera::PreviewCamera() {
+#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) && YUZU_USE_QT_MULTIMEDIA
const auto index = ui->ir_sensor_combo_box->currentIndex();
bool camera_found = false;
const QList<QCameraInfo> cameras = QCameraInfo::availableCameras();
@@ -101,6 +105,7 @@ void ConfigureCamera::PreviewCamera() {
});
camera_timer->start(250);
+#endif
}
void ConfigureCamera::DisplayCapturedFrame(int requestId, const QImage& img) {
@@ -133,11 +138,13 @@ void ConfigureCamera::LoadConfiguration() {
ui->ir_sensor_combo_box->clear();
input_devices.push_back("Auto");
ui->ir_sensor_combo_box->addItem(tr("Auto"));
+#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) && YUZU_USE_QT_MULTIMEDIA
const auto cameras = QCameraInfo::availableCameras();
for (const QCameraInfo& cameraInfo : cameras) {
input_devices.push_back(cameraInfo.deviceName().toStdString());
ui->ir_sensor_combo_box->addItem(cameraInfo.description());
}
+#endif
const auto current_device = Settings::values.ir_sensor_device.GetValue();
diff --git a/src/yuzu/configuration/configure_camera.h b/src/yuzu/configuration/configure_camera.h
index db9833b5c..9a90512b3 100644
--- a/src/yuzu/configuration/configure_camera.h
+++ b/src/yuzu/configuration/configure_camera.h
@@ -46,8 +46,10 @@ private:
bool is_virtual_camera;
int pending_snapshots;
+#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) && YUZU_USE_QT_MULTIMEDIA
std::unique_ptr<QCamera> camera;
std::unique_ptr<QCameraImageCapture> camera_capture;
+#endif
std::unique_ptr<QTimer> camera_timer;
std::vector<std::string> input_devices;
std::unique_ptr<Ui::ConfigureCamera> ui;
diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp
index bd69d04a6..8ca683966 100644
--- a/src/yuzu/configuration/configure_graphics.cpp
+++ b/src/yuzu/configuration/configure_graphics.cpp
@@ -63,6 +63,11 @@ ConfigureGraphics::ConfigureGraphics(const Core::System& system_, QWidget* paren
ui->api_widget->isEnabled());
ui->bg_label->setVisible(Settings::IsConfiguringGlobal());
ui->bg_combobox->setVisible(!Settings::IsConfiguringGlobal());
+
+ connect(ui->fsr_sharpening_slider, &QSlider::valueChanged, this,
+ &ConfigureGraphics::SetFSRIndicatorText);
+ ui->fsr_sharpening_combobox->setVisible(!Settings::IsConfiguringGlobal());
+ ui->fsr_sharpening_label->setVisible(Settings::IsConfiguringGlobal());
}
void ConfigureGraphics::UpdateDeviceSelection(int device) {
@@ -110,6 +115,7 @@ void ConfigureGraphics::SetConfiguration() {
static_cast<int>(Settings::values.resolution_setup.GetValue()));
ui->scaling_filter_combobox->setCurrentIndex(
static_cast<int>(Settings::values.scaling_filter.GetValue()));
+ ui->fsr_sharpening_slider->setValue(Settings::values.fsr_sharpening_slider.GetValue());
ui->anti_aliasing_combobox->setCurrentIndex(
static_cast<int>(Settings::values.anti_aliasing.GetValue()));
} else {
@@ -147,6 +153,15 @@ void ConfigureGraphics::SetConfiguration() {
ConfigurationShared::SetHighlight(ui->anti_aliasing_label,
!Settings::values.anti_aliasing.UsingGlobal());
+ ui->fsr_sharpening_combobox->setCurrentIndex(
+ Settings::values.fsr_sharpening_slider.UsingGlobal() ? 0 : 1);
+ ui->fsr_sharpening_slider->setEnabled(
+ !Settings::values.fsr_sharpening_slider.UsingGlobal());
+ ui->fsr_sharpening_value->setEnabled(!Settings::values.fsr_sharpening_slider.UsingGlobal());
+ ConfigurationShared::SetHighlight(ui->fsr_sharpening_layout,
+ !Settings::values.fsr_sharpening_slider.UsingGlobal());
+ ui->fsr_sharpening_slider->setValue(Settings::values.fsr_sharpening_slider.GetValue());
+
ui->bg_combobox->setCurrentIndex(Settings::values.bg_red.UsingGlobal() ? 0 : 1);
ui->bg_button->setEnabled(!Settings::values.bg_red.UsingGlobal());
ConfigurationShared::SetHighlight(ui->bg_layout, !Settings::values.bg_red.UsingGlobal());
@@ -155,6 +170,12 @@ void ConfigureGraphics::SetConfiguration() {
Settings::values.bg_green.GetValue(),
Settings::values.bg_blue.GetValue()));
UpdateAPILayout();
+ SetFSRIndicatorText(ui->fsr_sharpening_slider->sliderPosition());
+}
+
+void ConfigureGraphics::SetFSRIndicatorText(int percentage) {
+ ui->fsr_sharpening_value->setText(
+ tr("%1%", "FSR sharpening percentage (e.g. 50%)").arg(100 - (percentage / 2)));
}
void ConfigureGraphics::ApplyConfiguration() {
@@ -210,6 +231,7 @@ void ConfigureGraphics::ApplyConfiguration() {
if (Settings::values.anti_aliasing.UsingGlobal()) {
Settings::values.anti_aliasing.SetValue(anti_aliasing);
}
+ Settings::values.fsr_sharpening_slider.SetValue(ui->fsr_sharpening_slider->value());
} else {
if (ui->resolution_combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
Settings::values.resolution_setup.SetGlobal(true);
@@ -238,6 +260,7 @@ void ConfigureGraphics::ApplyConfiguration() {
Settings::values.renderer_backend.SetValue(GetCurrentGraphicsBackend());
switch (GetCurrentGraphicsBackend()) {
case Settings::RendererBackend::OpenGL:
+ case Settings::RendererBackend::Null:
Settings::values.shader_backend.SetGlobal(false);
Settings::values.vulkan_device.SetGlobal(true);
Settings::values.shader_backend.SetValue(shader_backend);
@@ -269,6 +292,13 @@ void ConfigureGraphics::ApplyConfiguration() {
Settings::values.bg_green.SetValue(static_cast<u8>(bg_color.green()));
Settings::values.bg_blue.SetValue(static_cast<u8>(bg_color.blue()));
}
+
+ if (ui->fsr_sharpening_combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
+ Settings::values.fsr_sharpening_slider.SetGlobal(true);
+ } else {
+ Settings::values.fsr_sharpening_slider.SetGlobal(false);
+ Settings::values.fsr_sharpening_slider.SetValue(ui->fsr_sharpening_slider->value());
+ }
}
}
@@ -319,6 +349,10 @@ void ConfigureGraphics::UpdateAPILayout() {
ui->device_widget->setVisible(true);
ui->backend_widget->setVisible(false);
break;
+ case Settings::RendererBackend::Null:
+ ui->device_widget->setVisible(false);
+ ui->backend_widget->setVisible(false);
+ break;
}
}
@@ -331,7 +365,7 @@ void ConfigureGraphics::RetrieveVulkanDevices() try {
vk::InstanceDispatch dld;
const Common::DynamicLibrary library = OpenLibrary();
- const vk::Instance instance = CreateInstance(library, dld, VK_API_VERSION_1_0);
+ const vk::Instance instance = CreateInstance(library, dld, VK_API_VERSION_1_1);
const std::vector<VkPhysicalDevice> physical_devices = instance.EnumeratePhysicalDevices();
vulkan_devices.clear();
@@ -380,6 +414,7 @@ void ConfigureGraphics::SetupPerGameUI() {
ui->aspect_ratio_combobox->setEnabled(Settings::values.aspect_ratio.UsingGlobal());
ui->resolution_combobox->setEnabled(Settings::values.resolution_setup.UsingGlobal());
ui->scaling_filter_combobox->setEnabled(Settings::values.scaling_filter.UsingGlobal());
+ ui->fsr_sharpening_slider->setEnabled(Settings::values.fsr_sharpening_slider.UsingGlobal());
ui->anti_aliasing_combobox->setEnabled(Settings::values.anti_aliasing.UsingGlobal());
ui->use_asynchronous_gpu_emulation->setEnabled(
Settings::values.use_asynchronous_gpu_emulation.UsingGlobal());
@@ -387,6 +422,7 @@ void ConfigureGraphics::SetupPerGameUI() {
ui->accelerate_astc->setEnabled(Settings::values.accelerate_astc.UsingGlobal());
ui->use_disk_shader_cache->setEnabled(Settings::values.use_disk_shader_cache.UsingGlobal());
ui->bg_button->setEnabled(Settings::values.bg_red.UsingGlobal());
+ ui->fsr_slider_layout->setEnabled(Settings::values.fsr_sharpening_slider.UsingGlobal());
return;
}
@@ -396,6 +432,13 @@ void ConfigureGraphics::SetupPerGameUI() {
ConfigurationShared::SetHighlight(ui->bg_layout, index == 1);
});
+ connect(ui->fsr_sharpening_combobox, qOverload<int>(&QComboBox::activated), this,
+ [this](int index) {
+ ui->fsr_sharpening_slider->setEnabled(index == 1);
+ ui->fsr_sharpening_value->setEnabled(index == 1);
+ ConfigurationShared::SetHighlight(ui->fsr_sharpening_layout, index == 1);
+ });
+
ConfigurationShared::SetColoredTristate(
ui->use_disk_shader_cache, Settings::values.use_disk_shader_cache, use_disk_shader_cache);
ConfigurationShared::SetColoredTristate(ui->accelerate_astc, Settings::values.accelerate_astc,
diff --git a/src/yuzu/configuration/configure_graphics.h b/src/yuzu/configuration/configure_graphics.h
index 70034eb1b..d98d6624e 100644
--- a/src/yuzu/configuration/configure_graphics.h
+++ b/src/yuzu/configuration/configure_graphics.h
@@ -42,6 +42,8 @@ private:
void RetrieveVulkanDevices();
+ void SetFSRIndicatorText(int percentage);
+
void SetupPerGameUI();
Settings::RendererBackend GetCurrentGraphicsBackend() const;
diff --git a/src/yuzu/configuration/configure_graphics.ui b/src/yuzu/configuration/configure_graphics.ui
index fdbb33372..f78396690 100644
--- a/src/yuzu/configuration/configure_graphics.ui
+++ b/src/yuzu/configuration/configure_graphics.ui
@@ -139,6 +139,11 @@
<string notr="true">Vulkan</string>
</property>
</item>
+ <item>
+ <property name="text">
+ <string>None</string>
+ </property>
+ </item>
</widget>
</item>
</layout>
@@ -152,6 +157,12 @@
</item>
<item>
<widget class="QGroupBox" name="groupBox">
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>16777215</height>
+ </size>
+ </property>
<property name="title">
<string>Graphics Settings</string>
</property>
@@ -482,6 +493,146 @@
</widget>
</item>
<item>
+ <widget class="QWidget" name="fsr_sharpening_layout" native="true">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="sizeConstraint">
+ <enum>QLayout::SetDefaultConstraint</enum>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <layout class="QHBoxLayout" name="fsr_sharpening_label_group">
+ <item>
+ <widget class="QComboBox" name="fsr_sharpening_combobox">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <item>
+ <property name="text">
+ <string>Use global FSR Sharpness</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Set FSR Sharpness</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="fsr_sharpening_label">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>FSR Sharpness:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="fsr_slider_layout">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QSlider" name="fsr_sharpening_slider">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="baseSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximum">
+ <number>200</number>
+ </property>
+ <property name="sliderPosition">
+ <number>25</number>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="invertedAppearance">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="fsr_sharpening_value">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>32</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>100%</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
<widget class="QWidget" name="bg_layout" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
diff --git a/src/yuzu/configuration/configure_input_advanced.cpp b/src/yuzu/configuration/configure_input_advanced.cpp
index 10f841b98..235b813d9 100644
--- a/src/yuzu/configuration/configure_input_advanced.cpp
+++ b/src/yuzu/configuration/configure_input_advanced.cpp
@@ -194,4 +194,8 @@ void ConfigureInputAdvanced::UpdateUIEnabled() {
ui->mouse_panning->setEnabled(!ui->mouse_enabled->isChecked());
ui->mouse_panning_sensitivity->setEnabled(!ui->mouse_enabled->isChecked());
ui->ring_controller_configure->setEnabled(ui->enable_ring_controller->isChecked());
+#if QT_VERSION > QT_VERSION_CHECK(6, 0, 0) || !defined(YUZU_USE_QT_MULTIMEDIA)
+ ui->enable_ir_sensor->setEnabled(false);
+ ui->camera_configure->setEnabled(false);
+#endif
}
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 21983a799..c0afb2e5f 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -15,6 +15,7 @@
#endif
// VFS includes must be before glad as they will conflict with Windows file api, which uses defines.
+#include "applets/qt_amiibo_settings.h"
#include "applets/qt_controller.h"
#include "applets/qt_error.h"
#include "applets/qt_profile_select.h"
@@ -26,6 +27,7 @@
#include "configuration/configure_tas.h"
#include "core/file_sys/vfs.h"
#include "core/file_sys/vfs_real.h"
+#include "core/frontend/applets/cabinet.h"
#include "core/frontend/applets/controller.h"
#include "core/frontend/applets/general_frontend.h"
#include "core/frontend/applets/mii_edit.h"
@@ -166,6 +168,7 @@ __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
constexpr int default_mouse_hide_timeout = 2500;
constexpr int default_mouse_center_timeout = 10;
+constexpr int default_input_update_timeout = 1;
/**
* "Callouts" are one-time instructional messages shown to the user. In the config settings, there
@@ -236,6 +239,7 @@ static void LogRuntimes() {
LOG_INFO(Frontend, "Unable to inspect {}", runtime_dll_name);
}
#endif
+ LOG_INFO(Frontend, "Qt Compile: {} Runtime: {}", QT_VERSION_STR, qVersion());
}
static QString PrettyProductName() {
@@ -403,6 +407,10 @@ GMainWindow::GMainWindow(std::unique_ptr<Config> config_, bool has_broken_vulkan
mouse_center_timer.setInterval(default_mouse_center_timeout);
connect(&mouse_center_timer, &QTimer::timeout, this, &GMainWindow::CenterMouseCursor);
+ update_input_timer.setInterval(default_input_update_timeout);
+ connect(&update_input_timer, &QTimer::timeout, this, &GMainWindow::UpdateInputDrivers);
+ update_input_timer.start();
+
MigrateConfigFiles();
if (has_broken_vulkan) {
@@ -549,6 +557,11 @@ void GMainWindow::RegisterMetaTypes() {
// Register applet types
+ // Cabinet Applet
+ qRegisterMetaType<Core::Frontend::CabinetParameters>("Core::Frontend::CabinetParameters");
+ qRegisterMetaType<std::shared_ptr<Service::NFP::NfpDevice>>(
+ "std::shared_ptr<Service::NFP::NfpDevice>");
+
// Controller Applet
qRegisterMetaType<Core::Frontend::ControllerParameters>("Core::Frontend::ControllerParameters");
@@ -570,6 +583,21 @@ void GMainWindow::RegisterMetaTypes() {
qRegisterMetaType<Core::SystemResultStatus>("Core::SystemResultStatus");
}
+void GMainWindow::AmiiboSettingsShowDialog(const Core::Frontend::CabinetParameters& parameters,
+ std::shared_ptr<Service::NFP::NfpDevice> nfp_device) {
+ QtAmiiboSettingsDialog dialog(this, parameters, input_subsystem.get(), nfp_device);
+
+ dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint |
+ Qt::WindowTitleHint | Qt::WindowSystemMenuHint);
+ dialog.setWindowModality(Qt::WindowModal);
+ if (dialog.exec() == QDialog::Rejected) {
+ emit AmiiboSettingsFinished(false, {});
+ return;
+ }
+
+ emit AmiiboSettingsFinished(true, dialog.GetName());
+}
+
void GMainWindow::ControllerSelectorReconfigureControllers(
const Core::Frontend::ControllerParameters& parameters) {
QtControllerSelectorDialog dialog(this, parameters, input_subsystem.get(), *system);
@@ -985,29 +1013,11 @@ void GMainWindow::InitializeWidgets() {
renderer_status_button->setObjectName(QStringLiteral("RendererStatusBarButton"));
renderer_status_button->setCheckable(true);
renderer_status_button->setFocusPolicy(Qt::NoFocus);
- connect(renderer_status_button, &QPushButton::toggled, [this](bool checked) {
- renderer_status_button->setText(checked ? tr("VULKAN") : tr("OPENGL"));
- });
- renderer_status_button->toggle();
-
+ connect(renderer_status_button, &QPushButton::clicked, this, &GMainWindow::OnToggleGraphicsAPI);
+ UpdateAPIText();
+ renderer_status_button->setCheckable(true);
renderer_status_button->setChecked(Settings::values.renderer_backend.GetValue() ==
Settings::RendererBackend::Vulkan);
- connect(renderer_status_button, &QPushButton::clicked, [this] {
- if (emulation_running) {
- return;
- }
- if (renderer_status_button->isChecked()) {
- Settings::values.renderer_backend.SetValue(Settings::RendererBackend::Vulkan);
- } else {
- Settings::values.renderer_backend.SetValue(Settings::RendererBackend::OpenGL);
- if (Settings::values.scaling_filter.GetValue() == Settings::ScalingFilter::Fsr) {
- Settings::values.scaling_filter.SetValue(Settings::ScalingFilter::NearestNeighbor);
- UpdateFilterText();
- }
- }
-
- system->ApplySettings();
- });
statusBar()->insertPermanentWidget(0, renderer_status_button);
statusBar()->setVisible(true);
@@ -1547,6 +1557,7 @@ bool GMainWindow::LoadROM(const QString& filename, u64 program_id, std::size_t p
system->SetFilesystem(vfs);
system->SetAppletFrontendSet({
+ std::make_unique<QtAmiiboSettings>(*this), // Amiibo Settings
std::make_unique<QtControllerSelector>(*this), // Controller Selector
std::make_unique<QtErrorDisplay>(*this), // Error Display
nullptr, // Mii Editor
@@ -1958,6 +1969,7 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target
}
default:
UNIMPLEMENTED();
+ break;
}
const QString qpath = QString::fromStdString(Common::FS::PathToUTF8String(path));
@@ -2823,6 +2835,7 @@ void GMainWindow::ErrorDisplayDisplayError(QString error_code, QString error_tex
}
void GMainWindow::OnMenuReportCompatibility() {
+#if defined(ARCHITECTURE_x86_64) && !defined(__APPLE__)
const auto& caps = Common::GetCPUCaps();
const bool has_fma = caps.fma || caps.fma4;
const auto processor_count = std::thread::hardware_concurrency();
@@ -2849,6 +2862,11 @@ void GMainWindow::OnMenuReportCompatibility() {
"&gt; "
"Web."));
}
+#else
+ QMessageBox::critical(this, tr("Hardware requirements not met"),
+ tr("Your system does not meet the recommended hardware requirements. "
+ "Compatibility reporting has been disabled."));
+#endif
}
void GMainWindow::OpenURL(const QUrl& url) {
@@ -3202,6 +3220,7 @@ void GMainWindow::OnToggleGpuAccuracy() {
case Settings::GPUAccuracy::Extreme:
default: {
Settings::values.gpu_accuracy.SetValue(Settings::GPUAccuracy::High);
+ break;
}
}
@@ -3225,6 +3244,18 @@ void GMainWindow::OnToggleAdaptingFilter() {
UpdateFilterText();
}
+void GMainWindow::OnToggleGraphicsAPI() {
+ auto api = Settings::values.renderer_backend.GetValue();
+ if (api == Settings::RendererBackend::OpenGL) {
+ api = Settings::RendererBackend::Vulkan;
+ } else {
+ api = Settings::RendererBackend::OpenGL;
+ }
+ Settings::values.renderer_backend.SetValue(api);
+ renderer_status_button->setChecked(api == Settings::RendererBackend::Vulkan);
+ UpdateAPIText();
+}
+
void GMainWindow::OnConfigurePerGame() {
const u64 title_id = system->GetCurrentProcessProgramID();
OpenPerGameConfiguration(title_id, current_game_path.toStdString());
@@ -3535,6 +3566,7 @@ void GMainWindow::UpdateGPUAccuracyButton() {
default: {
gpu_accuracy_button->setText(tr("GPU ERROR"));
gpu_accuracy_button->setChecked(true);
+ break;
}
}
}
@@ -3545,6 +3577,21 @@ void GMainWindow::UpdateDockedButton() {
dock_status_button->setText(is_docked ? tr("DOCKED") : tr("HANDHELD"));
}
+void GMainWindow::UpdateAPIText() {
+ const auto api = Settings::values.renderer_backend.GetValue();
+ switch (api) {
+ case Settings::RendererBackend::OpenGL:
+ renderer_status_button->setText(tr("OPENGL"));
+ break;
+ case Settings::RendererBackend::Vulkan:
+ renderer_status_button->setText(tr("VULKAN"));
+ break;
+ case Settings::RendererBackend::Null:
+ renderer_status_button->setText(tr("NULL"));
+ break;
+ }
+}
+
void GMainWindow::UpdateFilterText() {
const auto filter = Settings::values.scaling_filter.GetValue();
switch (filter) {
@@ -3590,6 +3637,7 @@ void GMainWindow::UpdateAAText() {
void GMainWindow::UpdateStatusButtons() {
renderer_status_button->setChecked(Settings::values.renderer_backend.GetValue() ==
Settings::RendererBackend::Vulkan);
+ UpdateAPIText();
UpdateGPUAccuracyButton();
UpdateDockedButton();
UpdateFilterText();
@@ -3614,6 +3662,13 @@ void GMainWindow::UpdateUISettings() {
UISettings::values.first_start = false;
}
+void GMainWindow::UpdateInputDrivers() {
+ if (!input_subsystem) {
+ return;
+ }
+ input_subsystem->PumpEvents();
+}
+
void GMainWindow::HideMouseCursor() {
if (emu_thread == nullptr && UISettings::values.hide_mouse) {
mouse_hide_timer.stop();
@@ -4016,7 +4071,6 @@ void GMainWindow::UpdateUITheme() {
const QString default_theme =
QString::fromUtf8(UISettings::themes[static_cast<size_t>(Config::default_theme)].second);
QString current_theme = UISettings::values.theme;
- QStringList theme_paths(default_theme_paths);
if (current_theme.isEmpty()) {
current_theme = default_theme;
@@ -4029,7 +4083,7 @@ void GMainWindow::UpdateUITheme() {
if (current_theme == QStringLiteral("default") || current_theme == QStringLiteral("colorful")) {
QIcon::setThemeName(current_theme == QStringLiteral("colorful") ? current_theme
: startup_icon_theme);
- QIcon::setThemeSearchPaths(theme_paths);
+ QIcon::setThemeSearchPaths(QStringList(default_theme_paths));
if (CheckDarkMode()) {
current_theme = QStringLiteral("default_dark");
}
@@ -4197,10 +4251,12 @@ int main(int argc, char* argv[]) {
// so we can see if we get \u3008 instead
// TL;DR all other number formats are consecutive in unicode code points
// This bug is fixed in Qt6, specifically 6.0.0-alpha1
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
const QLocale locale = QLocale::system();
if (QStringLiteral("\u3008") == locale.toString(1)) {
QLocale::setDefault(QLocale::system().name());
}
+#endif
// Qt changes the locale and causes issues in float conversion using std::to_string() when
// generating shaders
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index b73f550dd..62d629973 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -55,6 +55,7 @@ class System;
} // namespace Core
namespace Core::Frontend {
+struct CabinetParameters;
struct ControllerParameters;
struct InlineAppearParameters;
struct InlineTextParameters;
@@ -82,6 +83,10 @@ enum class SwkbdReplyType : u32;
enum class WebExitReason : u32;
} // namespace Service::AM::Applets
+namespace Service::NFP {
+class NfpDevice;
+} // namespace Service::NFP
+
namespace Ui {
class MainWindow;
}
@@ -149,6 +154,8 @@ signals:
void UpdateInstallProgress();
+ void AmiiboSettingsFinished(bool is_success, const std::string& name);
+
void ControllerSelectorReconfigureFinished();
void ErrorDisplayFinished();
@@ -170,6 +177,8 @@ public slots:
void OnExecuteProgram(std::size_t program_index);
void OnExit();
void OnSaveConfig();
+ void AmiiboSettingsShowDialog(const Core::Frontend::CabinetParameters& parameters,
+ std::shared_ptr<Service::NFP::NfpDevice> nfp_device);
void ControllerSelectorReconfigureControllers(
const Core::Frontend::ControllerParameters& parameters);
void SoftwareKeyboardInitialize(
@@ -298,6 +307,7 @@ private slots:
void OnTasStartStop();
void OnTasRecord();
void OnTasReset();
+ void OnToggleGraphicsAPI();
void OnToggleDockedMode();
void OnToggleGpuAccuracy();
void OnToggleAdaptingFilter();
@@ -338,12 +348,14 @@ private:
void UpdateWindowTitle(std::string_view title_name = {}, std::string_view title_version = {},
std::string_view gpu_vendor = {});
void UpdateDockedButton();
+ void UpdateAPIText();
void UpdateFilterText();
void UpdateAAText();
void UpdateStatusBar();
void UpdateGPUAccuracyButton();
void UpdateStatusButtons();
void UpdateUISettings();
+ void UpdateInputDrivers();
void HideMouseCursor();
void ShowMouseCursor();
void CenterMouseCursor();
@@ -395,6 +407,7 @@ private:
bool auto_muted = false;
QTimer mouse_hide_timer;
QTimer mouse_center_timer;
+ QTimer update_input_timer;
QString startup_icon_theme;
bool os_dark_mode = false;
diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui
index e670acc30..013ba0ceb 100644
--- a/src/yuzu/main.ui
+++ b/src/yuzu/main.ui
@@ -231,6 +231,9 @@
<property name="text">
<string>Con&amp;figure...</string>
</property>
+ <property name="menuRole">
+ <enum>QAction::PreferencesRole</enum>
+ </property>
</action>
<action name="action_Display_Dock_Widget_Headers">
<property name="checkable">
@@ -363,6 +366,9 @@
<property name="text">
<string>&amp;Configure TAS...</string>
</property>
+ <property name="menuRole">
+ <enum>QAction::NoRole</enum>
+ </property>
</action>
<action name="action_Configure_Current_Game">
<property name="enabled">
@@ -371,6 +377,9 @@
<property name="text">
<string>Configure C&amp;urrent Game...</string>
</property>
+ <property name="menuRole">
+ <enum>QAction::NoRole</enum>
+ </property>
</action>
<action name="action_TAS_Start">
<property name="enabled">
diff --git a/src/yuzu/multiplayer/chat_room.h b/src/yuzu/multiplayer/chat_room.h
index 01c70fad0..dd71ea4cd 100644
--- a/src/yuzu/multiplayer/chat_room.h
+++ b/src/yuzu/multiplayer/chat_room.h
@@ -4,6 +4,7 @@
#pragma once
#include <memory>
+#include <unordered_map>
#include <unordered_set>
#include <QDialog>
#include <QSortFilterProxyModel>
diff --git a/src/yuzu/multiplayer/direct_connect.cpp b/src/yuzu/multiplayer/direct_connect.cpp
index 10bf0a4fb..cbd52da85 100644
--- a/src/yuzu/multiplayer/direct_connect.cpp
+++ b/src/yuzu/multiplayer/direct_connect.cpp
@@ -4,7 +4,7 @@
#include <QComboBox>
#include <QFuture>
#include <QIntValidator>
-#include <QRegExpValidator>
+#include <QRegularExpressionValidator>
#include <QString>
#include <QtConcurrent/QtConcurrentRun>
#include "common/settings.h"
diff --git a/src/yuzu/multiplayer/validation.h b/src/yuzu/multiplayer/validation.h
index dabf860be..dd25af280 100644
--- a/src/yuzu/multiplayer/validation.h
+++ b/src/yuzu/multiplayer/validation.h
@@ -3,7 +3,7 @@
#pragma once
-#include <QRegExp>
+#include <QRegularExpression>
#include <QString>
#include <QValidator>
@@ -29,19 +29,21 @@ public:
private:
/// room name can be alphanumeric and " " "_" "." and "-" and must have a size of 4-20
- QRegExp room_name_regex = QRegExp(QStringLiteral("^[a-zA-Z0-9._- ]{4,20}$"));
- QRegExpValidator room_name;
+ QRegularExpression room_name_regex =
+ QRegularExpression(QStringLiteral("^[a-zA-Z0-9._ -]{4,20}"));
+ QRegularExpressionValidator room_name;
/// nickname can be alphanumeric and " " "_" "." and "-" and must have a size of 4-20
- QRegExp nickname_regex = QRegExp(QStringLiteral("^[a-zA-Z0-9._- ]{4,20}$"));
- QRegExpValidator nickname;
+ const QRegularExpression nickname_regex =
+ QRegularExpression(QStringLiteral("^[a-zA-Z0-9._ -]{4,20}"));
+ QRegularExpressionValidator nickname;
/// ipv4 address only
// TODO remove this when we support hostnames in direct connect
- QRegExp ip_regex = QRegExp(QStringLiteral(
+ QRegularExpression ip_regex = QRegularExpression(QStringLiteral(
"(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|"
"2[0-4][0-9]|25[0-5])"));
- QRegExpValidator ip;
+ QRegularExpressionValidator ip;
/// port must be between 0 and 65535
QIntValidator port;
diff --git a/src/yuzu/precompiled_headers.h b/src/yuzu/precompiled_headers.h
new file mode 100644
index 000000000..aabae730b
--- /dev/null
+++ b/src/yuzu/precompiled_headers.h
@@ -0,0 +1,6 @@
+// SPDX-FileCopyrightText: 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "common/common_precompiled_headers.h"
diff --git a/src/yuzu/startup_checks.cpp b/src/yuzu/startup_checks.cpp
index 6a91212e2..563818362 100644
--- a/src/yuzu/startup_checks.cpp
+++ b/src/yuzu/startup_checks.cpp
@@ -4,16 +4,19 @@
#include "video_core/vulkan_common/vulkan_wrapper.h"
#ifdef _WIN32
-#include <cstring> // for memset, strncpy
+#include <cstring>
#include <processthreadsapi.h>
#include <windows.h>
#elif defined(YUZU_UNIX)
+#include <cstring>
#include <errno.h>
+#include <spawn.h>
+#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#endif
-#include <cstdio>
+#include <fmt/core.h>
#include "video_core/vulkan_common/vulkan_instance.h"
#include "video_core/vulkan_common/vulkan_library.h"
#include "yuzu/startup_checks.h"
@@ -24,10 +27,10 @@ void CheckVulkan() {
Vulkan::vk::InstanceDispatch dld;
const Common::DynamicLibrary library = Vulkan::OpenLibrary();
const Vulkan::vk::Instance instance =
- Vulkan::CreateInstance(library, dld, VK_API_VERSION_1_0);
+ Vulkan::CreateInstance(library, dld, VK_API_VERSION_1_1);
} catch (const Vulkan::vk::Exception& exception) {
- std::fprintf(stderr, "Failed to initialize Vulkan: %s\n", exception.what());
+ fmt::print(stderr, "Failed to initialize Vulkan: {}\n", exception.what());
}
}
@@ -49,8 +52,15 @@ bool CheckEnvVars(bool* is_child) {
*is_child = true;
return false;
} else if (!SetEnvironmentVariableA(IS_CHILD_ENV_VAR, ENV_VAR_ENABLED_TEXT)) {
- std::fprintf(stderr, "SetEnvironmentVariableA failed to set %s with error %lu\n",
- IS_CHILD_ENV_VAR, GetLastError());
+ fmt::print(stderr, "SetEnvironmentVariableA failed to set {} with error {}\n",
+ IS_CHILD_ENV_VAR, GetLastError());
+ return true;
+ }
+#elif defined(YUZU_UNIX)
+ const char* startup_check_var = getenv(STARTUP_CHECK_ENV_VAR);
+ if (startup_check_var != nullptr &&
+ std::strncmp(startup_check_var, ENV_VAR_ENABLED_TEXT, 8) == 0) {
+ CheckVulkan();
return true;
}
#endif
@@ -62,8 +72,8 @@ bool StartupChecks(const char* arg0, bool* has_broken_vulkan, bool perform_vulka
// Set the startup variable for child processes
const bool env_var_set = SetEnvironmentVariableA(STARTUP_CHECK_ENV_VAR, ENV_VAR_ENABLED_TEXT);
if (!env_var_set) {
- std::fprintf(stderr, "SetEnvironmentVariableA failed to set %s with error %lu\n",
- STARTUP_CHECK_ENV_VAR, GetLastError());
+ fmt::print(stderr, "SetEnvironmentVariableA failed to set {} with error {}\n",
+ STARTUP_CHECK_ENV_VAR, GetLastError());
return false;
}
@@ -81,48 +91,57 @@ bool StartupChecks(const char* arg0, bool* has_broken_vulkan, bool perform_vulka
DWORD exit_code = STILL_ACTIVE;
const int err = GetExitCodeProcess(process_info.hProcess, &exit_code);
if (err == 0) {
- std::fprintf(stderr, "GetExitCodeProcess failed with error %lu\n", GetLastError());
+ fmt::print(stderr, "GetExitCodeProcess failed with error {}\n", GetLastError());
}
// Vulkan is broken if the child crashed (return value is not zero)
*has_broken_vulkan = (exit_code != 0);
if (CloseHandle(process_info.hProcess) == 0) {
- std::fprintf(stderr, "CloseHandle failed with error %lu\n", GetLastError());
+ fmt::print(stderr, "CloseHandle failed with error {}\n", GetLastError());
}
if (CloseHandle(process_info.hThread) == 0) {
- std::fprintf(stderr, "CloseHandle failed with error %lu\n", GetLastError());
+ fmt::print(stderr, "CloseHandle failed with error {}\n", GetLastError());
}
}
if (!SetEnvironmentVariableA(STARTUP_CHECK_ENV_VAR, nullptr)) {
- std::fprintf(stderr, "SetEnvironmentVariableA failed to clear %s with error %lu\n",
- STARTUP_CHECK_ENV_VAR, GetLastError());
+ fmt::print(stderr, "SetEnvironmentVariableA failed to clear {} with error {}\n",
+ STARTUP_CHECK_ENV_VAR, GetLastError());
}
#elif defined(YUZU_UNIX)
+ const int env_var_set = setenv(STARTUP_CHECK_ENV_VAR, ENV_VAR_ENABLED_TEXT, 1);
+ if (env_var_set == -1) {
+ const int err = errno;
+ fmt::print(stderr, "setenv failed to set {} with error {}\n", STARTUP_CHECK_ENV_VAR, err);
+ return false;
+ }
+
if (perform_vulkan_check) {
- const pid_t pid = fork();
- if (pid == 0) {
- CheckVulkan();
- return true;
- } else if (pid == -1) {
- const int err = errno;
- std::fprintf(stderr, "fork failed with error %d\n", err);
+ const pid_t pid = SpawnChild(arg0);
+ if (pid == -1) {
return false;
}
// Get exit code from child process
int status;
- const int r_val = wait(&status);
+ const int r_val = waitpid(pid, &status, 0);
if (r_val == -1) {
const int err = errno;
- std::fprintf(stderr, "wait failed with error %d\n", err);
+ fmt::print(stderr, "wait failed with error {}\n", err);
return false;
}
// Vulkan is broken if the child crashed (return value is not zero)
*has_broken_vulkan = (status != 0);
}
+
+ const int env_var_cleared = unsetenv(STARTUP_CHECK_ENV_VAR);
+ if (env_var_cleared == -1) {
+ const int err = errno;
+ fmt::print(stderr, "unsetenv failed to clear {} with error {}\n", STARTUP_CHECK_ENV_VAR,
+ err);
+ }
#endif
return false;
}
@@ -150,10 +169,29 @@ bool SpawnChild(const char* arg0, PROCESS_INFORMATION* pi, int flags) {
pi // lpProcessInformation
);
if (!process_created) {
- std::fprintf(stderr, "CreateProcessA failed with error %lu\n", GetLastError());
+ fmt::print(stderr, "CreateProcessA failed with error {}\n", GetLastError());
return false;
}
return true;
}
+#elif defined(YUZU_UNIX)
+pid_t SpawnChild(const char* arg0) {
+ const pid_t pid = fork();
+
+ if (pid == -1) {
+ // error
+ const int err = errno;
+ fmt::print(stderr, "fork failed with error {}\n", err);
+ return pid;
+ } else if (pid == 0) {
+ // child
+ execl(arg0, arg0, nullptr);
+ const int err = errno;
+ fmt::print(stderr, "execl failed with error {}\n", err);
+ _exit(0);
+ }
+
+ return pid;
+}
#endif
diff --git a/src/yuzu/startup_checks.h b/src/yuzu/startup_checks.h
index d8e563be6..2f86fb843 100644
--- a/src/yuzu/startup_checks.h
+++ b/src/yuzu/startup_checks.h
@@ -5,6 +5,8 @@
#ifdef _WIN32
#include <windows.h>
+#elif defined(YUZU_UNIX)
+#include <sys/types.h>
#endif
constexpr char IS_CHILD_ENV_VAR[] = "YUZU_IS_CHILD";
@@ -17,4 +19,6 @@ bool StartupChecks(const char* arg0, bool* has_broken_vulkan, bool perform_vulka
#ifdef _WIN32
bool SpawnChild(const char* arg0, PROCESS_INFORMATION* pi, int flags);
+#elif defined(YUZU_UNIX)
+pid_t SpawnChild(const char* arg0);
#endif