From a84ad180e8e16ed04de5551b2f72349e2ec4d215 Mon Sep 17 00:00:00 2001 From: EBADBEEF Date: Sun, 22 Jan 2023 23:36:40 -0800 Subject: qt: add option to disable controller applet - add checkbox to disable the controller applet UI - when controller applet is disabled, use the yuzu-cmd fallback controller applet that applies controller config based on rules - See https://github.com/yuzu-emu/yuzu/issues/8552 for some discussion --- src/yuzu/configuration/config.cpp | 2 ++ src/yuzu/configuration/configure_general.cpp | 4 ++++ src/yuzu/configuration/configure_general.ui | 7 +++++++ src/yuzu/main.cpp | 1 + src/yuzu/uisettings.h | 2 ++ 5 files changed, 16 insertions(+) (limited to 'src') diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index fd3bb30e1..1f1ef658c 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -836,6 +836,7 @@ void Config::ReadUIValues() { ReadBasicSetting(UISettings::values.pause_when_in_background); ReadBasicSetting(UISettings::values.mute_when_in_background); ReadBasicSetting(UISettings::values.hide_mouse); + ReadBasicSetting(UISettings::values.controller_applet_disabled); ReadBasicSetting(UISettings::values.disable_web_applet); qt_config->endGroup(); @@ -1456,6 +1457,7 @@ void Config::SaveUIValues() { WriteBasicSetting(UISettings::values.pause_when_in_background); WriteBasicSetting(UISettings::values.mute_when_in_background); WriteBasicSetting(UISettings::values.hide_mouse); + WriteBasicSetting(UISettings::values.controller_applet_disabled); WriteBasicSetting(UISettings::values.disable_web_applet); qt_config->endGroup(); diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp index 7ade01ba6..7783f362a 100644 --- a/src/yuzu/configuration/configure_general.cpp +++ b/src/yuzu/configuration/configure_general.cpp @@ -44,6 +44,8 @@ void ConfigureGeneral::SetConfiguration() { ui->toggle_background_pause->setChecked(UISettings::values.pause_when_in_background.GetValue()); ui->toggle_background_mute->setChecked(UISettings::values.mute_when_in_background.GetValue()); ui->toggle_hide_mouse->setChecked(UISettings::values.hide_mouse.GetValue()); + ui->toggle_controller_applet_disabled->setEnabled(runtime_lock); + ui->toggle_controller_applet_disabled->setChecked(UISettings::values.controller_applet_disabled.GetValue()); ui->toggle_speed_limit->setChecked(Settings::values.use_speed_limit.GetValue()); ui->speed_limit->setValue(Settings::values.speed_limit.GetValue()); @@ -90,6 +92,7 @@ void ConfigureGeneral::ApplyConfiguration() { UISettings::values.pause_when_in_background = ui->toggle_background_pause->isChecked(); UISettings::values.mute_when_in_background = ui->toggle_background_mute->isChecked(); UISettings::values.hide_mouse = ui->toggle_hide_mouse->isChecked(); + UISettings::values.controller_applet_disabled = ui->toggle_controller_applet_disabled->isChecked(); // Guard if during game and set to game-specific value if (Settings::values.use_speed_limit.UsingGlobal()) { @@ -136,6 +139,7 @@ void ConfigureGeneral::SetupPerGameUI() { ui->toggle_user_on_boot->setVisible(false); ui->toggle_background_pause->setVisible(false); ui->toggle_hide_mouse->setVisible(false); + ui->toggle_controller_applet_disabled->setVisible(false); ui->button_reset_defaults->setVisible(false); diff --git a/src/yuzu/configuration/configure_general.ui b/src/yuzu/configuration/configure_general.ui index 5b90b1109..2fa8324fb 100644 --- a/src/yuzu/configuration/configure_general.ui +++ b/src/yuzu/configuration/configure_general.ui @@ -103,6 +103,13 @@ + + + + Disable controller applet + + + diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 571eacf9f..e57e02652 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -1562,6 +1562,7 @@ bool GMainWindow::LoadROM(const QString& filename, u64 program_id, std::size_t p system->SetAppletFrontendSet({ std::make_unique(*this), // Amiibo Settings + (UISettings::values.controller_applet_disabled.GetValue() == true) ? nullptr : std::make_unique(*this), // Controller Selector std::make_unique(*this), // Error Display nullptr, // Mii Editor diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h index db43b7033..20a517d34 100644 --- a/src/yuzu/uisettings.h +++ b/src/yuzu/uisettings.h @@ -77,6 +77,8 @@ struct Values { Settings::Setting pause_when_in_background{false, "pauseWhenInBackground"}; Settings::Setting mute_when_in_background{false, "muteWhenInBackground"}; Settings::Setting hide_mouse{true, "hideInactiveMouse"}; + Settings::Setting controller_applet_disabled{false, "disableControllerApplet"}; + // Set when Vulkan is known to crash the application bool has_broken_vulkan = false; -- cgit v1.2.3 From dd12dd4c67dd4bc6e7a7d071b925afc38e687f8b Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Sat, 22 Apr 2023 22:55:03 -0400 Subject: x64: Deduplicate RDTSC usage --- src/common/CMakeLists.txt | 2 ++ src/common/x64/cpu_detect.cpp | 3 +++ src/common/x64/cpu_wait.cpp | 20 +------------------- src/common/x64/rdtsc.cpp | 39 +++++++++++++++++++++++++++++++++++++++ src/common/x64/rdtsc.h | 37 +++++++++++++++++++++++++++++++++++++ 5 files changed, 82 insertions(+), 19 deletions(-) create mode 100644 src/common/x64/rdtsc.cpp create mode 100644 src/common/x64/rdtsc.h (limited to 'src') diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index efc4a9fe9..3adf13a3f 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -172,6 +172,8 @@ if(ARCHITECTURE_x86_64) x64/cpu_wait.h x64/native_clock.cpp x64/native_clock.h + x64/rdtsc.cpp + x64/rdtsc.h x64/xbyak_abi.h x64/xbyak_util.h ) diff --git a/src/common/x64/cpu_detect.cpp b/src/common/x64/cpu_detect.cpp index 72ed6e96c..c998b1197 100644 --- a/src/common/x64/cpu_detect.cpp +++ b/src/common/x64/cpu_detect.cpp @@ -14,6 +14,7 @@ #include "common/common_types.h" #include "common/logging/log.h" #include "common/x64/cpu_detect.h" +#include "common/x64/rdtsc.h" #ifdef _WIN32 #include @@ -187,6 +188,8 @@ static CPUCaps Detect() { caps.tsc_frequency = static_cast(caps.crystal_frequency) * caps.tsc_crystal_ratio_numerator / caps.tsc_crystal_ratio_denominator; + } else { + caps.tsc_frequency = X64::EstimateRDTSCFrequency(); } } diff --git a/src/common/x64/cpu_wait.cpp b/src/common/x64/cpu_wait.cpp index cfeef6a3d..c53dd4945 100644 --- a/src/common/x64/cpu_wait.cpp +++ b/src/common/x64/cpu_wait.cpp @@ -9,19 +9,11 @@ #include "common/x64/cpu_detect.h" #include "common/x64/cpu_wait.h" +#include "common/x64/rdtsc.h" namespace Common::X64 { #ifdef _MSC_VER -__forceinline static u64 FencedRDTSC() { - _mm_lfence(); - _ReadWriteBarrier(); - const u64 result = __rdtsc(); - _mm_lfence(); - _ReadWriteBarrier(); - return result; -} - __forceinline static void TPAUSE() { // 100,000 cycles is a reasonable amount of time to wait to save on CPU resources. // For reference: @@ -32,16 +24,6 @@ __forceinline static void TPAUSE() { _tpause(0, FencedRDTSC() + PauseCycles); } #else -static u64 FencedRDTSC() { - u64 eax; - u64 edx; - asm volatile("lfence\n\t" - "rdtsc\n\t" - "lfence\n\t" - : "=a"(eax), "=d"(edx)); - return (edx << 32) | eax; -} - static void TPAUSE() { // 100,000 cycles is a reasonable amount of time to wait to save on CPU resources. // For reference: diff --git a/src/common/x64/rdtsc.cpp b/src/common/x64/rdtsc.cpp new file mode 100644 index 000000000..9273274a3 --- /dev/null +++ b/src/common/x64/rdtsc.cpp @@ -0,0 +1,39 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include + +#include "common/steady_clock.h" +#include "common/uint128.h" +#include "common/x64/rdtsc.h" + +namespace Common::X64 { + +template +static u64 RoundToNearest(u64 value) { + const auto mod = value % Nearest; + return mod >= (Nearest / 2) ? (value - mod + Nearest) : (value - mod); +} + +u64 EstimateRDTSCFrequency() { + // Discard the first result measuring the rdtsc. + FencedRDTSC(); + std::this_thread::sleep_for(std::chrono::milliseconds{1}); + FencedRDTSC(); + + // Get the current time. + const auto start_time = RealTimeClock::Now(); + const u64 tsc_start = FencedRDTSC(); + // Wait for 100 milliseconds. + std::this_thread::sleep_for(std::chrono::milliseconds{100}); + const auto end_time = RealTimeClock::Now(); + const u64 tsc_end = FencedRDTSC(); + // Calculate differences. + const u64 timer_diff = static_cast( + std::chrono::duration_cast(end_time - start_time).count()); + const u64 tsc_diff = tsc_end - tsc_start; + const u64 tsc_freq = MultiplyAndDivide64(tsc_diff, 1000000000ULL, timer_diff); + return RoundToNearest<100'000>(tsc_freq); +} + +} // namespace Common::X64 diff --git a/src/common/x64/rdtsc.h b/src/common/x64/rdtsc.h new file mode 100644 index 000000000..0ec4f52f9 --- /dev/null +++ b/src/common/x64/rdtsc.h @@ -0,0 +1,37 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#ifdef _MSC_VER +#include +#endif + +#include "common/common_types.h" + +namespace Common::X64 { + +#ifdef _MSC_VER +__forceinline static u64 FencedRDTSC() { + _mm_lfence(); + _ReadWriteBarrier(); + const u64 result = __rdtsc(); + _mm_lfence(); + _ReadWriteBarrier(); + return result; +} +#else +static inline u64 FencedRDTSC() { + u64 eax; + u64 edx; + asm volatile("lfence\n\t" + "rdtsc\n\t" + "lfence\n\t" + : "=a"(eax), "=d"(edx)); + return (edx << 32) | eax; +} +#endif + +u64 EstimateRDTSCFrequency(); + +} // namespace Common::X64 -- cgit v1.2.3 From 1492a65454d6a03f641b136cc61e68870be00218 Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Sat, 22 Apr 2023 23:08:28 -0400 Subject: (wall, native)_clock: Rework NativeClock --- src/common/steady_clock.cpp | 5 +- src/common/wall_clock.cpp | 73 +++++++----------- src/common/wall_clock.h | 54 ++++++------- src/common/x64/native_clock.cpp | 165 ++++++---------------------------------- src/common/x64/native_clock.h | 56 +++++--------- 5 files changed, 94 insertions(+), 259 deletions(-) (limited to 'src') diff --git a/src/common/steady_clock.cpp b/src/common/steady_clock.cpp index 782859196..9415eed29 100644 --- a/src/common/steady_clock.cpp +++ b/src/common/steady_clock.cpp @@ -28,13 +28,12 @@ static s64 GetSystemTimeNS() { // GetSystemTimePreciseAsFileTime returns the file time in 100ns units. static constexpr s64 Multiplier = 100; // Convert Windows epoch to Unix epoch. - static constexpr s64 WindowsEpochToUnixEpochNS = 0x19DB1DED53E8000LL; + static constexpr s64 WindowsEpochToUnixEpoch = 0x19DB1DED53E8000LL; FILETIME filetime; GetSystemTimePreciseAsFileTime(&filetime); return Multiplier * ((static_cast(filetime.dwHighDateTime) << 32) + - static_cast(filetime.dwLowDateTime)) - - WindowsEpochToUnixEpochNS; + static_cast(filetime.dwLowDateTime) - WindowsEpochToUnixEpoch); } #endif diff --git a/src/common/wall_clock.cpp b/src/common/wall_clock.cpp index 817e71d52..ad8db06b0 100644 --- a/src/common/wall_clock.cpp +++ b/src/common/wall_clock.cpp @@ -2,88 +2,71 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "common/steady_clock.h" -#include "common/uint128.h" #include "common/wall_clock.h" #ifdef ARCHITECTURE_x86_64 #include "common/x64/cpu_detect.h" #include "common/x64/native_clock.h" +#include "common/x64/rdtsc.h" #endif namespace Common { class StandardWallClock final : public WallClock { public: - explicit StandardWallClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequency_) - : WallClock{emulated_cpu_frequency_, emulated_clock_frequency_, false}, - start_time{SteadyClock::Now()} {} + explicit StandardWallClock() : start_time{SteadyClock::Now()} {} - std::chrono::nanoseconds GetTimeNS() override { + std::chrono::nanoseconds GetTimeNS() const override { return SteadyClock::Now() - start_time; } - std::chrono::microseconds GetTimeUS() override { - return std::chrono::duration_cast(GetTimeNS()); + std::chrono::microseconds GetTimeUS() const override { + return static_cast(GetHostTicksElapsed() / NsToUsRatio::den); } - std::chrono::milliseconds GetTimeMS() override { - return std::chrono::duration_cast(GetTimeNS()); + std::chrono::milliseconds GetTimeMS() const override { + return static_cast(GetHostTicksElapsed() / NsToMsRatio::den); } - u64 GetClockCycles() override { - const u128 temp = Common::Multiply64Into128(GetTimeNS().count(), emulated_clock_frequency); - return Common::Divide128On32(temp, NS_RATIO).first; + u64 GetCNTPCT() const override { + return GetHostTicksElapsed() * NsToCNTPCTRatio::num / NsToCNTPCTRatio::den; } - u64 GetCPUCycles() override { - const u128 temp = Common::Multiply64Into128(GetTimeNS().count(), emulated_cpu_frequency); - return Common::Divide128On32(temp, NS_RATIO).first; + u64 GetHostTicksNow() const override { + return static_cast(SteadyClock::Now().time_since_epoch().count()); } - void Pause([[maybe_unused]] bool is_paused) override { - // Do nothing in this clock type. + u64 GetHostTicksElapsed() const override { + return static_cast(GetTimeNS().count()); + } + + bool IsNative() const override { + return false; } private: SteadyClock::time_point start_time; }; +std::unique_ptr CreateOptimalClock() { #ifdef ARCHITECTURE_x86_64 - -std::unique_ptr CreateBestMatchingClock(u64 emulated_cpu_frequency, - u64 emulated_clock_frequency) { const auto& caps = GetCPUCaps(); - u64 rtsc_frequency = 0; - if (caps.invariant_tsc) { - rtsc_frequency = caps.tsc_frequency ? caps.tsc_frequency : EstimateRDTSCFrequency(); - } - // Fallback to StandardWallClock if the hardware TSC does not have the precision greater than: - // - A nanosecond - // - The emulated CPU frequency - // - The emulated clock counter frequency (CNTFRQ) - if (rtsc_frequency <= WallClock::NS_RATIO || rtsc_frequency <= emulated_cpu_frequency || - rtsc_frequency <= emulated_clock_frequency) { - return std::make_unique(emulated_cpu_frequency, - emulated_clock_frequency); + if (caps.invariant_tsc && caps.tsc_frequency >= WallClock::CNTFRQ) { + return std::make_unique(caps.tsc_frequency); } else { - return std::make_unique(emulated_cpu_frequency, emulated_clock_frequency, - rtsc_frequency); + // Fallback to StandardWallClock if the hardware TSC + // - Is not invariant + // - Is not more precise than CNTFRQ + return std::make_unique(); } -} - #else - -std::unique_ptr CreateBestMatchingClock(u64 emulated_cpu_frequency, - u64 emulated_clock_frequency) { - return std::make_unique(emulated_cpu_frequency, emulated_clock_frequency); -} - + return std::make_unique(); #endif +} -std::unique_ptr CreateStandardWallClock(u64 emulated_cpu_frequency, - u64 emulated_clock_frequency) { - return std::make_unique(emulated_cpu_frequency, emulated_clock_frequency); +std::unique_ptr CreateStandardWallClock() { + return std::make_unique(); } } // namespace Common diff --git a/src/common/wall_clock.h b/src/common/wall_clock.h index 157ec5eae..a73e6e644 100644 --- a/src/common/wall_clock.h +++ b/src/common/wall_clock.h @@ -5,6 +5,7 @@ #include #include +#include #include "common/common_types.h" @@ -12,50 +13,43 @@ namespace Common { class WallClock { public: - static constexpr u64 NS_RATIO = 1'000'000'000; - static constexpr u64 US_RATIO = 1'000'000; - static constexpr u64 MS_RATIO = 1'000; + static constexpr u64 CNTFRQ = 19'200'000; // CNTPCT_EL0 Frequency = 19.2 MHz virtual ~WallClock() = default; - /// Returns current wall time in nanoseconds - [[nodiscard]] virtual std::chrono::nanoseconds GetTimeNS() = 0; + /// @returns The time in nanoseconds since the construction of this clock. + virtual std::chrono::nanoseconds GetTimeNS() const = 0; - /// Returns current wall time in microseconds - [[nodiscard]] virtual std::chrono::microseconds GetTimeUS() = 0; + /// @returns The time in microseconds since the construction of this clock. + virtual std::chrono::microseconds GetTimeUS() const = 0; - /// Returns current wall time in milliseconds - [[nodiscard]] virtual std::chrono::milliseconds GetTimeMS() = 0; + /// @returns The time in milliseconds since the construction of this clock. + virtual std::chrono::milliseconds GetTimeMS() const = 0; - /// Returns current wall time in emulated clock cycles - [[nodiscard]] virtual u64 GetClockCycles() = 0; + /// @returns The guest CNTPCT ticks since the construction of this clock. + virtual u64 GetCNTPCT() const = 0; - /// Returns current wall time in emulated cpu cycles - [[nodiscard]] virtual u64 GetCPUCycles() = 0; + /// @returns The raw host timer ticks since an indeterminate epoch. + virtual u64 GetHostTicksNow() const = 0; - virtual void Pause(bool is_paused) = 0; + /// @returns The raw host timer ticks since the construction of this clock. + virtual u64 GetHostTicksElapsed() const = 0; - /// Tells if the wall clock, uses the host CPU's hardware clock - [[nodiscard]] bool IsNative() const { - return is_native; - } + /// @returns Whether the clock directly uses the host's hardware clock. + virtual bool IsNative() const = 0; protected: - explicit WallClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequency_, bool is_native_) - : emulated_cpu_frequency{emulated_cpu_frequency_}, - emulated_clock_frequency{emulated_clock_frequency_}, is_native{is_native_} {} + using NsRatio = std::nano; + using UsRatio = std::micro; + using MsRatio = std::milli; - u64 emulated_cpu_frequency; - u64 emulated_clock_frequency; - -private: - bool is_native; + using NsToUsRatio = std::ratio_divide; + using NsToMsRatio = std::ratio_divide; + using NsToCNTPCTRatio = std::ratio; }; -[[nodiscard]] std::unique_ptr CreateBestMatchingClock(u64 emulated_cpu_frequency, - u64 emulated_clock_frequency); +std::unique_ptr CreateOptimalClock(); -[[nodiscard]] std::unique_ptr CreateStandardWallClock(u64 emulated_cpu_frequency, - u64 emulated_clock_frequency); +std::unique_ptr CreateStandardWallClock(); } // namespace Common diff --git a/src/common/x64/native_clock.cpp b/src/common/x64/native_clock.cpp index 277b00662..5d1eb0590 100644 --- a/src/common/x64/native_clock.cpp +++ b/src/common/x64/native_clock.cpp @@ -1,164 +1,45 @@ // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include -#include -#include - -#include "common/atomic_ops.h" -#include "common/steady_clock.h" #include "common/uint128.h" #include "common/x64/native_clock.h" +#include "common/x64/rdtsc.h" -#ifdef _MSC_VER -#include -#endif +namespace Common::X64 { -namespace Common { +NativeClock::NativeClock(u64 rdtsc_frequency_) + : start_ticks{FencedRDTSC()}, rdtsc_frequency{rdtsc_frequency_}, + ns_rdtsc_factor{GetFixedPoint64Factor(NsRatio::den, rdtsc_frequency)}, + us_rdtsc_factor{GetFixedPoint64Factor(UsRatio::den, rdtsc_frequency)}, + ms_rdtsc_factor{GetFixedPoint64Factor(MsRatio::den, rdtsc_frequency)}, + cntpct_rdtsc_factor{GetFixedPoint64Factor(CNTFRQ, rdtsc_frequency)} {} -#ifdef _MSC_VER -__forceinline static u64 FencedRDTSC() { - _mm_lfence(); - _ReadWriteBarrier(); - const u64 result = __rdtsc(); - _mm_lfence(); - _ReadWriteBarrier(); - return result; -} -#else -static u64 FencedRDTSC() { - u64 eax; - u64 edx; - asm volatile("lfence\n\t" - "rdtsc\n\t" - "lfence\n\t" - : "=a"(eax), "=d"(edx)); - return (edx << 32) | eax; +std::chrono::nanoseconds NativeClock::GetTimeNS() const { + return std::chrono::nanoseconds{MultiplyHigh(GetHostTicksElapsed(), ns_rdtsc_factor)}; } -#endif -template -static u64 RoundToNearest(u64 value) { - const auto mod = value % Nearest; - return mod >= (Nearest / 2) ? (value - mod + Nearest) : (value - mod); +std::chrono::microseconds NativeClock::GetTimeUS() const { + return std::chrono::microseconds{MultiplyHigh(GetHostTicksElapsed(), us_rdtsc_factor)}; } -u64 EstimateRDTSCFrequency() { - // Discard the first result measuring the rdtsc. - FencedRDTSC(); - std::this_thread::sleep_for(std::chrono::milliseconds{1}); - FencedRDTSC(); - - // Get the current time. - const auto start_time = Common::RealTimeClock::Now(); - const u64 tsc_start = FencedRDTSC(); - // Wait for 250 milliseconds. - std::this_thread::sleep_for(std::chrono::milliseconds{250}); - const auto end_time = Common::RealTimeClock::Now(); - const u64 tsc_end = FencedRDTSC(); - // Calculate differences. - const u64 timer_diff = static_cast( - std::chrono::duration_cast(end_time - start_time).count()); - const u64 tsc_diff = tsc_end - tsc_start; - const u64 tsc_freq = MultiplyAndDivide64(tsc_diff, 1000000000ULL, timer_diff); - return RoundToNearest<1000>(tsc_freq); +std::chrono::milliseconds NativeClock::GetTimeMS() const { + return std::chrono::milliseconds{MultiplyHigh(GetHostTicksElapsed(), ms_rdtsc_factor)}; } -namespace X64 { -NativeClock::NativeClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequency_, - u64 rtsc_frequency_) - : WallClock(emulated_cpu_frequency_, emulated_clock_frequency_, true), rtsc_frequency{ - rtsc_frequency_} { - // Thread to re-adjust the RDTSC frequency after 10 seconds has elapsed. - time_sync_thread = std::jthread{[this](std::stop_token token) { - // Get the current time. - const auto start_time = Common::RealTimeClock::Now(); - const u64 tsc_start = FencedRDTSC(); - // Wait for 10 seconds. - if (!Common::StoppableTimedWait(token, std::chrono::seconds{10})) { - return; - } - const auto end_time = Common::RealTimeClock::Now(); - const u64 tsc_end = FencedRDTSC(); - // Calculate differences. - const u64 timer_diff = static_cast( - std::chrono::duration_cast(end_time - start_time).count()); - const u64 tsc_diff = tsc_end - tsc_start; - const u64 tsc_freq = MultiplyAndDivide64(tsc_diff, 1000000000ULL, timer_diff); - rtsc_frequency = tsc_freq; - CalculateAndSetFactors(); - }}; - - time_point.inner.last_measure = FencedRDTSC(); - time_point.inner.accumulated_ticks = 0U; - CalculateAndSetFactors(); +u64 NativeClock::GetCNTPCT() const { + return MultiplyHigh(GetHostTicksElapsed(), cntpct_rdtsc_factor); } -u64 NativeClock::GetRTSC() { - TimePoint new_time_point{}; - TimePoint current_time_point{}; - - current_time_point.pack = Common::AtomicLoad128(time_point.pack.data()); - do { - const u64 current_measure = FencedRDTSC(); - u64 diff = current_measure - current_time_point.inner.last_measure; - diff = diff & ~static_cast(static_cast(diff) >> 63); // max(diff, 0) - new_time_point.inner.last_measure = current_measure > current_time_point.inner.last_measure - ? current_measure - : current_time_point.inner.last_measure; - new_time_point.inner.accumulated_ticks = current_time_point.inner.accumulated_ticks + diff; - } while (!Common::AtomicCompareAndSwap(time_point.pack.data(), new_time_point.pack, - current_time_point.pack, current_time_point.pack)); - return new_time_point.inner.accumulated_ticks; +u64 NativeClock::GetHostTicksNow() const { + return FencedRDTSC(); } -void NativeClock::Pause(bool is_paused) { - if (!is_paused) { - TimePoint current_time_point{}; - TimePoint new_time_point{}; - - current_time_point.pack = Common::AtomicLoad128(time_point.pack.data()); - do { - new_time_point.pack = current_time_point.pack; - new_time_point.inner.last_measure = FencedRDTSC(); - } while (!Common::AtomicCompareAndSwap(time_point.pack.data(), new_time_point.pack, - current_time_point.pack, current_time_point.pack)); - } -} - -std::chrono::nanoseconds NativeClock::GetTimeNS() { - const u64 rtsc_value = GetRTSC(); - return std::chrono::nanoseconds{MultiplyHigh(rtsc_value, ns_rtsc_factor)}; +u64 NativeClock::GetHostTicksElapsed() const { + return FencedRDTSC() - start_ticks; } -std::chrono::microseconds NativeClock::GetTimeUS() { - const u64 rtsc_value = GetRTSC(); - return std::chrono::microseconds{MultiplyHigh(rtsc_value, us_rtsc_factor)}; +bool NativeClock::IsNative() const { + return true; } -std::chrono::milliseconds NativeClock::GetTimeMS() { - const u64 rtsc_value = GetRTSC(); - return std::chrono::milliseconds{MultiplyHigh(rtsc_value, ms_rtsc_factor)}; -} - -u64 NativeClock::GetClockCycles() { - const u64 rtsc_value = GetRTSC(); - return MultiplyHigh(rtsc_value, clock_rtsc_factor); -} - -u64 NativeClock::GetCPUCycles() { - const u64 rtsc_value = GetRTSC(); - return MultiplyHigh(rtsc_value, cpu_rtsc_factor); -} - -void NativeClock::CalculateAndSetFactors() { - ns_rtsc_factor = GetFixedPoint64Factor(NS_RATIO, rtsc_frequency); - us_rtsc_factor = GetFixedPoint64Factor(US_RATIO, rtsc_frequency); - ms_rtsc_factor = GetFixedPoint64Factor(MS_RATIO, rtsc_frequency); - clock_rtsc_factor = GetFixedPoint64Factor(emulated_clock_frequency, rtsc_frequency); - cpu_rtsc_factor = GetFixedPoint64Factor(emulated_cpu_frequency, rtsc_frequency); -} - -} // namespace X64 - -} // namespace Common +} // namespace Common::X64 diff --git a/src/common/x64/native_clock.h b/src/common/x64/native_clock.h index 03ca291d8..d6f8626c1 100644 --- a/src/common/x64/native_clock.h +++ b/src/common/x64/native_clock.h @@ -3,58 +3,36 @@ #pragma once -#include "common/polyfill_thread.h" #include "common/wall_clock.h" -namespace Common { +namespace Common::X64 { -namespace X64 { class NativeClock final : public WallClock { public: - explicit NativeClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequency_, - u64 rtsc_frequency_); + explicit NativeClock(u64 rdtsc_frequency_); - std::chrono::nanoseconds GetTimeNS() override; + std::chrono::nanoseconds GetTimeNS() const override; - std::chrono::microseconds GetTimeUS() override; + std::chrono::microseconds GetTimeUS() const override; - std::chrono::milliseconds GetTimeMS() override; + std::chrono::milliseconds GetTimeMS() const override; - u64 GetClockCycles() override; + u64 GetCNTPCT() const override; - u64 GetCPUCycles() override; + u64 GetHostTicksNow() const override; - void Pause(bool is_paused) override; + u64 GetHostTicksElapsed() const override; -private: - u64 GetRTSC(); - - void CalculateAndSetFactors(); - - union alignas(16) TimePoint { - TimePoint() : pack{} {} - u128 pack{}; - struct Inner { - u64 last_measure{}; - u64 accumulated_ticks{}; - } inner; - }; - - TimePoint time_point; + bool IsNative() const override; - // factors - u64 clock_rtsc_factor{}; - u64 cpu_rtsc_factor{}; - u64 ns_rtsc_factor{}; - u64 us_rtsc_factor{}; - u64 ms_rtsc_factor{}; - - u64 rtsc_frequency; +private: + u64 start_ticks; + u64 rdtsc_frequency; - std::jthread time_sync_thread; + u64 ns_rdtsc_factor; + u64 us_rdtsc_factor; + u64 ms_rdtsc_factor; + u64 cntpct_rdtsc_factor; }; -} // namespace X64 - -u64 EstimateRDTSCFrequency(); -} // namespace Common +} // namespace Common::X64 -- cgit v1.2.3 From bbd502f67adb17b00b33f1b7158cfff2b2fa8a3e Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Sat, 22 Apr 2023 23:58:27 -0400 Subject: nvnflinger: Acquire lock prior to signaling the vsync variable --- src/core/hle/service/nvnflinger/nvnflinger.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/hle/service/nvnflinger/nvnflinger.cpp b/src/core/hle/service/nvnflinger/nvnflinger.cpp index 4988e6e17..aa3356611 100644 --- a/src/core/hle/service/nvnflinger/nvnflinger.cpp +++ b/src/core/hle/service/nvnflinger/nvnflinger.cpp @@ -70,7 +70,8 @@ Nvnflinger::Nvnflinger(Core::System& system_, HosBinderDriverServer& hos_binder_ [this](std::uintptr_t, s64 time, std::chrono::nanoseconds ns_late) -> std::optional { vsync_signal.store(true); - vsync_signal.notify_all(); + { const auto lock_guard = Lock(); } + vsync_signal.notify_one(); return std::chrono::nanoseconds(GetNextTicks()); }); -- cgit v1.2.3 From 8e56a84566036cfff0aa5c3d80ae1b051d2bd0bf Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Sun, 23 Apr 2023 00:01:08 -0400 Subject: core_timing: Use CNTPCT as the guest CPU tick Previously, we were mixing the raw CPU frequency and CNTFRQ. The raw CPU frequency (1020 MHz) should've never been used as CNTPCT (whose frequency is CNTFRQ) is the only counter available. --- src/audio_core/renderer/adsp/adsp.cpp | 1 - src/audio_core/renderer/adsp/audio_renderer.cpp | 5 +- .../renderer/adsp/command_list_processor.cpp | 1 - .../renderer/command/performance/performance.cpp | 15 +++--- src/audio_core/sink/sink_stream.cpp | 1 - src/common/wall_clock.h | 17 +++++++ src/core/CMakeLists.txt | 1 - src/core/core_timing.cpp | 35 +++---------- src/core/core_timing.h | 11 +--- src/core/core_timing_util.h | 58 ---------------------- src/core/hle/kernel/k_scheduler.cpp | 5 +- src/core/hle/kernel/svc/svc_info.cpp | 4 +- src/core/hle/service/hid/hidbus.cpp | 1 - src/video_core/gpu.cpp | 14 +++--- 14 files changed, 47 insertions(+), 122 deletions(-) delete mode 100644 src/core/core_timing_util.h (limited to 'src') diff --git a/src/audio_core/renderer/adsp/adsp.cpp b/src/audio_core/renderer/adsp/adsp.cpp index 74772fc50..b1db31e93 100644 --- a/src/audio_core/renderer/adsp/adsp.cpp +++ b/src/audio_core/renderer/adsp/adsp.cpp @@ -7,7 +7,6 @@ #include "common/logging/log.h" #include "core/core.h" #include "core/core_timing.h" -#include "core/core_timing_util.h" #include "core/memory.h" namespace AudioCore::AudioRenderer::ADSP { diff --git a/src/audio_core/renderer/adsp/audio_renderer.cpp b/src/audio_core/renderer/adsp/audio_renderer.cpp index 8bc39f9f9..9ca716b60 100644 --- a/src/audio_core/renderer/adsp/audio_renderer.cpp +++ b/src/audio_core/renderer/adsp/audio_renderer.cpp @@ -13,7 +13,6 @@ #include "common/thread.h" #include "core/core.h" #include "core/core_timing.h" -#include "core/core_timing_util.h" MICROPROFILE_DEFINE(Audio_Renderer, "Audio", "DSP", MP_RGB(60, 19, 97)); @@ -144,6 +143,7 @@ void AudioRenderer::ThreadFunc(std::stop_token stop_token) { mailbox->ADSPSendMessage(RenderMessage::AudioRenderer_InitializeOK); + // 0.12 seconds (2304000 / 19200000) constexpr u64 max_process_time{2'304'000ULL}; while (!stop_token.stop_requested()) { @@ -184,8 +184,7 @@ void AudioRenderer::ThreadFunc(std::stop_token stop_token) { u64 max_time{max_process_time}; if (index == 1 && command_buffer.applet_resource_user_id == mailbox->GetCommandBuffer(0).applet_resource_user_id) { - max_time = max_process_time - - Core::Timing::CyclesToNs(render_times_taken[0]).count(); + max_time = max_process_time - render_times_taken[0]; if (render_times_taken[0] > max_process_time) { max_time = 0; } diff --git a/src/audio_core/renderer/adsp/command_list_processor.cpp b/src/audio_core/renderer/adsp/command_list_processor.cpp index 7a300d216..3a0f1ae38 100644 --- a/src/audio_core/renderer/adsp/command_list_processor.cpp +++ b/src/audio_core/renderer/adsp/command_list_processor.cpp @@ -9,7 +9,6 @@ #include "common/settings.h" #include "core/core.h" #include "core/core_timing.h" -#include "core/core_timing_util.h" #include "core/memory.h" namespace AudioCore::AudioRenderer::ADSP { diff --git a/src/audio_core/renderer/command/performance/performance.cpp b/src/audio_core/renderer/command/performance/performance.cpp index 985958b03..4a881547f 100644 --- a/src/audio_core/renderer/command/performance/performance.cpp +++ b/src/audio_core/renderer/command/performance/performance.cpp @@ -5,7 +5,6 @@ #include "audio_core/renderer/command/performance/performance.h" #include "core/core.h" #include "core/core_timing.h" -#include "core/core_timing_util.h" namespace AudioCore::AudioRenderer { @@ -18,20 +17,18 @@ void PerformanceCommand::Process(const ADSP::CommandListProcessor& processor) { auto base{entry_address.translated_address}; if (state == PerformanceState::Start) { auto start_time_ptr{reinterpret_cast(base + entry_address.entry_start_time_offset)}; - *start_time_ptr = static_cast( - Core::Timing::CyclesToUs(processor.system->CoreTiming().GetClockTicks() - - processor.start_time - processor.current_processing_time) - .count()); + *start_time_ptr = + static_cast(processor.system->CoreTiming().GetClockTicks() - processor.start_time - + processor.current_processing_time); } else if (state == PerformanceState::Stop) { auto processed_time_ptr{ reinterpret_cast(base + entry_address.entry_processed_time_offset)}; auto entry_count_ptr{ reinterpret_cast(base + entry_address.header_entry_count_offset)}; - *processed_time_ptr = static_cast( - Core::Timing::CyclesToUs(processor.system->CoreTiming().GetClockTicks() - - processor.start_time - processor.current_processing_time) - .count()); + *processed_time_ptr = + static_cast(processor.system->CoreTiming().GetClockTicks() - processor.start_time - + processor.current_processing_time); (*entry_count_ptr)++; } } diff --git a/src/audio_core/sink/sink_stream.cpp b/src/audio_core/sink/sink_stream.cpp index f44fedfd5..9a718a9cc 100644 --- a/src/audio_core/sink/sink_stream.cpp +++ b/src/audio_core/sink/sink_stream.cpp @@ -15,7 +15,6 @@ #include "common/settings.h" #include "core/core.h" #include "core/core_timing.h" -#include "core/core_timing_util.h" namespace AudioCore::Sink { diff --git a/src/common/wall_clock.h b/src/common/wall_clock.h index a73e6e644..56c18ca25 100644 --- a/src/common/wall_clock.h +++ b/src/common/wall_clock.h @@ -38,6 +38,22 @@ public: /// @returns Whether the clock directly uses the host's hardware clock. virtual bool IsNative() const = 0; + static inline u64 NSToCNTPCT(u64 ns) { + return ns * NsToCNTPCTRatio::num / NsToCNTPCTRatio::den; + } + + static inline u64 USToCNTPCT(u64 us) { + return us * UsToCNTPCTRatio::num / UsToCNTPCTRatio::den; + } + + static inline u64 CNTPCTToNS(u64 cntpct) { + return cntpct * NsToCNTPCTRatio::den / NsToCNTPCTRatio::num; + } + + static inline u64 CNTPCTToUS(u64 cntpct) { + return cntpct * UsToCNTPCTRatio::den / UsToCNTPCTRatio::num; + } + protected: using NsRatio = std::nano; using UsRatio = std::micro; @@ -46,6 +62,7 @@ protected: using NsToUsRatio = std::ratio_divide; using NsToMsRatio = std::ratio_divide; using NsToCNTPCTRatio = std::ratio; + using UsToCNTPCTRatio = std::ratio; }; std::unique_ptr CreateOptimalClock(); diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 99602699a..3df4094a7 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -16,7 +16,6 @@ add_library(core STATIC core.h core_timing.cpp core_timing.h - core_timing_util.h cpu_manager.cpp cpu_manager.h crypto/aes_util.cpp diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp index 4f2692b05..9a1d5a69a 100644 --- a/src/core/core_timing.cpp +++ b/src/core/core_timing.cpp @@ -16,7 +16,6 @@ #include "common/microprofile.h" #include "core/core_timing.h" -#include "core/core_timing_util.h" #include "core/hardware_properties.h" namespace Core::Timing { @@ -45,9 +44,7 @@ struct CoreTiming::Event { } }; -CoreTiming::CoreTiming() - : cpu_clock{Common::CreateBestMatchingClock(Hardware::BASE_CLOCK_RATE, Hardware::CNTFREQ)}, - event_clock{Common::CreateStandardWallClock(Hardware::BASE_CLOCK_RATE, Hardware::CNTFREQ)} {} +CoreTiming::CoreTiming() : clock{Common::CreateOptimalClock()} {} CoreTiming::~CoreTiming() { Reset(); @@ -180,7 +177,7 @@ void CoreTiming::AddTicks(u64 ticks_to_add) { void CoreTiming::Idle() { if (!event_queue.empty()) { const u64 next_event_time = event_queue.front().time; - const u64 next_ticks = nsToCycles(std::chrono::nanoseconds(next_event_time)) + 10U; + const u64 next_ticks = Common::WallClock::NSToCNTPCT(next_event_time) + 10U; if (next_ticks > ticks) { ticks = next_ticks; } @@ -193,18 +190,11 @@ void CoreTiming::ResetTicks() { downcount = MAX_SLICE_LENGTH; } -u64 CoreTiming::GetCPUTicks() const { - if (is_multicore) [[likely]] { - return cpu_clock->GetCPUCycles(); - } - return ticks; -} - u64 CoreTiming::GetClockTicks() const { if (is_multicore) [[likely]] { - return cpu_clock->GetClockCycles(); + return clock->GetCNTPCT(); } - return CpuCyclesToClockCycles(ticks); + return ticks; } std::optional CoreTiming::Advance() { @@ -297,9 +287,7 @@ void CoreTiming::ThreadLoop() { } paused_set = true; - event_clock->Pause(true); pause_event.Wait(); - event_clock->Pause(false); } } @@ -315,25 +303,18 @@ void CoreTiming::Reset() { has_started = false; } -std::chrono::nanoseconds CoreTiming::GetCPUTimeNs() const { - if (is_multicore) [[likely]] { - return cpu_clock->GetTimeNS(); - } - return CyclesToNs(ticks); -} - std::chrono::nanoseconds CoreTiming::GetGlobalTimeNs() const { if (is_multicore) [[likely]] { - return event_clock->GetTimeNS(); + return clock->GetTimeNS(); } - return CyclesToNs(ticks); + return std::chrono::nanoseconds{Common::WallClock::CNTPCTToNS(ticks)}; } std::chrono::microseconds CoreTiming::GetGlobalTimeUs() const { if (is_multicore) [[likely]] { - return event_clock->GetTimeUS(); + return clock->GetTimeUS(); } - return CyclesToUs(ticks); + return std::chrono::microseconds{Common::WallClock::CNTPCTToUS(ticks)}; } } // namespace Core::Timing diff --git a/src/core/core_timing.h b/src/core/core_timing.h index e7c4a949f..fdacdd94a 100644 --- a/src/core/core_timing.h +++ b/src/core/core_timing.h @@ -116,15 +116,9 @@ public: return downcount; } - /// Returns current time in emulated CPU cycles - u64 GetCPUTicks() const; - - /// Returns current time in emulated in Clock cycles + /// Returns the current CNTPCT tick value. u64 GetClockTicks() const; - /// Returns current time in nanoseconds. - std::chrono::nanoseconds GetCPUTimeNs() const; - /// Returns current time in microseconds. std::chrono::microseconds GetGlobalTimeUs() const; @@ -142,8 +136,7 @@ private: void Reset(); - std::unique_ptr cpu_clock; - std::unique_ptr event_clock; + std::unique_ptr clock; s64 global_timer = 0; diff --git a/src/core/core_timing_util.h b/src/core/core_timing_util.h deleted file mode 100644 index fe5aaefc7..000000000 --- a/src/core/core_timing_util.h +++ /dev/null @@ -1,58 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include - -#include "common/common_types.h" -#include "core/hardware_properties.h" - -namespace Core::Timing { - -namespace detail { -constexpr u64 CNTFREQ_ADJUSTED = Hardware::CNTFREQ / 1000; -constexpr u64 BASE_CLOCK_RATE_ADJUSTED = Hardware::BASE_CLOCK_RATE / 1000; -} // namespace detail - -[[nodiscard]] constexpr s64 msToCycles(std::chrono::milliseconds ms) { - return ms.count() * detail::BASE_CLOCK_RATE_ADJUSTED; -} - -[[nodiscard]] constexpr s64 usToCycles(std::chrono::microseconds us) { - return us.count() * detail::BASE_CLOCK_RATE_ADJUSTED / 1000; -} - -[[nodiscard]] constexpr s64 nsToCycles(std::chrono::nanoseconds ns) { - return ns.count() * detail::BASE_CLOCK_RATE_ADJUSTED / 1000000; -} - -[[nodiscard]] constexpr u64 msToClockCycles(std::chrono::milliseconds ms) { - return static_cast(ms.count()) * detail::CNTFREQ_ADJUSTED; -} - -[[nodiscard]] constexpr u64 usToClockCycles(std::chrono::microseconds us) { - return us.count() * detail::CNTFREQ_ADJUSTED / 1000; -} - -[[nodiscard]] constexpr u64 nsToClockCycles(std::chrono::nanoseconds ns) { - return ns.count() * detail::CNTFREQ_ADJUSTED / 1000000; -} - -[[nodiscard]] constexpr u64 CpuCyclesToClockCycles(u64 ticks) { - return ticks * detail::CNTFREQ_ADJUSTED / detail::BASE_CLOCK_RATE_ADJUSTED; -} - -[[nodiscard]] constexpr std::chrono::milliseconds CyclesToMs(s64 cycles) { - return std::chrono::milliseconds(cycles / detail::BASE_CLOCK_RATE_ADJUSTED); -} - -[[nodiscard]] constexpr std::chrono::nanoseconds CyclesToNs(s64 cycles) { - return std::chrono::nanoseconds(cycles * 1000000 / detail::BASE_CLOCK_RATE_ADJUSTED); -} - -[[nodiscard]] constexpr std::chrono::microseconds CyclesToUs(s64 cycles) { - return std::chrono::microseconds(cycles * 1000 / detail::BASE_CLOCK_RATE_ADJUSTED); -} - -} // namespace Core::Timing diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index faa12b4f0..75ce5a23c 100644 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp @@ -184,7 +184,8 @@ u64 KScheduler::UpdateHighestPriorityThread(KThread* highest_thread) { prev_highest_thread != highest_thread) [[likely]] { if (prev_highest_thread != nullptr) [[likely]] { IncrementScheduledCount(prev_highest_thread); - prev_highest_thread->SetLastScheduledTick(m_kernel.System().CoreTiming().GetCPUTicks()); + prev_highest_thread->SetLastScheduledTick( + m_kernel.System().CoreTiming().GetClockTicks()); } if (m_state.should_count_idle) { if (highest_thread != nullptr) [[likely]] { @@ -351,7 +352,7 @@ void KScheduler::SwitchThread(KThread* next_thread) { // Update the CPU time tracking variables. const s64 prev_tick = m_last_context_switch_time; - const s64 cur_tick = m_kernel.System().CoreTiming().GetCPUTicks(); + const s64 cur_tick = m_kernel.System().CoreTiming().GetClockTicks(); const s64 tick_diff = cur_tick - prev_tick; cur_thread->AddCpuTime(m_core_id, tick_diff); if (cur_process != nullptr) { diff --git a/src/core/hle/kernel/svc/svc_info.cpp b/src/core/hle/kernel/svc/svc_info.cpp index 2b2c878b5..445cdd87b 100644 --- a/src/core/hle/kernel/svc/svc_info.cpp +++ b/src/core/hle/kernel/svc/svc_info.cpp @@ -199,9 +199,9 @@ Result GetInfo(Core::System& system, u64* result, InfoType info_id_type, Handle if (same_thread && info_sub_id == 0xFFFFFFFFFFFFFFFF) { const u64 thread_ticks = current_thread->GetCpuTime(); - out_ticks = thread_ticks + (core_timing.GetCPUTicks() - prev_ctx_ticks); + out_ticks = thread_ticks + (core_timing.GetClockTicks() - prev_ctx_ticks); } else if (same_thread && info_sub_id == system.Kernel().CurrentPhysicalCoreIndex()) { - out_ticks = core_timing.GetCPUTicks() - prev_ctx_ticks; + out_ticks = core_timing.GetClockTicks() - prev_ctx_ticks; } *result = out_ticks; diff --git a/src/core/hle/service/hid/hidbus.cpp b/src/core/hle/service/hid/hidbus.cpp index 5604a6fda..80aac221b 100644 --- a/src/core/hle/service/hid/hidbus.cpp +++ b/src/core/hle/service/hid/hidbus.cpp @@ -5,7 +5,6 @@ #include "common/settings.h" #include "core/core.h" #include "core/core_timing.h" -#include "core/core_timing_util.h" #include "core/hid/hid_types.h" #include "core/hle/kernel/k_event.h" #include "core/hle/kernel/k_readable_event.h" diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp index 456f733cf..70762c51a 100644 --- a/src/video_core/gpu.cpp +++ b/src/video_core/gpu.cpp @@ -194,17 +194,17 @@ struct GPU::Impl { [[nodiscard]] u64 GetTicks() const { // This values were reversed engineered by fincs from NVN - // The gpu clock is reported in units of 385/625 nanoseconds - constexpr u64 gpu_ticks_num = 384; - constexpr u64 gpu_ticks_den = 625; + // The GPU clock is 614.4 MHz + using NsToGPUTickRatio = std::ratio<614'400'000, std::nano::den>; + static_assert(NsToGPUTickRatio::num == 384 && NsToGPUTickRatio::den == 625); + + u64 nanoseconds = system.CoreTiming().GetGlobalTimeNs().count(); - u64 nanoseconds = system.CoreTiming().GetCPUTimeNs().count(); if (Settings::values.use_fast_gpu_time.GetValue()) { nanoseconds /= 256; } - const u64 nanoseconds_num = nanoseconds / gpu_ticks_den; - const u64 nanoseconds_rem = nanoseconds % gpu_ticks_den; - return nanoseconds_num * gpu_ticks_num + (nanoseconds_rem * gpu_ticks_num) / gpu_ticks_den; + + return nanoseconds * NsToGPUTickRatio::num / NsToGPUTickRatio::den; } [[nodiscard]] bool IsAsync() const { -- cgit v1.2.3 From 9dcc7bde8bb05dbc62fa196bcbe1484762e66917 Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Sun, 23 Apr 2023 00:09:49 -0400 Subject: time: Use compile time division for TimeSpanType conversion --- src/core/hle/service/time/clock_types.h | 13 ++++++++----- src/core/hle/service/time/standard_steady_clock_core.cpp | 2 +- src/core/hle/service/time/tick_based_steady_clock_core.cpp | 2 +- src/core/hle/service/time/time.cpp | 4 ++-- src/core/hle/service/time/time_sharedmemory.cpp | 5 +++-- 5 files changed, 15 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/core/hle/service/time/clock_types.h b/src/core/hle/service/time/clock_types.h index e6293ffb9..9fc01ea90 100644 --- a/src/core/hle/service/time/clock_types.h +++ b/src/core/hle/service/time/clock_types.h @@ -3,6 +3,8 @@ #pragma once +#include + #include "common/common_funcs.h" #include "common/common_types.h" #include "common/uuid.h" @@ -74,18 +76,19 @@ static_assert(std::is_trivially_copyable_v, /// https://switchbrew.org/wiki/Glue_services#TimeSpanType struct TimeSpanType { s64 nanoseconds{}; - static constexpr s64 ns_per_second{1000000000ULL}; s64 ToSeconds() const { - return nanoseconds / ns_per_second; + return nanoseconds / std::nano::den; } static TimeSpanType FromSeconds(s64 seconds) { - return {seconds * ns_per_second}; + return {seconds * std::nano::den}; } - static TimeSpanType FromTicks(u64 ticks, u64 frequency) { - return FromSeconds(static_cast(ticks) / static_cast(frequency)); + template + static TimeSpanType FromTicks(u64 ticks) { + using TicksToNSRatio = std::ratio; + return {static_cast(ticks * TicksToNSRatio::num / TicksToNSRatio::den)}; } }; static_assert(sizeof(TimeSpanType) == 8, "TimeSpanType is incorrect size"); diff --git a/src/core/hle/service/time/standard_steady_clock_core.cpp b/src/core/hle/service/time/standard_steady_clock_core.cpp index 3dbbb9850..5627b7003 100644 --- a/src/core/hle/service/time/standard_steady_clock_core.cpp +++ b/src/core/hle/service/time/standard_steady_clock_core.cpp @@ -10,7 +10,7 @@ namespace Service::Time::Clock { TimeSpanType StandardSteadyClockCore::GetCurrentRawTimePoint(Core::System& system) { const TimeSpanType ticks_time_span{ - TimeSpanType::FromTicks(system.CoreTiming().GetClockTicks(), Core::Hardware::CNTFREQ)}; + TimeSpanType::FromTicks(system.CoreTiming().GetClockTicks())}; TimeSpanType raw_time_point{setup_value.nanoseconds + ticks_time_span.nanoseconds}; if (raw_time_point.nanoseconds < cached_raw_time_point.nanoseconds) { diff --git a/src/core/hle/service/time/tick_based_steady_clock_core.cpp b/src/core/hle/service/time/tick_based_steady_clock_core.cpp index 27600413e..0d9fb3143 100644 --- a/src/core/hle/service/time/tick_based_steady_clock_core.cpp +++ b/src/core/hle/service/time/tick_based_steady_clock_core.cpp @@ -10,7 +10,7 @@ namespace Service::Time::Clock { SteadyClockTimePoint TickBasedSteadyClockCore::GetTimePoint(Core::System& system) { const TimeSpanType ticks_time_span{ - TimeSpanType::FromTicks(system.CoreTiming().GetClockTicks(), Core::Hardware::CNTFREQ)}; + TimeSpanType::FromTicks(system.CoreTiming().GetClockTicks())}; return {ticks_time_span.ToSeconds(), GetClockSourceId()}; } diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp index 868be60c5..7197ca30f 100644 --- a/src/core/hle/service/time/time.cpp +++ b/src/core/hle/service/time/time.cpp @@ -240,8 +240,8 @@ void Module::Interface::CalculateMonotonicSystemClockBaseTimePoint(HLERequestCon const auto current_time_point{steady_clock_core.GetCurrentTimePoint(system)}; if (current_time_point.clock_source_id == context.steady_time_point.clock_source_id) { - const auto ticks{Clock::TimeSpanType::FromTicks(system.CoreTiming().GetClockTicks(), - Core::Hardware::CNTFREQ)}; + const auto ticks{Clock::TimeSpanType::FromTicks( + system.CoreTiming().GetClockTicks())}; const s64 base_time_point{context.offset + current_time_point.time_point - ticks.ToSeconds()}; IPC::ResponseBuilder rb{ctx, (sizeof(s64) / 4) + 2}; diff --git a/src/core/hle/service/time/time_sharedmemory.cpp b/src/core/hle/service/time/time_sharedmemory.cpp index ce1c85bcc..a00676669 100644 --- a/src/core/hle/service/time/time_sharedmemory.cpp +++ b/src/core/hle/service/time/time_sharedmemory.cpp @@ -21,8 +21,9 @@ SharedMemory::~SharedMemory() = default; void SharedMemory::SetupStandardSteadyClock(const Common::UUID& clock_source_id, Clock::TimeSpanType current_time_point) { - const Clock::TimeSpanType ticks_time_span{Clock::TimeSpanType::FromTicks( - system.CoreTiming().GetClockTicks(), Core::Hardware::CNTFREQ)}; + const Clock::TimeSpanType ticks_time_span{ + Clock::TimeSpanType::FromTicks( + system.CoreTiming().GetClockTicks())}; const Clock::SteadyClockContext context{ static_cast(current_time_point.nanoseconds - ticks_time_span.nanoseconds), clock_source_id}; -- cgit v1.2.3 From 907507886d755fa56099713c4b8f05bb640a8b7d Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Sun, 28 May 2023 17:45:47 -0400 Subject: (wall, native)_clock: Add GetGPUTick Allows us to directly calculate the GPU tick without double conversion to and from the host clock tick. --- src/common/wall_clock.cpp | 8 ++++++-- src/common/wall_clock.h | 20 +++++++++++++++++++- src/common/x64/native_clock.cpp | 7 ++++++- src/common/x64/native_clock.h | 3 +++ src/core/core_timing.cpp | 7 +++++++ src/core/core_timing.h | 3 +++ src/video_core/gpu.cpp | 11 +++-------- 7 files changed, 47 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/common/wall_clock.cpp b/src/common/wall_clock.cpp index ad8db06b0..dc0dcbd68 100644 --- a/src/common/wall_clock.cpp +++ b/src/common/wall_clock.cpp @@ -32,6 +32,10 @@ public: return GetHostTicksElapsed() * NsToCNTPCTRatio::num / NsToCNTPCTRatio::den; } + u64 GetGPUTick() const override { + return GetHostTicksElapsed() * NsToGPUTickRatio::num / NsToGPUTickRatio::den; + } + u64 GetHostTicksNow() const override { return static_cast(SteadyClock::Now().time_since_epoch().count()); } @@ -52,12 +56,12 @@ std::unique_ptr CreateOptimalClock() { #ifdef ARCHITECTURE_x86_64 const auto& caps = GetCPUCaps(); - if (caps.invariant_tsc && caps.tsc_frequency >= WallClock::CNTFRQ) { + if (caps.invariant_tsc && caps.tsc_frequency >= WallClock::GPUTickFreq) { return std::make_unique(caps.tsc_frequency); } else { // Fallback to StandardWallClock if the hardware TSC // - Is not invariant - // - Is not more precise than CNTFRQ + // - Is not more precise than GPUTickFreq return std::make_unique(); } #else diff --git a/src/common/wall_clock.h b/src/common/wall_clock.h index 56c18ca25..fcfdd637c 100644 --- a/src/common/wall_clock.h +++ b/src/common/wall_clock.h @@ -13,7 +13,8 @@ namespace Common { class WallClock { public: - static constexpr u64 CNTFRQ = 19'200'000; // CNTPCT_EL0 Frequency = 19.2 MHz + static constexpr u64 CNTFRQ = 19'200'000; // CNTPCT_EL0 Frequency = 19.2 MHz + static constexpr u64 GPUTickFreq = 614'400'000; // GM20B GPU Tick Frequency = 614.4 MHz virtual ~WallClock() = default; @@ -29,6 +30,9 @@ public: /// @returns The guest CNTPCT ticks since the construction of this clock. virtual u64 GetCNTPCT() const = 0; + /// @returns The guest GPU ticks since the construction of this clock. + virtual u64 GetGPUTick() const = 0; + /// @returns The raw host timer ticks since an indeterminate epoch. virtual u64 GetHostTicksNow() const = 0; @@ -46,6 +50,10 @@ public: return us * UsToCNTPCTRatio::num / UsToCNTPCTRatio::den; } + static inline u64 NSToGPUTick(u64 ns) { + return ns * NsToGPUTickRatio::num / NsToGPUTickRatio::den; + } + static inline u64 CNTPCTToNS(u64 cntpct) { return cntpct * NsToCNTPCTRatio::den / NsToCNTPCTRatio::num; } @@ -54,6 +62,14 @@ public: return cntpct * UsToCNTPCTRatio::den / UsToCNTPCTRatio::num; } + static inline u64 GPUTickToNS(u64 gpu_tick) { + return gpu_tick * NsToGPUTickRatio::den / NsToGPUTickRatio::num; + } + + static inline u64 CNTPCTToGPUTick(u64 cntpct) { + return cntpct * CNTPCTToGPUTickRatio::num / CNTPCTToGPUTickRatio::den; + } + protected: using NsRatio = std::nano; using UsRatio = std::micro; @@ -63,6 +79,8 @@ protected: using NsToMsRatio = std::ratio_divide; using NsToCNTPCTRatio = std::ratio; using UsToCNTPCTRatio = std::ratio; + using NsToGPUTickRatio = std::ratio; + using CNTPCTToGPUTickRatio = std::ratio; }; std::unique_ptr CreateOptimalClock(); diff --git a/src/common/x64/native_clock.cpp b/src/common/x64/native_clock.cpp index 5d1eb0590..7d2a26bd9 100644 --- a/src/common/x64/native_clock.cpp +++ b/src/common/x64/native_clock.cpp @@ -12,7 +12,8 @@ NativeClock::NativeClock(u64 rdtsc_frequency_) ns_rdtsc_factor{GetFixedPoint64Factor(NsRatio::den, rdtsc_frequency)}, us_rdtsc_factor{GetFixedPoint64Factor(UsRatio::den, rdtsc_frequency)}, ms_rdtsc_factor{GetFixedPoint64Factor(MsRatio::den, rdtsc_frequency)}, - cntpct_rdtsc_factor{GetFixedPoint64Factor(CNTFRQ, rdtsc_frequency)} {} + cntpct_rdtsc_factor{GetFixedPoint64Factor(CNTFRQ, rdtsc_frequency)}, + gputick_rdtsc_factor{GetFixedPoint64Factor(GPUTickFreq, rdtsc_frequency)} {} std::chrono::nanoseconds NativeClock::GetTimeNS() const { return std::chrono::nanoseconds{MultiplyHigh(GetHostTicksElapsed(), ns_rdtsc_factor)}; @@ -30,6 +31,10 @@ u64 NativeClock::GetCNTPCT() const { return MultiplyHigh(GetHostTicksElapsed(), cntpct_rdtsc_factor); } +u64 NativeClock::GetGPUTick() const { + return MultiplyHigh(GetHostTicksElapsed(), gputick_rdtsc_factor); +} + u64 NativeClock::GetHostTicksNow() const { return FencedRDTSC(); } diff --git a/src/common/x64/native_clock.h b/src/common/x64/native_clock.h index d6f8626c1..334415eff 100644 --- a/src/common/x64/native_clock.h +++ b/src/common/x64/native_clock.h @@ -19,6 +19,8 @@ public: u64 GetCNTPCT() const override; + u64 GetGPUTick() const override; + u64 GetHostTicksNow() const override; u64 GetHostTicksElapsed() const override; @@ -33,6 +35,7 @@ private: u64 us_rdtsc_factor; u64 ms_rdtsc_factor; u64 cntpct_rdtsc_factor; + u64 gputick_rdtsc_factor; }; } // namespace Common::X64 diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp index 9a1d5a69a..e57bca70a 100644 --- a/src/core/core_timing.cpp +++ b/src/core/core_timing.cpp @@ -197,6 +197,13 @@ u64 CoreTiming::GetClockTicks() const { return ticks; } +u64 CoreTiming::GetGPUTicks() const { + if (is_multicore) [[likely]] { + return clock->GetGPUTick(); + } + return Common::WallClock::CNTPCTToGPUTick(ticks); +} + std::optional CoreTiming::Advance() { std::scoped_lock lock{advance_lock, basic_lock}; global_timer = GetGlobalTimeNs().count(); diff --git a/src/core/core_timing.h b/src/core/core_timing.h index fdacdd94a..1873852c4 100644 --- a/src/core/core_timing.h +++ b/src/core/core_timing.h @@ -119,6 +119,9 @@ public: /// Returns the current CNTPCT tick value. u64 GetClockTicks() const; + /// Returns the current GPU tick value. + u64 GetGPUTicks() const; + /// Returns current time in microseconds. std::chrono::microseconds GetGlobalTimeUs() const; diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp index 70762c51a..db385076d 100644 --- a/src/video_core/gpu.cpp +++ b/src/video_core/gpu.cpp @@ -193,18 +193,13 @@ struct GPU::Impl { } [[nodiscard]] u64 GetTicks() const { - // This values were reversed engineered by fincs from NVN - // The GPU clock is 614.4 MHz - using NsToGPUTickRatio = std::ratio<614'400'000, std::nano::den>; - static_assert(NsToGPUTickRatio::num == 384 && NsToGPUTickRatio::den == 625); - - u64 nanoseconds = system.CoreTiming().GetGlobalTimeNs().count(); + u64 gpu_tick = system.CoreTiming().GetGPUTicks(); if (Settings::values.use_fast_gpu_time.GetValue()) { - nanoseconds /= 256; + gpu_tick /= 256; } - return nanoseconds * NsToGPUTickRatio::num / NsToGPUTickRatio::den; + return gpu_tick; } [[nodiscard]] bool IsAsync() const { -- cgit v1.2.3 From 2e1e7254436b032f133372c76d9484aa756d56df Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Wed, 7 Jun 2023 21:38:28 -0400 Subject: core_timing: Fix SingleCore cycle timer --- src/common/wall_clock.h | 36 ++++++++++++++++++++---------------- src/core/core_timing.cpp | 26 +++++++++----------------- src/core/core_timing.h | 2 +- src/core/hle/kernel/svc/svc_tick.cpp | 10 +--------- 4 files changed, 31 insertions(+), 43 deletions(-) (limited to 'src') diff --git a/src/common/wall_clock.h b/src/common/wall_clock.h index fcfdd637c..f45d3d8c5 100644 --- a/src/common/wall_clock.h +++ b/src/common/wall_clock.h @@ -13,8 +13,9 @@ namespace Common { class WallClock { public: - static constexpr u64 CNTFRQ = 19'200'000; // CNTPCT_EL0 Frequency = 19.2 MHz - static constexpr u64 GPUTickFreq = 614'400'000; // GM20B GPU Tick Frequency = 614.4 MHz + static constexpr u64 CNTFRQ = 19'200'000; // CNTPCT_EL0 Frequency = 19.2 MHz + static constexpr u64 GPUTickFreq = 614'400'000; // GM20B GPU Tick Frequency = 614.4 MHz + static constexpr u64 CPUTickFreq = 1'020'000'000; // T210/4 A57 CPU Tick Frequency = 1020.0 MHz virtual ~WallClock() = default; @@ -46,28 +47,26 @@ public: return ns * NsToCNTPCTRatio::num / NsToCNTPCTRatio::den; } - static inline u64 USToCNTPCT(u64 us) { - return us * UsToCNTPCTRatio::num / UsToCNTPCTRatio::den; - } - static inline u64 NSToGPUTick(u64 ns) { return ns * NsToGPUTickRatio::num / NsToGPUTickRatio::den; } - static inline u64 CNTPCTToNS(u64 cntpct) { - return cntpct * NsToCNTPCTRatio::den / NsToCNTPCTRatio::num; + // Cycle Timing + + static inline u64 CPUTickToNS(u64 cpu_tick) { + return cpu_tick * CPUTickToNsRatio::num / CPUTickToNsRatio::den; } - static inline u64 CNTPCTToUS(u64 cntpct) { - return cntpct * UsToCNTPCTRatio::den / UsToCNTPCTRatio::num; + static inline u64 CPUTickToUS(u64 cpu_tick) { + return cpu_tick * CPUTickToUsRatio::num / CPUTickToUsRatio::den; } - static inline u64 GPUTickToNS(u64 gpu_tick) { - return gpu_tick * NsToGPUTickRatio::den / NsToGPUTickRatio::num; + static inline u64 CPUTickToCNTPCT(u64 cpu_tick) { + return cpu_tick * CPUTickToCNTPCTRatio::num / CPUTickToCNTPCTRatio::den; } - static inline u64 CNTPCTToGPUTick(u64 cntpct) { - return cntpct * CNTPCTToGPUTickRatio::num / CNTPCTToGPUTickRatio::den; + static inline u64 CPUTickToGPUTick(u64 cpu_tick) { + return cpu_tick * CPUTickToGPUTickRatio::num / CPUTickToGPUTickRatio::den; } protected: @@ -78,9 +77,14 @@ protected: using NsToUsRatio = std::ratio_divide; using NsToMsRatio = std::ratio_divide; using NsToCNTPCTRatio = std::ratio; - using UsToCNTPCTRatio = std::ratio; using NsToGPUTickRatio = std::ratio; - using CNTPCTToGPUTickRatio = std::ratio; + + // Cycle Timing + + using CPUTickToNsRatio = std::ratio; + using CPUTickToUsRatio = std::ratio; + using CPUTickToCNTPCTRatio = std::ratio; + using CPUTickToGPUTickRatio = std::ratio; }; std::unique_ptr CreateOptimalClock(); diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp index e57bca70a..4f0a3f8ea 100644 --- a/src/core/core_timing.cpp +++ b/src/core/core_timing.cpp @@ -20,7 +20,7 @@ namespace Core::Timing { -constexpr s64 MAX_SLICE_LENGTH = 4000; +constexpr s64 MAX_SLICE_LENGTH = 10000; std::shared_ptr CreateEvent(std::string name, TimedCallback&& callback) { return std::make_shared(std::move(callback), std::move(name)); @@ -65,7 +65,7 @@ void CoreTiming::Initialize(std::function&& on_thread_init_) { on_thread_init = std::move(on_thread_init_); event_fifo_id = 0; shutting_down = false; - ticks = 0; + cpu_ticks = 0; const auto empty_timed_callback = [](std::uintptr_t, u64, std::chrono::nanoseconds) -> std::optional { return std::nullopt; }; ev_lost = CreateEvent("_lost_event", empty_timed_callback); @@ -170,20 +170,12 @@ void CoreTiming::UnscheduleEvent(const std::shared_ptr& event_type, } void CoreTiming::AddTicks(u64 ticks_to_add) { - ticks += ticks_to_add; - downcount -= static_cast(ticks); + cpu_ticks += ticks_to_add; + downcount -= static_cast(cpu_ticks); } void CoreTiming::Idle() { - if (!event_queue.empty()) { - const u64 next_event_time = event_queue.front().time; - const u64 next_ticks = Common::WallClock::NSToCNTPCT(next_event_time) + 10U; - if (next_ticks > ticks) { - ticks = next_ticks; - } - return; - } - ticks += 1000U; + cpu_ticks += 1000U; } void CoreTiming::ResetTicks() { @@ -194,14 +186,14 @@ u64 CoreTiming::GetClockTicks() const { if (is_multicore) [[likely]] { return clock->GetCNTPCT(); } - return ticks; + return Common::WallClock::CPUTickToCNTPCT(cpu_ticks); } u64 CoreTiming::GetGPUTicks() const { if (is_multicore) [[likely]] { return clock->GetGPUTick(); } - return Common::WallClock::CNTPCTToGPUTick(ticks); + return Common::WallClock::CPUTickToGPUTick(cpu_ticks); } std::optional CoreTiming::Advance() { @@ -314,14 +306,14 @@ std::chrono::nanoseconds CoreTiming::GetGlobalTimeNs() const { if (is_multicore) [[likely]] { return clock->GetTimeNS(); } - return std::chrono::nanoseconds{Common::WallClock::CNTPCTToNS(ticks)}; + return std::chrono::nanoseconds{Common::WallClock::CPUTickToNS(cpu_ticks)}; } std::chrono::microseconds CoreTiming::GetGlobalTimeUs() const { if (is_multicore) [[likely]] { return clock->GetTimeUS(); } - return std::chrono::microseconds{Common::WallClock::CNTPCTToUS(ticks)}; + return std::chrono::microseconds{Common::WallClock::CPUTickToUS(cpu_ticks)}; } } // namespace Core::Timing diff --git a/src/core/core_timing.h b/src/core/core_timing.h index 1873852c4..10db1de55 100644 --- a/src/core/core_timing.h +++ b/src/core/core_timing.h @@ -167,7 +167,7 @@ private: s64 pause_end_time{}; /// Cycle timing - u64 ticks{}; + u64 cpu_ticks{}; s64 downcount{}; }; diff --git a/src/core/hle/kernel/svc/svc_tick.cpp b/src/core/hle/kernel/svc/svc_tick.cpp index 561336482..7dd7c6e51 100644 --- a/src/core/hle/kernel/svc/svc_tick.cpp +++ b/src/core/hle/kernel/svc/svc_tick.cpp @@ -12,16 +12,8 @@ namespace Kernel::Svc { int64_t GetSystemTick(Core::System& system) { LOG_TRACE(Kernel_SVC, "called"); - auto& core_timing = system.CoreTiming(); - // Returns the value of cntpct_el0 (https://switchbrew.org/wiki/SVC#svcGetSystemTick) - const u64 result{core_timing.GetClockTicks()}; - - if (!system.Kernel().IsMulticore()) { - core_timing.AddTicks(400U); - } - - return static_cast(result); + return static_cast(system.CoreTiming().GetClockTicks()); } int64_t GetSystemTick64(Core::System& system) { -- cgit v1.2.3 From 3e6d81a00899f7f488bfedd849edb64f927b124d Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Wed, 7 Jun 2023 22:04:02 -0400 Subject: nvdisp: Fix SingleCore frametime reporting --- src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp index 5a5b2e305..0fe242e9d 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp @@ -51,8 +51,8 @@ void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, android::PixelFormat form stride, format, transform, crop_rect}; system.GPU().RequestSwapBuffers(&framebuffer, fences, num_fences); - system.GetPerfStats().EndSystemFrame(); system.SpeedLimiter().DoSpeedLimiting(system.CoreTiming().GetGlobalTimeUs()); + system.GetPerfStats().EndSystemFrame(); system.GetPerfStats().BeginSystemFrame(); } -- cgit v1.2.3 From 8e3d4e33961ef7276247ee03ac5c342d4055ac3a Mon Sep 17 00:00:00 2001 From: Baptiste Marie Date: Mon, 29 May 2023 14:51:56 +0200 Subject: input_common: Redesign mouse panning --- src/common/settings.h | 11 +- src/input_common/drivers/mouse.cpp | 99 +++++---- src/input_common/drivers/mouse.h | 2 - src/yuzu/CMakeLists.txt | 3 + src/yuzu/configuration/config.cpp | 33 ++- src/yuzu/configuration/config.h | 2 + .../configuration/configure_input_advanced.cpp | 7 - src/yuzu/configuration/configure_input_advanced.ui | 37 +--- src/yuzu/configuration/configure_input_player.cpp | 16 ++ src/yuzu/configuration/configure_input_player.ui | 96 +++++++++ src/yuzu/configuration/configure_mouse_panning.cpp | 79 +++++++ src/yuzu/configuration/configure_mouse_panning.h | 35 +++ src/yuzu/configuration/configure_mouse_panning.ui | 238 +++++++++++++++++++++ src/yuzu_cmd/default_ini.h | 26 ++- 14 files changed, 581 insertions(+), 103 deletions(-) create mode 100644 src/yuzu/configuration/configure_mouse_panning.cpp create mode 100644 src/yuzu/configuration/configure_mouse_panning.h create mode 100644 src/yuzu/configuration/configure_mouse_panning.ui (limited to 'src') diff --git a/src/common/settings.h b/src/common/settings.h index 9682281b0..3c775d3d2 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -524,9 +524,16 @@ struct Values { Setting tas_loop{false, "tas_loop"}; Setting mouse_panning{false, "mouse_panning"}; - Setting mouse_panning_sensitivity{50, 1, 100, "mouse_panning_sensitivity"}; - Setting mouse_enabled{false, "mouse_enabled"}; + Setting mouse_panning_x_sensitivity{50, 1, 100, "mouse_panning_x_sensitivity"}; + Setting mouse_panning_y_sensitivity{50, 1, 100, "mouse_panning_y_sensitivity"}; + Setting mouse_panning_deadzone_x_counterweight{ + 0, 0, 100, "mouse_panning_deadzone_x_counterweight"}; + Setting mouse_panning_deadzone_y_counterweight{ + 0, 0, 100, "mouse_panning_deadzone_y_counterweight"}; + Setting mouse_panning_decay_strength{22, 0, 100, "mouse_panning_decay_strength"}; + Setting mouse_panning_min_decay{5, 0, 100, "mouse_panning_min_decay"}; + Setting mouse_enabled{false, "mouse_enabled"}; Setting emulate_analog_keyboard{false, "emulate_analog_keyboard"}; Setting keyboard_enabled{false, "keyboard_enabled"}; diff --git a/src/input_common/drivers/mouse.cpp b/src/input_common/drivers/mouse.cpp index 0c9f642bb..f07cf8a0e 100644 --- a/src/input_common/drivers/mouse.cpp +++ b/src/input_common/drivers/mouse.cpp @@ -76,9 +76,6 @@ void Mouse::UpdateThread(std::stop_token stop_token) { UpdateStickInput(); UpdateMotionInput(); - if (mouse_panning_timeout++ > 20) { - StopPanning(); - } std::this_thread::sleep_for(std::chrono::milliseconds(update_time)); } } @@ -88,18 +85,45 @@ void Mouse::UpdateStickInput() { return; } - const float sensitivity = - Settings::values.mouse_panning_sensitivity.GetValue() * default_stick_sensitivity; + const float length = last_mouse_change.Length(); - // Slow movement by 4% - last_mouse_change *= 0.96f; - SetAxis(identifier, mouse_axis_x, last_mouse_change.x * sensitivity); - SetAxis(identifier, mouse_axis_y, -last_mouse_change.y * sensitivity); + // Prevent input from exceeding the max range (1.0f) too much, + // but allow some room to make it easier to sustain + if (length > 1.2f) { + last_mouse_change /= length; + last_mouse_change *= 1.2f; + } + + auto mouse_change = last_mouse_change; + + // Bind the mouse change to [0 <= deadzone_counterweight <= 1,1] + if (length < 1.0f) { + const float deadzone_h_counterweight = + Settings::values.mouse_panning_deadzone_x_counterweight.GetValue(); + const float deadzone_v_counterweight = + Settings::values.mouse_panning_deadzone_y_counterweight.GetValue(); + mouse_change /= length; + mouse_change.x *= length + (1 - length) * deadzone_h_counterweight * 0.01f; + mouse_change.y *= length + (1 - length) * deadzone_v_counterweight * 0.01f; + } + + SetAxis(identifier, mouse_axis_x, mouse_change.x); + SetAxis(identifier, mouse_axis_y, -mouse_change.y); + + // Decay input over time + const float clamped_length = std::min(1.0f, length); + const float decay_strength = Settings::values.mouse_panning_decay_strength.GetValue(); + const float decay = 1 - clamped_length * clamped_length * decay_strength * 0.01f; + const float min_decay = Settings::values.mouse_panning_min_decay.GetValue(); + const float clamped_decay = std::min(1 - min_decay / 100.0f, decay); + last_mouse_change *= clamped_decay; } void Mouse::UpdateMotionInput() { - const float sensitivity = - Settings::values.mouse_panning_sensitivity.GetValue() * default_motion_sensitivity; + // This may need its own sensitivity instead of using the average + const float sensitivity = (Settings::values.mouse_panning_x_sensitivity.GetValue() + + Settings::values.mouse_panning_y_sensitivity.GetValue()) / + 2.0f * default_motion_sensitivity; const float rotation_velocity = std::sqrt(last_motion_change.x * last_motion_change.x + last_motion_change.y * last_motion_change.y); @@ -131,49 +155,28 @@ void Mouse::UpdateMotionInput() { void Mouse::Move(int x, int y, int center_x, int center_y) { if (Settings::values.mouse_panning) { - mouse_panning_timeout = 0; - - auto mouse_change = + const auto mouse_change = (Common::MakeVec(x, y) - Common::MakeVec(center_x, center_y)).Cast(); - last_motion_change += {-mouse_change.y, -mouse_change.x, 0}; - - const auto move_distance = mouse_change.Length(); - if (move_distance == 0) { - return; - } + const float x_sensitivity = + Settings::values.mouse_panning_x_sensitivity.GetValue() * default_stick_sensitivity; + const float y_sensitivity = + Settings::values.mouse_panning_y_sensitivity.GetValue() * default_stick_sensitivity; - // Make slow movements at least 3 units on length - if (move_distance < 3.0f) { - // Normalize value - mouse_change /= move_distance; - mouse_change *= 3.0f; - } - - // Average mouse movements - last_mouse_change = (last_mouse_change * 0.91f) + (mouse_change * 0.09f); - - const auto last_move_distance = last_mouse_change.Length(); - - // Make fast movements clamp to 8 units on length - if (last_move_distance > 8.0f) { - // Normalize value - last_mouse_change /= last_move_distance; - last_mouse_change *= 8.0f; - } - - // Ignore average if it's less than 1 unit and use current movement value - if (last_move_distance < 1.0f) { - last_mouse_change = mouse_change / mouse_change.Length(); - } + last_motion_change += {-mouse_change.y, -mouse_change.x, 0}; + last_mouse_change.x += mouse_change.x * x_sensitivity * 0.09f; + last_mouse_change.y += mouse_change.y * y_sensitivity * 0.09f; return; } if (button_pressed) { const auto mouse_move = Common::MakeVec(x, y) - mouse_origin; - const float sensitivity = Settings::values.mouse_panning_sensitivity.GetValue() * 0.0012f; - SetAxis(identifier, mouse_axis_x, static_cast(mouse_move.x) * sensitivity); - SetAxis(identifier, mouse_axis_y, static_cast(-mouse_move.y) * sensitivity); + const float x_sensitivity = Settings::values.mouse_panning_x_sensitivity.GetValue(); + const float y_sensitivity = Settings::values.mouse_panning_y_sensitivity.GetValue(); + SetAxis(identifier, mouse_axis_x, + static_cast(mouse_move.x) * x_sensitivity * 0.0012f); + SetAxis(identifier, mouse_axis_y, + static_cast(-mouse_move.y) * y_sensitivity * 0.0012f); last_motion_change = { static_cast(-mouse_move.y) / 50.0f, @@ -241,10 +244,6 @@ void Mouse::ReleaseAllButtons() { button_pressed = false; } -void Mouse::StopPanning() { - last_mouse_change = {}; -} - std::vector Mouse::GetInputDevices() const { std::vector devices; devices.emplace_back(Common::ParamPackage{ diff --git a/src/input_common/drivers/mouse.h b/src/input_common/drivers/mouse.h index b872c7a0f..0e8edcce1 100644 --- a/src/input_common/drivers/mouse.h +++ b/src/input_common/drivers/mouse.h @@ -98,7 +98,6 @@ private: void UpdateThread(std::stop_token stop_token); void UpdateStickInput(); void UpdateMotionInput(); - void StopPanning(); Common::Input::ButtonNames GetUIButtonName(const Common::ParamPackage& params) const; @@ -108,7 +107,6 @@ private: Common::Vec3 last_motion_change; Common::Vec2 wheel_position; bool button_pressed; - int mouse_panning_timeout{}; std::jthread update_thread; }; diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 84d9ca796..8676bfd8a 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -98,6 +98,9 @@ add_executable(yuzu configuration/configure_input_profile_dialog.cpp configuration/configure_input_profile_dialog.h configuration/configure_input_profile_dialog.ui + configuration/configure_mouse_panning.cpp + configuration/configure_mouse_panning.h + configuration/configure_mouse_panning.ui configuration/configure_motion_touch.cpp configuration/configure_motion_touch.h configuration/configure_motion_touch.ui diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index bac9dff90..b58a1e9d1 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -351,6 +351,10 @@ void Config::ReadPlayerValue(std::size_t player_index) { player_motions = default_param; } } + + if (player_index == 0) { + ReadMousePanningValues(); + } } void Config::ReadDebugValues() { @@ -471,6 +475,7 @@ void Config::ReadControlValues() { ReadKeyboardValues(); ReadMouseValues(); ReadTouchscreenValues(); + ReadMousePanningValues(); ReadMotionTouchValues(); ReadHidbusValues(); ReadIrCameraValues(); @@ -481,8 +486,6 @@ void Config::ReadControlValues() { Settings::values.enable_raw_input = false; #endif ReadBasicSetting(Settings::values.emulate_analog_keyboard); - Settings::values.mouse_panning = false; - ReadBasicSetting(Settings::values.mouse_panning_sensitivity); ReadBasicSetting(Settings::values.enable_joycon_driver); ReadBasicSetting(Settings::values.enable_procon_driver); ReadBasicSetting(Settings::values.random_amiibo_id); @@ -496,6 +499,16 @@ void Config::ReadControlValues() { qt_config->endGroup(); } +void Config::ReadMousePanningValues() { + ReadBasicSetting(Settings::values.mouse_panning); + ReadBasicSetting(Settings::values.mouse_panning_x_sensitivity); + ReadBasicSetting(Settings::values.mouse_panning_y_sensitivity); + ReadBasicSetting(Settings::values.mouse_panning_deadzone_x_counterweight); + ReadBasicSetting(Settings::values.mouse_panning_deadzone_y_counterweight); + ReadBasicSetting(Settings::values.mouse_panning_decay_strength); + ReadBasicSetting(Settings::values.mouse_panning_min_decay); +} + void Config::ReadMotionTouchValues() { int num_touch_from_button_maps = qt_config->beginReadArray(QStringLiteral("touch_from_button_maps")); @@ -1063,6 +1076,10 @@ void Config::SavePlayerValue(std::size_t player_index) { QString::fromStdString(player.motions[i]), QString::fromStdString(default_param)); } + + if (player_index == 0) { + SaveMousePanningValues(); + } } void Config::SaveDebugValues() { @@ -1099,6 +1116,16 @@ void Config::SaveTouchscreenValues() { WriteSetting(QStringLiteral("touchscreen_diameter_y"), touchscreen.diameter_y, 15); } +void Config::SaveMousePanningValues() { + // Don't overwrite values.mouse_panning + WriteBasicSetting(Settings::values.mouse_panning_x_sensitivity); + WriteBasicSetting(Settings::values.mouse_panning_y_sensitivity); + WriteBasicSetting(Settings::values.mouse_panning_deadzone_x_counterweight); + WriteBasicSetting(Settings::values.mouse_panning_deadzone_y_counterweight); + WriteBasicSetting(Settings::values.mouse_panning_decay_strength); + WriteBasicSetting(Settings::values.mouse_panning_min_decay); +} + void Config::SaveMotionTouchValues() { WriteBasicSetting(Settings::values.touch_device); WriteBasicSetting(Settings::values.touch_from_button_map_index); @@ -1185,6 +1212,7 @@ void Config::SaveControlValues() { SaveDebugValues(); SaveMouseValues(); SaveTouchscreenValues(); + SaveMousePanningValues(); SaveMotionTouchValues(); SaveHidbusValues(); SaveIrCameraValues(); @@ -1199,7 +1227,6 @@ void Config::SaveControlValues() { WriteBasicSetting(Settings::values.random_amiibo_id); WriteBasicSetting(Settings::values.keyboard_enabled); WriteBasicSetting(Settings::values.emulate_analog_keyboard); - WriteBasicSetting(Settings::values.mouse_panning_sensitivity); WriteBasicSetting(Settings::values.controller_navigation); WriteBasicSetting(Settings::values.tas_enable); diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h index 0fd4baf6b..1211389d2 100644 --- a/src/yuzu/configuration/config.h +++ b/src/yuzu/configuration/config.h @@ -74,6 +74,7 @@ private: void ReadKeyboardValues(); void ReadMouseValues(); void ReadTouchscreenValues(); + void ReadMousePanningValues(); void ReadMotionTouchValues(); void ReadHidbusValues(); void ReadIrCameraValues(); @@ -104,6 +105,7 @@ private: void SaveDebugValues(); void SaveMouseValues(); void SaveTouchscreenValues(); + void SaveMousePanningValues(); void SaveMotionTouchValues(); void SaveHidbusValues(); void SaveIrCameraValues(); diff --git a/src/yuzu/configuration/configure_input_advanced.cpp b/src/yuzu/configuration/configure_input_advanced.cpp index f13156434..3cfd5d439 100644 --- a/src/yuzu/configuration/configure_input_advanced.cpp +++ b/src/yuzu/configuration/configure_input_advanced.cpp @@ -129,9 +129,6 @@ void ConfigureInputAdvanced::ApplyConfiguration() { Settings::values.mouse_enabled = ui->mouse_enabled->isChecked(); Settings::values.keyboard_enabled = ui->keyboard_enabled->isChecked(); Settings::values.emulate_analog_keyboard = ui->emulate_analog_keyboard->isChecked(); - Settings::values.mouse_panning = ui->mouse_panning->isChecked(); - Settings::values.mouse_panning_sensitivity = - static_cast(ui->mouse_panning_sensitivity->value()); Settings::values.touchscreen.enabled = ui->touchscreen_enabled->isChecked(); Settings::values.enable_raw_input = ui->enable_raw_input->isChecked(); Settings::values.enable_udp_controller = ui->enable_udp_controller->isChecked(); @@ -167,8 +164,6 @@ void ConfigureInputAdvanced::LoadConfiguration() { ui->mouse_enabled->setChecked(Settings::values.mouse_enabled.GetValue()); ui->keyboard_enabled->setChecked(Settings::values.keyboard_enabled.GetValue()); ui->emulate_analog_keyboard->setChecked(Settings::values.emulate_analog_keyboard.GetValue()); - ui->mouse_panning->setChecked(Settings::values.mouse_panning.GetValue()); - ui->mouse_panning_sensitivity->setValue(Settings::values.mouse_panning_sensitivity.GetValue()); ui->touchscreen_enabled->setChecked(Settings::values.touchscreen.enabled); ui->enable_raw_input->setChecked(Settings::values.enable_raw_input.GetValue()); ui->enable_udp_controller->setChecked(Settings::values.enable_udp_controller.GetValue()); @@ -197,8 +192,6 @@ void ConfigureInputAdvanced::RetranslateUI() { void ConfigureInputAdvanced::UpdateUIEnabled() { ui->debug_configure->setEnabled(ui->debug_enabled->isChecked()); ui->touchscreen_advanced->setEnabled(ui->touchscreen_enabled->isChecked()); - 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); diff --git a/src/yuzu/configuration/configure_input_advanced.ui b/src/yuzu/configuration/configure_input_advanced.ui index 2e8b13660..2994d0ab4 100644 --- a/src/yuzu/configuration/configure_input_advanced.ui +++ b/src/yuzu/configuration/configure_input_advanced.ui @@ -2744,48 +2744,13 @@ - - - - 0 - 23 - - - - Enable mouse panning - - - - - - - Mouse sensitivity - - - Qt::AlignCenter - - - % - - - 1 - - - 100 - - - 100 - - - - Motion / Touch - + Configure diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index 2c2e7e47b..576f5b571 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp @@ -23,6 +23,7 @@ #include "yuzu/configuration/config.h" #include "yuzu/configuration/configure_input_player.h" #include "yuzu/configuration/configure_input_player_widget.h" +#include "yuzu/configuration/configure_mouse_panning.h" #include "yuzu/configuration/input_profiles.h" #include "yuzu/util/limitable_input_dialog.h" @@ -711,6 +712,21 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i }); } + if (player_index_ == 0) { + connect(ui->mousePanningButton, &QPushButton::clicked, [this, input_subsystem_] { + const auto right_stick_param = + emulated_controller->GetStickParam(Settings::NativeAnalog::RStick); + ConfigureMousePanning dialog(this, input_subsystem_, + right_stick_param.Get("deadzone", 0.0f), + right_stick_param.Get("range", 1.0f)); + if (dialog.exec() == QDialog::Accepted) { + dialog.ApplyConfiguration(); + } + }); + } else { + ui->mousePanningWidget->hide(); + } + // Player Connected checkbox connect(ui->groupConnectedController, &QGroupBox::toggled, [this](bool checked) { emit Connected(checked); }); diff --git a/src/yuzu/configuration/configure_input_player.ui b/src/yuzu/configuration/configure_input_player.ui index a9567c6ee..43f6c7b50 100644 --- a/src/yuzu/configuration/configure_input_player.ui +++ b/src/yuzu/configuration/configure_input_player.ui @@ -3048,6 +3048,102 @@ + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 3 + + + + + Qt::Horizontal + + + + 20 + 20 + + + + + + + + Mouse panning + + + Qt::AlignCenter + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 68 + 0 + + + + + 68 + 16777215 + + + + min-width: 68px; + + + Configure + + + + + + + + + + Qt::Horizontal + + + + 20 + 20 + + + + + + + diff --git a/src/yuzu/configuration/configure_mouse_panning.cpp b/src/yuzu/configuration/configure_mouse_panning.cpp new file mode 100644 index 000000000..f183d2740 --- /dev/null +++ b/src/yuzu/configuration/configure_mouse_panning.cpp @@ -0,0 +1,79 @@ +// SPDX-FileCopyrightText: 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include + +#include "common/settings.h" +#include "ui_configure_mouse_panning.h" +#include "yuzu/configuration/configure_mouse_panning.h" + +ConfigureMousePanning::ConfigureMousePanning(QWidget* parent, + InputCommon::InputSubsystem* input_subsystem_, + float right_stick_deadzone, float right_stick_range) + : QDialog(parent), input_subsystem{input_subsystem_}, + ui(std::make_unique()) { + ui->setupUi(this); + SetConfiguration(right_stick_deadzone, right_stick_range); + ConnectEvents(); +} + +ConfigureMousePanning::~ConfigureMousePanning() = default; + +void ConfigureMousePanning::closeEvent(QCloseEvent* event) { + event->accept(); +} + +void ConfigureMousePanning::SetConfiguration(float right_stick_deadzone, float right_stick_range) { + ui->enable->setChecked(Settings::values.mouse_panning.GetValue()); + ui->x_sensitivity->setValue(Settings::values.mouse_panning_x_sensitivity.GetValue()); + ui->y_sensitivity->setValue(Settings::values.mouse_panning_y_sensitivity.GetValue()); + ui->deadzone_x_counterweight->setValue( + Settings::values.mouse_panning_deadzone_x_counterweight.GetValue()); + ui->deadzone_y_counterweight->setValue( + Settings::values.mouse_panning_deadzone_y_counterweight.GetValue()); + ui->decay_strength->setValue(Settings::values.mouse_panning_decay_strength.GetValue()); + ui->min_decay->setValue(Settings::values.mouse_panning_min_decay.GetValue()); + + if (right_stick_deadzone > 0.0f || right_stick_range != 1.0f) { + ui->warning_label->setText(QString::fromStdString( + "Mouse panning works better with a deadzone of 0% and a range of 100%.\n" + "Current values are " + + std::to_string(static_cast(right_stick_deadzone * 100.0f)) + "% and " + + std::to_string(static_cast(right_stick_range * 100.0f)) + "% respectively.")); + } else { + ui->warning_label->hide(); + } +} + +void ConfigureMousePanning::SetDefaultConfiguration() { + ui->x_sensitivity->setValue(Settings::values.mouse_panning_x_sensitivity.GetDefault()); + ui->y_sensitivity->setValue(Settings::values.mouse_panning_y_sensitivity.GetDefault()); + ui->deadzone_x_counterweight->setValue( + Settings::values.mouse_panning_deadzone_x_counterweight.GetDefault()); + ui->deadzone_y_counterweight->setValue( + Settings::values.mouse_panning_deadzone_y_counterweight.GetDefault()); + ui->decay_strength->setValue(Settings::values.mouse_panning_decay_strength.GetDefault()); + ui->min_decay->setValue(Settings::values.mouse_panning_min_decay.GetDefault()); +} + +void ConfigureMousePanning::ConnectEvents() { + connect(ui->default_button, &QPushButton::clicked, this, + &ConfigureMousePanning::SetDefaultConfiguration); + connect(ui->button_box, &QDialogButtonBox::accepted, this, + &ConfigureMousePanning::ApplyConfiguration); + connect(ui->button_box, &QDialogButtonBox::rejected, this, [this] { reject(); }); +} + +void ConfigureMousePanning::ApplyConfiguration() { + Settings::values.mouse_panning = ui->enable->isChecked(); + Settings::values.mouse_panning_x_sensitivity = static_cast(ui->x_sensitivity->value()); + Settings::values.mouse_panning_y_sensitivity = static_cast(ui->y_sensitivity->value()); + Settings::values.mouse_panning_deadzone_x_counterweight = + static_cast(ui->deadzone_x_counterweight->value()); + Settings::values.mouse_panning_deadzone_y_counterweight = + static_cast(ui->deadzone_y_counterweight->value()); + Settings::values.mouse_panning_decay_strength = static_cast(ui->decay_strength->value()); + Settings::values.mouse_panning_min_decay = static_cast(ui->min_decay->value()); + + accept(); +} diff --git a/src/yuzu/configuration/configure_mouse_panning.h b/src/yuzu/configuration/configure_mouse_panning.h new file mode 100644 index 000000000..08c6e1f62 --- /dev/null +++ b/src/yuzu/configuration/configure_mouse_panning.h @@ -0,0 +1,35 @@ +// SPDX-FileCopyrightText: 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include + +namespace InputCommon { +class InputSubsystem; +} + +namespace Ui { +class ConfigureMousePanning; +} + +class ConfigureMousePanning : public QDialog { + Q_OBJECT +public: + explicit ConfigureMousePanning(QWidget* parent, InputCommon::InputSubsystem* input_subsystem_, + float right_stick_deadzone, float right_stick_range); + ~ConfigureMousePanning() override; + +public slots: + void ApplyConfiguration(); + +private: + void closeEvent(QCloseEvent* event) override; + void SetConfiguration(float right_stick_deadzone, float right_stick_range); + void SetDefaultConfiguration(); + void ConnectEvents(); + + InputCommon::InputSubsystem* input_subsystem; + std::unique_ptr ui; +}; diff --git a/src/yuzu/configuration/configure_mouse_panning.ui b/src/yuzu/configuration/configure_mouse_panning.ui new file mode 100644 index 000000000..75795b727 --- /dev/null +++ b/src/yuzu/configuration/configure_mouse_panning.ui @@ -0,0 +1,238 @@ + + + ConfigureMousePanning + + + Configure mouse panning + + + + + + Enable + + + Can be toggled via a hotkey + + + + + + + + + Sensitivity + + + + + + Horizontal + + + + + + + Qt::AlignCenter + + + % + + + 1 + + + 100 + + + 50 + + + + + + + Vertical + + + + + + + Qt::AlignCenter + + + % + + + 1 + + + 100 + + + 50 + + + + + + + + + + Deadzone counterweight + + + Counteracts a game's built-in deadzone + + + + + + Horizontal + + + + + + + Qt::AlignCenter + + + % + + + 0 + + + 100 + + + 0 + + + + + + + Vertical + + + + + + + Qt::AlignCenter + + + % + + + 0 + + + 100 + + + 0 + + + + + + + + + + Stick decay + + + + + + Strength + + + + + + + Qt::AlignCenter + + + % + + + 0 + + + 100 + + + 22 + + + + + + + Minimum + + + + + + + Qt::AlignCenter + + + % + + + 0 + + + 100 + + + 5 + + + + + + + + + + + + + + + + + + + + + Default + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h index 911d461e4..119e22183 100644 --- a/src/yuzu_cmd/default_ini.h +++ b/src/yuzu_cmd/default_ini.h @@ -140,9 +140,29 @@ udp_input_servers = # 0 (default): Off, 1: On mouse_panning = -# Set mouse sensitivity. -# Default: 1.0 -mouse_panning_sensitivity = +# Set mouse panning horizontal sensitivity. +# Default: 50.0 +mouse_panning_x_sensitivity = + +# Set mouse panning vertical sensitivity. +# Default: 50.0 +mouse_panning_y_sensitivity = + +# Set mouse panning deadzone horizontal counterweight. +# Default: 0.0 +mouse_panning_deadzone_x_counterweight = + +# Set mouse panning deadzone vertical counterweight. +# Default: 0.0 +mouse_panning_deadzone_y_counterweight = + +# Set mouse panning stick decay strength. +# Default: 22.0 +mouse_panning_decay_strength = + +# Set mouse panning stick minimum decay. +# Default: 5.0 +mouse_panning_minimum_decay = # Emulate an analog control stick from keyboard inputs. # 0 (default): Disabled, 1: Enabled -- cgit v1.2.3 From 8d6aefdcc452b602d94a84d13bbbc15f806b689c Mon Sep 17 00:00:00 2001 From: Liam Date: Wed, 14 Jun 2023 14:11:46 -0400 Subject: video_core: optionally skip barriers on feedback loops --- src/common/settings.h | 1 + src/video_core/texture_cache/texture_cache.h | 4 ++++ src/yuzu/configuration/config.cpp | 2 ++ src/yuzu/configuration/configure_graphics_advanced.cpp | 10 ++++++++++ src/yuzu/configuration/configure_graphics_advanced.h | 1 + src/yuzu/configuration/configure_graphics_advanced.ui | 10 ++++++++++ 6 files changed, 28 insertions(+) (limited to 'src') diff --git a/src/common/settings.h b/src/common/settings.h index 9682281b0..3aedf3850 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -483,6 +483,7 @@ struct Values { AstcRecompression::Uncompressed, AstcRecompression::Uncompressed, AstcRecompression::Bc3, "astc_recompression"}; SwitchableSetting use_video_framerate{false, "use_video_framerate"}; + SwitchableSetting barrier_feedback_loops{true, "barrier_feedback_loops"}; SwitchableSetting bg_red{0, "bg_red"}; SwitchableSetting bg_green{0, "bg_green"}; diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index c7f7448e9..43b7ac0a6 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -186,6 +186,10 @@ void TextureCache

::FillComputeImageViews(std::span views) { template void TextureCache

::CheckFeedbackLoop(std::span views) { + if (!Settings::values.barrier_feedback_loops.GetValue()) { + return; + } + const bool requires_barrier = [&] { for (const auto& view : views) { if (!view.id) { diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index bac9dff90..edc206a25 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -761,6 +761,7 @@ void Config::ReadRendererValues() { ReadGlobalSetting(Settings::values.use_vulkan_driver_pipeline_cache); ReadGlobalSetting(Settings::values.enable_compute_pipelines); ReadGlobalSetting(Settings::values.use_video_framerate); + ReadGlobalSetting(Settings::values.barrier_feedback_loops); ReadGlobalSetting(Settings::values.bg_red); ReadGlobalSetting(Settings::values.bg_green); ReadGlobalSetting(Settings::values.bg_blue); @@ -1417,6 +1418,7 @@ void Config::SaveRendererValues() { WriteGlobalSetting(Settings::values.use_vulkan_driver_pipeline_cache); WriteGlobalSetting(Settings::values.enable_compute_pipelines); WriteGlobalSetting(Settings::values.use_video_framerate); + WriteGlobalSetting(Settings::values.barrier_feedback_loops); WriteGlobalSetting(Settings::values.bg_red); WriteGlobalSetting(Settings::values.bg_green); WriteGlobalSetting(Settings::values.bg_blue); diff --git a/src/yuzu/configuration/configure_graphics_advanced.cpp b/src/yuzu/configuration/configure_graphics_advanced.cpp index 0463ac8b9..c0a044767 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.cpp +++ b/src/yuzu/configuration/configure_graphics_advanced.cpp @@ -43,6 +43,8 @@ void ConfigureGraphicsAdvanced::SetConfiguration() { ui->enable_compute_pipelines_checkbox->setChecked( Settings::values.enable_compute_pipelines.GetValue()); ui->use_video_framerate_checkbox->setChecked(Settings::values.use_video_framerate.GetValue()); + ui->barrier_feedback_loops_checkbox->setChecked( + Settings::values.barrier_feedback_loops.GetValue()); if (Settings::IsConfiguringGlobal()) { ui->gpu_accuracy->setCurrentIndex( @@ -94,6 +96,9 @@ void ConfigureGraphicsAdvanced::ApplyConfiguration() { enable_compute_pipelines); ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_video_framerate, ui->use_video_framerate_checkbox, use_video_framerate); + ConfigurationShared::ApplyPerGameSetting(&Settings::values.barrier_feedback_loops, + ui->barrier_feedback_loops_checkbox, + barrier_feedback_loops); } void ConfigureGraphicsAdvanced::changeEvent(QEvent* event) { @@ -130,6 +135,8 @@ void ConfigureGraphicsAdvanced::SetupPerGameUI() { Settings::values.enable_compute_pipelines.UsingGlobal()); ui->use_video_framerate_checkbox->setEnabled( Settings::values.use_video_framerate.UsingGlobal()); + ui->barrier_feedback_loops_checkbox->setEnabled( + Settings::values.barrier_feedback_loops.UsingGlobal()); return; } @@ -157,6 +164,9 @@ void ConfigureGraphicsAdvanced::SetupPerGameUI() { ConfigurationShared::SetColoredTristate(ui->use_video_framerate_checkbox, Settings::values.use_video_framerate, use_video_framerate); + ConfigurationShared::SetColoredTristate(ui->barrier_feedback_loops_checkbox, + Settings::values.barrier_feedback_loops, + barrier_feedback_loops); ConfigurationShared::SetColoredComboBox( ui->gpu_accuracy, ui->label_gpu_accuracy, static_cast(Settings::values.gpu_accuracy.GetValue(true))); diff --git a/src/yuzu/configuration/configure_graphics_advanced.h b/src/yuzu/configuration/configure_graphics_advanced.h index a4dc8ceb0..369a7c83e 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.h +++ b/src/yuzu/configuration/configure_graphics_advanced.h @@ -48,6 +48,7 @@ private: ConfigurationShared::CheckState use_vulkan_driver_pipeline_cache; ConfigurationShared::CheckState enable_compute_pipelines; ConfigurationShared::CheckState use_video_framerate; + ConfigurationShared::CheckState barrier_feedback_loops; const Core::System& system; }; diff --git a/src/yuzu/configuration/configure_graphics_advanced.ui b/src/yuzu/configuration/configure_graphics_advanced.ui index e7f0ef6be..d527a6f38 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.ui +++ b/src/yuzu/configuration/configure_graphics_advanced.ui @@ -201,6 +201,16 @@ Compute pipelines are always enabled on all other drivers. + + + + Improves rendering of transparency effects in specific games. + + + Barrier feedback loops + + + -- cgit v1.2.3 From 734242c5bcd56dbd7fc69fb49dba5b7d5ca090bc Mon Sep 17 00:00:00 2001 From: Liam Date: Fri, 16 Jun 2023 15:12:46 -0400 Subject: vfs_real: misc optimizations --- src/common/fs/fs.cpp | 8 ++++---- src/common/fs/fs_types.h | 2 +- src/core/file_sys/vfs_real.cpp | 44 +++++++++++++++++++++++++----------------- src/core/file_sys/vfs_real.h | 11 ++++++++++- 4 files changed, 41 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/common/fs/fs.cpp b/src/common/fs/fs.cpp index 6d66c926d..1baf6d746 100644 --- a/src/common/fs/fs.cpp +++ b/src/common/fs/fs.cpp @@ -436,7 +436,7 @@ void IterateDirEntries(const std::filesystem::path& path, const DirEntryCallable if (True(filter & DirEntryFilter::File) && entry.status().type() == fs::file_type::regular) { - if (!callback(entry.path())) { + if (!callback(entry)) { callback_error = true; break; } @@ -444,7 +444,7 @@ void IterateDirEntries(const std::filesystem::path& path, const DirEntryCallable if (True(filter & DirEntryFilter::Directory) && entry.status().type() == fs::file_type::directory) { - if (!callback(entry.path())) { + if (!callback(entry)) { callback_error = true; break; } @@ -493,7 +493,7 @@ void IterateDirEntriesRecursively(const std::filesystem::path& path, if (True(filter & DirEntryFilter::File) && entry.status().type() == fs::file_type::regular) { - if (!callback(entry.path())) { + if (!callback(entry)) { callback_error = true; break; } @@ -501,7 +501,7 @@ void IterateDirEntriesRecursively(const std::filesystem::path& path, if (True(filter & DirEntryFilter::Directory) && entry.status().type() == fs::file_type::directory) { - if (!callback(entry.path())) { + if (!callback(entry)) { callback_error = true; break; } diff --git a/src/common/fs/fs_types.h b/src/common/fs/fs_types.h index 5a4090c19..900f85d24 100644 --- a/src/common/fs/fs_types.h +++ b/src/common/fs/fs_types.h @@ -66,6 +66,6 @@ DECLARE_ENUM_FLAG_OPERATORS(DirEntryFilter); * @returns A boolean value. * Return true to indicate whether the callback is successful, false otherwise. */ -using DirEntryCallable = std::function; +using DirEntryCallable = std::function; } // namespace Common::FS diff --git a/src/core/file_sys/vfs_real.cpp b/src/core/file_sys/vfs_real.cpp index 7a15d8438..a8fdc8f3e 100644 --- a/src/core/file_sys/vfs_real.cpp +++ b/src/core/file_sys/vfs_real.cpp @@ -10,6 +10,7 @@ #include "common/fs/fs.h" #include "common/fs/path_util.h" #include "common/logging/log.h" +#include "core/file_sys/vfs.h" #include "core/file_sys/vfs_real.h" // For FileTimeStampRaw @@ -72,7 +73,8 @@ VfsEntryType RealVfsFilesystem::GetEntryType(std::string_view path_) const { return VfsEntryType::File; } -VirtualFile RealVfsFilesystem::OpenFile(std::string_view path_, Mode perms) { +VirtualFile RealVfsFilesystem::OpenFileFromEntry(std::string_view path_, std::optional size, + Mode perms) { const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault); if (auto it = cache.find(path); it != cache.end()) { @@ -81,20 +83,24 @@ VirtualFile RealVfsFilesystem::OpenFile(std::string_view path_, Mode perms) { } } - if (!FS::Exists(path) || !FS::IsFile(path)) { + if (!size && !FS::IsFile(path)) { return nullptr; } auto reference = std::make_unique(); this->InsertReferenceIntoList(*reference); - auto file = - std::shared_ptr(new RealVfsFile(*this, std::move(reference), path, perms)); + auto file = std::shared_ptr( + new RealVfsFile(*this, std::move(reference), path, perms, size)); cache[path] = file; return file; } +VirtualFile RealVfsFilesystem::OpenFile(std::string_view path_, Mode perms) { + return OpenFileFromEntry(path_, {}, perms); +} + VirtualFile RealVfsFilesystem::CreateFile(std::string_view path_, Mode perms) { const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault); cache.erase(path); @@ -243,10 +249,10 @@ void RealVfsFilesystem::RemoveReferenceFromList(FileReference& reference) { } RealVfsFile::RealVfsFile(RealVfsFilesystem& base_, std::unique_ptr reference_, - const std::string& path_, Mode perms_) + const std::string& path_, Mode perms_, std::optional size_) : base(base_), reference(std::move(reference_)), path(path_), parent_path(FS::GetParentPath(path_)), path_components(FS::SplitPathComponents(path_)), - perms(perms_) {} + size(size_), perms(perms_) {} RealVfsFile::~RealVfsFile() { base.DropReference(std::move(reference)); @@ -257,8 +263,10 @@ std::string RealVfsFile::GetName() const { } std::size_t RealVfsFile::GetSize() const { - base.RefreshReference(path, perms, *reference); - return reference->file ? reference->file->GetSize() : 0; + if (size) { + return *size; + } + return FS::GetSize(path); } bool RealVfsFile::Resize(std::size_t new_size) { @@ -309,10 +317,11 @@ std::vector RealVfsDirectory::IterateEntries( std::vector out; - const FS::DirEntryCallable callback = [this, &out](const std::filesystem::path& full_path) { - const auto full_path_string = FS::PathToUTF8String(full_path); + const FS::DirEntryCallable callback = [this, + &out](const std::filesystem::directory_entry& entry) { + const auto full_path_string = FS::PathToUTF8String(entry.path()); - out.emplace_back(base.OpenFile(full_path_string, perms)); + out.emplace_back(base.OpenFileFromEntry(full_path_string, entry.file_size(), perms)); return true; }; @@ -330,8 +339,9 @@ std::vector RealVfsDirectory::IterateEntries out; - const FS::DirEntryCallable callback = [this, &out](const std::filesystem::path& full_path) { - const auto full_path_string = FS::PathToUTF8String(full_path); + const FS::DirEntryCallable callback = [this, + &out](const std::filesystem::directory_entry& entry) { + const auto full_path_string = FS::PathToUTF8String(entry.path()); out.emplace_back(base.OpenDirectory(full_path_string, perms)); @@ -483,12 +493,10 @@ std::map> RealVfsDirectory::GetEntries() std::map> out; - const FS::DirEntryCallable callback = [&out](const std::filesystem::path& full_path) { - const auto filename = FS::PathToUTF8String(full_path.filename()); - + const FS::DirEntryCallable callback = [&out](const std::filesystem::directory_entry& entry) { + const auto filename = FS::PathToUTF8String(entry.path().filename()); out.insert_or_assign(filename, - FS::IsDir(full_path) ? VfsEntryType::Directory : VfsEntryType::File); - + entry.is_directory() ? VfsEntryType::Directory : VfsEntryType::File); return true; }; diff --git a/src/core/file_sys/vfs_real.h b/src/core/file_sys/vfs_real.h index d8c900e33..67f4c4422 100644 --- a/src/core/file_sys/vfs_real.h +++ b/src/core/file_sys/vfs_real.h @@ -4,6 +4,7 @@ #pragma once #include +#include #include #include "common/intrusive_list.h" #include "core/file_sys/mode.h" @@ -20,6 +21,8 @@ struct FileReference : public Common::IntrusiveListBaseNode { }; class RealVfsFile; +class RealVfsDirectory; + class RealVfsFilesystem : public VfsFilesystem { public: RealVfsFilesystem(); @@ -56,6 +59,11 @@ private: private: void InsertReferenceIntoList(FileReference& reference); void RemoveReferenceFromList(FileReference& reference); + +private: + friend class RealVfsDirectory; + VirtualFile OpenFileFromEntry(std::string_view path, std::optional size, + Mode perms = Mode::Read); }; // An implementation of VfsFile that represents a file on the user's computer. @@ -78,13 +86,14 @@ public: private: RealVfsFile(RealVfsFilesystem& base, std::unique_ptr reference, - const std::string& path, Mode perms = Mode::Read); + const std::string& path, Mode perms = Mode::Read, std::optional size = {}); RealVfsFilesystem& base; std::unique_ptr reference; std::string path; std::string parent_path; std::vector path_components; + std::optional size; Mode perms; }; -- cgit v1.2.3 From bf47f777b1f55e0c88fc26afbbc5dd3c6d1eb0ca Mon Sep 17 00:00:00 2001 From: Liam Date: Fri, 16 Jun 2023 15:16:38 -0400 Subject: patch_manager: remove unnecessary GetSize calls --- src/core/file_sys/patch_manager.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp index 4e61d4335..d3286b352 100644 --- a/src/core/file_sys/patch_manager.cpp +++ b/src/core/file_sys/patch_manager.cpp @@ -153,7 +153,7 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const { const auto sdmc_load_dir = fs_controller.GetSDMCModificationLoadRoot(title_id); std::vector patch_dirs = {sdmc_load_dir}; - if (load_dir != nullptr && load_dir->GetSize() > 0) { + if (load_dir != nullptr) { const auto load_patch_dirs = load_dir->GetSubdirectories(); patch_dirs.insert(patch_dirs.end(), load_patch_dirs.begin(), load_patch_dirs.end()); } @@ -354,8 +354,7 @@ static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType t const auto load_dir = fs_controller.GetModificationLoadRoot(title_id); const auto sdmc_load_dir = fs_controller.GetSDMCModificationLoadRoot(title_id); if ((type != ContentRecordType::Program && type != ContentRecordType::Data) || - ((load_dir == nullptr || load_dir->GetSize() <= 0) && - (sdmc_load_dir == nullptr || sdmc_load_dir->GetSize() <= 0))) { + (load_dir == nullptr && sdmc_load_dir == nullptr)) { return; } @@ -496,7 +495,7 @@ PatchManager::PatchVersionNames PatchManager::GetPatchVersionNames(VirtualFile u // General Mods (LayeredFS and IPS) const auto mod_dir = fs_controller.GetModificationLoadRoot(title_id); - if (mod_dir != nullptr && mod_dir->GetSize() > 0) { + if (mod_dir != nullptr) { for (const auto& mod : mod_dir->GetSubdirectories()) { std::string types; @@ -540,7 +539,7 @@ PatchManager::PatchVersionNames PatchManager::GetPatchVersionNames(VirtualFile u // SDMC mod directory (RomFS LayeredFS) const auto sdmc_mod_dir = fs_controller.GetSDMCModificationLoadRoot(title_id); - if (sdmc_mod_dir != nullptr && sdmc_mod_dir->GetSize() > 0) { + if (sdmc_mod_dir != nullptr) { std::string types; if (IsDirValidAndNonEmpty(FindSubdirectoryCaseless(sdmc_mod_dir, "exefs"))) { AppendCommaIfNotEmpty(types, "LayeredExeFS"); -- cgit v1.2.3 From 94e7cb05da68a59fcaa3e5b51fc15cdbf5577299 Mon Sep 17 00:00:00 2001 From: Liam Date: Fri, 16 Jun 2023 16:43:14 -0400 Subject: vfs_real: ensure size cache is reset on write --- src/core/file_sys/vfs_real.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/core/file_sys/vfs_real.cpp b/src/core/file_sys/vfs_real.cpp index a8fdc8f3e..fcc81a664 100644 --- a/src/core/file_sys/vfs_real.cpp +++ b/src/core/file_sys/vfs_real.cpp @@ -270,6 +270,7 @@ std::size_t RealVfsFile::GetSize() const { } bool RealVfsFile::Resize(std::size_t new_size) { + size.reset(); base.RefreshReference(path, perms, *reference); return reference->file ? reference->file->SetSize(new_size) : false; } @@ -295,6 +296,7 @@ std::size_t RealVfsFile::Read(u8* data, std::size_t length, std::size_t offset) } std::size_t RealVfsFile::Write(const u8* data, std::size_t length, std::size_t offset) { + size.reset(); base.RefreshReference(path, perms, *reference); if (!reference->file || !reference->file->Seek(static_cast(offset))) { return 0; -- cgit v1.2.3 From 76a676883a17523fb12eeac6f2b9702e4916b2c2 Mon Sep 17 00:00:00 2001 From: FengChen Date: Sat, 17 Jun 2023 23:26:39 +0800 Subject: video_core: add samples check when find render target --- src/video_core/texture_cache/texture_cache.h | 22 ++++++++++------------ src/video_core/texture_cache/texture_cache_base.h | 10 ++++------ 2 files changed, 14 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index c7f7448e9..f11998e20 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -280,7 +280,7 @@ void TextureCache

::SynchronizeComputeDescriptors() { } template -bool TextureCache

::RescaleRenderTargets(bool is_clear) { +bool TextureCache

::RescaleRenderTargets() { auto& flags = maxwell3d->dirty.flags; u32 scale_rating = 0; bool rescaled = false; @@ -318,13 +318,13 @@ bool TextureCache

::RescaleRenderTargets(bool is_clear) { ImageViewId& color_buffer_id = render_targets.color_buffer_ids[index]; if (flags[Dirty::ColorBuffer0 + index] || force) { flags[Dirty::ColorBuffer0 + index] = false; - BindRenderTarget(&color_buffer_id, FindColorBuffer(index, is_clear)); + BindRenderTarget(&color_buffer_id, FindColorBuffer(index)); } check_rescale(color_buffer_id, tmp_color_images[index]); } if (flags[Dirty::ZetaBuffer] || force) { flags[Dirty::ZetaBuffer] = false; - BindRenderTarget(&render_targets.depth_buffer_id, FindDepthBuffer(is_clear)); + BindRenderTarget(&render_targets.depth_buffer_id, FindDepthBuffer()); } check_rescale(render_targets.depth_buffer_id, tmp_depth_image); @@ -389,7 +389,7 @@ void TextureCache

::UpdateRenderTargets(bool is_clear) { return; } - const bool rescaled = RescaleRenderTargets(is_clear); + const bool rescaled = RescaleRenderTargets(); if (is_rescaling != rescaled) { flags[Dirty::RescaleViewports] = true; flags[Dirty::RescaleScissors] = true; @@ -1658,7 +1658,7 @@ SamplerId TextureCache

::FindSampler(const TSCEntry& config) { } template -ImageViewId TextureCache

::FindColorBuffer(size_t index, bool is_clear) { +ImageViewId TextureCache

::FindColorBuffer(size_t index) { const auto& regs = maxwell3d->regs; if (index >= regs.rt_control.count) { return ImageViewId{}; @@ -1672,11 +1672,11 @@ ImageViewId TextureCache

::FindColorBuffer(size_t index, bool is_clear) { return ImageViewId{}; } const ImageInfo info(regs.rt[index], regs.anti_alias_samples_mode); - return FindRenderTargetView(info, gpu_addr, is_clear); + return FindRenderTargetView(info, gpu_addr); } template -ImageViewId TextureCache

::FindDepthBuffer(bool is_clear) { +ImageViewId TextureCache

::FindDepthBuffer() { const auto& regs = maxwell3d->regs; if (!regs.zeta_enable) { return ImageViewId{}; @@ -1686,18 +1686,16 @@ ImageViewId TextureCache

::FindDepthBuffer(bool is_clear) { return ImageViewId{}; } const ImageInfo info(regs.zeta, regs.zeta_size, regs.anti_alias_samples_mode); - return FindRenderTargetView(info, gpu_addr, is_clear); + return FindRenderTargetView(info, gpu_addr); } template -ImageViewId TextureCache

::FindRenderTargetView(const ImageInfo& info, GPUVAddr gpu_addr, - bool is_clear) { - const auto options = is_clear ? RelaxedOptions::Samples : RelaxedOptions{}; +ImageViewId TextureCache

::FindRenderTargetView(const ImageInfo& info, GPUVAddr gpu_addr) { ImageId image_id{}; bool delete_state = has_deleted_images; do { has_deleted_images = false; - image_id = FindOrInsertImage(info, gpu_addr, options); + image_id = FindOrInsertImage(info, gpu_addr); delete_state |= has_deleted_images; } while (has_deleted_images); has_deleted_images = delete_state; diff --git a/src/video_core/texture_cache/texture_cache_base.h b/src/video_core/texture_cache/texture_cache_base.h index 3bfa92154..c347eccd6 100644 --- a/src/video_core/texture_cache/texture_cache_base.h +++ b/src/video_core/texture_cache/texture_cache_base.h @@ -166,9 +166,8 @@ public: void SynchronizeComputeDescriptors(); /// Updates the Render Targets if they can be rescaled - /// @param is_clear True when the render targets are being used for clears /// @retval True if the Render Targets have been rescaled. - bool RescaleRenderTargets(bool is_clear); + bool RescaleRenderTargets(); /// Update bound render targets and upload memory if necessary /// @param is_clear True when the render targets are being used for clears @@ -324,14 +323,13 @@ private: [[nodiscard]] SamplerId FindSampler(const TSCEntry& config); /// Find or create an image view for the given color buffer index - [[nodiscard]] ImageViewId FindColorBuffer(size_t index, bool is_clear); + [[nodiscard]] ImageViewId FindColorBuffer(size_t index); /// Find or create an image view for the depth buffer - [[nodiscard]] ImageViewId FindDepthBuffer(bool is_clear); + [[nodiscard]] ImageViewId FindDepthBuffer(); /// Find or create a view for a render target with the given image parameters - [[nodiscard]] ImageViewId FindRenderTargetView(const ImageInfo& info, GPUVAddr gpu_addr, - bool is_clear); + [[nodiscard]] ImageViewId FindRenderTargetView(const ImageInfo& info, GPUVAddr gpu_addr); /// Iterates over all the images in a region calling func template -- cgit v1.2.3 From 6448eade2ef126a88068cde66b77e7788c3fab08 Mon Sep 17 00:00:00 2001 From: lat9nq <22451773+lat9nq@users.noreply.github.com> Date: Sun, 18 Jun 2023 04:59:12 -0400 Subject: externals: Add vma and initialize it video_core: Move vma implementation to library --- src/video_core/CMakeLists.txt | 2 +- src/video_core/vulkan_common/vulkan_device.cpp | 23 ++++++++++++++++++++++- src/video_core/vulkan_common/vulkan_device.h | 3 +++ 3 files changed, 26 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index bf6439530..e9e6f278d 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -291,7 +291,7 @@ target_link_options(video_core PRIVATE ${FFmpeg_LDFLAGS}) add_dependencies(video_core host_shaders) target_include_directories(video_core PRIVATE ${HOST_SHADERS_INCLUDE}) -target_link_libraries(video_core PRIVATE sirit Vulkan::Headers) +target_link_libraries(video_core PRIVATE sirit Vulkan::Headers vma) if (ENABLE_NSIGHT_AFTERMATH) if (NOT DEFINED ENV{NSIGHT_AFTERMATH_SDK}) diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 3d2e9a16a..631d5e378 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -22,6 +22,10 @@ #include #endif +#define VMA_STATIC_VULKAN_FUNCTIONS 0 +#define VMA_DYNAMIC_VULKAN_FUNCTIONS 1 +#include + namespace Vulkan { using namespace Common::Literals; namespace { @@ -592,9 +596,26 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR graphics_queue = logical.GetQueue(graphics_family); present_queue = logical.GetQueue(present_family); + + const VmaVulkanFunctions functions = { + .vkGetInstanceProcAddr = dld.vkGetInstanceProcAddr, + .vkGetDeviceProcAddr = dld.vkGetDeviceProcAddr, + }; + + const VmaAllocatorCreateInfo allocator_info = { + .physicalDevice = physical, + .device = *logical, + .pVulkanFunctions = &functions, + .instance = instance, + .vulkanApiVersion = VK_API_VERSION_1_1, + }; + + vk::Check(vmaCreateAllocator(&allocator_info, &allocator)); } -Device::~Device() = default; +Device::~Device() { + vmaDestroyAllocator(allocator); +} VkFormat Device::GetSupportedFormat(VkFormat wanted_format, VkFormatFeatureFlags wanted_usage, FormatType format_type) const { diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index f314d0ffe..123d3b1c4 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h @@ -13,6 +13,8 @@ #include "common/settings.h" #include "video_core/vulkan_common/vulkan_wrapper.h" +VK_DEFINE_HANDLE(VmaAllocator) + // Define all features which may be used by the implementation here. // Vulkan version in the macro describes the minimum version required for feature availability. // If the Vulkan version is lower than the required version, the named extension is required. @@ -618,6 +620,7 @@ private: private: VkInstance instance; ///< Vulkan instance. + VmaAllocator allocator; ///< VMA allocator. vk::DeviceDispatch dld; ///< Device function pointers. vk::PhysicalDevice physical; ///< Physical device. vk::Device logical; ///< Logical device. -- cgit v1.2.3 From c60eed36b7439a7921ea5e86e1300e96e30c8f8a Mon Sep 17 00:00:00 2001 From: GPUCode Date: Wed, 24 May 2023 20:32:12 +0300 Subject: memory_allocator: Remove OpenGL interop * Appears to be unused atm --- src/video_core/renderer_vulkan/renderer_vulkan.cpp | 4 +- src/video_core/renderer_vulkan/vk_turbo_mode.cpp | 2 +- .../vulkan_common/vulkan_memory_allocator.cpp | 58 +--------------------- .../vulkan_common/vulkan_memory_allocator.h | 11 ++-- 4 files changed, 8 insertions(+), 67 deletions(-) (limited to 'src') diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index 77128c6e2..5bae8d24f 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -89,8 +89,8 @@ RendererVulkan::RendererVulkan(Core::TelemetrySession& telemetry_session_, Settings::values.renderer_debug.GetValue())), debug_callback(Settings::values.renderer_debug ? CreateDebugCallback(instance) : nullptr), surface(CreateSurface(instance, render_window.GetWindowInfo())), - device(CreateDevice(instance, dld, *surface)), memory_allocator(device, false), - state_tracker(), scheduler(device, state_tracker), + device(CreateDevice(instance, dld, *surface)), memory_allocator(device), state_tracker(), + scheduler(device, state_tracker), swapchain(*surface, device, scheduler, render_window.GetFramebufferLayout().width, render_window.GetFramebufferLayout().height, false), present_manager(instance, render_window, device, memory_allocator, scheduler, swapchain, diff --git a/src/video_core/renderer_vulkan/vk_turbo_mode.cpp b/src/video_core/renderer_vulkan/vk_turbo_mode.cpp index a802d3c49..6417d7e31 100644 --- a/src/video_core/renderer_vulkan/vk_turbo_mode.cpp +++ b/src/video_core/renderer_vulkan/vk_turbo_mode.cpp @@ -18,7 +18,7 @@ using namespace Common::Literals; TurboMode::TurboMode(const vk::Instance& instance, const vk::InstanceDispatch& dld) #ifndef ANDROID - : m_device{CreateDevice(instance, dld, VK_NULL_HANDLE)}, m_allocator{m_device, false} + : m_device{CreateDevice(instance, dld, VK_NULL_HANDLE)}, m_allocator{m_device} #endif { { diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp index e28a556f8..f87c99603 100644 --- a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp +++ b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp @@ -6,8 +6,6 @@ #include #include -#include - #include "common/alignment.h" #include "common/assert.h" #include "common/common_types.h" @@ -54,17 +52,6 @@ struct Range { return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; } -constexpr VkExportMemoryAllocateInfo EXPORT_ALLOCATE_INFO{ - .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO, - .pNext = nullptr, -#ifdef _WIN32 - .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT, -#elif __unix__ - .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT, -#else - .handleTypes = 0, -#endif -}; } // Anonymous namespace class MemoryAllocation { @@ -74,14 +61,6 @@ public: : allocator{allocator_}, memory{std::move(memory_)}, allocation_size{allocation_size_}, property_flags{properties}, shifted_memory_type{1U << type} {} -#if defined(_WIN32) || defined(__unix__) - ~MemoryAllocation() { - if (owning_opengl_handle != 0) { - glDeleteMemoryObjectsEXT(1, &owning_opengl_handle); - } - } -#endif - MemoryAllocation& operator=(const MemoryAllocation&) = delete; MemoryAllocation(const MemoryAllocation&) = delete; @@ -120,31 +99,6 @@ public: return memory_mapped_span; } -#ifdef _WIN32 - [[nodiscard]] u32 ExportOpenGLHandle() { - if (!owning_opengl_handle) { - glCreateMemoryObjectsEXT(1, &owning_opengl_handle); - glImportMemoryWin32HandleEXT(owning_opengl_handle, allocation_size, - GL_HANDLE_TYPE_OPAQUE_WIN32_EXT, - memory.GetMemoryWin32HandleKHR()); - } - return owning_opengl_handle; - } -#elif __unix__ - [[nodiscard]] u32 ExportOpenGLHandle() { - if (!owning_opengl_handle) { - glCreateMemoryObjectsEXT(1, &owning_opengl_handle); - glImportMemoryFdEXT(owning_opengl_handle, allocation_size, GL_HANDLE_TYPE_OPAQUE_FD_EXT, - memory.GetMemoryFdKHR()); - } - return owning_opengl_handle; - } -#else - [[nodiscard]] u32 ExportOpenGLHandle() { - return 0; - } -#endif - /// Returns whether this allocation is compatible with the arguments. [[nodiscard]] bool IsCompatible(VkMemoryPropertyFlags flags, u32 type_mask) const { return (flags & property_flags) == flags && (type_mask & shifted_memory_type) != 0; @@ -182,9 +136,6 @@ private: const u32 shifted_memory_type; ///< Shifted Vulkan memory type. std::vector commits; ///< All commit ranges done from this allocation. std::span memory_mapped_span; ///< Memory mapped span. Empty if not queried before. -#if defined(_WIN32) || defined(__unix__) - u32 owning_opengl_handle{}; ///< Owning OpenGL memory object handle. -#endif }; MemoryCommit::MemoryCommit(MemoryAllocation* allocation_, VkDeviceMemory memory_, u64 begin_, @@ -216,19 +167,14 @@ std::span MemoryCommit::Map() { return span; } -u32 MemoryCommit::ExportOpenGLHandle() const { - return allocation->ExportOpenGLHandle(); -} - void MemoryCommit::Release() { if (allocation) { allocation->Free(begin); } } -MemoryAllocator::MemoryAllocator(const Device& device_, bool export_allocations_) +MemoryAllocator::MemoryAllocator(const Device& device_) : device{device_}, properties{device_.GetPhysical().GetMemoryProperties().memoryProperties}, - export_allocations{export_allocations_}, buffer_image_granularity{ device_.GetPhysical().GetProperties().limits.bufferImageGranularity} {} @@ -271,7 +217,7 @@ bool MemoryAllocator::TryAllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, const u32 type = FindType(flags, type_mask).value(); vk::DeviceMemory memory = device.GetLogical().TryAllocateMemory({ .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, - .pNext = export_allocations ? &EXPORT_ALLOCATE_INFO : nullptr, + .pNext = nullptr, .allocationSize = size, .memoryTypeIndex = type, }); diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.h b/src/video_core/vulkan_common/vulkan_memory_allocator.h index a5bff03fe..494f30f51 100644 --- a/src/video_core/vulkan_common/vulkan_memory_allocator.h +++ b/src/video_core/vulkan_common/vulkan_memory_allocator.h @@ -41,9 +41,6 @@ public: /// It will map the backing allocation if it hasn't been mapped before. std::span Map(); - /// Returns an non-owning OpenGL handle, creating one if it doesn't exist. - u32 ExportOpenGLHandle() const; - /// Returns the Vulkan memory handler. VkDeviceMemory Memory() const { return memory; @@ -74,11 +71,10 @@ public: * Construct memory allocator * * @param device_ Device to allocate from - * @param export_allocations_ True when allocations have to be exported * * @throw vk::Exception on failure */ - explicit MemoryAllocator(const Device& device_, bool export_allocations_); + explicit MemoryAllocator(const Device& device_); ~MemoryAllocator(); MemoryAllocator& operator=(const MemoryAllocator&) = delete; @@ -117,9 +113,8 @@ private: /// Returns index to the fastest memory type compatible with the passed requirements. std::optional FindType(VkMemoryPropertyFlags flags, u32 type_mask) const; - const Device& device; ///< Device handle. - const VkPhysicalDeviceMemoryProperties properties; ///< Physical device properties. - const bool export_allocations; ///< True when memory allocations have to be exported. + const Device& device; ///< Device handle. + const VkPhysicalDeviceMemoryProperties properties; ///< Physical device properties. std::vector> allocations; ///< Current allocations. VkDeviceSize buffer_image_granularity; // The granularity for adjacent offsets between buffers // and optimal images -- cgit v1.2.3 From 48e39756f1ec6e6b0ef48f2444ce38a4e861e898 Mon Sep 17 00:00:00 2001 From: GPUCode Date: Wed, 24 May 2023 22:39:58 +0300 Subject: renderer_vulkan: Use VMA for images --- src/video_core/renderer_vulkan/renderer_vulkan.cpp | 3 +- src/video_core/renderer_vulkan/vk_blit_screen.cpp | 12 +--- src/video_core/renderer_vulkan/vk_blit_screen.h | 2 - src/video_core/renderer_vulkan/vk_fsr.cpp | 4 +- src/video_core/renderer_vulkan/vk_fsr.h | 1 - .../renderer_vulkan/vk_present_manager.cpp | 4 +- .../renderer_vulkan/vk_present_manager.h | 1 - src/video_core/renderer_vulkan/vk_smaa.cpp | 27 +++------ src/video_core/renderer_vulkan/vk_smaa.h | 2 - .../renderer_vulkan/vk_texture_cache.cpp | 14 ++--- src/video_core/renderer_vulkan/vk_texture_cache.h | 2 - src/video_core/vulkan_common/vulkan_device.h | 5 ++ .../vulkan_common/vulkan_memory_allocator.cpp | 30 +++++++--- .../vulkan_common/vulkan_memory_allocator.h | 5 +- src/video_core/vulkan_common/vulkan_wrapper.cpp | 28 ++++----- src/video_core/vulkan_common/vulkan_wrapper.h | 70 ++++++++++++++++++---- 16 files changed, 119 insertions(+), 91 deletions(-) (limited to 'src') diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index 5bae8d24f..e569523b6 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -173,7 +173,7 @@ void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& fr return; } const Layout::FramebufferLayout layout{renderer_settings.screenshot_framebuffer_layout}; - vk::Image staging_image = device.GetLogical().CreateImage(VkImageCreateInfo{ + vk::Image staging_image = memory_allocator.CreateImage(VkImageCreateInfo{ .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, .pNext = nullptr, .flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT, @@ -196,7 +196,6 @@ void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& fr .pQueueFamilyIndices = nullptr, .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, }); - const auto image_commit = memory_allocator.Commit(staging_image, MemoryUsage::DeviceLocal); const vk::ImageView dst_view = device.GetLogical().CreateImageView(VkImageViewCreateInfo{ .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp index acb143fc7..82ca81c7e 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp +++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp @@ -1071,12 +1071,8 @@ void BlitScreen::ReleaseRawImages() { scheduler.Wait(tick); } raw_images.clear(); - raw_buffer_commits.clear(); - aa_image_view.reset(); aa_image.reset(); - aa_commit = MemoryCommit{}; - buffer.reset(); buffer_commit = MemoryCommit{}; } @@ -1101,13 +1097,12 @@ void BlitScreen::CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) { raw_images.resize(image_count); raw_image_views.resize(image_count); - raw_buffer_commits.resize(image_count); const auto create_image = [&](bool used_on_framebuffer = false, u32 up_scale = 1, u32 down_shift = 0) { u32 extra_usages = used_on_framebuffer ? VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT : VK_IMAGE_USAGE_TRANSFER_DST_BIT; - return device.GetLogical().CreateImage(VkImageCreateInfo{ + return memory_allocator.CreateImage(VkImageCreateInfo{ .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, .pNext = nullptr, .flags = 0, @@ -1130,9 +1125,6 @@ void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) { .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, }); }; - const auto create_commit = [&](vk::Image& image) { - return memory_allocator.Commit(image, MemoryUsage::DeviceLocal); - }; const auto create_image_view = [&](vk::Image& image, bool used_on_framebuffer = false) { return device.GetLogical().CreateImageView(VkImageViewCreateInfo{ .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, @@ -1161,7 +1153,6 @@ void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) { for (size_t i = 0; i < image_count; ++i) { raw_images[i] = create_image(); - raw_buffer_commits[i] = create_commit(raw_images[i]); raw_image_views[i] = create_image_view(raw_images[i]); } @@ -1169,7 +1160,6 @@ void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) { const u32 up_scale = Settings::values.resolution_info.up_scale; const u32 down_shift = Settings::values.resolution_info.down_shift; aa_image = create_image(true, up_scale, down_shift); - aa_commit = create_commit(aa_image); aa_image_view = create_image_view(aa_image, true); VkExtent2D size{ .width = (up_scale * framebuffer.width) >> down_shift, diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.h b/src/video_core/renderer_vulkan/vk_blit_screen.h index 68ec20253..7fcfa9976 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.h +++ b/src/video_core/renderer_vulkan/vk_blit_screen.h @@ -148,7 +148,6 @@ private: std::vector raw_images; std::vector raw_image_views; - std::vector raw_buffer_commits; vk::DescriptorPool aa_descriptor_pool; vk::DescriptorSetLayout aa_descriptor_set_layout; @@ -159,7 +158,6 @@ private: vk::DescriptorSets aa_descriptor_sets; vk::Image aa_image; vk::ImageView aa_image_view; - MemoryCommit aa_commit; u32 raw_width = 0; u32 raw_height = 0; diff --git a/src/video_core/renderer_vulkan/vk_fsr.cpp b/src/video_core/renderer_vulkan/vk_fsr.cpp index df972cd54..9bcdca2fb 100644 --- a/src/video_core/renderer_vulkan/vk_fsr.cpp +++ b/src/video_core/renderer_vulkan/vk_fsr.cpp @@ -205,10 +205,9 @@ void FSR::CreateDescriptorSets() { void FSR::CreateImages() { images.resize(image_count * 2); image_views.resize(image_count * 2); - buffer_commits.resize(image_count * 2); for (size_t i = 0; i < image_count * 2; ++i) { - images[i] = device.GetLogical().CreateImage(VkImageCreateInfo{ + images[i] = memory_allocator.CreateImage(VkImageCreateInfo{ .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, .pNext = nullptr, .flags = 0, @@ -231,7 +230,6 @@ void FSR::CreateImages() { .pQueueFamilyIndices = nullptr, .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, }); - buffer_commits[i] = memory_allocator.Commit(images[i], MemoryUsage::DeviceLocal); image_views[i] = device.GetLogical().CreateImageView(VkImageViewCreateInfo{ .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, .pNext = nullptr, diff --git a/src/video_core/renderer_vulkan/vk_fsr.h b/src/video_core/renderer_vulkan/vk_fsr.h index 5d872861f..8bb9fc23a 100644 --- a/src/video_core/renderer_vulkan/vk_fsr.h +++ b/src/video_core/renderer_vulkan/vk_fsr.h @@ -47,7 +47,6 @@ private: vk::Sampler sampler; std::vector images; std::vector image_views; - std::vector buffer_commits; }; } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_present_manager.cpp b/src/video_core/renderer_vulkan/vk_present_manager.cpp index 10ace0420..d681bd22a 100644 --- a/src/video_core/renderer_vulkan/vk_present_manager.cpp +++ b/src/video_core/renderer_vulkan/vk_present_manager.cpp @@ -181,7 +181,7 @@ void PresentManager::RecreateFrame(Frame* frame, u32 width, u32 height, bool is_ frame->height = height; frame->is_srgb = is_srgb; - frame->image = dld.CreateImage({ + frame->image = memory_allocator.CreateImage({ .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, .pNext = nullptr, .flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT, @@ -204,8 +204,6 @@ void PresentManager::RecreateFrame(Frame* frame, u32 width, u32 height, bool is_ .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, }); - frame->image_commit = memory_allocator.Commit(frame->image, MemoryUsage::DeviceLocal); - frame->image_view = dld.CreateImageView({ .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, .pNext = nullptr, diff --git a/src/video_core/renderer_vulkan/vk_present_manager.h b/src/video_core/renderer_vulkan/vk_present_manager.h index 4ac2e2395..83e859416 100644 --- a/src/video_core/renderer_vulkan/vk_present_manager.h +++ b/src/video_core/renderer_vulkan/vk_present_manager.h @@ -29,7 +29,6 @@ struct Frame { vk::Image image; vk::ImageView image_view; vk::Framebuffer framebuffer; - MemoryCommit image_commit; vk::CommandBuffer cmdbuf; vk::Semaphore render_ready; vk::Fence present_done; diff --git a/src/video_core/renderer_vulkan/vk_smaa.cpp b/src/video_core/renderer_vulkan/vk_smaa.cpp index f8735189d..ff7c3a419 100644 --- a/src/video_core/renderer_vulkan/vk_smaa.cpp +++ b/src/video_core/renderer_vulkan/vk_smaa.cpp @@ -25,9 +25,7 @@ namespace { #define ARRAY_TO_SPAN(a) std::span(a, (sizeof(a) / sizeof(a[0]))) -std::pair CreateWrappedImage(const Device& device, - MemoryAllocator& allocator, - VkExtent2D dimensions, VkFormat format) { +vk::Image CreateWrappedImage(MemoryAllocator& allocator, VkExtent2D dimensions, VkFormat format) { const VkImageCreateInfo image_ci{ .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, .pNext = nullptr, @@ -46,11 +44,7 @@ std::pair CreateWrappedImage(const Device& device, .pQueueFamilyIndices = nullptr, .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, }; - - auto image = device.GetLogical().CreateImage(image_ci); - auto commit = allocator.Commit(image, Vulkan::MemoryUsage::DeviceLocal); - - return std::make_pair(std::move(image), std::move(commit)); + return allocator.CreateImage(image_ci); } void TransitionImageLayout(vk::CommandBuffer& cmdbuf, VkImage image, VkImageLayout target_layout, @@ -531,10 +525,8 @@ void SMAA::CreateImages() { static constexpr VkExtent2D area_extent{AREATEX_WIDTH, AREATEX_HEIGHT}; static constexpr VkExtent2D search_extent{SEARCHTEX_WIDTH, SEARCHTEX_HEIGHT}; - std::tie(m_static_images[Area], m_static_buffer_commits[Area]) = - CreateWrappedImage(m_device, m_allocator, area_extent, VK_FORMAT_R8G8_UNORM); - std::tie(m_static_images[Search], m_static_buffer_commits[Search]) = - CreateWrappedImage(m_device, m_allocator, search_extent, VK_FORMAT_R8_UNORM); + m_static_images[Area] = CreateWrappedImage(m_allocator, area_extent, VK_FORMAT_R8G8_UNORM); + m_static_images[Search] = CreateWrappedImage(m_allocator, search_extent, VK_FORMAT_R8_UNORM); m_static_image_views[Area] = CreateWrappedImageView(m_device, m_static_images[Area], VK_FORMAT_R8G8_UNORM); @@ -544,12 +536,11 @@ void SMAA::CreateImages() { for (u32 i = 0; i < m_image_count; i++) { Images& images = m_dynamic_images.emplace_back(); - std::tie(images.images[Blend], images.buffer_commits[Blend]) = - CreateWrappedImage(m_device, m_allocator, m_extent, VK_FORMAT_R16G16B16A16_SFLOAT); - std::tie(images.images[Edges], images.buffer_commits[Edges]) = - CreateWrappedImage(m_device, m_allocator, m_extent, VK_FORMAT_R16G16_SFLOAT); - std::tie(images.images[Output], images.buffer_commits[Output]) = - CreateWrappedImage(m_device, m_allocator, m_extent, VK_FORMAT_R16G16B16A16_SFLOAT); + images.images[Blend] = + CreateWrappedImage(m_allocator, m_extent, VK_FORMAT_R16G16B16A16_SFLOAT); + images.images[Edges] = CreateWrappedImage(m_allocator, m_extent, VK_FORMAT_R16G16_SFLOAT); + images.images[Output] = + CreateWrappedImage(m_allocator, m_extent, VK_FORMAT_R16G16B16A16_SFLOAT); images.image_views[Blend] = CreateWrappedImageView(m_device, images.images[Blend], VK_FORMAT_R16G16B16A16_SFLOAT); diff --git a/src/video_core/renderer_vulkan/vk_smaa.h b/src/video_core/renderer_vulkan/vk_smaa.h index 99a369148..0e214258a 100644 --- a/src/video_core/renderer_vulkan/vk_smaa.h +++ b/src/video_core/renderer_vulkan/vk_smaa.h @@ -66,13 +66,11 @@ private: std::array m_pipelines{}; std::array m_renderpasses{}; - std::array m_static_buffer_commits; std::array m_static_images{}; std::array m_static_image_views{}; struct Images { vk::DescriptorSets descriptor_sets{}; - std::array buffer_commits; std::array images{}; std::array image_views{}; std::array framebuffers{}; diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index f025f618b..10defe6cb 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -15,7 +15,6 @@ #include "video_core/renderer_vulkan/blit_image.h" #include "video_core/renderer_vulkan/maxwell_to_vk.h" #include "video_core/renderer_vulkan/vk_compute_pass.h" -#include "video_core/renderer_vulkan/vk_rasterizer.h" #include "video_core/renderer_vulkan/vk_render_pass_cache.h" #include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" @@ -163,11 +162,12 @@ constexpr VkBorderColor ConvertBorderColor(const std::array& color) { }; } -[[nodiscard]] vk::Image MakeImage(const Device& device, const ImageInfo& info) { +[[nodiscard]] vk::Image MakeImage(const Device& device, const MemoryAllocator& allocator, + const ImageInfo& info) { if (info.type == ImageType::Buffer) { return vk::Image{}; } - return device.GetLogical().CreateImage(MakeImageCreateInfo(device, info)); + return allocator.CreateImage(MakeImageCreateInfo(device, info)); } [[nodiscard]] VkImageAspectFlags ImageAspectMask(PixelFormat format) { @@ -1266,8 +1266,8 @@ void TextureCacheRuntime::TickFrame() {} Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info_, GPUVAddr gpu_addr_, VAddr cpu_addr_) : VideoCommon::ImageBase(info_, gpu_addr_, cpu_addr_), scheduler{&runtime_.scheduler}, - runtime{&runtime_}, original_image(MakeImage(runtime_.device, info)), - commit(runtime_.memory_allocator.Commit(original_image, MemoryUsage::DeviceLocal)), + runtime{&runtime_}, + original_image(MakeImage(runtime_.device, runtime_.memory_allocator, info)), aspect_mask(ImageAspectMask(info.format)) { if (IsPixelFormatASTC(info.format) && !runtime->device.IsOptimalAstcSupported()) { if (Settings::values.async_astc.GetValue()) { @@ -1467,9 +1467,7 @@ bool Image::ScaleUp(bool ignore) { auto scaled_info = info; scaled_info.size.width = scaled_width; scaled_info.size.height = scaled_height; - scaled_image = MakeImage(runtime->device, scaled_info); - auto& allocator = runtime->memory_allocator; - scaled_commit = MemoryCommit(allocator.Commit(scaled_image, MemoryUsage::DeviceLocal)); + scaled_image = MakeImage(runtime->device, runtime->memory_allocator, scaled_info); ignore = false; } current_image = *scaled_image; diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h index f14525dcb..9481f2531 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h @@ -180,12 +180,10 @@ private: TextureCacheRuntime* runtime{}; vk::Image original_image; - MemoryCommit commit; std::vector storage_image_views; VkImageAspectFlags aspect_mask = 0; bool initialized = false; vk::Image scaled_image{}; - MemoryCommit scaled_commit{}; VkImage current_image{}; std::unique_ptr scale_framebuffer; diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index 123d3b1c4..9936f5658 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h @@ -210,6 +210,11 @@ public: return dld; } + /// Returns the VMA allocator. + VmaAllocator GetAllocator() const { + return allocator; + } + /// Returns the logical device. const vk::Device& GetLogical() const { return logical; diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp index f87c99603..7f860cccd 100644 --- a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp +++ b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp @@ -15,6 +15,10 @@ #include "video_core/vulkan_common/vulkan_memory_allocator.h" #include "video_core/vulkan_common/vulkan_wrapper.h" +#define VMA_STATIC_VULKAN_FUNCTIONS 0 +#define VMA_DYNAMIC_VULKAN_FUNCTIONS 1 +#include + namespace Vulkan { namespace { struct Range { @@ -180,6 +184,24 @@ MemoryAllocator::MemoryAllocator(const Device& device_) MemoryAllocator::~MemoryAllocator() = default; +vk::Image MemoryAllocator::CreateImage(const VkImageCreateInfo& ci) const { + const VmaAllocationCreateInfo alloc_info = { + .flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT, + .usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, + .requiredFlags = 0, + .preferredFlags = 0, + .pool = VK_NULL_HANDLE, + .pUserData = nullptr, + }; + + VkImage handle{}; + VmaAllocation allocation{}; + vk::Check( + vmaCreateImage(device.GetAllocator(), &ci, &alloc_info, &handle, &allocation, nullptr)); + return vk::Image(handle, *device.GetLogical(), device.GetAllocator(), allocation, + device.GetDispatchLoader()); +} + MemoryCommit MemoryAllocator::Commit(const VkMemoryRequirements& requirements, MemoryUsage usage) { // Find the fastest memory flags we can afford with the current requirements const u32 type_mask = requirements.memoryTypeBits; @@ -205,14 +227,6 @@ MemoryCommit MemoryAllocator::Commit(const vk::Buffer& buffer, MemoryUsage usage return commit; } -MemoryCommit MemoryAllocator::Commit(const vk::Image& image, MemoryUsage usage) { - VkMemoryRequirements requirements = device.GetLogical().GetImageMemoryRequirements(*image); - requirements.size = Common::AlignUp(requirements.size, buffer_image_granularity); - auto commit = Commit(requirements, usage); - image.BindMemory(commit.Memory(), commit.Offset()); - return commit; -} - bool MemoryAllocator::TryAllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u64 size) { const u32 type = FindType(flags, type_mask).value(); vk::DeviceMemory memory = device.GetLogical().TryAllocateMemory({ diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.h b/src/video_core/vulkan_common/vulkan_memory_allocator.h index 494f30f51..f9ee53cfb 100644 --- a/src/video_core/vulkan_common/vulkan_memory_allocator.h +++ b/src/video_core/vulkan_common/vulkan_memory_allocator.h @@ -80,6 +80,8 @@ public: MemoryAllocator& operator=(const MemoryAllocator&) = delete; MemoryAllocator(const MemoryAllocator&) = delete; + vk::Image CreateImage(const VkImageCreateInfo& ci) const; + /** * Commits a memory with the specified requirements. * @@ -93,9 +95,6 @@ public: /// Commits memory required by the buffer and binds it. MemoryCommit Commit(const vk::Buffer& buffer, MemoryUsage usage); - /// Commits memory required by the image and binds it. - MemoryCommit Commit(const vk::Image& image, MemoryUsage usage); - private: /// Tries to allocate a chunk of memory. bool TryAllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u64 size); diff --git a/src/video_core/vulkan_common/vulkan_wrapper.cpp b/src/video_core/vulkan_common/vulkan_wrapper.cpp index 336f53700..5d088dc58 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.cpp +++ b/src/video_core/vulkan_common/vulkan_wrapper.cpp @@ -12,6 +12,10 @@ #include "video_core/vulkan_common/vulkan_wrapper.h" +#define VMA_STATIC_VULKAN_FUNCTIONS 0 +#define VMA_DYNAMIC_VULKAN_FUNCTIONS 1 +#include + namespace Vulkan::vk { namespace { @@ -547,6 +551,16 @@ DebugUtilsMessenger Instance::CreateDebugUtilsMessenger( return DebugUtilsMessenger(object, handle, *dld); } +void Image::SetObjectNameEXT(const char* name) const { + SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_IMAGE, name); +} + +void Image::Release() const noexcept { + if (handle) { + vmaDestroyImage(allocator, handle, allocation); + } +} + void Buffer::BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const { Check(dld->vkBindBufferMemory(owner, handle, memory, offset)); } @@ -559,14 +573,6 @@ void BufferView::SetObjectNameEXT(const char* name) const { SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_BUFFER_VIEW, name); } -void Image::BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const { - Check(dld->vkBindImageMemory(owner, handle, memory, offset)); -} - -void Image::SetObjectNameEXT(const char* name) const { - SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_IMAGE, name); -} - void ImageView::SetObjectNameEXT(const char* name) const { SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_IMAGE_VIEW, name); } @@ -713,12 +719,6 @@ BufferView Device::CreateBufferView(const VkBufferViewCreateInfo& ci) const { return BufferView(object, handle, *dld); } -Image Device::CreateImage(const VkImageCreateInfo& ci) const { - VkImage object; - Check(dld->vkCreateImage(handle, &ci, nullptr, &object)); - return Image(object, handle, *dld); -} - ImageView Device::CreateImageView(const VkImageViewCreateInfo& ci) const { VkImageView object; Check(dld->vkCreateImageView(handle, &ci, nullptr, &object)); diff --git a/src/video_core/vulkan_common/vulkan_wrapper.h b/src/video_core/vulkan_common/vulkan_wrapper.h index 4ff328a21..8ec708774 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.h +++ b/src/video_core/vulkan_common/vulkan_wrapper.h @@ -32,6 +32,9 @@ #pragma warning(disable : 26812) // Disable prefer enum class over enum #endif +VK_DEFINE_HANDLE(VmaAllocator) +VK_DEFINE_HANDLE(VmaAllocation) + namespace Vulkan::vk { /** @@ -616,6 +619,60 @@ public: } }; +class Image { +public: + explicit Image(VkImage handle_, VkDevice owner_, VmaAllocator allocator_, + VmaAllocation allocation_, const DeviceDispatch& dld_) noexcept + : handle{handle_}, owner{owner_}, allocator{allocator_}, + allocation{allocation_}, dld{&dld_} {} + Image() = default; + + Image(const Image&) = delete; + Image& operator=(const Image&) = delete; + + Image(Image&& rhs) noexcept + : handle{std::exchange(rhs.handle, nullptr)}, owner{rhs.owner}, allocator{rhs.allocator}, + allocation{rhs.allocation}, dld{rhs.dld} {} + + Image& operator=(Image&& rhs) noexcept { + Release(); + handle = std::exchange(rhs.handle, nullptr); + owner = rhs.owner; + allocator = rhs.allocator; + allocation = rhs.allocation; + dld = rhs.dld; + return *this; + } + + ~Image() noexcept { + Release(); + } + + VkImage operator*() const noexcept { + return handle; + } + + void reset() noexcept { + Release(); + handle = nullptr; + } + + explicit operator bool() const noexcept { + return handle != nullptr; + } + + void SetObjectNameEXT(const char* name) const; + +private: + void Release() const noexcept; + + VkImage handle = nullptr; + VkDevice owner = nullptr; + VmaAllocator allocator = nullptr; + VmaAllocation allocation = nullptr; + const DeviceDispatch* dld = nullptr; +}; + class Queue { public: /// Construct an empty queue handle. @@ -658,17 +715,6 @@ public: void SetObjectNameEXT(const char* name) const; }; -class Image : public Handle { - using Handle::Handle; - -public: - /// Attaches a memory allocation. - void BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const; - - /// Set object name. - void SetObjectNameEXT(const char* name) const; -}; - class ImageView : public Handle { using Handle::Handle; @@ -844,8 +890,6 @@ public: BufferView CreateBufferView(const VkBufferViewCreateInfo& ci) const; - Image CreateImage(const VkImageCreateInfo& ci) const; - ImageView CreateImageView(const VkImageViewCreateInfo& ci) const; Semaphore CreateSemaphore() const; -- cgit v1.2.3 From 7b2f680468bbac206f96b26a1300939be90f5f1b Mon Sep 17 00:00:00 2001 From: GPUCode Date: Sat, 27 May 2023 17:09:17 +0300 Subject: renderer_vulkan: Use VMA for buffers --- src/video_core/renderer_vulkan/renderer_vulkan.cpp | 9 +- src/video_core/renderer_vulkan/vk_blit_screen.cpp | 6 +- src/video_core/renderer_vulkan/vk_blit_screen.h | 1 - src/video_core/renderer_vulkan/vk_buffer_cache.cpp | 81 +++++++++------- src/video_core/renderer_vulkan/vk_buffer_cache.h | 2 - src/video_core/renderer_vulkan/vk_smaa.cpp | 12 +-- .../renderer_vulkan/vk_staging_buffer_pool.cpp | 105 ++------------------ .../renderer_vulkan/vk_staging_buffer_pool.h | 4 +- .../renderer_vulkan/vk_texture_cache.cpp | 9 +- src/video_core/renderer_vulkan/vk_texture_cache.h | 1 - src/video_core/renderer_vulkan/vk_turbo_mode.cpp | 8 +- src/video_core/vulkan_common/vulkan_device.cpp | 1 + .../vulkan_common/vulkan_memory_allocator.cpp | 107 ++++++++++++++++----- .../vulkan_common/vulkan_memory_allocator.h | 12 ++- src/video_core/vulkan_common/vulkan_wrapper.cpp | 24 +++-- src/video_core/vulkan_common/vulkan_wrapper.h | 91 +++++++++++++++--- 16 files changed, 262 insertions(+), 211 deletions(-) (limited to 'src') diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index e569523b6..ddf28ca28 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -233,8 +233,8 @@ void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& fr .queueFamilyIndexCount = 0, .pQueueFamilyIndices = nullptr, }; - const vk::Buffer dst_buffer = device.GetLogical().CreateBuffer(dst_buffer_info); - MemoryCommit dst_buffer_memory = memory_allocator.Commit(dst_buffer, MemoryUsage::Download); + const vk::Buffer dst_buffer = + memory_allocator.CreateBuffer(dst_buffer_info, MemoryUsage::Download); scheduler.RequestOutsideRenderPassOperationContext(); scheduler.Record([&](vk::CommandBuffer cmdbuf) { @@ -308,8 +308,9 @@ void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& fr scheduler.Finish(); // Copy backing image data to the QImage screenshot buffer - const auto dst_memory_map = dst_buffer_memory.Map(); - std::memcpy(renderer_settings.screenshot_bits, dst_memory_map.data(), dst_memory_map.size()); + dst_buffer.Invalidate(); + std::memcpy(renderer_settings.screenshot_bits, dst_buffer.Mapped().data(), + dst_buffer.Mapped().size()); renderer_settings.screenshot_complete_callback(false); renderer_settings.screenshot_requested = false; } diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp index 82ca81c7e..ad3b29f0e 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp +++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp @@ -162,7 +162,7 @@ void BlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, SetUniformData(data, layout); SetVertexData(data, framebuffer, layout); - const std::span mapped_span = buffer_commit.Map(); + const std::span mapped_span = buffer.Mapped(); std::memcpy(mapped_span.data(), &data, sizeof(data)); if (!use_accelerated) { @@ -1074,7 +1074,6 @@ void BlitScreen::ReleaseRawImages() { aa_image_view.reset(); aa_image.reset(); buffer.reset(); - buffer_commit = MemoryCommit{}; } void BlitScreen::CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer) { @@ -1090,8 +1089,7 @@ void BlitScreen::CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer .pQueueFamilyIndices = nullptr, }; - buffer = device.GetLogical().CreateBuffer(ci); - buffer_commit = memory_allocator.Commit(buffer, MemoryUsage::Upload); + buffer = memory_allocator.CreateBuffer(ci, MemoryUsage::Upload); } void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) { diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.h b/src/video_core/renderer_vulkan/vk_blit_screen.h index 7fcfa9976..8365b5668 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.h +++ b/src/video_core/renderer_vulkan/vk_blit_screen.h @@ -142,7 +142,6 @@ private: vk::Sampler sampler; vk::Buffer buffer; - MemoryCommit buffer_commit; std::vector resource_ticks; diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp index 8c33722d3..67356c679 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp @@ -50,7 +50,7 @@ size_t BytesPerIndex(VkIndexType index_type) { } } -vk::Buffer CreateBuffer(const Device& device, u64 size) { +vk::Buffer CreateBuffer(const Device& device, const MemoryAllocator& memory_allocator, u64 size) { VkBufferUsageFlags flags = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT | @@ -60,7 +60,7 @@ vk::Buffer CreateBuffer(const Device& device, u64 size) { if (device.IsExtTransformFeedbackSupported()) { flags |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT; } - return device.GetLogical().CreateBuffer({ + const VkBufferCreateInfo buffer_ci = { .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, .pNext = nullptr, .flags = 0, @@ -69,7 +69,8 @@ vk::Buffer CreateBuffer(const Device& device, u64 size) { .sharingMode = VK_SHARING_MODE_EXCLUSIVE, .queueFamilyIndexCount = 0, .pQueueFamilyIndices = nullptr, - }); + }; + return memory_allocator.CreateBuffer(buffer_ci, MemoryUsage::DeviceLocal); } } // Anonymous namespace @@ -79,8 +80,8 @@ Buffer::Buffer(BufferCacheRuntime&, VideoCommon::NullBufferParams null_params) Buffer::Buffer(BufferCacheRuntime& runtime, VideoCore::RasterizerInterface& rasterizer_, VAddr cpu_addr_, u64 size_bytes_) : VideoCommon::BufferBase(rasterizer_, cpu_addr_, size_bytes_), - device{&runtime.device}, buffer{CreateBuffer(*device, SizeBytes())}, - commit{runtime.memory_allocator.Commit(buffer, MemoryUsage::DeviceLocal)} { + device{&runtime.device}, buffer{ + CreateBuffer(*device, runtime.memory_allocator, SizeBytes())} { if (runtime.device.HasDebuggingToolAttached()) { buffer.SetObjectNameEXT(fmt::format("Buffer 0x{:x}", CpuAddr()).c_str()); } @@ -138,7 +139,7 @@ public: const u32 num_first_offset_copies = 4; const size_t bytes_per_index = BytesPerIndex(index_type); const size_t size_bytes = num_triangle_indices * bytes_per_index * num_first_offset_copies; - buffer = device.GetLogical().CreateBuffer(VkBufferCreateInfo{ + const VkBufferCreateInfo buffer_ci = { .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, .pNext = nullptr, .flags = 0, @@ -147,14 +148,21 @@ public: .sharingMode = VK_SHARING_MODE_EXCLUSIVE, .queueFamilyIndexCount = 0, .pQueueFamilyIndices = nullptr, - }); + }; + buffer = memory_allocator.CreateBuffer(buffer_ci, MemoryUsage::DeviceLocal); if (device.HasDebuggingToolAttached()) { buffer.SetObjectNameEXT("Quad LUT"); } - memory_commit = memory_allocator.Commit(buffer, MemoryUsage::DeviceLocal); - const StagingBufferRef staging = staging_pool.Request(size_bytes, MemoryUsage::Upload); - u8* staging_data = staging.mapped_span.data(); + const bool host_visible = buffer.IsHostVisible(); + const StagingBufferRef staging = [&] { + if (host_visible) { + return StagingBufferRef{}; + } + return staging_pool.Request(size_bytes, MemoryUsage::Upload); + }(); + + u8* staging_data = host_visible ? buffer.Mapped().data() : staging.mapped_span.data(); const size_t quad_size = bytes_per_index * 6; for (u32 first = 0; first < num_first_offset_copies; ++first) { @@ -164,29 +172,33 @@ public: } } - scheduler.RequestOutsideRenderPassOperationContext(); - scheduler.Record([src_buffer = staging.buffer, src_offset = staging.offset, - dst_buffer = *buffer, size_bytes](vk::CommandBuffer cmdbuf) { - const VkBufferCopy copy{ - .srcOffset = src_offset, - .dstOffset = 0, - .size = size_bytes, - }; - const VkBufferMemoryBarrier write_barrier{ - .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, - .pNext = nullptr, - .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, - .dstAccessMask = VK_ACCESS_INDEX_READ_BIT, - .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .buffer = dst_buffer, - .offset = 0, - .size = size_bytes, - }; - cmdbuf.CopyBuffer(src_buffer, dst_buffer, copy); - cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0, write_barrier); - }); + if (!host_visible) { + scheduler.RequestOutsideRenderPassOperationContext(); + scheduler.Record([src_buffer = staging.buffer, src_offset = staging.offset, + dst_buffer = *buffer, size_bytes](vk::CommandBuffer cmdbuf) { + const VkBufferCopy copy{ + .srcOffset = src_offset, + .dstOffset = 0, + .size = size_bytes, + }; + const VkBufferMemoryBarrier write_barrier{ + .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, + .pNext = nullptr, + .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, + .dstAccessMask = VK_ACCESS_INDEX_READ_BIT, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .buffer = dst_buffer, + .offset = 0, + .size = size_bytes, + }; + cmdbuf.CopyBuffer(src_buffer, dst_buffer, copy); + cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0, write_barrier); + }); + } else { + buffer.Flush(); + } } void BindBuffer(u32 first) { @@ -587,11 +599,10 @@ void BufferCacheRuntime::ReserveNullBuffer() { create_info.usage |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT; } create_info.usage |= VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT; - null_buffer = device.GetLogical().CreateBuffer(create_info); + null_buffer = memory_allocator.CreateBuffer(create_info, MemoryUsage::DeviceLocal); if (device.HasDebuggingToolAttached()) { null_buffer.SetObjectNameEXT("Null buffer"); } - null_buffer_commit = memory_allocator.Commit(null_buffer, MemoryUsage::DeviceLocal); scheduler.RequestOutsideRenderPassOperationContext(); scheduler.Record([buffer = *null_buffer](vk::CommandBuffer cmdbuf) { diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.h b/src/video_core/renderer_vulkan/vk_buffer_cache.h index cdeef8846..95446c732 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.h +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.h @@ -48,7 +48,6 @@ private: const Device* device{}; vk::Buffer buffer; - MemoryCommit commit; std::vector views; }; @@ -142,7 +141,6 @@ private: std::shared_ptr quad_strip_index_buffer; vk::Buffer null_buffer; - MemoryCommit null_buffer_commit; std::unique_ptr uint8_pass; QuadIndexedPass quad_index_pass; diff --git a/src/video_core/renderer_vulkan/vk_smaa.cpp b/src/video_core/renderer_vulkan/vk_smaa.cpp index ff7c3a419..5efd7d66e 100644 --- a/src/video_core/renderer_vulkan/vk_smaa.cpp +++ b/src/video_core/renderer_vulkan/vk_smaa.cpp @@ -76,7 +76,7 @@ void TransitionImageLayout(vk::CommandBuffer& cmdbuf, VkImage image, VkImageLayo void UploadImage(const Device& device, MemoryAllocator& allocator, Scheduler& scheduler, vk::Image& image, VkExtent2D dimensions, VkFormat format, std::span initial_contents = {}) { - auto upload_buffer = device.GetLogical().CreateBuffer(VkBufferCreateInfo{ + const VkBufferCreateInfo upload_ci = { .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, .pNext = nullptr, .flags = 0, @@ -85,9 +85,10 @@ void UploadImage(const Device& device, MemoryAllocator& allocator, Scheduler& sc .sharingMode = VK_SHARING_MODE_EXCLUSIVE, .queueFamilyIndexCount = 0, .pQueueFamilyIndices = nullptr, - }); - auto upload_commit = allocator.Commit(upload_buffer, MemoryUsage::Upload); - std::ranges::copy(initial_contents, upload_commit.Map().begin()); + }; + auto upload_buffer = allocator.CreateBuffer(upload_ci, MemoryUsage::Upload); + std::ranges::copy(initial_contents, upload_buffer.Mapped().begin()); + upload_buffer.Flush(); const std::array regions{{{ .bufferOffset = 0, @@ -111,9 +112,6 @@ void UploadImage(const Device& device, MemoryAllocator& allocator, Scheduler& sc VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); }); scheduler.Finish(); - - // This should go out of scope before the commit - auto upload_buffer2 = std::move(upload_buffer); } vk::ImageView CreateWrappedImageView(const Device& device, vk::Image& image, VkFormat format) { diff --git a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp index 74ca77216..62b251a9b 100644 --- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp +++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp @@ -30,55 +30,6 @@ constexpr VkDeviceSize MAX_STREAM_BUFFER_REQUEST_SIZE = 8_MiB; constexpr VkDeviceSize STREAM_BUFFER_SIZE = 128_MiB; constexpr VkDeviceSize REGION_SIZE = STREAM_BUFFER_SIZE / StagingBufferPool::NUM_SYNCS; -constexpr VkMemoryPropertyFlags HOST_FLAGS = - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; -constexpr VkMemoryPropertyFlags STREAM_FLAGS = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | HOST_FLAGS; - -bool IsStreamHeap(VkMemoryHeap heap) noexcept { - return STREAM_BUFFER_SIZE < (heap.size * 2) / 3; -} - -std::optional FindMemoryTypeIndex(const VkPhysicalDeviceMemoryProperties& props, u32 type_mask, - VkMemoryPropertyFlags flags) noexcept { - for (u32 type_index = 0; type_index < props.memoryTypeCount; ++type_index) { - if (((type_mask >> type_index) & 1) == 0) { - // Memory type is incompatible - continue; - } - const VkMemoryType& memory_type = props.memoryTypes[type_index]; - if ((memory_type.propertyFlags & flags) != flags) { - // Memory type doesn't have the flags we want - continue; - } - if (!IsStreamHeap(props.memoryHeaps[memory_type.heapIndex])) { - // Memory heap is not suitable for streaming - continue; - } - // Success! - return type_index; - } - return std::nullopt; -} - -u32 FindMemoryTypeIndex(const VkPhysicalDeviceMemoryProperties& props, u32 type_mask, - bool try_device_local) { - std::optional type; - if (try_device_local) { - // Try to find a DEVICE_LOCAL_BIT type, Nvidia and AMD have a dedicated heap for this - type = FindMemoryTypeIndex(props, type_mask, STREAM_FLAGS); - if (type) { - return *type; - } - } - // Otherwise try without the DEVICE_LOCAL_BIT - type = FindMemoryTypeIndex(props, type_mask, HOST_FLAGS); - if (type) { - return *type; - } - // This should never happen, and in case it does, signal it as an out of memory situation - throw vk::Exception(VK_ERROR_OUT_OF_DEVICE_MEMORY); -} - size_t Region(size_t iterator) noexcept { return iterator / REGION_SIZE; } @@ -87,8 +38,7 @@ size_t Region(size_t iterator) noexcept { StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& memory_allocator_, Scheduler& scheduler_) : device{device_}, memory_allocator{memory_allocator_}, scheduler{scheduler_} { - const vk::Device& dev = device.GetLogical(); - stream_buffer = dev.CreateBuffer(VkBufferCreateInfo{ + const VkBufferCreateInfo stream_ci = { .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, .pNext = nullptr, .flags = 0, @@ -99,46 +49,13 @@ StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& mem .sharingMode = VK_SHARING_MODE_EXCLUSIVE, .queueFamilyIndexCount = 0, .pQueueFamilyIndices = nullptr, - }); - if (device.HasDebuggingToolAttached()) { - stream_buffer.SetObjectNameEXT("Stream Buffer"); - } - VkMemoryDedicatedRequirements dedicated_reqs{ - .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS, - .pNext = nullptr, - .prefersDedicatedAllocation = VK_FALSE, - .requiresDedicatedAllocation = VK_FALSE, - }; - const auto requirements = dev.GetBufferMemoryRequirements(*stream_buffer, &dedicated_reqs); - const bool make_dedicated = dedicated_reqs.prefersDedicatedAllocation == VK_TRUE || - dedicated_reqs.requiresDedicatedAllocation == VK_TRUE; - const VkMemoryDedicatedAllocateInfo dedicated_info{ - .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO, - .pNext = nullptr, - .image = nullptr, - .buffer = *stream_buffer, }; - const auto memory_properties = device.GetPhysical().GetMemoryProperties().memoryProperties; - VkMemoryAllocateInfo stream_memory_info{ - .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, - .pNext = make_dedicated ? &dedicated_info : nullptr, - .allocationSize = requirements.size, - .memoryTypeIndex = - FindMemoryTypeIndex(memory_properties, requirements.memoryTypeBits, true), - }; - stream_memory = dev.TryAllocateMemory(stream_memory_info); - if (!stream_memory) { - LOG_INFO(Render_Vulkan, "Dynamic memory allocation failed, trying with system memory"); - stream_memory_info.memoryTypeIndex = - FindMemoryTypeIndex(memory_properties, requirements.memoryTypeBits, false); - stream_memory = dev.AllocateMemory(stream_memory_info); - } - + stream_buffer = memory_allocator.CreateBuffer(stream_ci, MemoryUsage::Stream); if (device.HasDebuggingToolAttached()) { - stream_memory.SetObjectNameEXT("Stream Buffer Memory"); + stream_buffer.SetObjectNameEXT("Stream Buffer"); } - stream_buffer.BindMemory(*stream_memory, 0); - stream_pointer = stream_memory.Map(0, STREAM_BUFFER_SIZE); + stream_pointer = stream_buffer.Mapped(); + ASSERT_MSG(!stream_pointer.empty(), "Stream buffer must be host visible!"); } StagingBufferPool::~StagingBufferPool() = default; @@ -199,7 +116,7 @@ StagingBufferRef StagingBufferPool::GetStreamBuffer(size_t size) { return StagingBufferRef{ .buffer = *stream_buffer, .offset = static_cast(offset), - .mapped_span = std::span(stream_pointer + offset, size), + .mapped_span = stream_pointer.subspan(offset, size), .usage{}, .log2_level{}, .index{}, @@ -247,7 +164,7 @@ std::optional StagingBufferPool::TryGetReservedBuffer(size_t s StagingBufferRef StagingBufferPool::CreateStagingBuffer(size_t size, MemoryUsage usage, bool deferred) { const u32 log2 = Common::Log2Ceil64(size); - vk::Buffer buffer = device.GetLogical().CreateBuffer({ + const VkBufferCreateInfo buffer_ci = { .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, .pNext = nullptr, .flags = 0, @@ -259,17 +176,15 @@ StagingBufferRef StagingBufferPool::CreateStagingBuffer(size_t size, MemoryUsage .sharingMode = VK_SHARING_MODE_EXCLUSIVE, .queueFamilyIndexCount = 0, .pQueueFamilyIndices = nullptr, - }); + }; + vk::Buffer buffer = memory_allocator.CreateBuffer(buffer_ci, usage); if (device.HasDebuggingToolAttached()) { ++buffer_index; buffer.SetObjectNameEXT(fmt::format("Staging Buffer {}", buffer_index).c_str()); } - MemoryCommit commit = memory_allocator.Commit(buffer, usage); - const std::span mapped_span = IsHostVisible(usage) ? commit.Map() : std::span{}; - + const std::span mapped_span = buffer.Mapped(); StagingBuffer& entry = GetCache(usage)[log2].entries.emplace_back(StagingBuffer{ .buffer = std::move(buffer), - .commit = std::move(commit), .mapped_span = mapped_span, .usage = usage, .log2_level = log2, diff --git a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h index 4fd15f11a..5f69f08b1 100644 --- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h +++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h @@ -46,7 +46,6 @@ private: struct StagingBuffer { vk::Buffer buffer; - MemoryCommit commit; std::span mapped_span; MemoryUsage usage; u32 log2_level; @@ -97,8 +96,7 @@ private: Scheduler& scheduler; vk::Buffer stream_buffer; - vk::DeviceMemory stream_memory; - u8* stream_pointer = nullptr; + std::span stream_pointer; size_t iterator = 0; size_t used_iterator = 0; diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 10defe6cb..28985b6fe 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -839,14 +839,14 @@ bool TextureCacheRuntime::ShouldReinterpret(Image& dst, Image& src) { VkBuffer TextureCacheRuntime::GetTemporaryBuffer(size_t needed_size) { const auto level = (8 * sizeof(size_t)) - std::countl_zero(needed_size - 1ULL); - if (buffer_commits[level]) { + if (buffers[level]) { return *buffers[level]; } const auto new_size = Common::NextPow2(needed_size); static constexpr VkBufferUsageFlags flags = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT; - buffers[level] = device.GetLogical().CreateBuffer({ + const VkBufferCreateInfo temp_ci = { .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, .pNext = nullptr, .flags = 0, @@ -855,9 +855,8 @@ VkBuffer TextureCacheRuntime::GetTemporaryBuffer(size_t needed_size) { .sharingMode = VK_SHARING_MODE_EXCLUSIVE, .queueFamilyIndexCount = 0, .pQueueFamilyIndices = nullptr, - }); - buffer_commits[level] = std::make_unique( - memory_allocator.Commit(buffers[level], MemoryUsage::DeviceLocal)); + }; + buffers[level] = memory_allocator.CreateBuffer(temp_ci, MemoryUsage::DeviceLocal); return *buffers[level]; } diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h index 9481f2531..220943116 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h @@ -116,7 +116,6 @@ public: static constexpr size_t indexing_slots = 8 * sizeof(size_t); std::array buffers{}; - std::array, indexing_slots> buffer_commits{}; }; class Image : public VideoCommon::ImageBase { diff --git a/src/video_core/renderer_vulkan/vk_turbo_mode.cpp b/src/video_core/renderer_vulkan/vk_turbo_mode.cpp index 6417d7e31..460d8d59d 100644 --- a/src/video_core/renderer_vulkan/vk_turbo_mode.cpp +++ b/src/video_core/renderer_vulkan/vk_turbo_mode.cpp @@ -41,7 +41,7 @@ void TurboMode::Run(std::stop_token stop_token) { auto& dld = m_device.GetLogical(); // Allocate buffer. 2MiB should be sufficient. - auto buffer = dld.CreateBuffer(VkBufferCreateInfo{ + const VkBufferCreateInfo buffer_ci = { .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, .pNext = nullptr, .flags = 0, @@ -50,10 +50,8 @@ void TurboMode::Run(std::stop_token stop_token) { .sharingMode = VK_SHARING_MODE_EXCLUSIVE, .queueFamilyIndexCount = 0, .pQueueFamilyIndices = nullptr, - }); - - // Commit some device local memory for the buffer. - auto commit = m_allocator.Commit(buffer, MemoryUsage::DeviceLocal); + }; + vk::Buffer buffer = m_allocator.CreateBuffer(buffer_ci, MemoryUsage::DeviceLocal); // Create the descriptor pool to contain our descriptor. static constexpr VkDescriptorPoolSize pool_size{ diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 631d5e378..541f0c1da 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -603,6 +603,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR }; const VmaAllocatorCreateInfo allocator_info = { + .flags = VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT, .physicalDevice = physical, .device = *logical, .pVulkanFunctions = &functions, diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp index 7f860cccd..d2e1ef58e 100644 --- a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp +++ b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp @@ -51,11 +51,59 @@ struct Range { case MemoryUsage::Download: return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT; + case MemoryUsage::Stream: + return VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; } ASSERT_MSG(false, "Invalid memory usage={}", usage); return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; } +[[nodiscard]] VkMemoryPropertyFlags MemoryUsageRequiredVmaFlags(MemoryUsage usage) { + switch (usage) { + case MemoryUsage::DeviceLocal: + return VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + case MemoryUsage::Upload: + case MemoryUsage::Stream: + return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; + case MemoryUsage::Download: + return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT; + } + ASSERT_MSG(false, "Invalid memory usage={}", usage); + return {}; +} + +[[nodiscard]] VkMemoryPropertyFlags MemoryUsagePreferedVmaFlags(MemoryUsage usage) { + return usage != MemoryUsage::DeviceLocal ? VK_MEMORY_PROPERTY_HOST_COHERENT_BIT + : VkMemoryPropertyFlags{}; +} + +[[nodiscard]] VmaAllocationCreateFlags MemoryUsageVmaFlags(MemoryUsage usage) { + switch (usage) { + case MemoryUsage::Upload: + case MemoryUsage::Stream: + return VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT; + case MemoryUsage::Download: + return VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT; + case MemoryUsage::DeviceLocal: + return VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | + VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT; + } + return {}; +} + +[[nodiscard]] VmaMemoryUsage MemoryUsageVma(MemoryUsage usage) { + switch (usage) { + case MemoryUsage::DeviceLocal: + case MemoryUsage::Stream: + return VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE; + case MemoryUsage::Upload: + case MemoryUsage::Download: + return VMA_MEMORY_USAGE_AUTO_PREFER_HOST; + } + return VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE; +} + } // Anonymous namespace class MemoryAllocation { @@ -178,17 +226,18 @@ void MemoryCommit::Release() { } MemoryAllocator::MemoryAllocator(const Device& device_) - : device{device_}, properties{device_.GetPhysical().GetMemoryProperties().memoryProperties}, + : device{device_}, allocator{device.GetAllocator()}, + properties{device_.GetPhysical().GetMemoryProperties().memoryProperties}, buffer_image_granularity{ device_.GetPhysical().GetProperties().limits.bufferImageGranularity} {} MemoryAllocator::~MemoryAllocator() = default; vk::Image MemoryAllocator::CreateImage(const VkImageCreateInfo& ci) const { - const VmaAllocationCreateInfo alloc_info = { + const VmaAllocationCreateInfo alloc_ci = { .flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT, .usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, - .requiredFlags = 0, + .requiredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, .preferredFlags = 0, .pool = VK_NULL_HANDLE, .pUserData = nullptr, @@ -196,12 +245,40 @@ vk::Image MemoryAllocator::CreateImage(const VkImageCreateInfo& ci) const { VkImage handle{}; VmaAllocation allocation{}; - vk::Check( - vmaCreateImage(device.GetAllocator(), &ci, &alloc_info, &handle, &allocation, nullptr)); - return vk::Image(handle, *device.GetLogical(), device.GetAllocator(), allocation, + + vk::Check(vmaCreateImage(allocator, &ci, &alloc_ci, &handle, &allocation, nullptr)); + + return vk::Image(handle, *device.GetLogical(), allocator, allocation, device.GetDispatchLoader()); } +vk::Buffer MemoryAllocator::CreateBuffer(const VkBufferCreateInfo& ci, MemoryUsage usage) const { + const VmaAllocationCreateInfo alloc_ci = { + .flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT | + MemoryUsageVmaFlags(usage), + .usage = MemoryUsageVma(usage), + .requiredFlags = MemoryUsageRequiredVmaFlags(usage), + .preferredFlags = MemoryUsagePreferedVmaFlags(usage), + .pool = VK_NULL_HANDLE, + .pUserData = nullptr, + }; + + VkBuffer handle{}; + VmaAllocationInfo alloc_info{}; + VmaAllocation allocation{}; + VkMemoryPropertyFlags property_flags{}; + + vk::Check(vmaCreateBuffer(allocator, &ci, &alloc_ci, &handle, &allocation, &alloc_info)); + vmaGetAllocationMemoryProperties(allocator, allocation, &property_flags); + + u8* data = reinterpret_cast(alloc_info.pMappedData); + const std::span mapped_data = data ? std::span{data, ci.size} : std::span{}; + const bool is_coherent = property_flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + + return vk::Buffer(handle, *device.GetLogical(), allocator, allocation, mapped_data, is_coherent, + device.GetDispatchLoader()); +} + MemoryCommit MemoryAllocator::Commit(const VkMemoryRequirements& requirements, MemoryUsage usage) { // Find the fastest memory flags we can afford with the current requirements const u32 type_mask = requirements.memoryTypeBits; @@ -221,12 +298,6 @@ MemoryCommit MemoryAllocator::Commit(const VkMemoryRequirements& requirements, M return TryCommit(requirements, flags).value(); } -MemoryCommit MemoryAllocator::Commit(const vk::Buffer& buffer, MemoryUsage usage) { - auto commit = Commit(device.GetLogical().GetBufferMemoryRequirements(*buffer), usage); - buffer.BindMemory(commit.Memory(), commit.Offset()); - return commit; -} - bool MemoryAllocator::TryAllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u64 size) { const u32 type = FindType(flags, type_mask).value(); vk::DeviceMemory memory = device.GetLogical().TryAllocateMemory({ @@ -302,16 +373,4 @@ std::optional MemoryAllocator::FindType(VkMemoryPropertyFlags flags, u32 ty return std::nullopt; } -bool IsHostVisible(MemoryUsage usage) noexcept { - switch (usage) { - case MemoryUsage::DeviceLocal: - return false; - case MemoryUsage::Upload: - case MemoryUsage::Download: - return true; - } - ASSERT_MSG(false, "Invalid memory usage={}", usage); - return false; -} - } // namespace Vulkan diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.h b/src/video_core/vulkan_common/vulkan_memory_allocator.h index f9ee53cfb..f449bc8d0 100644 --- a/src/video_core/vulkan_common/vulkan_memory_allocator.h +++ b/src/video_core/vulkan_common/vulkan_memory_allocator.h @@ -9,6 +9,8 @@ #include "common/common_types.h" #include "video_core/vulkan_common/vulkan_wrapper.h" +VK_DEFINE_HANDLE(VmaAllocator) + namespace Vulkan { class Device; @@ -17,9 +19,11 @@ class MemoryAllocation; /// Hints and requirements for the backing memory type of a commit enum class MemoryUsage { - DeviceLocal, ///< Hints device local usages, fastest memory type to read and write from the GPU + DeviceLocal, ///< Requests device local host visible buffer, falling back to device local + ///< memory. Upload, ///< Requires a host visible memory type optimized for CPU to GPU uploads Download, ///< Requires a host visible memory type optimized for GPU to CPU readbacks + Stream, ///< Requests device local host visible buffer, falling back host memory. }; /// Ownership handle of a memory commitment. @@ -82,6 +86,8 @@ public: vk::Image CreateImage(const VkImageCreateInfo& ci) const; + vk::Buffer CreateBuffer(const VkBufferCreateInfo& ci, MemoryUsage usage) const; + /** * Commits a memory with the specified requirements. * @@ -113,13 +119,11 @@ private: std::optional FindType(VkMemoryPropertyFlags flags, u32 type_mask) const; const Device& device; ///< Device handle. + VmaAllocator allocator; ///< Vma allocator. const VkPhysicalDeviceMemoryProperties properties; ///< Physical device properties. std::vector> allocations; ///< Current allocations. VkDeviceSize buffer_image_granularity; // The granularity for adjacent offsets between buffers // and optimal images }; -/// Returns true when a memory usage is guaranteed to be host visible. -bool IsHostVisible(MemoryUsage usage) noexcept; - } // namespace Vulkan diff --git a/src/video_core/vulkan_common/vulkan_wrapper.cpp b/src/video_core/vulkan_common/vulkan_wrapper.cpp index 5d088dc58..c01a9478e 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.cpp +++ b/src/video_core/vulkan_common/vulkan_wrapper.cpp @@ -561,14 +561,28 @@ void Image::Release() const noexcept { } } -void Buffer::BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const { - Check(dld->vkBindBufferMemory(owner, handle, memory, offset)); +void Buffer::Flush() const { + if (!is_coherent) { + vmaFlushAllocation(allocator, allocation, 0, VK_WHOLE_SIZE); + } +} + +void Buffer::Invalidate() const { + if (!is_coherent) { + vmaInvalidateAllocation(allocator, allocation, 0, VK_WHOLE_SIZE); + } } void Buffer::SetObjectNameEXT(const char* name) const { SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_BUFFER, name); } +void Buffer::Release() const noexcept { + if (handle) { + vmaDestroyBuffer(allocator, handle, allocation); + } +} + void BufferView::SetObjectNameEXT(const char* name) const { SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_BUFFER_VIEW, name); } @@ -707,12 +721,6 @@ Queue Device::GetQueue(u32 family_index) const noexcept { return Queue(queue, *dld); } -Buffer Device::CreateBuffer(const VkBufferCreateInfo& ci) const { - VkBuffer object; - Check(dld->vkCreateBuffer(handle, &ci, nullptr, &object)); - return Buffer(object, handle, *dld); -} - BufferView Device::CreateBufferView(const VkBufferViewCreateInfo& ci) const { VkBufferView object; Check(dld->vkCreateBufferView(handle, &ci, nullptr, &object)); diff --git a/src/video_core/vulkan_common/vulkan_wrapper.h b/src/video_core/vulkan_common/vulkan_wrapper.h index 8ec708774..44fce47a5 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.h +++ b/src/video_core/vulkan_common/vulkan_wrapper.h @@ -673,6 +673,84 @@ private: const DeviceDispatch* dld = nullptr; }; +class Buffer { +public: + explicit Buffer(VkBuffer handle_, VkDevice owner_, VmaAllocator allocator_, + VmaAllocation allocation_, std::span mapped_, bool is_coherent_, + const DeviceDispatch& dld_) noexcept + : handle{handle_}, owner{owner_}, allocator{allocator_}, + allocation{allocation_}, mapped{mapped_}, is_coherent{is_coherent_}, dld{&dld_} {} + Buffer() = default; + + Buffer(const Buffer&) = delete; + Buffer& operator=(const Buffer&) = delete; + + Buffer(Buffer&& rhs) noexcept + : handle{std::exchange(rhs.handle, nullptr)}, owner{rhs.owner}, allocator{rhs.allocator}, + allocation{rhs.allocation}, mapped{rhs.mapped}, + is_coherent{rhs.is_coherent}, dld{rhs.dld} {} + + Buffer& operator=(Buffer&& rhs) noexcept { + Release(); + handle = std::exchange(rhs.handle, nullptr); + owner = rhs.owner; + allocator = rhs.allocator; + allocation = rhs.allocation; + mapped = rhs.mapped; + is_coherent = rhs.is_coherent; + dld = rhs.dld; + return *this; + } + + ~Buffer() noexcept { + Release(); + } + + VkBuffer operator*() const noexcept { + return handle; + } + + void reset() noexcept { + Release(); + handle = nullptr; + } + + explicit operator bool() const noexcept { + return handle != nullptr; + } + + /// Returns the host mapped memory, an empty span otherwise. + std::span Mapped() noexcept { + return mapped; + } + + std::span Mapped() const noexcept { + return mapped; + } + + /// Returns true if the buffer is mapped to the host. + bool IsHostVisible() const noexcept { + return !mapped.empty(); + } + + void Flush() const; + + void Invalidate() const; + + void SetObjectNameEXT(const char* name) const; + +private: + void Release() const noexcept; + + VkBuffer handle = nullptr; + VkDevice owner = nullptr; + VmaAllocator allocator = nullptr; + VmaAllocation allocation = nullptr; + std::span mapped = {}; + bool is_coherent = false; + const DeviceDispatch* dld = nullptr; +}; + class Queue { public: /// Construct an empty queue handle. @@ -696,17 +774,6 @@ private: const DeviceDispatch* dld = nullptr; }; -class Buffer : public Handle { - using Handle::Handle; - -public: - /// Attaches a memory allocation. - void BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const; - - /// Set object name. - void SetObjectNameEXT(const char* name) const; -}; - class BufferView : public Handle { using Handle::Handle; @@ -886,8 +953,6 @@ public: Queue GetQueue(u32 family_index) const noexcept; - Buffer CreateBuffer(const VkBufferCreateInfo& ci) const; - BufferView CreateBufferView(const VkBufferViewCreateInfo& ci) const; ImageView CreateImageView(const VkImageViewCreateInfo& ci) const; -- cgit v1.2.3 From ee0d68300e68a221d9930935f26d0c96be79357b Mon Sep 17 00:00:00 2001 From: GPUCode Date: Sun, 18 Jun 2023 12:27:31 +0300 Subject: renderer_vulkan: Add missing initializers --- src/video_core/vulkan_common/vulkan_device.cpp | 12 ++++++++---- src/video_core/vulkan_common/vulkan_memory_allocator.cpp | 6 +++++- 2 files changed, 13 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 541f0c1da..94dd1aa14 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -597,18 +597,22 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR graphics_queue = logical.GetQueue(graphics_family); present_queue = logical.GetQueue(present_family); - const VmaVulkanFunctions functions = { - .vkGetInstanceProcAddr = dld.vkGetInstanceProcAddr, - .vkGetDeviceProcAddr = dld.vkGetDeviceProcAddr, - }; + VmaVulkanFunctions functions{}; + functions.vkGetInstanceProcAddr = dld.vkGetInstanceProcAddr; + functions.vkGetDeviceProcAddr = dld.vkGetDeviceProcAddr; const VmaAllocatorCreateInfo allocator_info = { .flags = VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT, .physicalDevice = physical, .device = *logical, + .preferredLargeHeapBlockSize = 0, + .pAllocationCallbacks = nullptr, + .pDeviceMemoryCallbacks = nullptr, + .pHeapSizeLimit = nullptr, .pVulkanFunctions = &functions, .instance = instance, .vulkanApiVersion = VK_API_VERSION_1_1, + .pTypeExternalMemoryHandleTypes = nullptr, }; vk::Check(vmaCreateAllocator(&allocator_info, &allocator)); diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp index d2e1ef58e..20d36680c 100644 --- a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp +++ b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp @@ -75,7 +75,7 @@ struct Range { [[nodiscard]] VkMemoryPropertyFlags MemoryUsagePreferedVmaFlags(MemoryUsage usage) { return usage != MemoryUsage::DeviceLocal ? VK_MEMORY_PROPERTY_HOST_COHERENT_BIT - : VkMemoryPropertyFlags{}; + : VkMemoryPropertyFlagBits{}; } [[nodiscard]] VmaAllocationCreateFlags MemoryUsageVmaFlags(MemoryUsage usage) { @@ -239,8 +239,10 @@ vk::Image MemoryAllocator::CreateImage(const VkImageCreateInfo& ci) const { .usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, .requiredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, .preferredFlags = 0, + .memoryTypeBits = 0, .pool = VK_NULL_HANDLE, .pUserData = nullptr, + .priority = 0.f, }; VkImage handle{}; @@ -259,8 +261,10 @@ vk::Buffer MemoryAllocator::CreateBuffer(const VkBufferCreateInfo& ci, MemoryUsa .usage = MemoryUsageVma(usage), .requiredFlags = MemoryUsageRequiredVmaFlags(usage), .preferredFlags = MemoryUsagePreferedVmaFlags(usage), + .memoryTypeBits = 0, .pool = VK_NULL_HANDLE, .pUserData = nullptr, + .priority = 0.f, }; VkBuffer handle{}; -- cgit v1.2.3 From 346c253cd2397ac152fd10f6b99d6af79349a77f Mon Sep 17 00:00:00 2001 From: lat9nq <22451773+lat9nq@users.noreply.github.com> Date: Thu, 15 Jun 2023 16:16:36 -0400 Subject: video_core: Formalize HasBrokenCompute Also limits it to only affected Intel proprietrary driver versions. vulkan_device: Move broken compute determination vk_device: Remove errant back quote --- .../renderer_vulkan/vk_pipeline_cache.cpp | 5 +---- src/video_core/vulkan_common/vulkan_device.cpp | 2 ++ src/video_core/vulkan_common/vulkan_device.h | 23 ++++++++++++++++++++++ 3 files changed, 26 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 18e040a1b..ee2c33131 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -705,10 +705,7 @@ std::unique_ptr PipelineCache::CreateComputePipeline( std::unique_ptr PipelineCache::CreateComputePipeline( ShaderPools& pools, const ComputePipelineCacheKey& key, Shader::Environment& env, PipelineStatistics* statistics, bool build_in_parallel) try { - // TODO: Remove this when Intel fixes their shader compiler. - // https://github.com/IGCIT/Intel-GPU-Community-Issue-Tracker-IGCIT/issues/159 - if (device.GetDriverID() == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS && - !Settings::values.enable_compute_pipelines.GetValue()) { + if (device.HasBrokenCompute() && !Settings::values.enable_compute_pipelines.GetValue()) { LOG_ERROR(Render_Vulkan, "Skipping 0x{:016x}", key.Hash()); return nullptr; } diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index dcedf4425..e38e34bc8 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -562,6 +562,8 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR LOG_WARNING(Render_Vulkan, "Intel proprietary drivers do not support MSAA image blits"); cant_blit_msaa = true; } + has_broken_compute = + CheckBrokenCompute(properties.driver.driverID, properties.properties.driverVersion); if (is_intel_anv || (is_qualcomm && !is_s8gen2)) { LOG_WARNING(Render_Vulkan, "Driver does not support native BGR format"); must_emulate_bgr565 = true; diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index 8c7e44fcb..e54828088 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h @@ -10,6 +10,7 @@ #include #include "common/common_types.h" +#include "common/logging/log.h" #include "common/settings.h" #include "video_core/vulkan_common/vulkan_wrapper.h" @@ -518,6 +519,11 @@ public: return has_renderdoc || has_nsight_graphics || Settings::values.renderer_debug.GetValue(); } + /// @returns True if compute pipelines can cause crashing. + bool HasBrokenCompute() const { + return has_broken_compute; + } + /// Returns true when the device does not properly support cube compatibility. bool HasBrokenCubeImageCompability() const { return has_broken_cube_compatibility; @@ -579,6 +585,22 @@ public: return supports_conditional_barriers; } + [[nodiscard]] static constexpr bool CheckBrokenCompute(VkDriverId driver_id, + u32 driver_version) { + if (driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS) { + const u32 major = VK_API_VERSION_MAJOR(driver_version); + const u32 minor = VK_API_VERSION_MINOR(driver_version); + const u32 patch = VK_API_VERSION_PATCH(driver_version); + if (major == 0 && minor == 405 && patch < 286) { + LOG_WARNING( + Render_Vulkan, + "Intel proprietary drivers 0.405.0 until 0.405.286 have broken compute"); + return true; + } + } + return {}; + } + private: /// Checks if the physical device is suitable and configures the object state /// with all necessary info about its properties. @@ -672,6 +694,7 @@ private: bool is_integrated{}; ///< Is GPU an iGPU. bool is_virtual{}; ///< Is GPU a virtual GPU. bool is_non_gpu{}; ///< Is SoftwareRasterizer, FPGA, non-GPU device. + bool has_broken_compute{}; ///< Compute shaders can cause crashes bool has_broken_cube_compatibility{}; ///< Has broken cube compatibility bit bool has_renderdoc{}; ///< Has RenderDoc attached bool has_nsight_graphics{}; ///< Has Nsight Graphics attached -- cgit v1.2.3 From b9a86b040b7e310ad3b39540ce7b6249cb965536 Mon Sep 17 00:00:00 2001 From: lat9nq <22451773+lat9nq@users.noreply.github.com> Date: Thu, 15 Jun 2023 16:17:19 -0400 Subject: vk_device_info: Check only affected Intel drivers Renames is_intel_proprietary to has_broken_compute for accuracy. vk_device_info: Use vulkan::device to check compute --- src/yuzu/configuration/configure_graphics.cpp | 2 +- src/yuzu/vk_device_info.cpp | 13 ++++++++----- src/yuzu/vk_device_info.h | 4 ++-- 3 files changed, 11 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp index 78b487494..a4965524a 100644 --- a/src/yuzu/configuration/configure_graphics.cpp +++ b/src/yuzu/configuration/configure_graphics.cpp @@ -508,7 +508,7 @@ void ConfigureGraphics::RetrieveVulkanDevices() { vulkan_devices.push_back(QString::fromStdString(record.name)); device_present_modes.push_back(record.vsync_support); - if (record.is_intel_proprietary) { + if (record.has_broken_compute) { expose_compute_option(); } } diff --git a/src/yuzu/vk_device_info.cpp b/src/yuzu/vk_device_info.cpp index 9bd1ec686..7c26a3dc7 100644 --- a/src/yuzu/vk_device_info.cpp +++ b/src/yuzu/vk_device_info.cpp @@ -5,10 +5,12 @@ #include #include "common/dynamic_library.h" #include "common/logging/log.h" +#include "video_core/vulkan_common/vulkan_device.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 "video_core/vulkan_common/vulkan_wrapper.h" +#include "vulkan/vulkan_core.h" #include "yuzu/qt_common.h" #include "yuzu/vk_device_info.h" @@ -16,8 +18,8 @@ class QWindow; namespace VkDeviceInfo { Record::Record(std::string_view name_, const std::vector& vsync_modes_, - bool is_intel_proprietary_) - : name{name_}, vsync_support{vsync_modes_}, is_intel_proprietary{is_intel_proprietary_} {} + bool has_broken_compute_) + : name{name_}, vsync_support{vsync_modes_}, has_broken_compute{has_broken_compute_} {} Record::~Record() = default; @@ -48,9 +50,10 @@ void PopulateRecords(std::vector& records, QWindow* window) try { properties.pNext = &driver_properties; dld.vkGetPhysicalDeviceProperties2(physical_device, &properties); - records.push_back(VkDeviceInfo::Record(name, present_modes, - driver_properties.driverID == - VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS)); + bool has_broken_compute{Vulkan::Device::CheckBrokenCompute( + driver_properties.driverID, properties.properties.driverVersion)}; + + records.push_back(VkDeviceInfo::Record(name, present_modes, has_broken_compute)); } } catch (const Vulkan::vk::Exception& exception) { LOG_ERROR(Frontend, "Failed to enumerate devices with error: {}", exception.what()); diff --git a/src/yuzu/vk_device_info.h b/src/yuzu/vk_device_info.h index 5a6c64416..bda8262f4 100644 --- a/src/yuzu/vk_device_info.h +++ b/src/yuzu/vk_device_info.h @@ -24,12 +24,12 @@ namespace VkDeviceInfo { class Record { public: explicit Record(std::string_view name, const std::vector& vsync_modes, - bool is_intel_proprietary); + bool has_broken_compute); ~Record(); const std::string name; const std::vector vsync_support; - const bool is_intel_proprietary; + const bool has_broken_compute; }; void PopulateRecords(std::vector& records, QWindow* window); -- cgit v1.2.3 From 711190bb6708f822a3bdb7afd30168d2cc3ed0e4 Mon Sep 17 00:00:00 2001 From: Kelebek1 Date: Mon, 19 Jun 2023 00:19:28 +0100 Subject: Use current GPU address when unmapping GPU pages, not the base --- src/video_core/memory_manager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp index 7b2cde7a7..b2f7e160a 100644 --- a/src/video_core/memory_manager.cpp +++ b/src/video_core/memory_manager.cpp @@ -111,7 +111,7 @@ GPUVAddr MemoryManager::PageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] VAddr cp [[maybe_unused]] const auto current_entry_type = GetEntry(current_gpu_addr); SetEntry(current_gpu_addr, entry_type); if (current_entry_type != entry_type) { - rasterizer->ModifyGPUMemory(unique_identifier, gpu_addr, page_size); + rasterizer->ModifyGPUMemory(unique_identifier, current_gpu_addr, page_size); } if constexpr (entry_type == EntryType::Mapped) { const VAddr current_cpu_addr = cpu_addr + offset; @@ -134,7 +134,7 @@ GPUVAddr MemoryManager::BigPageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] VAddr [[maybe_unused]] const auto current_entry_type = GetEntry(current_gpu_addr); SetEntry(current_gpu_addr, entry_type); if (current_entry_type != entry_type) { - rasterizer->ModifyGPUMemory(unique_identifier, gpu_addr, big_page_size); + rasterizer->ModifyGPUMemory(unique_identifier, current_gpu_addr, big_page_size); } if constexpr (entry_type == EntryType::Mapped) { const VAddr current_cpu_addr = cpu_addr + offset; -- cgit v1.2.3 From b0beca52a34bae1ac73731ab5a0a2504a471d23f Mon Sep 17 00:00:00 2001 From: Liam Date: Sun, 18 Jun 2023 22:21:29 -0400 Subject: vfs_concat: fix offset calculation when not aligned to file boundary --- src/core/file_sys/vfs_concat.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/core/file_sys/vfs_concat.cpp b/src/core/file_sys/vfs_concat.cpp index 853b893a1..5285467d2 100644 --- a/src/core/file_sys/vfs_concat.cpp +++ b/src/core/file_sys/vfs_concat.cpp @@ -150,18 +150,19 @@ std::size_t ConcatenatedVfsFile::Read(u8* data, std::size_t length, std::size_t while (cur_length > 0 && it != concatenation_map.end()) { // Check if we can read the file at this position. const auto& file = it->file; - const u64 file_offset = it->offset; + const u64 map_offset = it->offset; const u64 file_size = file->GetSize(); - if (cur_offset >= file_offset + file_size) { + if (cur_offset > map_offset + file_size) { // Entirely out of bounds read. break; } // Read the file at this position. - const u64 intended_read_size = std::min(cur_length, file_size); + const u64 file_seek = cur_offset - map_offset; + const u64 intended_read_size = std::min(cur_length, file_size - file_seek); const u64 actual_read_size = - file->Read(data + (cur_offset - offset), intended_read_size, cur_offset - file_offset); + file->Read(data + (cur_offset - offset), intended_read_size, file_seek); // Update tracking. cur_offset += actual_read_size; -- cgit v1.2.3 From e5f1b22e16b32f36ca3a7af24cbda4f39bc861aa Mon Sep 17 00:00:00 2001 From: Liam Date: Mon, 19 Jun 2023 09:47:05 -0400 Subject: vfs_concat: verify short read --- src/core/file_sys/vfs_concat.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src') diff --git a/src/core/file_sys/vfs_concat.cpp b/src/core/file_sys/vfs_concat.cpp index 5285467d2..311a59e5f 100644 --- a/src/core/file_sys/vfs_concat.cpp +++ b/src/core/file_sys/vfs_concat.cpp @@ -168,6 +168,11 @@ std::size_t ConcatenatedVfsFile::Read(u8* data, std::size_t length, std::size_t cur_offset += actual_read_size; cur_length -= actual_read_size; it++; + + // If we encountered a short read, we're done. + if (actual_read_size < intended_read_size) { + break; + } } return cur_offset - offset; -- cgit v1.2.3 From 197e13d93d6740cda589d88804262d6bdd176a74 Mon Sep 17 00:00:00 2001 From: lat9nq <22451773+lat9nq@users.noreply.github.com> Date: Mon, 19 Jun 2023 17:33:30 -0400 Subject: video_core: Check broken compute earlier Checks it as the system is determining what settings to enable. Reduces the need to check settings while the system is running. --- src/video_core/renderer_vulkan/vk_pipeline_cache.cpp | 2 +- src/video_core/vulkan_common/vulkan_device.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index ee2c33131..a2cfb2105 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -705,7 +705,7 @@ std::unique_ptr PipelineCache::CreateComputePipeline( std::unique_ptr PipelineCache::CreateComputePipeline( ShaderPools& pools, const ComputePipelineCacheKey& key, Shader::Environment& env, PipelineStatistics* statistics, bool build_in_parallel) try { - if (device.HasBrokenCompute() && !Settings::values.enable_compute_pipelines.GetValue()) { + if (device.HasBrokenCompute()) { LOG_ERROR(Render_Vulkan, "Skipping 0x{:016x}", key.Hash()); return nullptr; } diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index e38e34bc8..fa9cde75b 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -563,7 +563,8 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR cant_blit_msaa = true; } has_broken_compute = - CheckBrokenCompute(properties.driver.driverID, properties.properties.driverVersion); + CheckBrokenCompute(properties.driver.driverID, properties.properties.driverVersion) && + !Settings::values.enable_compute_pipelines.GetValue(); if (is_intel_anv || (is_qualcomm && !is_s8gen2)) { LOG_WARNING(Render_Vulkan, "Driver does not support native BGR format"); must_emulate_bgr565 = true; -- cgit v1.2.3 From 78ff2862f6a0785247d3aa64bdc210b545e4d82d Mon Sep 17 00:00:00 2001 From: toast2903 <22451773+lat9nq@users.noreply.github.com> Date: Sun, 18 Jun 2023 23:29:27 -0400 Subject: vulkan_device: Remove brace initializer Co-authored-by: Tobias --- src/video_core/vulkan_common/vulkan_device.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index e54828088..0b634a876 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h @@ -598,7 +598,7 @@ public: return true; } } - return {}; + return false; } private: -- cgit v1.2.3 From fd5d7947f614d837cb3b08e132a025c4e1536d37 Mon Sep 17 00:00:00 2001 From: lat9nq <22451773+lat9nq@users.noreply.github.com> Date: Tue, 20 Jun 2023 15:49:47 -0400 Subject: time_zone_manager: Stop on comma This is a deviation from the reference time zone implementation. The actual code will set a pointer to the time zone name here, but for us we have a limited number of characters to work with, and the name of the time zone here could be larger than 8 characters. We can make the assumption that time zone names greater than five characters in length include a comma that denotes more data. Nintendo just truncates that data for the name, so we can do the same. time_zone_manager: Check for length of array Just to be double sure that we never break past the array length, directly compare against it. --- src/core/hle/service/time/time_zone_manager.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/hle/service/time/time_zone_manager.cpp b/src/core/hle/service/time/time_zone_manager.cpp index 63aacd19f..43d0a19b8 100644 --- a/src/core/hle/service/time/time_zone_manager.cpp +++ b/src/core/hle/service/time/time_zone_manager.cpp @@ -911,7 +911,9 @@ static Result ToCalendarTimeInternal(const TimeZoneRule& rules, s64 time, calendar_additional_info.is_dst = rules.ttis[tti_index].is_dst; const char* time_zone{&rules.chars[rules.ttis[tti_index].abbreviation_list_index]}; - for (int index{}; time_zone[index] != '\0'; ++index) { + for (u32 index{}; time_zone[index] != '\0' && time_zone[index] != ',' && + index < calendar_additional_info.timezone_name.size() - 1; + ++index) { calendar_additional_info.timezone_name[index] = time_zone[index]; } return ResultSuccess; -- cgit v1.2.3 From ae1a8a7dc7bbe656d9abac646472df2ccf1660db Mon Sep 17 00:00:00 2001 From: lat9nq <22451773+lat9nq@users.noreply.github.com> Date: Tue, 20 Jun 2023 15:52:17 -0400 Subject: time_zone_manager: Add null terminator We aren't null-terminating this string after the copy, and we need to. --- src/core/hle/service/time/time_zone_manager.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/core/hle/service/time/time_zone_manager.cpp b/src/core/hle/service/time/time_zone_manager.cpp index 43d0a19b8..205371a26 100644 --- a/src/core/hle/service/time/time_zone_manager.cpp +++ b/src/core/hle/service/time/time_zone_manager.cpp @@ -911,11 +911,13 @@ static Result ToCalendarTimeInternal(const TimeZoneRule& rules, s64 time, calendar_additional_info.is_dst = rules.ttis[tti_index].is_dst; const char* time_zone{&rules.chars[rules.ttis[tti_index].abbreviation_list_index]}; - for (u32 index{}; time_zone[index] != '\0' && time_zone[index] != ',' && - index < calendar_additional_info.timezone_name.size() - 1; + u32 index; + for (index = 0; time_zone[index] != '\0' && time_zone[index] != ',' && + index < calendar_additional_info.timezone_name.size() - 1; ++index) { calendar_additional_info.timezone_name[index] = time_zone[index]; } + calendar_additional_info.timezone_name[index] = '\0'; return ResultSuccess; } -- cgit v1.2.3 From e6845155782eb05b45c2574d6a363a8ccfbf9a38 Mon Sep 17 00:00:00 2001 From: Charles Lombardo Date: Tue, 20 Jun 2023 16:48:20 -0400 Subject: android: Don't show custom driver button on mali and x86 --- .../yuzu_emu/fragments/HomeSettingsFragment.kt | 172 ++++++++++++--------- .../org/yuzu/yuzu_emu/utils/GpuDriverHelper.kt | 2 + src/android/app/src/main/jni/native.cpp | 20 +++ 3 files changed, 123 insertions(+), 71 deletions(-) (limited to 'src') diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/HomeSettingsFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/HomeSettingsFragment.kt index 6f8adbba5..5a36ffad4 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/HomeSettingsFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/HomeSettingsFragment.kt @@ -68,79 +68,109 @@ class HomeSettingsFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { mainActivity = requireActivity() as MainActivity - val optionsList: MutableList = mutableListOf( - HomeSetting( - R.string.advanced_settings, - R.string.settings_description, - R.drawable.ic_settings - ) { SettingsActivity.launch(requireContext(), SettingsFile.FILE_NAME_CONFIG, "") }, - HomeSetting( - R.string.open_user_folder, - R.string.open_user_folder_description, - R.drawable.ic_folder_open - ) { openFileManager() }, - HomeSetting( - R.string.preferences_theme, - R.string.theme_and_color_description, - R.drawable.ic_palette - ) { SettingsActivity.launch(requireContext(), Settings.SECTION_THEME, "") }, - HomeSetting( - R.string.install_gpu_driver, - R.string.install_gpu_driver_description, - R.drawable.ic_exit - ) { driverInstaller() }, - HomeSetting( - R.string.install_amiibo_keys, - R.string.install_amiibo_keys_description, - R.drawable.ic_nfc - ) { mainActivity.getAmiiboKey.launch(arrayOf("*/*")) }, - HomeSetting( - R.string.install_game_content, - R.string.install_game_content_description, - R.drawable.ic_system_update_alt - ) { mainActivity.installGameUpdate.launch(arrayOf("*/*")) }, - HomeSetting( - R.string.select_games_folder, - R.string.select_games_folder_description, - R.drawable.ic_add - ) { - mainActivity.getGamesDirectory.launch(Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).data) - }, - HomeSetting( - R.string.manage_save_data, - R.string.import_export_saves_description, - R.drawable.ic_save - ) { - ImportExportSavesFragment().show( - parentFragmentManager, - ImportExportSavesFragment.TAG + val optionsList: MutableList = mutableListOf().apply { + add( + HomeSetting( + R.string.advanced_settings, + R.string.settings_description, + R.drawable.ic_settings + ) { SettingsActivity.launch(requireContext(), SettingsFile.FILE_NAME_CONFIG, "") } + ) + add( + HomeSetting( + R.string.open_user_folder, + R.string.open_user_folder_description, + R.drawable.ic_folder_open + ) { openFileManager() } + ) + add( + HomeSetting( + R.string.preferences_theme, + R.string.theme_and_color_description, + R.drawable.ic_palette + ) { SettingsActivity.launch(requireContext(), Settings.SECTION_THEME, "") } + ) + + if (GpuDriverHelper.supportsCustomDriverLoading()) { + add( + HomeSetting( + R.string.install_gpu_driver, + R.string.install_gpu_driver_description, + R.drawable.ic_exit + ) { driverInstaller() } ) - }, - HomeSetting( - R.string.install_prod_keys, - R.string.install_prod_keys_description, - R.drawable.ic_unlock - ) { mainActivity.getProdKey.launch(arrayOf("*/*")) }, - HomeSetting( - R.string.install_firmware, - R.string.install_firmware_description, - R.drawable.ic_firmware - ) { mainActivity.getFirmware.launch(arrayOf("application/zip")) }, - HomeSetting( - R.string.share_log, - R.string.share_log_description, - R.drawable.ic_log - ) { shareLog() }, - HomeSetting( - R.string.about, - R.string.about_description, - R.drawable.ic_info_outline - ) { - exitTransition = MaterialSharedAxis(MaterialSharedAxis.X, true) - parentFragmentManager.primaryNavigationFragment?.findNavController() - ?.navigate(R.id.action_homeSettingsFragment_to_aboutFragment) } - ) + + add( + HomeSetting( + R.string.install_amiibo_keys, + R.string.install_amiibo_keys_description, + R.drawable.ic_nfc + ) { mainActivity.getAmiiboKey.launch(arrayOf("*/*")) } + ) + add( + HomeSetting( + R.string.install_game_content, + R.string.install_game_content_description, + R.drawable.ic_system_update_alt + ) { mainActivity.installGameUpdate.launch(arrayOf("*/*")) } + ) + add( + HomeSetting( + R.string.select_games_folder, + R.string.select_games_folder_description, + R.drawable.ic_add + ) { + mainActivity.getGamesDirectory.launch( + Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).data + ) + } + ) + add( + HomeSetting( + R.string.manage_save_data, + R.string.import_export_saves_description, + R.drawable.ic_save + ) { + ImportExportSavesFragment().show( + parentFragmentManager, + ImportExportSavesFragment.TAG + ) + } + ) + add( + HomeSetting( + R.string.install_prod_keys, + R.string.install_prod_keys_description, + R.drawable.ic_unlock + ) { mainActivity.getProdKey.launch(arrayOf("*/*")) } + ) + add( + HomeSetting( + R.string.install_firmware, + R.string.install_firmware_description, + R.drawable.ic_firmware + ) { mainActivity.getFirmware.launch(arrayOf("application/zip")) } + ) + add( + HomeSetting( + R.string.share_log, + R.string.share_log_description, + R.drawable.ic_log + ) { shareLog() } + ) + add( + HomeSetting( + R.string.about, + R.string.about_description, + R.drawable.ic_info_outline + ) { + exitTransition = MaterialSharedAxis(MaterialSharedAxis.X, true) + parentFragmentManager.primaryNavigationFragment?.findNavController() + ?.navigate(R.id.action_homeSettingsFragment_to_aboutFragment) + } + ) + } if (!BuildConfig.PREMIUM) { optionsList.add( diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GpuDriverHelper.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GpuDriverHelper.kt index dad159481..1d4695a2a 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GpuDriverHelper.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GpuDriverHelper.kt @@ -113,6 +113,8 @@ object GpuDriverHelper { initializeDriverParameters(context) } + external fun supportsCustomDriverLoading(): Boolean + // Parse the custom driver metadata to retrieve the name. val customDriverName: String? get() { diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp index f9617202b..632aa50b3 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp @@ -560,6 +560,26 @@ void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeGpuDriver( GetJString(env, custom_driver_name), GetJString(env, file_redirect_dir)); } +[[maybe_unused]] static bool CheckKgslPresent() { + constexpr auto KgslPath{"/dev/kgsl-3d0"}; + + return access(KgslPath, F_OK) == 0; +} + +[[maybe_unused]] bool SupportsCustomDriver() { + return android_get_device_api_level() >= 28 && CheckKgslPresent(); +} + +jboolean JNICALL Java_org_yuzu_yuzu_1emu_utils_GpuDriverHelper_supportsCustomDriverLoading( + [[maybe_unused]] JNIEnv* env, [[maybe_unused]] jobject instance) { +#ifdef ARCHITECTURE_arm64 + // If the KGSL device exists custom drivers can be loaded using adrenotools + return SupportsCustomDriver(); +#else + return false; +#endif +} + jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_reloadKeys(JNIEnv* env, [[maybe_unused]] jclass clazz) { Core::Crypto::KeyManager::Instance().ReloadKeys(); -- cgit v1.2.3 From e31152ee347c2dddeba847ca08bd101ef53d1cce Mon Sep 17 00:00:00 2001 From: Abandoned Cart Date: Fri, 16 Jun 2023 18:50:36 -0400 Subject: android: Add a PiP interface to mute / unmute --- .../yuzu/yuzu_emu/activities/EmulationActivity.kt | 48 ++++++++++++++++++++++ .../app/src/main/res/drawable/ic_pip_audio.xml | 9 ++++ .../app/src/main/res/drawable/ic_pip_mute.xml | 9 ++++ src/android/app/src/main/res/values/strings.xml | 2 + 4 files changed, 68 insertions(+) create mode 100644 src/android/app/src/main/res/drawable/ic_pip_audio.xml create mode 100644 src/android/app/src/main/res/drawable/ic_pip_mute.xml (limited to 'src') diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt index f0a6753a9..8a071f4da 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt @@ -63,6 +63,10 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { private val actionPause = "ACTION_EMULATOR_PAUSE" private val actionPlay = "ACTION_EMULATOR_PLAY" + private val actionMute = "ACTION_EMULATOR_MUTE" + private val actionAudio = "ACTION_EMULATOR_AUDIO" + private var isAudioMuted = false + private var userAudio = IntSetting.AUDIO_VOLUME.int private val settingsViewModel: SettingsViewModel by viewModels() @@ -305,6 +309,38 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { pictureInPictureActions.add(pauseRemoteAction) } + if (isAudioMuted) { + val audioIcon = Icon.createWithResource(this@EmulationActivity, R.drawable.ic_pip_audio) + val audioPendingIntent = PendingIntent.getBroadcast( + this@EmulationActivity, + R.drawable.ic_pip_audio, + Intent(actionAudio), + pendingFlags + ) + val audioRemoteAction = RemoteAction( + audioIcon, + getString(R.string.audio), + getString(R.string.audio), + audioPendingIntent + ) + pictureInPictureActions.add(audioRemoteAction) + } else { + val muteIcon = Icon.createWithResource(this@EmulationActivity, R.drawable.ic_pip_mute) + val mutePendingIntent = PendingIntent.getBroadcast( + this@EmulationActivity, + R.drawable.ic_pip_mute, + Intent(actionMute), + pendingFlags + ) + val muteRemoteAction = RemoteAction( + muteIcon, + getString(R.string.mute), + getString(R.string.mute), + mutePendingIntent + ) + pictureInPictureActions.add(muteRemoteAction) + } + return this.apply { setActions(pictureInPictureActions) } } @@ -326,6 +362,18 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { } else if (intent.action == actionPause) { if (!NativeLibrary.isPaused()) NativeLibrary.pauseEmulation() } + if (intent.action == actionAudio) { + if (isAudioMuted) { + IntSetting.AUDIO_VOLUME.int = userAudio + isAudioMuted = false + } + } else if (intent.action == actionMute) { + if (!isAudioMuted) { + isAudioMuted = true + userAudio = IntSetting.AUDIO_VOLUME.int + IntSetting.AUDIO_VOLUME.int = 0 + } + } buildPictureInPictureParams() } } diff --git a/src/android/app/src/main/res/drawable/ic_pip_audio.xml b/src/android/app/src/main/res/drawable/ic_pip_audio.xml new file mode 100644 index 000000000..f7ed0862e --- /dev/null +++ b/src/android/app/src/main/res/drawable/ic_pip_audio.xml @@ -0,0 +1,9 @@ + + + diff --git a/src/android/app/src/main/res/drawable/ic_pip_mute.xml b/src/android/app/src/main/res/drawable/ic_pip_mute.xml new file mode 100644 index 000000000..a271c5fe8 --- /dev/null +++ b/src/android/app/src/main/res/drawable/ic_pip_mute.xml @@ -0,0 +1,9 @@ + + + diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index cc1d8c39d..d4f089c7f 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -387,6 +387,8 @@ Minimize window when placed in the background Pause Play + Mute + Audio Licenses -- cgit v1.2.3 From e35371e50c458abdca5c68fbae5c78869a6246e2 Mon Sep 17 00:00:00 2001 From: Abandoned Cart Date: Fri, 16 Jun 2023 20:55:38 -0400 Subject: Fix JNI and expose mute settings to Android --- .../main/java/org/yuzu/yuzu_emu/NativeLibrary.kt | 15 ++ .../yuzu/yuzu_emu/activities/EmulationActivity.kt | 43 +++--- src/android/app/src/main/jni/CMakeLists.txt | 1 - src/android/app/src/main/jni/native.cpp | 150 ++++++++----------- src/android/app/src/main/jni/native.h | 165 --------------------- .../app/src/main/res/drawable/ic_pip_audio.xml | 9 -- .../app/src/main/res/drawable/ic_pip_sound.xml | 9 ++ src/android/app/src/main/res/values/strings.xml | 2 +- 8 files changed, 108 insertions(+), 286 deletions(-) delete mode 100644 src/android/app/src/main/jni/native.h delete mode 100644 src/android/app/src/main/res/drawable/ic_pip_audio.xml create mode 100644 src/android/app/src/main/res/drawable/ic_pip_sound.xml (limited to 'src') diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt index f860cdd4b..6a4e07046 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt @@ -313,6 +313,21 @@ object NativeLibrary { */ external fun isPaused(): Boolean + /** + * Mutes emulation sound + */ + external fun muteAudio(): Boolean + + /** + * Unmutes emulation sound + */ + external fun unMuteAudio(): Boolean + + /** + * Returns true if emulation audio is muted. + */ + external fun isMuted(): Boolean + /** * Returns the performance stats for the current game */ diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt index 8a071f4da..b77c21380 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt @@ -64,9 +64,7 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { private val actionPause = "ACTION_EMULATOR_PAUSE" private val actionPlay = "ACTION_EMULATOR_PLAY" private val actionMute = "ACTION_EMULATOR_MUTE" - private val actionAudio = "ACTION_EMULATOR_AUDIO" - private var isAudioMuted = false - private var userAudio = IntSetting.AUDIO_VOLUME.int + private val actionSound = "ACTION_EMULATOR_SOUND" private val settingsViewModel: SettingsViewModel by viewModels() @@ -309,21 +307,21 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { pictureInPictureActions.add(pauseRemoteAction) } - if (isAudioMuted) { - val audioIcon = Icon.createWithResource(this@EmulationActivity, R.drawable.ic_pip_audio) - val audioPendingIntent = PendingIntent.getBroadcast( + if (NativeLibrary.isMuted()) { + val soundIcon = Icon.createWithResource(this@EmulationActivity, R.drawable.ic_pip_sound) + val soundPendingIntent = PendingIntent.getBroadcast( this@EmulationActivity, - R.drawable.ic_pip_audio, - Intent(actionAudio), + R.drawable.ic_pip_sound, + Intent(actionSound), pendingFlags ) - val audioRemoteAction = RemoteAction( - audioIcon, - getString(R.string.audio), - getString(R.string.audio), - audioPendingIntent + val soundRemoteAction = RemoteAction( + soundIcon, + getString(R.string.sound), + getString(R.string.sound), + soundPendingIntent ) - pictureInPictureActions.add(audioRemoteAction) + pictureInPictureActions.add(soundRemoteAction) } else { val muteIcon = Icon.createWithResource(this@EmulationActivity, R.drawable.ic_pip_mute) val mutePendingIntent = PendingIntent.getBroadcast( @@ -362,17 +360,10 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { } else if (intent.action == actionPause) { if (!NativeLibrary.isPaused()) NativeLibrary.pauseEmulation() } - if (intent.action == actionAudio) { - if (isAudioMuted) { - IntSetting.AUDIO_VOLUME.int = userAudio - isAudioMuted = false - } + if (intent.action == actionSound) { + if (NativeLibrary.isMuted()) NativeLibrary.unMuteAudio() } else if (intent.action == actionMute) { - if (!isAudioMuted) { - isAudioMuted = true - userAudio = IntSetting.AUDIO_VOLUME.int - IntSetting.AUDIO_VOLUME.int = 0 - } + if (!NativeLibrary.isMuted()) NativeLibrary.muteAudio() } buildPictureInPictureParams() } @@ -387,6 +378,8 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { IntentFilter().apply { addAction(actionPause) addAction(actionPlay) + addAction(actionMute) + addAction(actionSound) }.also { registerReceiver(pictureInPictureReceiver, it) } @@ -395,6 +388,8 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { unregisterReceiver(pictureInPictureReceiver) } catch (ignored: Exception) { } + // Always resume audio, since there is no UI button + if (NativeLibrary.isMuted()) NativeLibrary.unMuteAudio() } } diff --git a/src/android/app/src/main/jni/CMakeLists.txt b/src/android/app/src/main/jni/CMakeLists.txt index 041781577..e2ed08e9f 100644 --- a/src/android/app/src/main/jni/CMakeLists.txt +++ b/src/android/app/src/main/jni/CMakeLists.txt @@ -14,7 +14,6 @@ add_library(yuzu-android SHARED id_cache.cpp id_cache.h native.cpp - native.h ) set_property(TARGET yuzu-android PROPERTY IMPORTED_LOCATION ${FFmpeg_LIBRARY_DIR}) diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp index 632aa50b3..07c2a7850 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include "common/detached_tasks.h" #include "common/dynamic_library.h" @@ -526,35 +527,32 @@ static Core::SystemResultStatus RunEmulation(const std::string& filepath) { extern "C" { -void Java_org_yuzu_yuzu_1emu_NativeLibrary_surfaceChanged(JNIEnv* env, - [[maybe_unused]] jclass clazz, - jobject surf) { +void Java_org_yuzu_yuzu_1emu_NativeLibrary_surfaceChanged(JNIEnv* env, jclass clazz, jobject surf) { EmulationSession::GetInstance().SetNativeWindow(ANativeWindow_fromSurface(env, surf)); EmulationSession::GetInstance().SurfaceChanged(); } -void Java_org_yuzu_yuzu_1emu_NativeLibrary_surfaceDestroyed(JNIEnv* env, - [[maybe_unused]] jclass clazz) { +void Java_org_yuzu_yuzu_1emu_NativeLibrary_surfaceDestroyed(JNIEnv* env, jclass clazz) { ANativeWindow_release(EmulationSession::GetInstance().NativeWindow()); EmulationSession::GetInstance().SetNativeWindow(nullptr); EmulationSession::GetInstance().SurfaceChanged(); } -void Java_org_yuzu_yuzu_1emu_NativeLibrary_setAppDirectory(JNIEnv* env, - [[maybe_unused]] jclass clazz, +void Java_org_yuzu_yuzu_1emu_NativeLibrary_setAppDirectory(JNIEnv* env, jclass clazz, jstring j_directory) { Common::FS::SetAppDirectory(GetJString(env, j_directory)); } -int Java_org_yuzu_yuzu_1emu_NativeLibrary_installFileToNand(JNIEnv* env, - [[maybe_unused]] jclass clazz, +int Java_org_yuzu_yuzu_1emu_NativeLibrary_installFileToNand(JNIEnv* env, jclass clazz, jstring j_file) { return EmulationSession::GetInstance().InstallFileToNand(GetJString(env, j_file)); } -void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeGpuDriver( - JNIEnv* env, [[maybe_unused]] jclass clazz, jstring hook_lib_dir, jstring custom_driver_dir, - jstring custom_driver_name, jstring file_redirect_dir) { +void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeGpuDriver(JNIEnv* env, jclass clazz, + jstring hook_lib_dir, + jstring custom_driver_dir, + jstring custom_driver_name, + jstring file_redirect_dir) { EmulationSession::GetInstance().InitializeGpuDriver( GetJString(env, hook_lib_dir), GetJString(env, custom_driver_dir), GetJString(env, custom_driver_name), GetJString(env, file_redirect_dir)); @@ -571,7 +569,7 @@ void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeGpuDriver( } jboolean JNICALL Java_org_yuzu_yuzu_1emu_utils_GpuDriverHelper_supportsCustomDriverLoading( - [[maybe_unused]] JNIEnv* env, [[maybe_unused]] jobject instance) { + JNIEnv* env, [[maybe_unused]] jobject instance) { #ifdef ARCHITECTURE_arm64 // If the KGSL device exists custom drivers can be loaded using adrenotools return SupportsCustomDriver(); @@ -580,49 +578,52 @@ jboolean JNICALL Java_org_yuzu_yuzu_1emu_utils_GpuDriverHelper_supportsCustomDri #endif } -jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_reloadKeys(JNIEnv* env, - [[maybe_unused]] jclass clazz) { +jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_reloadKeys(JNIEnv* env, jclass clazz) { Core::Crypto::KeyManager::Instance().ReloadKeys(); return static_cast(Core::Crypto::KeyManager::Instance().AreKeysLoaded()); } -void Java_org_yuzu_yuzu_1emu_NativeLibrary_unPauseEmulation([[maybe_unused]] JNIEnv* env, - [[maybe_unused]] jclass clazz) { +void Java_org_yuzu_yuzu_1emu_NativeLibrary_unPauseEmulation(JNIEnv* env, jclass clazz) { EmulationSession::GetInstance().UnPauseEmulation(); } -void Java_org_yuzu_yuzu_1emu_NativeLibrary_pauseEmulation([[maybe_unused]] JNIEnv* env, - [[maybe_unused]] jclass clazz) { +void Java_org_yuzu_yuzu_1emu_NativeLibrary_pauseEmulation(JNIEnv* env, jclass clazz) { EmulationSession::GetInstance().PauseEmulation(); } -void Java_org_yuzu_yuzu_1emu_NativeLibrary_stopEmulation([[maybe_unused]] JNIEnv* env, - [[maybe_unused]] jclass clazz) { +void Java_org_yuzu_yuzu_1emu_NativeLibrary_stopEmulation(JNIEnv* env, jclass clazz) { EmulationSession::GetInstance().HaltEmulation(); } -void Java_org_yuzu_yuzu_1emu_NativeLibrary_resetRomMetadata([[maybe_unused]] JNIEnv* env, - [[maybe_unused]] jclass clazz) { +void Java_org_yuzu_yuzu_1emu_NativeLibrary_resetRomMetadata(JNIEnv* env, jclass clazz) { EmulationSession::GetInstance().ResetRomMetadata(); } -jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isRunning([[maybe_unused]] JNIEnv* env, - [[maybe_unused]] jclass clazz) { +jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isRunning(JNIEnv* env, jclass clazz) { return static_cast(EmulationSession::GetInstance().IsRunning()); } -jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isPaused([[maybe_unused]] JNIEnv* env, - [[maybe_unused]] jclass clazz) { +jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isPaused(JNIEnv* env, jclass clazz) { return static_cast(EmulationSession::GetInstance().IsPaused()); } -jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isHandheldOnly([[maybe_unused]] JNIEnv* env, - [[maybe_unused]] jclass clazz) { +void Java_org_yuzu_yuzu_1emu_NativeLibrary_muteAduio(JNIEnv* env, jclass clazz) { + Settings::values.audio_muted = true; +} + +void Java_org_yuzu_yuzu_1emu_NativeLibrary_unMuteAudio(JNIEnv* env, jclass clazz) { + Settings::values.audio_muted = false; +} + +jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isMuted(JNIEnv* env, jclass clazz) { + return static_cast(Settings::values.audio_muted.GetValue()); +} + +jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isHandheldOnly(JNIEnv* env, jclass clazz) { return EmulationSession::GetInstance().IsHandheldOnly(); } -jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_setDeviceType([[maybe_unused]] JNIEnv* env, - [[maybe_unused]] jclass clazz, +jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_setDeviceType(JNIEnv* env, jclass clazz, jint j_device, jint j_type) { if (EmulationSession::GetInstance().IsRunning()) { EmulationSession::GetInstance().SetDeviceType(j_device, j_type); @@ -630,8 +631,7 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_setDeviceType([[maybe_unused]] JN return static_cast(true); } -jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadConnectEvent([[maybe_unused]] JNIEnv* env, - [[maybe_unused]] jclass clazz, +jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadConnectEvent(JNIEnv* env, jclass clazz, jint j_device) { if (EmulationSession::GetInstance().IsRunning()) { EmulationSession::GetInstance().OnGamepadConnectEvent(j_device); @@ -639,15 +639,14 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadConnectEvent([[maybe_unu return static_cast(true); } -jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadDisconnectEvent( - [[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, jint j_device) { +jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadDisconnectEvent(JNIEnv* env, jclass clazz, + jint j_device) { if (EmulationSession::GetInstance().IsRunning()) { EmulationSession::GetInstance().OnGamepadDisconnectEvent(j_device); } return static_cast(true); } -jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadButtonEvent([[maybe_unused]] JNIEnv* env, - [[maybe_unused]] jclass clazz, +jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadButtonEvent(JNIEnv* env, jclass clazz, [[maybe_unused]] jint j_device, jint j_button, jint action) { if (EmulationSession::GetInstance().IsRunning()) { @@ -659,8 +658,7 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadButtonEvent([[maybe_unus return static_cast(true); } -jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadJoystickEvent([[maybe_unused]] JNIEnv* env, - [[maybe_unused]] jclass clazz, +jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadJoystickEvent(JNIEnv* env, jclass clazz, jint j_device, jint stick_id, jfloat x, jfloat y) { if (EmulationSession::GetInstance().IsRunning()) { @@ -670,9 +668,8 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadJoystickEvent([[maybe_un } jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadMotionEvent( - [[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, jint j_device, - jlong delta_timestamp, jfloat gyro_x, jfloat gyro_y, jfloat gyro_z, jfloat accel_x, - jfloat accel_y, jfloat accel_z) { + JNIEnv* env, jclass clazz, jint j_device, jlong delta_timestamp, jfloat gyro_x, jfloat gyro_y, + jfloat gyro_z, jfloat accel_x, jfloat accel_y, jfloat accel_z) { if (EmulationSession::GetInstance().IsRunning()) { EmulationSession::GetInstance().Window().OnGamepadMotionEvent( j_device, delta_timestamp, gyro_x, gyro_y, gyro_z, accel_x, accel_y, accel_z); @@ -680,8 +677,7 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadMotionEvent( return static_cast(true); } -jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onReadNfcTag([[maybe_unused]] JNIEnv* env, - [[maybe_unused]] jclass clazz, +jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onReadNfcTag(JNIEnv* env, jclass clazz, jbyteArray j_data) { jboolean isCopy{false}; std::span data(reinterpret_cast(env->GetByteArrayElements(j_data, &isCopy)), @@ -693,39 +689,34 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onReadNfcTag([[maybe_unused]] JNI return static_cast(true); } -jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onRemoveNfcTag([[maybe_unused]] JNIEnv* env, - [[maybe_unused]] jclass clazz) { +jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onRemoveNfcTag(JNIEnv* env, jclass clazz) { if (EmulationSession::GetInstance().IsRunning()) { EmulationSession::GetInstance().Window().OnRemoveNfcTag(); } return static_cast(true); } -void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchPressed([[maybe_unused]] JNIEnv* env, - [[maybe_unused]] jclass clazz, jint id, +void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchPressed(JNIEnv* env, jclass clazz, jint id, jfloat x, jfloat y) { if (EmulationSession::GetInstance().IsRunning()) { EmulationSession::GetInstance().Window().OnTouchPressed(id, x, y); } } -void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchMoved([[maybe_unused]] JNIEnv* env, - [[maybe_unused]] jclass clazz, jint id, +void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchMoved(JNIEnv* env, jclass clazz, jint id, jfloat x, jfloat y) { if (EmulationSession::GetInstance().IsRunning()) { EmulationSession::GetInstance().Window().OnTouchMoved(id, x, y); } } -void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchReleased([[maybe_unused]] JNIEnv* env, - [[maybe_unused]] jclass clazz, jint id) { +void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchReleased(JNIEnv* env, jclass clazz, jint id) { if (EmulationSession::GetInstance().IsRunning()) { EmulationSession::GetInstance().Window().OnTouchReleased(id); } } -jbyteArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getIcon([[maybe_unused]] JNIEnv* env, - [[maybe_unused]] jclass clazz, +jbyteArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getIcon(JNIEnv* env, jclass clazz, [[maybe_unused]] jstring j_filename) { auto icon_data = EmulationSession::GetInstance().GetRomIcon(GetJString(env, j_filename)); jbyteArray icon = env->NewByteArray(static_cast(icon_data.size())); @@ -734,67 +725,58 @@ jbyteArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getIcon([[maybe_unused]] JNIEnv return icon; } -jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getTitle([[maybe_unused]] JNIEnv* env, - [[maybe_unused]] jclass clazz, +jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getTitle(JNIEnv* env, jclass clazz, [[maybe_unused]] jstring j_filename) { auto title = EmulationSession::GetInstance().GetRomTitle(GetJString(env, j_filename)); return env->NewStringUTF(title.c_str()); } -jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getDescription([[maybe_unused]] JNIEnv* env, - [[maybe_unused]] jclass clazz, +jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getDescription(JNIEnv* env, jclass clazz, jstring j_filename) { return j_filename; } -jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getGameId([[maybe_unused]] JNIEnv* env, - [[maybe_unused]] jclass clazz, +jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getGameId(JNIEnv* env, jclass clazz, jstring j_filename) { return j_filename; } -jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getRegions([[maybe_unused]] JNIEnv* env, - [[maybe_unused]] jclass clazz, +jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getRegions(JNIEnv* env, jclass clazz, [[maybe_unused]] jstring j_filename) { return env->NewStringUTF(""); } -jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getCompany([[maybe_unused]] JNIEnv* env, - [[maybe_unused]] jclass clazz, +jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getCompany(JNIEnv* env, jclass clazz, [[maybe_unused]] jstring j_filename) { return env->NewStringUTF(""); } -jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isHomebrew([[maybe_unused]] JNIEnv* env, - [[maybe_unused]] jclass clazz, +jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isHomebrew(JNIEnv* env, jclass clazz, [[maybe_unused]] jstring j_filename) { return EmulationSession::GetInstance().GetIsHomebrew(GetJString(env, j_filename)); } void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeEmulation - [[maybe_unused]] (JNIEnv* env, [[maybe_unused]] jclass clazz) { + [[maybe_unused]] (JNIEnv* env, jclass clazz) { // Create the default config.ini. Config{}; // Initialize the emulated system. EmulationSession::GetInstance().System().Initialize(); } -jint Java_org_yuzu_yuzu_1emu_NativeLibrary_defaultCPUCore([[maybe_unused]] JNIEnv* env, - [[maybe_unused]] jclass clazz) { +jint Java_org_yuzu_yuzu_1emu_NativeLibrary_defaultCPUCore(JNIEnv* env, jclass clazz) { return {}; } void Java_org_yuzu_yuzu_1emu_NativeLibrary_run__Ljava_lang_String_2Ljava_lang_String_2Z( - [[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, [[maybe_unused]] jstring j_file, + JNIEnv* env, jclass clazz, [[maybe_unused]] jstring j_file, [[maybe_unused]] jstring j_savestate, [[maybe_unused]] jboolean j_delete_savestate) {} -void Java_org_yuzu_yuzu_1emu_NativeLibrary_reloadSettings([[maybe_unused]] JNIEnv* env, - [[maybe_unused]] jclass clazz) { +void Java_org_yuzu_yuzu_1emu_NativeLibrary_reloadSettings(JNIEnv* env, jclass clazz) { Config{}; } -jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getUserSetting([[maybe_unused]] JNIEnv* env, - [[maybe_unused]] jclass clazz, +jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getUserSetting(JNIEnv* env, jclass clazz, jstring j_game_id, jstring j_section, jstring j_key) { std::string_view game_id = env->GetStringUTFChars(j_game_id, 0); @@ -808,8 +790,7 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getUserSetting([[maybe_unused]] JN return env->NewStringUTF(""); } -void Java_org_yuzu_yuzu_1emu_NativeLibrary_setUserSetting([[maybe_unused]] JNIEnv* env, - [[maybe_unused]] jclass clazz, +void Java_org_yuzu_yuzu_1emu_NativeLibrary_setUserSetting(JNIEnv* env, jclass clazz, jstring j_game_id, jstring j_section, jstring j_key, jstring j_value) { std::string_view game_id = env->GetStringUTFChars(j_game_id, 0); @@ -823,16 +804,14 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_setUserSetting([[maybe_unused]] JNIEn env->ReleaseStringUTFChars(j_value, value.data()); } -void Java_org_yuzu_yuzu_1emu_NativeLibrary_initGameIni([[maybe_unused]] JNIEnv* env, - [[maybe_unused]] jclass clazz, +void Java_org_yuzu_yuzu_1emu_NativeLibrary_initGameIni(JNIEnv* env, jclass clazz, jstring j_game_id) { std::string_view game_id = env->GetStringUTFChars(j_game_id, 0); env->ReleaseStringUTFChars(j_game_id, game_id.data()); } -jdoubleArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getPerfStats([[maybe_unused]] JNIEnv* env, - [[maybe_unused]] jclass clazz) { +jdoubleArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getPerfStats(JNIEnv* env, jclass clazz) { jdoubleArray j_stats = env->NewDoubleArray(4); if (EmulationSession::GetInstance().IsRunning()) { @@ -848,11 +827,11 @@ jdoubleArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getPerfStats([[maybe_unused]] return j_stats; } -void Java_org_yuzu_yuzu_1emu_utils_DirectoryInitialization_setSysDirectory( - [[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, jstring j_path) {} +void Java_org_yuzu_yuzu_1emu_utils_DirectoryInitialization_setSysDirectory(JNIEnv* env, + jclass clazz, + jstring j_path) {} -void Java_org_yuzu_yuzu_1emu_NativeLibrary_run__Ljava_lang_String_2([[maybe_unused]] JNIEnv* env, - [[maybe_unused]] jclass clazz, +void Java_org_yuzu_yuzu_1emu_NativeLibrary_run__Ljava_lang_String_2(JNIEnv* env, jclass clazz, jstring j_path) { const std::string path = GetJString(env, j_path); @@ -863,8 +842,7 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_run__Ljava_lang_String_2([[maybe_unus } } -void Java_org_yuzu_yuzu_1emu_NativeLibrary_logDeviceInfo([[maybe_unused]] JNIEnv* env, - [[maybe_unused]] jclass clazz) { +void Java_org_yuzu_yuzu_1emu_NativeLibrary_logDeviceInfo(JNIEnv* env, jclass clazz) { LOG_INFO(Frontend, "yuzu Version: {}-{}", Common::g_scm_branch, Common::g_scm_desc); LOG_INFO(Frontend, "Host OS: Android API level {}", android_get_device_api_level()); } diff --git a/src/android/app/src/main/jni/native.h b/src/android/app/src/main/jni/native.h deleted file mode 100644 index 24dcbbcb8..000000000 --- a/src/android/app/src/main/jni/native.h +++ /dev/null @@ -1,165 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include - -// Function calls from the Java side -#ifdef __cplusplus -extern "C" { -#endif - -JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_UnPauseEmulation(JNIEnv* env, - jclass clazz); - -JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_PauseEmulation(JNIEnv* env, - jclass clazz); - -JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_StopEmulation(JNIEnv* env, - jclass clazz); - -JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_ResetRomMetadata(JNIEnv* env, - jclass clazz); - -JNIEXPORT jboolean JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_IsRunning(JNIEnv* env, - jclass clazz); - -JNIEXPORT jboolean JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_isHandheldOnly(JNIEnv* env, - jclass clazz); - -JNIEXPORT jboolean JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_setDeviceType(JNIEnv* env, - jclass clazz, - jstring j_device, - jstring j_type); - -JNIEXPORT jboolean JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadConnectEvent( - JNIEnv* env, jclass clazz, jstring j_device); - -JNIEXPORT jboolean JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadDisconnectEvent( - JNIEnv* env, jclass clazz, jstring j_device); - -JNIEXPORT jboolean JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadEvent( - JNIEnv* env, jclass clazz, jstring j_device, jint j_button, jint action); - -JNIEXPORT jboolean JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadMoveEvent( - JNIEnv* env, jclass clazz, jstring j_device, jint axis, jfloat x, jfloat y); - -JNIEXPORT jboolean JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadAxisEvent( - JNIEnv* env, jclass clazz, jstring j_device, jint axis_id, jfloat axis_val); - -JNIEXPORT jboolean JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_onReadNfcTag(JNIEnv* env, - jclass clazz, - jbyteArray j_data); - -JNIEXPORT jboolean JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_onRemoveNfcTag(JNIEnv* env, - jclass clazz); - -JNIEXPORT jboolean JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchEvent(JNIEnv* env, - jclass clazz, - jfloat x, jfloat y, - jboolean pressed); - -JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchMoved(JNIEnv* env, jclass clazz, - jfloat x, jfloat y); - -JNIEXPORT jbyteArray JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_GetIcon(JNIEnv* env, - jclass clazz, - jstring j_file); - -JNIEXPORT jstring JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_GetTitle(JNIEnv* env, jclass clazz, - jstring j_filename); - -JNIEXPORT jstring JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_GetDescription(JNIEnv* env, - jclass clazz, - jstring j_filename); - -JNIEXPORT jstring JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_GetGameId(JNIEnv* env, jclass clazz, - jstring j_filename); - -JNIEXPORT jstring JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_GetRegions(JNIEnv* env, - jclass clazz, - jstring j_filename); - -JNIEXPORT jstring JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_GetCompany(JNIEnv* env, - jclass clazz, - jstring j_filename); - -JNIEXPORT jstring JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_GetGitRevision(JNIEnv* env, - jclass clazz); - -JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_SetAppDirectory(JNIEnv* env, - jclass clazz, - jstring j_directory); - -JNIEXPORT void JNICALL -Java_org_yuzu_yuzu_1emu_NativeLibrary_Java_org_yuzu_yuzu_1emu_NativeLibrary_InitializeGpuDriver( - JNIEnv* env, jclass clazz, jstring hook_lib_dir, jstring custom_driver_dir, - jstring custom_driver_name, jstring file_redirect_dir); - -JNIEXPORT jboolean JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_ReloadKeys(JNIEnv* env, - jclass clazz); - -JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_utils_DirectoryInitialization_SetSysDirectory( - JNIEnv* env, jclass clazz, jstring path_); - -JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_SetSysDirectory(JNIEnv* env, - jclass clazz, - jstring path); - -JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_InitializeEmulation(JNIEnv* env, - jclass clazz); - -JNIEXPORT jint JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_DefaultCPUCore(JNIEnv* env, - jclass clazz); -JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_SetProfiling(JNIEnv* env, jclass clazz, - jboolean enable); - -JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_WriteProfileResults(JNIEnv* env, - jclass clazz); - -JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_NotifyOrientationChange( - JNIEnv* env, jclass clazz, jint layout_option, jint rotation); - -JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_Run__Ljava_lang_String_2( - JNIEnv* env, jclass clazz, jstring j_path); - -JNIEXPORT void JNICALL -Java_org_yuzu_yuzu_1emu_NativeLibrary_Run__Ljava_lang_String_2Ljava_lang_String_2Z( - JNIEnv* env, jclass clazz, jstring j_file, jstring j_savestate, jboolean j_delete_savestate); - -JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_SurfaceChanged(JNIEnv* env, - jclass clazz, - jobject surf); - -JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_SurfaceDestroyed(JNIEnv* env, - jclass clazz); - -JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_InitGameIni(JNIEnv* env, jclass clazz, - jstring j_game_id); - -JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_ReloadSettings(JNIEnv* env, - jclass clazz); - -JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_SetUserSetting( - JNIEnv* env, jclass clazz, jstring j_game_id, jstring j_section, jstring j_key, - jstring j_value); - -JNIEXPORT jstring JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_GetUserSetting( - JNIEnv* env, jclass clazz, jstring game_id, jstring section, jstring key); - -JNIEXPORT jdoubleArray JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_GetPerfStats(JNIEnv* env, - jclass clazz); - -JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_LogDeviceInfo(JNIEnv* env, - jclass clazz); - -JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_SubmitInlineKeyboardText( - JNIEnv* env, jclass clazz, jstring j_text); - -JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_SubmitInlineKeyboardInput( - JNIEnv* env, jclass clazz, jint j_key_code); - -#ifdef __cplusplus -} -#endif diff --git a/src/android/app/src/main/res/drawable/ic_pip_audio.xml b/src/android/app/src/main/res/drawable/ic_pip_audio.xml deleted file mode 100644 index f7ed0862e..000000000 --- a/src/android/app/src/main/res/drawable/ic_pip_audio.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/src/android/app/src/main/res/drawable/ic_pip_sound.xml b/src/android/app/src/main/res/drawable/ic_pip_sound.xml new file mode 100644 index 000000000..f7ed0862e --- /dev/null +++ b/src/android/app/src/main/res/drawable/ic_pip_sound.xml @@ -0,0 +1,9 @@ + + + diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index d4f089c7f..eb1d83693 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -388,7 +388,7 @@ Pause Play Mute - Audio + Sound Licenses -- cgit v1.2.3 From cfc6ef42d965ac9391080876fc25e5acb1d3af77 Mon Sep 17 00:00:00 2001 From: Abandoned Cart Date: Sat, 17 Jun 2023 11:24:19 -0400 Subject: android: Refactor native and corresponding variables --- .../main/java/org/yuzu/yuzu_emu/NativeLibrary.kt | 4 +-- .../yuzu/yuzu_emu/activities/EmulationActivity.kt | 35 ++++++++++++---------- .../yuzu/yuzu_emu/fragments/EmulationFragment.kt | 2 +- src/android/app/src/main/jni/native.cpp | 4 +-- .../app/src/main/res/drawable/ic_pip_sound.xml | 9 ------ .../app/src/main/res/drawable/ic_pip_unmute.xml | 9 ++++++ src/android/app/src/main/res/values/strings.xml | 2 +- 7 files changed, 34 insertions(+), 31 deletions(-) delete mode 100644 src/android/app/src/main/res/drawable/ic_pip_sound.xml create mode 100644 src/android/app/src/main/res/drawable/ic_pip_unmute.xml (limited to 'src') diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt index 6a4e07046..9c32e044c 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt @@ -286,7 +286,7 @@ object NativeLibrary { /** * Unpauses emulation from a paused state. */ - external fun unPauseEmulation() + external fun unpauseEmulation() /** * Pauses emulation. @@ -321,7 +321,7 @@ object NativeLibrary { /** * Unmutes emulation sound */ - external fun unMuteAudio(): Boolean + external fun unmuteAudio(): Boolean /** * Returns true if emulation audio is muted. diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt index b77c21380..2b63388cc 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt @@ -64,7 +64,7 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { private val actionPause = "ACTION_EMULATOR_PAUSE" private val actionPlay = "ACTION_EMULATOR_PLAY" private val actionMute = "ACTION_EMULATOR_MUTE" - private val actionSound = "ACTION_EMULATOR_SOUND" + private val actionUnmute = "ACTION_EMULATOR_UNMUTE" private val settingsViewModel: SettingsViewModel by viewModels() @@ -308,20 +308,23 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { } if (NativeLibrary.isMuted()) { - val soundIcon = Icon.createWithResource(this@EmulationActivity, R.drawable.ic_pip_sound) - val soundPendingIntent = PendingIntent.getBroadcast( + val unmuteIcon = Icon.createWithResource( this@EmulationActivity, - R.drawable.ic_pip_sound, - Intent(actionSound), + R.drawable.ic_pip_unmute + ) + val unmutePendingIntent = PendingIntent.getBroadcast( + this@EmulationActivity, + R.drawable.ic_pip_unmute, + Intent(actionUnmute), pendingFlags ) - val soundRemoteAction = RemoteAction( - soundIcon, - getString(R.string.sound), - getString(R.string.sound), - soundPendingIntent + val unmuteRemoteAction = RemoteAction( + unmuteIcon, + getString(R.string.unmute), + getString(R.string.unmute), + unmutePendingIntent ) - pictureInPictureActions.add(soundRemoteAction) + pictureInPictureActions.add(unmuteRemoteAction) } else { val muteIcon = Icon.createWithResource(this@EmulationActivity, R.drawable.ic_pip_mute) val mutePendingIntent = PendingIntent.getBroadcast( @@ -356,12 +359,12 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { private var pictureInPictureReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent) { if (intent.action == actionPlay) { - if (NativeLibrary.isPaused()) NativeLibrary.unPauseEmulation() + if (NativeLibrary.isPaused()) NativeLibrary.unpauseEmulation() } else if (intent.action == actionPause) { if (!NativeLibrary.isPaused()) NativeLibrary.pauseEmulation() } - if (intent.action == actionSound) { - if (NativeLibrary.isMuted()) NativeLibrary.unMuteAudio() + if (intent.action == actionUnmute) { + if (NativeLibrary.isMuted()) NativeLibrary.unmuteAudio() } else if (intent.action == actionMute) { if (!NativeLibrary.isMuted()) NativeLibrary.muteAudio() } @@ -379,7 +382,7 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { addAction(actionPause) addAction(actionPlay) addAction(actionMute) - addAction(actionSound) + addAction(actionUnmute) }.also { registerReceiver(pictureInPictureReceiver, it) } @@ -389,7 +392,7 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { } catch (ignored: Exception) { } // Always resume audio, since there is no UI button - if (NativeLibrary.isMuted()) NativeLibrary.unMuteAudio() + if (NativeLibrary.isMuted()) NativeLibrary.unmuteAudio() } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt index 4643418c1..09976db62 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt @@ -714,7 +714,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { State.PAUSED -> { Log.debug("[EmulationFragment] Resuming emulation.") NativeLibrary.surfaceChanged(surface) - NativeLibrary.unPauseEmulation() + NativeLibrary.unpauseEmulation() } else -> Log.debug("[EmulationFragment] Bug, run called while already running.") diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp index 07c2a7850..6688416d6 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp @@ -583,7 +583,7 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_reloadKeys(JNIEnv* env, jclass cl return static_cast(Core::Crypto::KeyManager::Instance().AreKeysLoaded()); } -void Java_org_yuzu_yuzu_1emu_NativeLibrary_unPauseEmulation(JNIEnv* env, jclass clazz) { +void Java_org_yuzu_yuzu_1emu_NativeLibrary_unpauseEmulation(JNIEnv* env, jclass clazz) { EmulationSession::GetInstance().UnPauseEmulation(); } @@ -611,7 +611,7 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_muteAduio(JNIEnv* env, jclass clazz) Settings::values.audio_muted = true; } -void Java_org_yuzu_yuzu_1emu_NativeLibrary_unMuteAudio(JNIEnv* env, jclass clazz) { +void Java_org_yuzu_yuzu_1emu_NativeLibrary_unmuteAudio(JNIEnv* env, jclass clazz) { Settings::values.audio_muted = false; } diff --git a/src/android/app/src/main/res/drawable/ic_pip_sound.xml b/src/android/app/src/main/res/drawable/ic_pip_sound.xml deleted file mode 100644 index f7ed0862e..000000000 --- a/src/android/app/src/main/res/drawable/ic_pip_sound.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/src/android/app/src/main/res/drawable/ic_pip_unmute.xml b/src/android/app/src/main/res/drawable/ic_pip_unmute.xml new file mode 100644 index 000000000..f7ed0862e --- /dev/null +++ b/src/android/app/src/main/res/drawable/ic_pip_unmute.xml @@ -0,0 +1,9 @@ + + + diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index eb1d83693..381dfbc3b 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -388,7 +388,7 @@ Pause Play Mute - Sound + Unmute Licenses -- cgit v1.2.3 From 699e78c666188a06ef218a54e0d85023f3fa93fc Mon Sep 17 00:00:00 2001 From: Abandoned Cart Date: Fri, 16 Jun 2023 13:26:24 -0400 Subject: android: Add a notice when RAM inadequate --- .../yuzu/yuzu_emu/activities/EmulationActivity.kt | 17 ++++++- .../java/org/yuzu/yuzu_emu/utils/MemoryUtil.kt | 58 ++++++++++++++++++++++ src/android/app/src/main/res/values/strings.xml | 1 + 3 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/MemoryUtil.kt (limited to 'src') diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt index f0a6753a9..75d994c9c 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt @@ -27,13 +27,13 @@ import android.view.MotionEvent import android.view.Surface import android.view.View import android.view.inputmethod.InputMethodManager +import android.widget.Toast import androidx.activity.viewModels import androidx.appcompat.app.AppCompatActivity import androidx.core.view.WindowCompat import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsControllerCompat import androidx.navigation.fragment.NavHostFragment -import kotlin.math.roundToInt import org.yuzu.yuzu_emu.NativeLibrary import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.databinding.ActivityEmulationBinding @@ -44,8 +44,10 @@ import org.yuzu.yuzu_emu.model.Game import org.yuzu.yuzu_emu.utils.ControllerMappingHelper import org.yuzu.yuzu_emu.utils.ForegroundService import org.yuzu.yuzu_emu.utils.InputHandler +import org.yuzu.yuzu_emu.utils.MemoryUtil import org.yuzu.yuzu_emu.utils.NfcReader import org.yuzu.yuzu_emu.utils.ThemeHelper +import kotlin.math.roundToInt class EmulationActivity : AppCompatActivity(), SensorEventListener { private lateinit var binding: ActivityEmulationBinding @@ -102,6 +104,19 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { inputHandler = InputHandler() inputHandler.initialize() + val memoryUtil = MemoryUtil(this) + if (memoryUtil.isLessThan(8, MemoryUtil.Gb)) { + Toast.makeText( + this, + getString( + R.string.device_memory_inadequate_description, + memoryUtil.getDeviceRAM(), + "8 GB" + ), + Toast.LENGTH_LONG + ).show() + } + // Start a foreground service to prevent the app from getting killed in the background val startIntent = Intent(this, ForegroundService::class.java) startForegroundService(startIntent) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/MemoryUtil.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/MemoryUtil.kt new file mode 100644 index 000000000..390767e47 --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/MemoryUtil.kt @@ -0,0 +1,58 @@ +// SPDX-FileCopyrightText: 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.yuzu.yuzu_emu.utils + +import android.app.ActivityManager +import android.content.Context +import java.util.Locale + +class MemoryUtil(context: Context) { + + private val Long.floatForm: String + get() = String.format(Locale.ROOT, "%.2f", this.toDouble()) + + private fun bytesToSizeUnit(size: Long): String { + return when { + size < Kb -> size.floatForm + " byte" + size < Mb -> (size / Kb).floatForm + " KB" + size < Gb -> (size / Mb).floatForm + " MB" + size < Tb -> (size / Gb).floatForm + " GB" + size < Pb -> (size / Tb).floatForm + " TB" + size < Eb -> (size / Pb).floatForm + " Pb" + else -> (size / Eb).floatForm + " Eb" + } + } + + private val totalMemory = + with(context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager) { + val memInfo = ActivityManager.MemoryInfo() + getMemoryInfo(memInfo) + memInfo.totalMem + } + + fun isLessThan(minimum: Int, size: Long): Boolean { + return when (size) { + Kb -> totalMemory < Mb && totalMemory < minimum + Mb -> totalMemory < Gb && (totalMemory / Mb) < minimum + Gb -> totalMemory < Tb && (totalMemory / Gb) < minimum + Tb -> totalMemory < Pb && (totalMemory / Tb) < minimum + Pb -> totalMemory < Eb && (totalMemory / Pb) < minimum + Eb -> totalMemory / Eb < minimum + else -> totalMemory < Kb && totalMemory < minimum + } + } + + fun getDeviceRAM(): String { + return bytesToSizeUnit(totalMemory) + } + + companion object { + const val Kb: Long = 1024 + const val Mb = Kb * 1024 + const val Gb = Mb * 1024 + const val Tb = Gb * 1024 + const val Pb = Tb * 1024 + const val Eb = Pb * 1024 + } +} diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index cc1d8c39d..7d37d2bee 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -270,6 +270,7 @@ Fatal Error A fatal error occurred. Check the log for details.\nContinuing emulation may result in crashes and bugs. Turning off this setting will significantly reduce emulation performance! For the best experience, it is recommended that you leave this setting enabled. + Device RAM: %1$s\nRecommended: %2$s Japan -- cgit v1.2.3 From 8b841aa7ba8b1bdcb6e631365c1bdc074867109c Mon Sep 17 00:00:00 2001 From: Abandoned Cart Date: Wed, 21 Jun 2023 15:06:48 -0400 Subject: android: Convert memory sizes to resource --- .../org/yuzu/yuzu_emu/activities/EmulationActivity.kt | 4 ++-- .../src/main/java/org/yuzu/yuzu_emu/utils/MemoryUtil.kt | 17 +++++++++-------- src/android/app/src/main/res/values/strings.xml | 11 ++++++++++- 3 files changed, 21 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt index 75d994c9c..b1771b424 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt @@ -109,9 +109,9 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { Toast.makeText( this, getString( - R.string.device_memory_inadequate_description, + R.string.device_memory_inadequate, memoryUtil.getDeviceRAM(), - "8 GB" + "8 ${getString(R.string.memory_gigabyte)}" ), Toast.LENGTH_LONG ).show() diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/MemoryUtil.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/MemoryUtil.kt index 390767e47..18e5fa0b0 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/MemoryUtil.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/MemoryUtil.kt @@ -5,22 +5,23 @@ package org.yuzu.yuzu_emu.utils import android.app.ActivityManager import android.content.Context +import org.yuzu.yuzu_emu.R import java.util.Locale -class MemoryUtil(context: Context) { +class MemoryUtil(val context: Context) { private val Long.floatForm: String get() = String.format(Locale.ROOT, "%.2f", this.toDouble()) private fun bytesToSizeUnit(size: Long): String { return when { - size < Kb -> size.floatForm + " byte" - size < Mb -> (size / Kb).floatForm + " KB" - size < Gb -> (size / Mb).floatForm + " MB" - size < Tb -> (size / Gb).floatForm + " GB" - size < Pb -> (size / Tb).floatForm + " TB" - size < Eb -> (size / Pb).floatForm + " Pb" - else -> (size / Eb).floatForm + " Eb" + size < Kb -> "${size.floatForm} ${context.getString(R.string.memory_byte)}" + size < Mb -> "${(size / Kb).floatForm} ${context.getString(R.string.memory_kilobyte)}" + size < Gb -> "${(size / Mb).floatForm} ${context.getString(R.string.memory_megabyte)}" + size < Tb -> "${(size / Gb).floatForm} ${context.getString(R.string.memory_gigabyte)}" + size < Pb -> "${(size / Tb).floatForm} ${context.getString(R.string.memory_terabyte)}" + size < Eb -> "${(size / Pb).floatForm} ${context.getString(R.string.memory_petabyte)}" + else -> "${(size / Eb).floatForm} ${context.getString(R.string.memory_exabyte)}" } } diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index 7d37d2bee..85fc682f2 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -270,7 +270,7 @@ Fatal Error A fatal error occurred. Check the log for details.\nContinuing emulation may result in crashes and bugs. Turning off this setting will significantly reduce emulation performance! For the best experience, it is recommended that you leave this setting enabled. - Device RAM: %1$s\nRecommended: %2$s + Device RAM: %1$s\nRecommended: %2$s Japan @@ -301,6 +301,15 @@ Traditional Chinese (正體中文) Brazilian Portuguese (Português do Brasil) + + Byte + KB + MB + GB + TB + PB + EB + Vulkan None -- cgit v1.2.3 From 6c7e284f64dd4f2f02014dd6488924a0343a3292 Mon Sep 17 00:00:00 2001 From: Abandoned Cart Date: Thu, 15 Jun 2023 22:36:03 -0400 Subject: android: Add support for concurrent installs --- .../yuzu_emu/fragments/InstallDialogFragment.kt | 62 +++++++++++ .../java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt | 118 +++++++++++++++------ src/android/app/src/main/res/values/strings.xml | 14 +-- 3 files changed, 154 insertions(+), 40 deletions(-) create mode 100644 src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/InstallDialogFragment.kt (limited to 'src') diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/InstallDialogFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/InstallDialogFragment.kt new file mode 100644 index 000000000..d8850f941 --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/InstallDialogFragment.kt @@ -0,0 +1,62 @@ +// SPDX-FileCopyrightText: 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.yuzu.yuzu_emu.fragments + +import android.app.Dialog +import android.content.Intent +import android.net.Uri +import android.os.Bundle +import androidx.fragment.app.DialogFragment +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import org.yuzu.yuzu_emu.R + +class InstallDialogFragment : DialogFragment() { + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + val titleId = requireArguments().getInt(TITLE) + val description = requireArguments().getString(DESCRIPTION) + val helpLinkId = requireArguments().getInt(HELP_LINK) + + val dialog = MaterialAlertDialogBuilder(requireContext()) + .setPositiveButton(R.string.close, null) + .setTitle(titleId) + .setMessage(description) + + if (helpLinkId != 0) { + dialog.setNeutralButton(R.string.learn_more) { _, _ -> + openLink(getString(helpLinkId)) + } + } + + return dialog.show() + } + + private fun openLink(link: String) { + val intent = Intent(Intent.ACTION_VIEW, Uri.parse(link)) + startActivity(intent) + } + + companion object { + const val TAG = "MessageDialogFragment" + + private const val TITLE = "Title" + private const val DESCRIPTION = "Description" + private const val HELP_LINK = "Link" + + fun newInstance( + titleId: Int, + description: String, + helpLinkId: Int = 0 + ): InstallDialogFragment { + val dialog = InstallDialogFragment() + val bundle = Bundle() + bundle.apply { + putInt(TITLE, titleId) + putString(DESCRIPTION, description) + putInt(HELP_LINK, helpLinkId) + } + dialog.arguments = bundle + return dialog + } + } +} diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt index cc1d87f1b..5257d7b36 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt @@ -4,6 +4,7 @@ package org.yuzu.yuzu_emu.ui.main import android.content.Intent +import android.net.Uri import android.os.Bundle import android.view.View import android.view.ViewGroup.MarginLayoutParams @@ -42,6 +43,7 @@ import org.yuzu.yuzu_emu.features.settings.model.SettingsViewModel import org.yuzu.yuzu_emu.features.settings.ui.SettingsActivity import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile import org.yuzu.yuzu_emu.fragments.IndeterminateProgressDialogFragment +import org.yuzu.yuzu_emu.fragments.InstallDialogFragment import org.yuzu.yuzu_emu.fragments.MessageDialogFragment import org.yuzu.yuzu_emu.model.GamesViewModel import org.yuzu.yuzu_emu.model.HomeViewModel @@ -481,62 +483,110 @@ class MainActivity : AppCompatActivity(), ThemeProvider { } } - val installGameUpdate = - registerForActivityResult(ActivityResultContracts.OpenDocument()) { - if (it == null) { - return@registerForActivityResult - } - + val installGameUpdate = registerForActivityResult( + ActivityResultContracts.OpenMultipleDocuments() + ) { documents: List -> + if (documents.isNotEmpty()) { IndeterminateProgressDialogFragment.newInstance( this@MainActivity, R.string.install_game_content ) { - val result = NativeLibrary.installFileToNand(it.toString()) + var installSuccess = 0 + var installOverwrite = 0 + var errorBaseGame = 0 + var errorExtension = 0 + var errorOther = 0 + var errorTotal = 0 lifecycleScope.launch { - withContext(Dispatchers.Main) { - when (result) { + documents.forEach { + when (NativeLibrary.installFileToNand(it.toString())) { NativeLibrary.InstallFileToNandResult.Success -> { - Toast.makeText( - applicationContext, - R.string.install_game_content_success, - Toast.LENGTH_SHORT - ).show() + installSuccess += 1 } NativeLibrary.InstallFileToNandResult.SuccessFileOverwritten -> { - Toast.makeText( - applicationContext, - R.string.install_game_content_success_overwrite, - Toast.LENGTH_SHORT - ).show() + installOverwrite += 1 } NativeLibrary.InstallFileToNandResult.ErrorBaseGame -> { - MessageDialogFragment.newInstance( - R.string.install_game_content_failure, - R.string.install_game_content_failure_base - ).show(supportFragmentManager, MessageDialogFragment.TAG) + errorBaseGame += 1 } NativeLibrary.InstallFileToNandResult.ErrorFilenameExtension -> { - MessageDialogFragment.newInstance( - R.string.install_game_content_failure, - R.string.install_game_content_failure_file_extension, - R.string.install_game_content_help_link - ).show(supportFragmentManager, MessageDialogFragment.TAG) + errorExtension += 1 } else -> { - MessageDialogFragment.newInstance( - R.string.install_game_content_failure, - R.string.install_game_content_failure_description, - R.string.install_game_content_help_link - ).show(supportFragmentManager, MessageDialogFragment.TAG) + errorOther += 1 } } } + withContext(Dispatchers.Main) { + val separator = System.getProperty("line.separator") ?: "\n" + val installResult = StringBuilder() + if (installSuccess > 0) { + installResult.append( + getString( + R.string.install_game_content_success_install, + installSuccess + ) + ) + installResult.append(separator) + } + if (installOverwrite > 0) { + installResult.append( + getString( + R.string.install_game_content_success_overwrite, + installOverwrite + ) + ) + installResult.append(separator) + } + errorTotal = errorBaseGame + errorExtension + errorOther + if (errorTotal > 0) { + installResult.append(separator) + installResult.append( + getString( + R.string.install_game_content_failed_count, + + ) + ) + installResult.append(separator) + if (errorBaseGame > 0) { + installResult.append(separator) + installResult.append( + getString(R.string.install_game_content_failure_base) + ) + installResult.append(separator) + } + if (errorExtension > 0) { + installResult.append(separator) + installResult.append( + getString(R.string.install_game_content_failure_file_extension) + ) + installResult.append(separator) + } + if (errorOther > 0) { + installResult.append( + getString(R.string.install_game_content_failure_description) + ) + installResult.append(separator) + } + InstallDialogFragment.newInstance( + R.string.install_game_content_failure, + installResult.toString().trim(), + R.string.install_game_content_help_link + ).show(supportFragmentManager, MessageDialogFragment.TAG) + } else { + InstallDialogFragment.newInstance( + R.string.install_game_content_success, + installResult.toString().trim(), + ).show(supportFragmentManager, MessageDialogFragment.TAG) + } + } } - return@newInstance result + return@newInstance installSuccess + installOverwrite + errorTotal }.show(supportFragmentManager, IndeterminateProgressDialogFragment.TAG) } + } } diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index cc1d8c39d..75eca30a1 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -104,12 +104,14 @@ No log file found Install game content Install game updates or DLC - Error installing file to NAND - Game content installation failed. Please ensure content is valid and that the prod.keys file is installed. - Installation of base games isn\'t permitted in order to avoid possible conflicts. Please select an update or DLC instead. - The selected file type is not supported. Only NSP and XCI content is supported for this action. Please verify the game content is valid. - Game content installed successfully - Game content was overwritten successfully + Error installing file(s) to NAND + Please ensure content(s) are valid and that the prod.keys file is installed. + Installation of base games isn\'t permitted in order to avoid possible conflicts. + Only NSP and XCI content is supported. Please verify the game content(s) are valid. + %1$d installation error(s) + Game content(s) installed successfully + %1$d installed successfully + %1$d overwritten successfully https://yuzu-emu.org/help/quickstart/#dumping-installed-updates -- cgit v1.2.3 From 1a85d8804a044d689e53b2497be01b65c76c34d2 Mon Sep 17 00:00:00 2001 From: Abandoned Cart Date: Fri, 16 Jun 2023 07:50:47 -0400 Subject: android: Generalize string message dialog --- .../yuzu_emu/fragments/InstallDialogFragment.kt | 62 ---------------------- .../fragments/LongMessageDialogFragment.kt | 62 ++++++++++++++++++++++ .../java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt | 14 ++--- 3 files changed, 69 insertions(+), 69 deletions(-) delete mode 100644 src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/InstallDialogFragment.kt create mode 100644 src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/LongMessageDialogFragment.kt (limited to 'src') diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/InstallDialogFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/InstallDialogFragment.kt deleted file mode 100644 index d8850f941..000000000 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/InstallDialogFragment.kt +++ /dev/null @@ -1,62 +0,0 @@ -// SPDX-FileCopyrightText: 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -package org.yuzu.yuzu_emu.fragments - -import android.app.Dialog -import android.content.Intent -import android.net.Uri -import android.os.Bundle -import androidx.fragment.app.DialogFragment -import com.google.android.material.dialog.MaterialAlertDialogBuilder -import org.yuzu.yuzu_emu.R - -class InstallDialogFragment : DialogFragment() { - override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { - val titleId = requireArguments().getInt(TITLE) - val description = requireArguments().getString(DESCRIPTION) - val helpLinkId = requireArguments().getInt(HELP_LINK) - - val dialog = MaterialAlertDialogBuilder(requireContext()) - .setPositiveButton(R.string.close, null) - .setTitle(titleId) - .setMessage(description) - - if (helpLinkId != 0) { - dialog.setNeutralButton(R.string.learn_more) { _, _ -> - openLink(getString(helpLinkId)) - } - } - - return dialog.show() - } - - private fun openLink(link: String) { - val intent = Intent(Intent.ACTION_VIEW, Uri.parse(link)) - startActivity(intent) - } - - companion object { - const val TAG = "MessageDialogFragment" - - private const val TITLE = "Title" - private const val DESCRIPTION = "Description" - private const val HELP_LINK = "Link" - - fun newInstance( - titleId: Int, - description: String, - helpLinkId: Int = 0 - ): InstallDialogFragment { - val dialog = InstallDialogFragment() - val bundle = Bundle() - bundle.apply { - putInt(TITLE, titleId) - putString(DESCRIPTION, description) - putInt(HELP_LINK, helpLinkId) - } - dialog.arguments = bundle - return dialog - } - } -} diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/LongMessageDialogFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/LongMessageDialogFragment.kt new file mode 100644 index 000000000..b29b627e9 --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/LongMessageDialogFragment.kt @@ -0,0 +1,62 @@ +// SPDX-FileCopyrightText: 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.yuzu.yuzu_emu.fragments + +import android.app.Dialog +import android.content.Intent +import android.net.Uri +import android.os.Bundle +import androidx.fragment.app.DialogFragment +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import org.yuzu.yuzu_emu.R + +class LongMessageDialogFragment : DialogFragment() { + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + val titleId = requireArguments().getInt(TITLE) + val description = requireArguments().getString(DESCRIPTION) + val helpLinkId = requireArguments().getInt(HELP_LINK) + + val dialog = MaterialAlertDialogBuilder(requireContext()) + .setPositiveButton(R.string.close, null) + .setTitle(titleId) + .setMessage(description) + + if (helpLinkId != 0) { + dialog.setNeutralButton(R.string.learn_more) { _, _ -> + openLink(getString(helpLinkId)) + } + } + + return dialog.show() + } + + private fun openLink(link: String) { + val intent = Intent(Intent.ACTION_VIEW, Uri.parse(link)) + startActivity(intent) + } + + companion object { + const val TAG = "LongMessageDialogFragment" + + private const val TITLE = "Title" + private const val DESCRIPTION = "Description" + private const val HELP_LINK = "Link" + + fun newInstance( + titleId: Int, + description: String, + helpLinkId: Int = 0 + ): LongMessageDialogFragment { + val dialog = LongMessageDialogFragment() + val bundle = Bundle() + bundle.apply { + putInt(TITLE, titleId) + putString(DESCRIPTION, description) + putInt(HELP_LINK, helpLinkId) + } + dialog.arguments = bundle + return dialog + } + } +} diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt index 5257d7b36..3086cfad3 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt @@ -43,7 +43,7 @@ import org.yuzu.yuzu_emu.features.settings.model.SettingsViewModel import org.yuzu.yuzu_emu.features.settings.ui.SettingsActivity import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile import org.yuzu.yuzu_emu.fragments.IndeterminateProgressDialogFragment -import org.yuzu.yuzu_emu.fragments.InstallDialogFragment +import org.yuzu.yuzu_emu.fragments.LongMessageDialogFragment import org.yuzu.yuzu_emu.fragments.MessageDialogFragment import org.yuzu.yuzu_emu.model.GamesViewModel import org.yuzu.yuzu_emu.model.HomeViewModel @@ -548,7 +548,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider { installResult.append( getString( R.string.install_game_content_failed_count, - + errorTotal ) ) installResult.append(separator) @@ -572,16 +572,16 @@ class MainActivity : AppCompatActivity(), ThemeProvider { ) installResult.append(separator) } - InstallDialogFragment.newInstance( + LongMessageDialogFragment.newInstance( R.string.install_game_content_failure, installResult.toString().trim(), R.string.install_game_content_help_link - ).show(supportFragmentManager, MessageDialogFragment.TAG) + ).show(supportFragmentManager, LongMessageDialogFragment.TAG) } else { - InstallDialogFragment.newInstance( + LongMessageDialogFragment.newInstance( R.string.install_game_content_success, - installResult.toString().trim(), - ).show(supportFragmentManager, MessageDialogFragment.TAG) + installResult.toString().trim() + ).show(supportFragmentManager, LongMessageDialogFragment.TAG) } } } -- cgit v1.2.3 From 84d43489c5df9f450efb0293cc58161d08e3b882 Mon Sep 17 00:00:00 2001 From: Narr the Reg Date: Fri, 16 Jun 2023 21:57:21 -0600 Subject: input_common: Implement native mifare support --- src/common/input.h | 43 ++- src/core/hid/emulated_controller.cpp | 82 ++++- src/core/hid/emulated_controller.h | 28 +- src/core/hid/input_converter.cpp | 6 +- src/core/hle/service/am/applets/applet_cabinet.cpp | 2 +- src/core/hle/service/nfc/common/device.cpp | 182 +++++----- src/core/hle/service/nfc/common/device.h | 10 +- src/core/hle/service/nfc/common/device_manager.cpp | 11 +- src/core/hle/service/nfc/common/device_manager.h | 2 +- src/core/hle/service/nfc/mifare_types.h | 11 +- src/core/hle/service/nfc/nfc_interface.cpp | 7 +- src/input_common/drivers/joycon.cpp | 133 ++++++- src/input_common/drivers/joycon.h | 18 +- src/input_common/drivers/virtual_amiibo.cpp | 130 ++++++- src/input_common/drivers/virtual_amiibo.h | 16 +- src/input_common/helpers/joycon_driver.cpp | 118 ++++++- src/input_common/helpers/joycon_driver.h | 6 + .../helpers/joycon_protocol/joycon_types.h | 59 +++- src/input_common/helpers/joycon_protocol/nfc.cpp | 390 ++++++++++++++++++++- src/input_common/helpers/joycon_protocol/nfc.h | 34 +- .../helpers/joycon_protocol/poller.cpp | 4 +- src/input_common/helpers/joycon_protocol/poller.h | 4 +- src/input_common/input_engine.h | 34 ++ src/input_common/input_poller.cpp | 24 +- src/yuzu/main.cpp | 4 +- 25 files changed, 1165 insertions(+), 193 deletions(-) (limited to 'src') diff --git a/src/common/input.h b/src/common/input.h index 66fb15f0a..ea30770ae 100644 --- a/src/common/input.h +++ b/src/common/input.h @@ -86,7 +86,7 @@ enum class NfcState { NewAmiibo, WaitingForAmiibo, AmiiboRemoved, - NotAnAmiibo, + InvalidTagType, NotSupported, WrongDeviceState, WriteFailed, @@ -218,8 +218,22 @@ struct CameraStatus { }; struct NfcStatus { - NfcState state{}; - std::vector data{}; + NfcState state{NfcState::Unknown}; + u8 uuid_length; + u8 protocol; + u8 tag_type; + std::array uuid; +}; + +struct MifareData { + u8 command; + u8 sector; + std::array key; + std::array data; +}; + +struct MifareRequest { + std::array data; }; // List of buttons to be passed to Qt that can be translated @@ -294,7 +308,7 @@ struct CallbackStatus { BatteryStatus battery_status{}; VibrationStatus vibration_status{}; CameraFormat camera_status{CameraFormat::None}; - NfcState nfc_status{NfcState::Unknown}; + NfcStatus nfc_status{}; std::vector raw_data{}; }; @@ -356,9 +370,30 @@ public: return NfcState::NotSupported; } + virtual NfcState StartNfcPolling() { + return NfcState::NotSupported; + } + + virtual NfcState StopNfcPolling() { + return NfcState::NotSupported; + } + + virtual NfcState ReadAmiiboData([[maybe_unused]] std::vector& out_data) { + return NfcState::NotSupported; + } + virtual NfcState WriteNfcData([[maybe_unused]] const std::vector& data) { return NfcState::NotSupported; } + + virtual NfcState ReadMifareData([[maybe_unused]] const MifareRequest& request, + [[maybe_unused]] MifareRequest& out_data) { + return NfcState::NotSupported; + } + + virtual NfcState WriteMifareData([[maybe_unused]] const MifareRequest& request) { + return NfcState::NotSupported; + } }; /// An abstract class template for a factory that can create input devices. diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 0a7777732..c937495f9 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -149,12 +149,16 @@ void EmulatedController::LoadDevices() { camera_params[0] = right_joycon; camera_params[0].Set("camera", true); - camera_params[1] = Common::ParamPackage{"engine:camera,camera:1"}; - ring_params[1] = Common::ParamPackage{"engine:joycon,axis_x:100,axis_y:101"}; - nfc_params[0] = Common::ParamPackage{"engine:virtual_amiibo,nfc:1"}; nfc_params[1] = right_joycon; nfc_params[1].Set("nfc", true); + // Only map virtual devices to the first controller + if (npad_id_type == NpadIdType::Player1 || npad_id_type == NpadIdType::Handheld) { + camera_params[1] = Common::ParamPackage{"engine:camera,camera:1"}; + ring_params[1] = Common::ParamPackage{"engine:joycon,axis_x:100,axis_y:101"}; + nfc_params[0] = Common::ParamPackage{"engine:virtual_amiibo,nfc:1"}; + } + output_params[LeftIndex] = left_joycon; output_params[RightIndex] = right_joycon; output_params[2] = camera_params[1]; @@ -1176,10 +1180,7 @@ void EmulatedController::SetNfc(const Common::Input::CallbackStatus& callback) { return; } - controller.nfc_state = { - controller.nfc_values.state, - controller.nfc_values.data, - }; + controller.nfc_state = controller.nfc_values; } bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue vibration) { @@ -1308,6 +1309,73 @@ bool EmulatedController::HasNfc() const { return is_connected && (has_virtual_nfc && is_virtual_nfc_supported); } +bool EmulatedController::AddNfcHandle() { + nfc_handles++; + return SetPollingMode(EmulatedDeviceIndex::RightIndex, Common::Input::PollingMode::NFC) == + Common::Input::DriverResult::Success; +} + +bool EmulatedController::RemoveNfcHandle() { + nfc_handles--; + if (nfc_handles <= 0) { + return SetPollingMode(EmulatedDeviceIndex::RightIndex, + Common::Input::PollingMode::Active) == + Common::Input::DriverResult::Success; + } + return true; +} + +bool EmulatedController::StartNfcPolling() { + auto& nfc_output_device = output_devices[static_cast(DeviceIndex::Right)]; + auto& nfc_virtual_output_device = output_devices[3]; + + return nfc_output_device->StartNfcPolling() == Common::Input::NfcState::Success || + nfc_virtual_output_device->StartNfcPolling() == Common::Input::NfcState::Success; +} + +bool EmulatedController::StopNfcPolling() { + auto& nfc_output_device = output_devices[static_cast(DeviceIndex::Right)]; + auto& nfc_virtual_output_device = output_devices[3]; + + return nfc_output_device->StopNfcPolling() == Common::Input::NfcState::Success || + nfc_virtual_output_device->StopNfcPolling() == Common::Input::NfcState::Success; +} + +bool EmulatedController::ReadAmiiboData(std::vector& data) { + auto& nfc_output_device = output_devices[static_cast(DeviceIndex::Right)]; + auto& nfc_virtual_output_device = output_devices[3]; + + if (nfc_output_device->ReadAmiiboData(data) == Common::Input::NfcState::Success) { + return true; + } + + return nfc_virtual_output_device->ReadAmiiboData(data) == Common::Input::NfcState::Success; +} + +bool EmulatedController::ReadMifareData(const Common::Input::MifareRequest& request, + Common::Input::MifareRequest& out_data) { + auto& nfc_output_device = output_devices[static_cast(DeviceIndex::Right)]; + auto& nfc_virtual_output_device = output_devices[3]; + + if (nfc_output_device->ReadMifareData(request, out_data) == Common::Input::NfcState::Success) { + return true; + } + + return nfc_virtual_output_device->ReadMifareData(request, out_data) == + Common::Input::NfcState::Success; +} + +bool EmulatedController::WriteMifareData(const Common::Input::MifareRequest& request) { + auto& nfc_output_device = output_devices[static_cast(DeviceIndex::Right)]; + auto& nfc_virtual_output_device = output_devices[3]; + + if (nfc_output_device->WriteMifareData(request) == Common::Input::NfcState::Success) { + return true; + } + + return nfc_virtual_output_device->WriteMifareData(request) == Common::Input::NfcState::Success; +} + bool EmulatedController::WriteNfc(const std::vector& data) { auto& nfc_output_device = output_devices[static_cast(DeviceIndex::Right)]; auto& nfc_virtual_output_device = output_devices[3]; diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index 09fe1a0ab..d511e5fac 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h @@ -97,10 +97,7 @@ struct RingSensorForce { f32 force; }; -struct NfcState { - Common::Input::NfcState state{}; - std::vector data{}; -}; +using NfcState = Common::Input::NfcStatus; struct ControllerMotion { Common::Vec3f accel{}; @@ -393,9 +390,31 @@ public: /// Returns true if the device has nfc support bool HasNfc() const; + /// Sets the joycon in nfc mode and increments the handle count + bool AddNfcHandle(); + + /// Decrements the handle count if zero sets the joycon in active mode + bool RemoveNfcHandle(); + + /// Start searching for nfc tags + bool StartNfcPolling(); + + /// Stop searching for nfc tags + bool StopNfcPolling(); + + /// Returns true if the nfc tag was readable + bool ReadAmiiboData(std::vector& data); + /// Returns true if the nfc tag was written bool WriteNfc(const std::vector& data); + /// Returns true if the nfc tag was readable + bool ReadMifareData(const Common::Input::MifareRequest& request, + Common::Input::MifareRequest& out_data); + + /// Returns true if the nfc tag was written + bool WriteMifareData(const Common::Input::MifareRequest& request); + /// Returns the led pattern corresponding to this emulated controller LedPattern GetLedPattern() const; @@ -532,6 +551,7 @@ private: bool system_buttons_enabled{true}; f32 motion_sensitivity{Core::HID::MotionInput::IsAtRestStandard}; u32 turbo_button_state{0}; + std::size_t nfc_handles{0}; // Temporary values to avoid doing changes while the controller is in configuring mode NpadStyleIndex tmp_npad_type{NpadStyleIndex::None}; diff --git a/src/core/hid/input_converter.cpp b/src/core/hid/input_converter.cpp index 4ccb1c596..a05716fd8 100644 --- a/src/core/hid/input_converter.cpp +++ b/src/core/hid/input_converter.cpp @@ -299,11 +299,7 @@ Common::Input::NfcStatus TransformToNfc(const Common::Input::CallbackStatus& cal Common::Input::NfcStatus nfc{}; switch (callback.type) { case Common::Input::InputType::Nfc: - nfc = { - .state = callback.nfc_status, - .data = callback.raw_data, - }; - break; + return callback.nfc_status; default: LOG_ERROR(Input, "Conversion from type {} to NFC not implemented", callback.type); break; diff --git a/src/core/hle/service/am/applets/applet_cabinet.cpp b/src/core/hle/service/am/applets/applet_cabinet.cpp index 8b754e9d4..19ed184e8 100644 --- a/src/core/hle/service/am/applets/applet_cabinet.cpp +++ b/src/core/hle/service/am/applets/applet_cabinet.cpp @@ -141,7 +141,7 @@ void Cabinet::DisplayCompleted(bool apply_changes, std::string_view amiibo_name) applet_output.device_handle = applet_input_common.device_handle; applet_output.result = CabinetResult::Cancel; const auto reg_result = nfp_device->GetRegisterInfo(applet_output.register_info); - const auto tag_result = nfp_device->GetTagInfo(applet_output.tag_info, false); + const auto tag_result = nfp_device->GetTagInfo(applet_output.tag_info); nfp_device->Finalize(); if (reg_result.IsSuccess()) { diff --git a/src/core/hle/service/nfc/common/device.cpp b/src/core/hle/service/nfc/common/device.cpp index f4b180b06..5bf289818 100644 --- a/src/core/hle/service/nfc/common/device.cpp +++ b/src/core/hle/service/nfc/common/device.cpp @@ -93,7 +93,8 @@ void NfcDevice::NpadUpdate(Core::HID::ControllerTriggerType type) { const auto nfc_status = npad_device->GetNfc(); switch (nfc_status.state) { case Common::Input::NfcState::NewAmiibo: - LoadNfcTag(nfc_status.data); + LoadNfcTag(nfc_status.protocol, nfc_status.tag_type, nfc_status.uuid_length, + nfc_status.uuid); break; case Common::Input::NfcState::AmiiboRemoved: if (device_state == DeviceState::Initialized || device_state == DeviceState::TagRemoved) { @@ -108,28 +109,46 @@ void NfcDevice::NpadUpdate(Core::HID::ControllerTriggerType type) { } } -bool NfcDevice::LoadNfcTag(std::span data) { +bool NfcDevice::LoadNfcTag(u8 protocol, u8 tag_type, u8 uuid_length, UniqueSerialNumber uuid) { if (device_state != DeviceState::SearchingForTag) { LOG_ERROR(Service_NFC, "Game is not looking for nfc tag, current state {}", device_state); return false; } + if ((protocol & static_cast(allowed_protocols)) == 0) { + LOG_ERROR(Service_NFC, "Protocol not supported {}", protocol); + return false; + } + + real_tag_info = { + .uuid = uuid, + .uuid_length = uuid_length, + .protocol = static_cast(protocol), + .tag_type = static_cast(tag_type), + }; + + device_state = DeviceState::TagFound; + deactivate_event->GetReadableEvent().Clear(); + activate_event->Signal(); + return true; +} + +bool NfcDevice::LoadAmiiboData() { + std::vector data{}; + + if (!npad_device->ReadAmiiboData(data)) { + return false; + } + if (data.size() < sizeof(NFP::EncryptedNTAG215File)) { LOG_ERROR(Service_NFC, "Not an amiibo, size={}", data.size()); return false; } - mifare_data.resize(data.size()); - memcpy(mifare_data.data(), data.data(), data.size()); - memcpy(&tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File)); is_plain_amiibo = NFP::AmiiboCrypto::IsAmiiboValid(tag_data); is_write_protected = false; - device_state = DeviceState::TagFound; - deactivate_event->GetReadableEvent().Clear(); - activate_event->Signal(); - // Fallback for plain amiibos if (is_plain_amiibo) { LOG_INFO(Service_NFP, "Using plain amiibo"); @@ -147,6 +166,7 @@ bool NfcDevice::LoadNfcTag(std::span data) { return true; } + LOG_INFO(Service_NFP, "Using encrypted amiibo"); tag_data = {}; memcpy(&encrypted_tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File)); return true; @@ -162,7 +182,6 @@ void NfcDevice::CloseNfcTag() { device_state = DeviceState::TagRemoved; encrypted_tag_data = {}; tag_data = {}; - mifare_data = {}; activate_event->GetReadableEvent().Clear(); deactivate_event->Signal(); } @@ -179,8 +198,12 @@ void NfcDevice::Initialize() { device_state = npad_device->HasNfc() ? DeviceState::Initialized : DeviceState::Unavailable; encrypted_tag_data = {}; tag_data = {}; - mifare_data = {}; - is_initalized = true; + + if (device_state != DeviceState::Initialized) { + return; + } + + is_initalized = npad_device->AddNfcHandle(); } void NfcDevice::Finalize() { @@ -190,6 +213,11 @@ void NfcDevice::Finalize() { if (device_state == DeviceState::SearchingForTag || device_state == DeviceState::TagRemoved) { StopDetection(); } + + if (device_state != DeviceState::Unavailable) { + npad_device->RemoveNfcHandle(); + } + device_state = DeviceState::Unavailable; is_initalized = false; } @@ -200,10 +228,8 @@ Result NfcDevice::StartDetection(NfcProtocol allowed_protocol) { return ResultWrongDeviceState; } - if (npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex, - Common::Input::PollingMode::NFC) != - Common::Input::DriverResult::Success) { - LOG_ERROR(Service_NFC, "Nfc not supported"); + if (!npad_device->StartNfcPolling()) { + LOG_ERROR(Service_NFC, "Nfc polling not supported"); return ResultNfcDisabled; } @@ -213,9 +239,6 @@ Result NfcDevice::StartDetection(NfcProtocol allowed_protocol) { } Result NfcDevice::StopDetection() { - npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex, - Common::Input::PollingMode::Active); - if (device_state == DeviceState::Initialized) { return ResultSuccess; } @@ -225,6 +248,7 @@ Result NfcDevice::StopDetection() { } if (device_state == DeviceState::SearchingForTag || device_state == DeviceState::TagRemoved) { + npad_device->StopNfcPolling(); device_state = DeviceState::Initialized; return ResultSuccess; } @@ -233,7 +257,7 @@ Result NfcDevice::StopDetection() { return ResultWrongDeviceState; } -Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info, bool is_mifare) const { +Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info) const { if (device_state != DeviceState::TagFound && device_state != DeviceState::TagMounted) { LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); if (device_state == DeviceState::TagRemoved) { @@ -242,41 +266,15 @@ Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info, bool is_mifare) const { return ResultWrongDeviceState; } - UniqueSerialNumber uuid{}; - u8 uuid_length{}; - NfcProtocol protocol{NfcProtocol::TypeA}; - TagType tag_type{TagType::Type2}; - - if (is_mifare) { - tag_type = TagType::Mifare; - uuid_length = sizeof(NFP::NtagTagUuid); - memcpy(uuid.data(), mifare_data.data(), uuid_length); - } else { - tag_type = TagType::Type2; - uuid_length = sizeof(NFP::NtagTagUuid); - NFP::NtagTagUuid nUuid{ - .part1 = encrypted_tag_data.uuid.part1, - .part2 = encrypted_tag_data.uuid.part2, - .nintendo_id = encrypted_tag_data.uuid.nintendo_id, - }; - memcpy(uuid.data(), &nUuid, uuid_length); + tag_info = real_tag_info; - // Generate random UUID to bypass amiibo load limits - if (Settings::values.random_amiibo_id) { - Common::TinyMT rng{}; - rng.Initialize(static_cast(GetCurrentPosixTime())); - rng.GenerateRandomBytes(uuid.data(), uuid_length); - } + // Generate random UUID to bypass amiibo load limits + if (real_tag_info.tag_type == TagType::Type2 && Settings::values.random_amiibo_id) { + Common::TinyMT rng{}; + rng.Initialize(static_cast(GetCurrentPosixTime())); + rng.GenerateRandomBytes(tag_info.uuid.data(), tag_info.uuid_length); } - // Protocol and tag type may change here - tag_info = { - .uuid = uuid, - .uuid_length = uuid_length, - .protocol = protocol, - .tag_type = tag_type, - }; - return ResultSuccess; } @@ -293,7 +291,7 @@ Result NfcDevice::ReadMifare(std::span parameter Result result = ResultSuccess; TagInfo tag_info{}; - result = GetTagInfo(tag_info, true); + result = GetTagInfo(tag_info); if (result.IsError()) { return result; @@ -307,6 +305,8 @@ Result NfcDevice::ReadMifare(std::span parameter return ResultInvalidArgument; } + Common::Input::MifareRequest request{}; + Common::Input::MifareRequest out_data{}; const auto unknown = parameters[0].sector_key.unknown; for (std::size_t i = 0; i < parameters.size(); i++) { if (unknown != parameters[i].sector_key.unknown) { @@ -315,25 +315,29 @@ Result NfcDevice::ReadMifare(std::span parameter } for (std::size_t i = 0; i < parameters.size(); i++) { - result = ReadMifare(parameters[i], read_block_data[i]); - if (result.IsError()) { - break; + if (parameters[i].sector_key.command == MifareCmd::None) { + continue; } + request.data[i].command = static_cast(parameters[i].sector_key.command); + request.data[i].sector = parameters[i].sector_number; + memcpy(request.data[i].key.data(), parameters[i].sector_key.sector_key.data(), + sizeof(KeyData)); } - return result; -} - -Result NfcDevice::ReadMifare(const MifareReadBlockParameter& parameter, - MifareReadBlockData& read_block_data) const { - const std::size_t sector_index = parameter.sector_number * sizeof(DataBlock); - read_block_data.sector_number = parameter.sector_number; - if (mifare_data.size() < sector_index + sizeof(DataBlock)) { + if (!npad_device->ReadMifareData(request, out_data)) { return ResultMifareError288; } - // TODO: Use parameter.sector_key to read encrypted data - memcpy(read_block_data.data.data(), mifare_data.data() + sector_index, sizeof(DataBlock)); + for (std::size_t i = 0; i < read_block_data.size(); i++) { + if (static_cast(out_data.data[i].command) == MifareCmd::None) { + continue; + } + + read_block_data[i] = { + .data = out_data.data[i].data, + .sector_number = out_data.data[i].sector, + }; + } return ResultSuccess; } @@ -342,7 +346,7 @@ Result NfcDevice::WriteMifare(std::span paramet Result result = ResultSuccess; TagInfo tag_info{}; - result = GetTagInfo(tag_info, true); + result = GetTagInfo(tag_info); if (result.IsError()) { return result; @@ -363,42 +367,25 @@ Result NfcDevice::WriteMifare(std::span paramet } } + Common::Input::MifareRequest request{}; for (std::size_t i = 0; i < parameters.size(); i++) { - result = WriteMifare(parameters[i]); - if (result.IsError()) { - break; + if (parameters[i].sector_key.command == MifareCmd::None) { + continue; } + request.data[i].command = static_cast(parameters[i].sector_key.command); + request.data[i].sector = parameters[i].sector_number; + memcpy(request.data[i].key.data(), parameters[i].sector_key.sector_key.data(), + sizeof(KeyData)); + memcpy(request.data[i].data.data(), parameters[i].data.data(), sizeof(KeyData)); } - if (!npad_device->WriteNfc(mifare_data)) { - LOG_ERROR(Service_NFP, "Error writing to file"); + if (!npad_device->WriteMifareData(request)) { return ResultMifareError288; } return result; } -Result NfcDevice::WriteMifare(const MifareWriteBlockParameter& parameter) { - const std::size_t sector_index = parameter.sector_number * sizeof(DataBlock); - - if (device_state != DeviceState::TagFound && device_state != DeviceState::TagMounted) { - LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); - if (device_state == DeviceState::TagRemoved) { - return ResultTagRemoved; - } - return ResultWrongDeviceState; - } - - if (mifare_data.size() < sector_index + sizeof(DataBlock)) { - return ResultMifareError288; - } - - // TODO: Use parameter.sector_key to encrypt the data - memcpy(mifare_data.data() + sector_index, parameter.data.data(), sizeof(DataBlock)); - - return ResultSuccess; -} - Result NfcDevice::SendCommandByPassThrough(const Time::Clock::TimeSpanType& timeout, std::span command_data, std::span out_data) { @@ -412,6 +399,11 @@ Result NfcDevice::Mount(NFP::ModelType model_type, NFP::MountTarget mount_target return ResultWrongDeviceState; } + if (!LoadAmiiboData()) { + LOG_ERROR(Service_NFP, "Not an amiibo"); + return ResultInvalidTagType; + } + if (!NFP::AmiiboCrypto::IsAmiiboValid(encrypted_tag_data)) { LOG_ERROR(Service_NFP, "Not an amiibo"); return ResultInvalidTagType; @@ -562,7 +554,7 @@ Result NfcDevice::Restore() { NFC::TagInfo tag_info{}; std::array data{}; - Result result = GetTagInfo(tag_info, false); + Result result = GetTagInfo(tag_info); if (result.IsError()) { return result; @@ -635,7 +627,7 @@ Result NfcDevice::GetCommonInfo(NFP::CommonInfo& common_info) const { // TODO: Validate this data common_info = { .last_write_date = settings.write_date.GetWriteDate(), - .write_counter = tag_data.write_counter, + .write_counter = tag_data.application_write_counter, .version = tag_data.amiibo_version, .application_area_size = sizeof(NFP::ApplicationArea), }; diff --git a/src/core/hle/service/nfc/common/device.h b/src/core/hle/service/nfc/common/device.h index 7560210d6..0ed1ff34c 100644 --- a/src/core/hle/service/nfc/common/device.h +++ b/src/core/hle/service/nfc/common/device.h @@ -42,15 +42,12 @@ public: Result StartDetection(NfcProtocol allowed_protocol); Result StopDetection(); - Result GetTagInfo(TagInfo& tag_info, bool is_mifare) const; + Result GetTagInfo(TagInfo& tag_info) const; Result ReadMifare(std::span parameters, std::span read_block_data) const; - Result ReadMifare(const MifareReadBlockParameter& parameter, - MifareReadBlockData& read_block_data) const; Result WriteMifare(std::span parameters); - Result WriteMifare(const MifareWriteBlockParameter& parameter); Result SendCommandByPassThrough(const Time::Clock::TimeSpanType& timeout, std::span command_data, std::span out_data); @@ -105,7 +102,8 @@ public: private: void NpadUpdate(Core::HID::ControllerTriggerType type); - bool LoadNfcTag(std::span data); + bool LoadNfcTag(u8 protocol, u8 tag_type, u8 uuid_length, UniqueSerialNumber uuid); + bool LoadAmiiboData(); void CloseNfcTag(); NFP::AmiiboName GetAmiiboName(const NFP::AmiiboSettings& settings) const; @@ -140,8 +138,8 @@ private: bool is_write_protected{}; NFP::MountTarget mount_target{NFP::MountTarget::None}; + TagInfo real_tag_info{}; NFP::NTAG215File tag_data{}; - std::vector mifare_data{}; NFP::EncryptedNTAG215File encrypted_tag_data{}; }; diff --git a/src/core/hle/service/nfc/common/device_manager.cpp b/src/core/hle/service/nfc/common/device_manager.cpp index b0456508e..562f3a28e 100644 --- a/src/core/hle/service/nfc/common/device_manager.cpp +++ b/src/core/hle/service/nfc/common/device_manager.cpp @@ -29,6 +29,9 @@ DeviceManager::DeviceManager(Core::System& system_, KernelHelpers::ServiceContex } DeviceManager ::~DeviceManager() { + if (is_initialized) { + Finalize(); + } service_context.CloseEvent(availability_change_event); } @@ -125,14 +128,14 @@ Result DeviceManager::StopDetection(u64 device_handle) { return result; } -Result DeviceManager::GetTagInfo(u64 device_handle, TagInfo& tag_info, bool is_mifare) const { +Result DeviceManager::GetTagInfo(u64 device_handle, TagInfo& tag_info) const { std::scoped_lock lock{mutex}; std::shared_ptr device = nullptr; auto result = GetDeviceHandle(device_handle, device); if (result.IsSuccess()) { - result = device->GetTagInfo(tag_info, is_mifare); + result = device->GetTagInfo(tag_info); result = VerifyDeviceResult(device, result); } @@ -546,7 +549,7 @@ Result DeviceManager::ReadBackupData(u64 device_handle, std::span data) cons NFC::TagInfo tag_info{}; if (result.IsSuccess()) { - result = device->GetTagInfo(tag_info, false); + result = device->GetTagInfo(tag_info); } if (result.IsSuccess()) { @@ -565,7 +568,7 @@ Result DeviceManager::WriteBackupData(u64 device_handle, std::span dat NFC::TagInfo tag_info{}; if (result.IsSuccess()) { - result = device->GetTagInfo(tag_info, false); + result = device->GetTagInfo(tag_info); } if (result.IsSuccess()) { diff --git a/src/core/hle/service/nfc/common/device_manager.h b/src/core/hle/service/nfc/common/device_manager.h index 2971e280f..c61ba0cf3 100644 --- a/src/core/hle/service/nfc/common/device_manager.h +++ b/src/core/hle/service/nfc/common/device_manager.h @@ -33,7 +33,7 @@ public: Kernel::KReadableEvent& AttachAvailabilityChangeEvent() const; Result StartDetection(u64 device_handle, NfcProtocol tag_protocol); Result StopDetection(u64 device_handle); - Result GetTagInfo(u64 device_handle, NFP::TagInfo& tag_info, bool is_mifare) const; + Result GetTagInfo(u64 device_handle, NFP::TagInfo& tag_info) const; Kernel::KReadableEvent& AttachActivateEvent(u64 device_handle) const; Kernel::KReadableEvent& AttachDeactivateEvent(u64 device_handle) const; Result ReadMifare(u64 device_handle, diff --git a/src/core/hle/service/nfc/mifare_types.h b/src/core/hle/service/nfc/mifare_types.h index 75b59f021..467937399 100644 --- a/src/core/hle/service/nfc/mifare_types.h +++ b/src/core/hle/service/nfc/mifare_types.h @@ -11,9 +11,10 @@ namespace Service::NFC { enum class MifareCmd : u8 { + None = 0x00, + Read = 0x30, AuthA = 0x60, AuthB = 0x61, - Read = 0x30, Write = 0xA0, Transfer = 0xB0, Decrement = 0xC0, @@ -35,17 +36,17 @@ static_assert(sizeof(SectorKey) == 0x10, "SectorKey is an invalid size"); // This is nn::nfc::MifareReadBlockParameter struct MifareReadBlockParameter { - u8 sector_number; + u8 sector_number{}; INSERT_PADDING_BYTES(0x7); - SectorKey sector_key; + SectorKey sector_key{}; }; static_assert(sizeof(MifareReadBlockParameter) == 0x18, "MifareReadBlockParameter is an invalid size"); // This is nn::nfc::MifareReadBlockData struct MifareReadBlockData { - DataBlock data; - u8 sector_number; + DataBlock data{}; + u8 sector_number{}; INSERT_PADDING_BYTES(0x7); }; static_assert(sizeof(MifareReadBlockData) == 0x18, "MifareReadBlockData is an invalid size"); diff --git a/src/core/hle/service/nfc/nfc_interface.cpp b/src/core/hle/service/nfc/nfc_interface.cpp index 130fb7f78..e7ca7582e 100644 --- a/src/core/hle/service/nfc/nfc_interface.cpp +++ b/src/core/hle/service/nfc/nfc_interface.cpp @@ -174,8 +174,7 @@ void NfcInterface::GetTagInfo(HLERequestContext& ctx) { LOG_INFO(Service_NFC, "called, device_handle={}", device_handle); TagInfo tag_info{}; - auto result = - GetManager()->GetTagInfo(device_handle, tag_info, backend_type == BackendType::Mifare); + auto result = GetManager()->GetTagInfo(device_handle, tag_info); result = TranslateResultToServiceError(result); if (result.IsSuccess()) { @@ -216,8 +215,8 @@ void NfcInterface::ReadMifare(HLERequestContext& ctx) { memcpy(read_commands.data(), buffer.data(), number_of_commands * sizeof(MifareReadBlockParameter)); - LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, read_commands_size={}", - device_handle, number_of_commands); + LOG_INFO(Service_NFC, "called, device_handle={}, read_commands_size={}", device_handle, + number_of_commands); std::vector out_data(number_of_commands); auto result = GetManager()->ReadMifare(device_handle, read_commands, out_data); diff --git a/src/input_common/drivers/joycon.cpp b/src/input_common/drivers/joycon.cpp index b2b5677c8..52494e0d9 100644 --- a/src/input_common/drivers/joycon.cpp +++ b/src/input_common/drivers/joycon.cpp @@ -195,8 +195,8 @@ void Joycons::RegisterNewDevice(SDL_hid_device_info* device_info) { OnMotionUpdate(port, type, id, value); }}, .on_ring_data = {[this](f32 ring_data) { OnRingConUpdate(ring_data); }}, - .on_amiibo_data = {[this, port, type](const std::vector& amiibo_data) { - OnAmiiboUpdate(port, type, amiibo_data); + .on_amiibo_data = {[this, port, type](const Joycon::TagInfo& tag_info) { + OnAmiiboUpdate(port, type, tag_info); }}, .on_camera_data = {[this, port](const std::vector& camera_data, Joycon::IrsResolution format) { @@ -291,13 +291,105 @@ Common::Input::NfcState Joycons::SupportsNfc(const PadIdentifier& identifier_) c return Common::Input::NfcState::Success; }; +Common::Input::NfcState Joycons::StartNfcPolling(const PadIdentifier& identifier) { + auto handle = GetHandle(identifier); + if (handle == nullptr) { + return Common::Input::NfcState::Unknown; + } + return TranslateDriverResult(handle->StartNfcPolling()); +}; + +Common::Input::NfcState Joycons::StopNfcPolling(const PadIdentifier& identifier) { + auto handle = GetHandle(identifier); + if (handle == nullptr) { + return Common::Input::NfcState::Unknown; + } + return TranslateDriverResult(handle->StopNfcPolling()); +}; + +Common::Input::NfcState Joycons::ReadAmiiboData(const PadIdentifier& identifier, + std::vector& out_data) { + auto handle = GetHandle(identifier); + if (handle == nullptr) { + return Common::Input::NfcState::Unknown; + } + return TranslateDriverResult(handle->ReadAmiiboData(out_data)); +} + Common::Input::NfcState Joycons::WriteNfcData(const PadIdentifier& identifier, const std::vector& data) { auto handle = GetHandle(identifier); - if (handle->WriteNfcData(data) != Joycon::DriverResult::Success) { - return Common::Input::NfcState::WriteFailed; + if (handle == nullptr) { + return Common::Input::NfcState::Unknown; } - return Common::Input::NfcState::Success; + return TranslateDriverResult(handle->WriteNfcData(data)); +}; + +Common::Input::NfcState Joycons::ReadMifareData(const PadIdentifier& identifier, + const Common::Input::MifareRequest& request, + Common::Input::MifareRequest& data) { + auto handle = GetHandle(identifier); + if (handle == nullptr) { + return Common::Input::NfcState::Unknown; + } + + const auto command = static_cast(request.data[0].command); + std::vector read_request{}; + for (const auto& request_data : request.data) { + if (request_data.command == 0) { + continue; + } + Joycon::MifareReadChunk chunk = { + .command = command, + .sector_key = {}, + .sector = request_data.sector, + }; + memcpy(chunk.sector_key.data(), request_data.key.data(), + sizeof(Joycon::MifareReadChunk::sector_key)); + read_request.emplace_back(chunk); + } + + std::vector read_data(read_request.size()); + const auto result = handle->ReadMifareData(read_request, read_data); + if (result == Joycon::DriverResult::Success) { + for (std::size_t i = 0; i < read_request.size(); i++) { + data.data[i] = { + .command = static_cast(command), + .sector = read_data[i].sector, + .key = {}, + .data = read_data[i].data, + }; + } + } + return TranslateDriverResult(result); +}; + +Common::Input::NfcState Joycons::WriteMifareData(const PadIdentifier& identifier, + const Common::Input::MifareRequest& request) { + auto handle = GetHandle(identifier); + if (handle == nullptr) { + return Common::Input::NfcState::Unknown; + } + + const auto command = static_cast(request.data[0].command); + std::vector write_request{}; + for (const auto& request_data : request.data) { + if (request_data.command == 0) { + continue; + } + Joycon::MifareWriteChunk chunk = { + .command = command, + .sector_key = {}, + .sector = request_data.sector, + .data = {}, + }; + memcpy(chunk.sector_key.data(), request_data.key.data(), + sizeof(Joycon::MifareReadChunk::sector_key)); + memcpy(chunk.data.data(), request_data.data.data(), sizeof(Joycon::MifareWriteChunk::data)); + write_request.emplace_back(chunk); + } + + return TranslateDriverResult(handle->WriteMifareData(write_request)); }; Common::Input::DriverResult Joycons::SetPollingMode(const PadIdentifier& identifier, @@ -403,11 +495,20 @@ void Joycons::OnRingConUpdate(f32 ring_data) { } void Joycons::OnAmiiboUpdate(std::size_t port, Joycon::ControllerType type, - const std::vector& amiibo_data) { + const Joycon::TagInfo& tag_info) { const auto identifier = GetIdentifier(port, type); - const auto nfc_state = amiibo_data.empty() ? Common::Input::NfcState::AmiiboRemoved - : Common::Input::NfcState::NewAmiibo; - SetNfc(identifier, {nfc_state, amiibo_data}); + const auto nfc_state = tag_info.uuid_length == 0 ? Common::Input::NfcState::AmiiboRemoved + : Common::Input::NfcState::NewAmiibo; + + const Common::Input::NfcStatus nfc_status{ + .state = nfc_state, + .uuid_length = tag_info.uuid_length, + .protocol = tag_info.protocol, + .tag_type = tag_info.tag_type, + .uuid = tag_info.uuid, + }; + + SetNfc(identifier, nfc_status); } void Joycons::OnCameraUpdate(std::size_t port, const std::vector& camera_data, @@ -726,4 +827,18 @@ std::string Joycons::JoyconName(Joycon::ControllerType type) const { return "Unknown Switch Controller"; } } + +Common::Input::NfcState Joycons::TranslateDriverResult(Joycon::DriverResult result) const { + switch (result) { + case Joycon::DriverResult::Success: + return Common::Input::NfcState::Success; + case Joycon::DriverResult::Disabled: + return Common::Input::NfcState::WrongDeviceState; + case Joycon::DriverResult::NotSupported: + return Common::Input::NfcState::NotSupported; + default: + return Common::Input::NfcState::Unknown; + } +} + } // namespace InputCommon diff --git a/src/input_common/drivers/joycon.h b/src/input_common/drivers/joycon.h index e3f0ad78f..4c323d7d6 100644 --- a/src/input_common/drivers/joycon.h +++ b/src/input_common/drivers/joycon.h @@ -15,6 +15,7 @@ using SerialNumber = std::array; struct Battery; struct Color; struct MotionData; +struct TagInfo; enum class ControllerType : u8; enum class DriverResult; enum class IrsResolution; @@ -39,9 +40,18 @@ public: Common::Input::DriverResult SetCameraFormat(const PadIdentifier& identifier, Common::Input::CameraFormat camera_format) override; - Common::Input::NfcState SupportsNfc(const PadIdentifier& identifier_) const override; - Common::Input::NfcState WriteNfcData(const PadIdentifier& identifier_, + Common::Input::NfcState SupportsNfc(const PadIdentifier& identifier) const override; + Common::Input::NfcState StartNfcPolling(const PadIdentifier& identifier) override; + Common::Input::NfcState StopNfcPolling(const PadIdentifier& identifier) override; + Common::Input::NfcState ReadAmiiboData(const PadIdentifier& identifier, + std::vector& out_data) override; + Common::Input::NfcState WriteNfcData(const PadIdentifier& identifier, const std::vector& data) override; + Common::Input::NfcState ReadMifareData(const PadIdentifier& identifier, + const Common::Input::MifareRequest& request, + Common::Input::MifareRequest& out_data) override; + Common::Input::NfcState WriteMifareData(const PadIdentifier& identifier, + const Common::Input::MifareRequest& request) override; Common::Input::DriverResult SetPollingMode( const PadIdentifier& identifier, const Common::Input::PollingMode polling_mode) override; @@ -82,7 +92,7 @@ private: const Joycon::MotionData& value); void OnRingConUpdate(f32 ring_data); void OnAmiiboUpdate(std::size_t port, Joycon::ControllerType type, - const std::vector& amiibo_data); + const Joycon::TagInfo& amiibo_data); void OnCameraUpdate(std::size_t port, const std::vector& camera_data, Joycon::IrsResolution format); @@ -102,6 +112,8 @@ private: /// Returns the name of the device in text format std::string JoyconName(Joycon::ControllerType type) const; + Common::Input::NfcState TranslateDriverResult(Joycon::DriverResult result) const; + std::jthread scan_thread; // Joycon types are split by type to ease supporting dualjoycon configurations diff --git a/src/input_common/drivers/virtual_amiibo.cpp b/src/input_common/drivers/virtual_amiibo.cpp index 6435b8af8..180eb53ef 100644 --- a/src/input_common/drivers/virtual_amiibo.cpp +++ b/src/input_common/drivers/virtual_amiibo.cpp @@ -29,14 +29,13 @@ Common::Input::DriverResult VirtualAmiibo::SetPollingMode( switch (polling_mode) { case Common::Input::PollingMode::NFC: - if (state == State::Initialized) { - state = State::WaitingForAmiibo; - } + state = State::Initialized; return Common::Input::DriverResult::Success; default: - if (state == State::AmiiboIsOpen) { + if (state == State::TagNearby) { CloseAmiibo(); } + state = State::Disabled; return Common::Input::DriverResult::NotSupported; } } @@ -45,6 +44,39 @@ Common::Input::NfcState VirtualAmiibo::SupportsNfc( [[maybe_unused]] const PadIdentifier& identifier_) const { return Common::Input::NfcState::Success; } +Common::Input::NfcState VirtualAmiibo::StartNfcPolling(const PadIdentifier& identifier_) { + if (state != State::Initialized) { + return Common::Input::NfcState::WrongDeviceState; + } + state = State::WaitingForAmiibo; + return Common::Input::NfcState::Success; +} + +Common::Input::NfcState VirtualAmiibo::StopNfcPolling(const PadIdentifier& identifier_) { + if (state == State::Disabled) { + return Common::Input::NfcState::WrongDeviceState; + } + if (state == State::TagNearby) { + CloseAmiibo(); + } + state = State::Initialized; + return Common::Input::NfcState::Success; +} + +Common::Input::NfcState VirtualAmiibo::ReadAmiiboData(const PadIdentifier& identifier_, + std::vector& out_data) { + if (state != State::TagNearby) { + return Common::Input::NfcState::WrongDeviceState; + } + + if (status.tag_type != 1U << 1) { + return Common::Input::NfcState::InvalidTagType; + } + + out_data.resize(nfc_data.size()); + memcpy(out_data.data(), nfc_data.data(), nfc_data.size()); + return Common::Input::NfcState::Success; +} Common::Input::NfcState VirtualAmiibo::WriteNfcData( [[maybe_unused]] const PadIdentifier& identifier_, const std::vector& data) { @@ -66,6 +98,69 @@ Common::Input::NfcState VirtualAmiibo::WriteNfcData( return Common::Input::NfcState::Success; } +Common::Input::NfcState VirtualAmiibo::ReadMifareData(const PadIdentifier& identifier_, + const Common::Input::MifareRequest& request, + Common::Input::MifareRequest& out_data) { + if (state != State::TagNearby) { + return Common::Input::NfcState::WrongDeviceState; + } + + if (status.tag_type != 1U << 6) { + return Common::Input::NfcState::InvalidTagType; + } + + for (std::size_t i = 0; i < request.data.size(); i++) { + if (request.data[i].command == 0) { + continue; + } + out_data.data[i].command = request.data[i].command; + out_data.data[i].sector = request.data[i].sector; + + const std::size_t sector_index = + request.data[i].sector * sizeof(Common::Input::MifareData::data); + + if (nfc_data.size() < sector_index + sizeof(Common::Input::MifareData::data)) { + return Common::Input::NfcState::WriteFailed; + } + + // Ignore the sector key as we don't support it + memcpy(out_data.data[i].data.data(), nfc_data.data() + sector_index, + sizeof(Common::Input::MifareData::data)); + } + + return Common::Input::NfcState::Success; +} + +Common::Input::NfcState VirtualAmiibo::WriteMifareData( + const PadIdentifier& identifier_, const Common::Input::MifareRequest& request) { + if (state != State::TagNearby) { + return Common::Input::NfcState::WrongDeviceState; + } + + if (status.tag_type != 1U << 6) { + return Common::Input::NfcState::InvalidTagType; + } + + for (std::size_t i = 0; i < request.data.size(); i++) { + if (request.data[i].command == 0) { + continue; + } + + const std::size_t sector_index = + request.data[i].sector * sizeof(Common::Input::MifareData::data); + + if (nfc_data.size() < sector_index + sizeof(Common::Input::MifareData::data)) { + return Common::Input::NfcState::WriteFailed; + } + + // Ignore the sector key as we don't support it + memcpy(nfc_data.data() + sector_index, request.data[i].data.data(), + sizeof(Common::Input::MifareData::data)); + } + + return Common::Input::NfcState::Success; +} + VirtualAmiibo::State VirtualAmiibo::GetCurrentState() const { return state; } @@ -112,23 +207,31 @@ VirtualAmiibo::Info VirtualAmiibo::LoadAmiibo(std::span data) { case AmiiboSizeWithoutPassword: case AmiiboSizeWithSignature: nfc_data.resize(AmiiboSize); + status.tag_type = 1U << 1; + status.uuid_length = 7; break; case MifareSize: nfc_data.resize(MifareSize); + status.tag_type = 1U << 6; + status.uuid_length = 4; break; default: return Info::NotAnAmiibo; } - state = State::AmiiboIsOpen; + status.uuid = {}; + status.protocol = 1; + state = State::TagNearby; + status.state = Common::Input::NfcState::NewAmiibo, memcpy(nfc_data.data(), data.data(), data.size_bytes()); - SetNfc(identifier, {Common::Input::NfcState::NewAmiibo, nfc_data}); + memcpy(status.uuid.data(), nfc_data.data(), status.uuid_length); + SetNfc(identifier, status); return Info::Success; } VirtualAmiibo::Info VirtualAmiibo::ReloadAmiibo() { - if (state == State::AmiiboIsOpen) { - SetNfc(identifier, {Common::Input::NfcState::NewAmiibo, nfc_data}); + if (state == State::TagNearby) { + SetNfc(identifier, status); return Info::Success; } @@ -136,9 +239,14 @@ VirtualAmiibo::Info VirtualAmiibo::ReloadAmiibo() { } VirtualAmiibo::Info VirtualAmiibo::CloseAmiibo() { - state = polling_mode == Common::Input::PollingMode::NFC ? State::WaitingForAmiibo - : State::Initialized; - SetNfc(identifier, {Common::Input::NfcState::AmiiboRemoved, {}}); + if (state != State::TagNearby) { + return Info::Success; + } + + state = State::WaitingForAmiibo; + status.state = Common::Input::NfcState::AmiiboRemoved; + SetNfc(identifier, status); + status.tag_type = 0; return Info::Success; } diff --git a/src/input_common/drivers/virtual_amiibo.h b/src/input_common/drivers/virtual_amiibo.h index 09ca09e68..490f38e05 100644 --- a/src/input_common/drivers/virtual_amiibo.h +++ b/src/input_common/drivers/virtual_amiibo.h @@ -20,9 +20,10 @@ namespace InputCommon { class VirtualAmiibo final : public InputEngine { public: enum class State { + Disabled, Initialized, WaitingForAmiibo, - AmiiboIsOpen, + TagNearby, }; enum class Info { @@ -41,9 +42,17 @@ public: const PadIdentifier& identifier_, const Common::Input::PollingMode polling_mode_) override; Common::Input::NfcState SupportsNfc(const PadIdentifier& identifier_) const override; - + Common::Input::NfcState StartNfcPolling(const PadIdentifier& identifier_) override; + Common::Input::NfcState StopNfcPolling(const PadIdentifier& identifier_) override; + Common::Input::NfcState ReadAmiiboData(const PadIdentifier& identifier_, + std::vector& out_data) override; Common::Input::NfcState WriteNfcData(const PadIdentifier& identifier_, const std::vector& data) override; + Common::Input::NfcState ReadMifareData(const PadIdentifier& identifier_, + const Common::Input::MifareRequest& data, + Common::Input::MifareRequest& out_data) override; + Common::Input::NfcState WriteMifareData(const PadIdentifier& identifier_, + const Common::Input::MifareRequest& data) override; State GetCurrentState() const; @@ -61,8 +70,9 @@ private: static constexpr std::size_t MifareSize = 0x400; std::string file_path{}; - State state{State::Initialized}; + State state{State::Disabled}; std::vector nfc_data; + Common::Input::NfcStatus status; Common::Input::PollingMode polling_mode{Common::Input::PollingMode::Passive}; }; } // namespace InputCommon diff --git a/src/input_common/helpers/joycon_driver.cpp b/src/input_common/helpers/joycon_driver.cpp index 95106f16d..2c8c66951 100644 --- a/src/input_common/helpers/joycon_driver.cpp +++ b/src/input_common/helpers/joycon_driver.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "common/logging/log.h" +#include "common/scope_exit.h" #include "common/swap.h" #include "common/thread.h" #include "input_common/helpers/joycon_driver.h" @@ -112,7 +113,7 @@ DriverResult JoyconDriver::InitializeDevice() { joycon_poller = std::make_unique(device_type, left_stick_calibration, right_stick_calibration, motion_calibration); - // Start pooling for data + // Start polling for data is_connected = true; if (!input_thread_running) { input_thread = @@ -208,7 +209,7 @@ void JoyconDriver::OnNewData(std::span buffer) { joycon_poller->UpdateCamera(irs_protocol->GetImage(), irs_protocol->GetIrsFormat()); } - if (nfc_protocol->IsEnabled()) { + if (nfc_protocol->IsPolling()) { if (amiibo_detected) { if (!nfc_protocol->HasAmiibo()) { joycon_poller->UpdateAmiibo({}); @@ -218,10 +219,10 @@ void JoyconDriver::OnNewData(std::span buffer) { } if (!amiibo_detected) { - std::vector data(0x21C); - const auto result = nfc_protocol->ScanAmiibo(data); + Joycon::TagInfo tag_info; + const auto result = nfc_protocol->GetTagInfo(tag_info); if (result == DriverResult::Success) { - joycon_poller->UpdateAmiibo(data); + joycon_poller->UpdateAmiibo(tag_info); amiibo_detected = true; } } @@ -247,6 +248,7 @@ void JoyconDriver::OnNewData(std::span buffer) { } DriverResult JoyconDriver::SetPollingMode() { + SCOPE_EXIT({ disable_input_thread = false; }); disable_input_thread = true; rumble_protocol->EnableRumble(vibration_enabled && supported_features.vibration); @@ -276,7 +278,6 @@ DriverResult JoyconDriver::SetPollingMode() { if (irs_enabled && supported_features.irs) { auto result = irs_protocol->EnableIrs(); if (result == DriverResult::Success) { - disable_input_thread = false; return result; } irs_protocol->DisableIrs(); @@ -286,10 +287,6 @@ DriverResult JoyconDriver::SetPollingMode() { if (nfc_enabled && supported_features.nfc) { auto result = nfc_protocol->EnableNfc(); if (result == DriverResult::Success) { - result = nfc_protocol->StartNFCPollingMode(); - } - if (result == DriverResult::Success) { - disable_input_thread = false; return result; } nfc_protocol->DisableNfc(); @@ -303,7 +300,6 @@ DriverResult JoyconDriver::SetPollingMode() { } if (result == DriverResult::Success) { ring_connected = true; - disable_input_thread = false; return result; } ring_connected = false; @@ -314,7 +310,6 @@ DriverResult JoyconDriver::SetPollingMode() { if (passive_enabled && supported_features.passive) { const auto result = generic_protocol->EnablePassiveMode(); if (result == DriverResult::Success) { - disable_input_thread = false; return result; } LOG_ERROR(Input, "Error enabling passive mode"); @@ -328,7 +323,6 @@ DriverResult JoyconDriver::SetPollingMode() { // Switch calls this function after enabling active mode generic_protocol->TriggersElapsed(); - disable_input_thread = false; return result; } @@ -492,9 +486,63 @@ DriverResult JoyconDriver::SetRingConMode() { return result; } -DriverResult JoyconDriver::WriteNfcData(std::span data) { +DriverResult JoyconDriver::StartNfcPolling() { std::scoped_lock lock{mutex}; + + if (!supported_features.nfc) { + return DriverResult::NotSupported; + } + if (!nfc_protocol->IsEnabled()) { + return DriverResult::Disabled; + } + + disable_input_thread = true; + const auto result = nfc_protocol->StartNFCPollingMode(); + disable_input_thread = false; + + return result; +} + +DriverResult JoyconDriver::StopNfcPolling() { + std::scoped_lock lock{mutex}; + + if (!supported_features.nfc) { + return DriverResult::NotSupported; + } + if (!nfc_protocol->IsEnabled()) { + return DriverResult::Disabled; + } + + disable_input_thread = true; + const auto result = nfc_protocol->StopNFCPollingMode(); + disable_input_thread = false; + + return result; +} + +DriverResult JoyconDriver::ReadAmiiboData(std::vector& out_data) { + std::scoped_lock lock{mutex}; + + if (!supported_features.nfc) { + return DriverResult::NotSupported; + } + if (!nfc_protocol->IsEnabled()) { + return DriverResult::Disabled; + } + if (!amiibo_detected) { + return DriverResult::ErrorWritingData; + } + + out_data.resize(0x21C); disable_input_thread = true; + const auto result = nfc_protocol->ReadAmiibo(out_data); + disable_input_thread = false; + + return result; +} + +DriverResult JoyconDriver::WriteNfcData(std::span data) { + std::scoped_lock lock{mutex}; if (!supported_features.nfc) { return DriverResult::NotSupported; @@ -506,9 +554,51 @@ DriverResult JoyconDriver::WriteNfcData(std::span data) { return DriverResult::ErrorWritingData; } + disable_input_thread = true; const auto result = nfc_protocol->WriteAmiibo(data); + disable_input_thread = false; + return result; +} + +DriverResult JoyconDriver::ReadMifareData(std::span data, + std::span out_data) { + std::scoped_lock lock{mutex}; + + if (!supported_features.nfc) { + return DriverResult::NotSupported; + } + if (!nfc_protocol->IsEnabled()) { + return DriverResult::Disabled; + } + if (!amiibo_detected) { + return DriverResult::ErrorWritingData; + } + + disable_input_thread = true; + const auto result = nfc_protocol->ReadMifare(data, out_data); + disable_input_thread = false; + + return result; +} + +DriverResult JoyconDriver::WriteMifareData(std::span data) { + std::scoped_lock lock{mutex}; + + if (!supported_features.nfc) { + return DriverResult::NotSupported; + } + if (!nfc_protocol->IsEnabled()) { + return DriverResult::Disabled; + } + if (!amiibo_detected) { + return DriverResult::ErrorWritingData; + } + + disable_input_thread = true; + const auto result = nfc_protocol->WriteMifare(data); disable_input_thread = false; + return result; } diff --git a/src/input_common/helpers/joycon_driver.h b/src/input_common/helpers/joycon_driver.h index e9b2fccbb..bc7025a21 100644 --- a/src/input_common/helpers/joycon_driver.h +++ b/src/input_common/helpers/joycon_driver.h @@ -49,7 +49,13 @@ public: DriverResult SetIrMode(); DriverResult SetNfcMode(); DriverResult SetRingConMode(); + DriverResult StartNfcPolling(); + DriverResult StopNfcPolling(); + DriverResult ReadAmiiboData(std::vector& out_data); DriverResult WriteNfcData(std::span data); + DriverResult ReadMifareData(std::span request, + std::span out_data); + DriverResult WriteMifareData(std::span request); void SetCallbacks(const JoyconCallbacks& callbacks); diff --git a/src/input_common/helpers/joycon_protocol/joycon_types.h b/src/input_common/helpers/joycon_protocol/joycon_types.h index 5007b0e18..e0e431156 100644 --- a/src/input_common/helpers/joycon_protocol/joycon_types.h +++ b/src/input_common/helpers/joycon_protocol/joycon_types.h @@ -24,6 +24,7 @@ constexpr std::array DefaultVibrationBuffer{0x0, 0x1, 0x40, 0x40, 0x0, 0x using MacAddress = std::array; using SerialNumber = std::array; using TagUUID = std::array; +using MifareUUID = std::array; enum class ControllerType : u8 { None = 0x00, @@ -307,6 +308,19 @@ enum class NFCStatus : u8 { WriteDone = 0x05, TagLost = 0x07, WriteReady = 0x09, + MifareDone = 0x10, +}; + +enum class MifareCmd : u8 { + None = 0x00, + Read = 0x30, + AuthA = 0x60, + AuthB = 0x61, + Write = 0xA0, + Transfer = 0xB0, + Decrement = 0xC0, + Increment = 0xC1, + Store = 0xC2 }; enum class IrsMode : u8 { @@ -592,6 +606,14 @@ struct NFCWriteCommandData { static_assert(sizeof(NFCWriteCommandData) == 0x15, "NFCWriteCommandData is an invalid size"); #pragma pack(pop) +struct MifareCommandData { + u8 unknown1; + u8 unknown2; + u8 number_of_short_bytes; + MifareUUID uid; +}; +static_assert(sizeof(MifareCommandData) == 0x7, "MifareCommandData is an invalid size"); + struct NFCPollingCommandData { u8 enable_mifare; u8 unknown_1; @@ -629,6 +651,41 @@ struct NFCWritePackage { std::array data_chunks; }; +struct MifareReadChunk { + MifareCmd command; + std::array sector_key; + u8 sector; +}; + +struct MifareWriteChunk { + MifareCmd command; + std::array sector_key; + u8 sector; + std::array data; +}; + +struct MifareReadData { + u8 sector; + std::array data; +}; + +struct MifareReadPackage { + MifareCommandData command_data; + std::array data_chunks; +}; + +struct MifareWritePackage { + MifareCommandData command_data; + std::array data_chunks; +}; + +struct TagInfo { + u8 uuid_length; + u8 protocol; + u8 tag_type; + std::array uuid; +}; + struct IrsConfigure { MCUCommand command; MCUSubCommand sub_command; @@ -744,7 +801,7 @@ struct JoyconCallbacks { std::function on_stick_data; std::function on_motion_data; std::function on_ring_data; - std::function&)> on_amiibo_data; + std::function on_amiibo_data; std::function&, IrsResolution)> on_camera_data; }; diff --git a/src/input_common/helpers/joycon_protocol/nfc.cpp b/src/input_common/helpers/joycon_protocol/nfc.cpp index f7058c4a7..261f46255 100644 --- a/src/input_common/helpers/joycon_protocol/nfc.cpp +++ b/src/input_common/helpers/joycon_protocol/nfc.cpp @@ -40,6 +40,16 @@ DriverResult NfcProtocol::EnableNfc() { if (result == DriverResult::Success) { result = WaitUntilNfcIs(NFCStatus::Ready); } + if (result == DriverResult::Success) { + MCUCommandResponse output{}; + result = SendStopPollingRequest(output); + } + if (result == DriverResult::Success) { + result = WaitUntilNfcIs(NFCStatus::Ready); + } + if (result == DriverResult::Success) { + is_enabled = true; + } return result; } @@ -54,37 +64,50 @@ DriverResult NfcProtocol::DisableNfc() { } is_enabled = false; + is_polling = false; return result; } DriverResult NfcProtocol::StartNFCPollingMode() { - LOG_DEBUG(Input, "Start NFC pooling Mode"); + LOG_DEBUG(Input, "Start NFC polling Mode"); ScopedSetBlocking sb(this); DriverResult result{DriverResult::Success}; if (result == DriverResult::Success) { MCUCommandResponse output{}; - result = SendStopPollingRequest(output); + result = SendStartPollingRequest(output); } if (result == DriverResult::Success) { - result = WaitUntilNfcIs(NFCStatus::Ready); + result = WaitUntilNfcIs(NFCStatus::Polling); } + if (result == DriverResult::Success) { + is_polling = true; + } + + return result; +} + +DriverResult NfcProtocol::StopNFCPollingMode() { + LOG_DEBUG(Input, "Stop NFC polling Mode"); + ScopedSetBlocking sb(this); + DriverResult result{DriverResult::Success}; + if (result == DriverResult::Success) { MCUCommandResponse output{}; - result = SendStartPollingRequest(output); + result = SendStopPollingRequest(output); } if (result == DriverResult::Success) { - result = WaitUntilNfcIs(NFCStatus::Polling); + result = WaitUntilNfcIs(NFCStatus::WriteReady); } if (result == DriverResult::Success) { - is_enabled = true; + is_polling = false; } return result; } -DriverResult NfcProtocol::ScanAmiibo(std::vector& data) { +DriverResult NfcProtocol::GetTagInfo(Joycon::TagInfo& tag_info) { if (update_counter++ < AMIIBO_UPDATE_DELAY) { return DriverResult::Delayed; } @@ -100,11 +123,41 @@ DriverResult NfcProtocol::ScanAmiibo(std::vector& data) { } if (result == DriverResult::Success) { + tag_info = { + .uuid_length = tag_data.uuid_size, + .protocol = 1, + .tag_type = tag_data.type, + .uuid = {}, + }; + + memcpy(tag_info.uuid.data(), tag_data.uuid.data(), tag_data.uuid_size); + + // Investigate why mifare type is not correct + if (tag_info.tag_type == 144) { + tag_info.tag_type = 1U << 6; + } + std::string uuid_string; for (auto& content : tag_data.uuid) { uuid_string += fmt::format(" {:02x}", content); } LOG_INFO(Input, "Tag detected, type={}, uuid={}", tag_data.type, uuid_string); + } + + return result; +} + +DriverResult NfcProtocol::ReadAmiibo(std::vector& data) { + LOG_DEBUG(Input, "Scan for amiibos"); + ScopedSetBlocking sb(this); + DriverResult result{DriverResult::Success}; + TagFoundData tag_data{}; + + if (result == DriverResult::Success) { + result = IsTagInRange(tag_data, 7); + } + + if (result == DriverResult::Success) { result = GetAmiiboData(data); } @@ -154,6 +207,69 @@ DriverResult NfcProtocol::WriteAmiibo(std::span data) { return result; } +DriverResult NfcProtocol::ReadMifare(std::span read_request, + std::span out_data) { + LOG_DEBUG(Input, "Read mifare"); + ScopedSetBlocking sb(this); + DriverResult result{DriverResult::Success}; + TagFoundData tag_data{}; + MifareUUID tag_uuid{}; + + if (result == DriverResult::Success) { + result = IsTagInRange(tag_data, 7); + } + if (result == DriverResult::Success) { + memcpy(tag_uuid.data(), tag_data.uuid.data(), sizeof(MifareUUID)); + result = GetMifareData(tag_uuid, read_request, out_data); + } + if (result == DriverResult::Success) { + MCUCommandResponse output{}; + result = SendStopPollingRequest(output); + } + if (result == DriverResult::Success) { + result = WaitUntilNfcIs(NFCStatus::Ready); + } + if (result == DriverResult::Success) { + MCUCommandResponse output{}; + result = SendStartPollingRequest(output, true); + } + if (result == DriverResult::Success) { + result = WaitUntilNfcIs(NFCStatus::WriteReady); + } + return result; +} + +DriverResult NfcProtocol::WriteMifare(std::span write_request) { + LOG_DEBUG(Input, "Write mifare"); + ScopedSetBlocking sb(this); + DriverResult result{DriverResult::Success}; + TagFoundData tag_data{}; + MifareUUID tag_uuid{}; + + if (result == DriverResult::Success) { + result = IsTagInRange(tag_data, 7); + } + if (result == DriverResult::Success) { + memcpy(tag_uuid.data(), tag_data.uuid.data(), sizeof(MifareUUID)); + result = WriteMifareData(tag_uuid, write_request); + } + if (result == DriverResult::Success) { + MCUCommandResponse output{}; + result = SendStopPollingRequest(output); + } + if (result == DriverResult::Success) { + result = WaitUntilNfcIs(NFCStatus::Ready); + } + if (result == DriverResult::Success) { + MCUCommandResponse output{}; + result = SendStartPollingRequest(output, true); + } + if (result == DriverResult::Success) { + result = WaitUntilNfcIs(NFCStatus::WriteReady); + } + return result; +} + bool NfcProtocol::HasAmiibo() { if (update_counter++ < AMIIBO_UPDATE_DELAY) { return true; @@ -341,6 +457,158 @@ DriverResult NfcProtocol::WriteAmiiboData(const TagUUID& tag_uuid, std::span read_request, + std::span out_data) { + constexpr std::size_t timeout_limit = 60; + const auto nfc_data = MakeMifareReadPackage(tag_uuid, read_request); + const std::vector nfc_buffer_data = SerializeMifareReadPackage(nfc_data); + std::span buffer(nfc_buffer_data); + DriverResult result = DriverResult::Success; + MCUCommandResponse output{}; + u8 block_id = 1; + u8 package_index = 0; + std::size_t tries = 0; + std::size_t current_position = 0; + + LOG_INFO(Input, "Reading Mifare data"); + + // Send data request. Nfc buffer size is 31, Send the data in smaller packages + while (current_position < buffer.size() && tries++ < timeout_limit) { + const std::size_t next_position = + std::min(current_position + sizeof(NFCRequestState::raw_data), buffer.size()); + const std::size_t block_size = next_position - current_position; + const bool is_last_packet = block_size < sizeof(NFCRequestState::raw_data); + + SendReadDataMifareRequest(output, block_id, is_last_packet, + buffer.subspan(current_position, block_size)); + + const auto nfc_status = static_cast(output.mcu_data[6]); + + if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) { + return DriverResult::ErrorReadingData; + } + + // Increase position when data is confirmed by the joycon + if (output.mcu_report == MCUReport::NFCState && + (output.mcu_data[1] << 8) + output.mcu_data[0] == 0x0500 && + output.mcu_data[3] == block_id) { + block_id++; + current_position = next_position; + } + } + + if (result != DriverResult::Success) { + return result; + } + + // Wait for reply and save the output data + while (tries++ < timeout_limit) { + result = SendNextPackageRequest(output, package_index); + const auto nfc_status = static_cast(output.mcu_data[6]); + + if (result != DriverResult::Success) { + return result; + } + + if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) { + return DriverResult::ErrorReadingData; + } + + if (output.mcu_report == MCUReport::NFCState && output.mcu_data[1] == 0x10) { + constexpr std::size_t DATA_LENGHT = 0x10 + 1; + constexpr std::size_t DATA_START = 11; + const u8 number_of_elements = output.mcu_data[10]; + for (std::size_t i = 0; i < number_of_elements; i++) { + out_data[i].sector = output.mcu_data[DATA_START + (i * DATA_LENGHT)]; + memcpy(out_data[i].data.data(), + output.mcu_data.data() + DATA_START + 1 + (i * DATA_LENGHT), + sizeof(MifareReadData::data)); + } + package_index++; + continue; + } + + if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::MifareDone) { + LOG_INFO(Input, "Finished reading mifare"); + break; + } + } + + return result; +} + +DriverResult NfcProtocol::WriteMifareData(const MifareUUID& tag_uuid, + std::span write_request) { + constexpr std::size_t timeout_limit = 60; + const auto nfc_data = MakeMifareWritePackage(tag_uuid, write_request); + const std::vector nfc_buffer_data = SerializeMifareWritePackage(nfc_data); + std::span buffer(nfc_buffer_data); + DriverResult result = DriverResult::Success; + MCUCommandResponse output{}; + u8 block_id = 1; + u8 package_index = 0; + std::size_t tries = 0; + std::size_t current_position = 0; + + LOG_INFO(Input, "Writing Mifare data"); + + // Send data request. Nfc buffer size is 31, Send the data in smaller packages + while (current_position < buffer.size() && tries++ < timeout_limit) { + const std::size_t next_position = + std::min(current_position + sizeof(NFCRequestState::raw_data), buffer.size()); + const std::size_t block_size = next_position - current_position; + const bool is_last_packet = block_size < sizeof(NFCRequestState::raw_data); + + SendReadDataMifareRequest(output, block_id, is_last_packet, + buffer.subspan(current_position, block_size)); + + const auto nfc_status = static_cast(output.mcu_data[6]); + + if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) { + return DriverResult::ErrorReadingData; + } + + // Increase position when data is confirmed by the joycon + if (output.mcu_report == MCUReport::NFCState && + (output.mcu_data[1] << 8) + output.mcu_data[0] == 0x0500 && + output.mcu_data[3] == block_id) { + block_id++; + current_position = next_position; + } + } + + if (result != DriverResult::Success) { + return result; + } + + // Wait for reply and ignore the output data + while (tries++ < timeout_limit) { + result = SendNextPackageRequest(output, package_index); + const auto nfc_status = static_cast(output.mcu_data[6]); + + if (result != DriverResult::Success) { + return result; + } + + if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) { + return DriverResult::ErrorReadingData; + } + + if (output.mcu_report == MCUReport::NFCState && output.mcu_data[1] == 0x10) { + package_index++; + continue; + } + + if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::MifareDone) { + LOG_INFO(Input, "Finished writing mifare"); + break; + } + } + + return result; +} + DriverResult NfcProtocol::SendStartPollingRequest(MCUCommandResponse& output, bool is_second_attempt) { NFCRequestState request{ @@ -477,6 +745,28 @@ DriverResult NfcProtocol::SendWriteDataAmiiboRequest(MCUCommandResponse& output, output); } +DriverResult NfcProtocol::SendReadDataMifareRequest(MCUCommandResponse& output, u8 block_id, + bool is_last_packet, std::span data) { + const auto data_size = std::min(data.size(), sizeof(NFCRequestState::raw_data)); + NFCRequestState request{ + .command_argument = NFCCommand::Mifare, + .block_id = block_id, + .packet_id = {}, + .packet_flag = + is_last_packet ? MCUPacketFlag::LastCommandPacket : MCUPacketFlag::MorePacketsRemaining, + .data_length = static_cast(data_size), + .raw_data = {}, + .crc = {}, + }; + memcpy(request.raw_data.data(), data.data(), data_size); + + std::array request_data{}; + memcpy(request_data.data(), &request, sizeof(NFCRequestState)); + request_data[36] = CalculateMCU_CRC8(request_data.data(), 36); + return SendMCUData(ReportMode::NFC_IR_MODE_60HZ, MCUSubCommand::ReadDeviceMode, request_data, + output); +} + std::vector NfcProtocol::SerializeWritePackage(const NFCWritePackage& package) const { const std::size_t header_size = sizeof(NFCWriteCommandData) + sizeof(NFCWritePackage::number_of_chunks); @@ -498,6 +788,48 @@ std::vector NfcProtocol::SerializeWritePackage(const NFCWritePackage& packag return serialized_data; } +std::vector NfcProtocol::SerializeMifareReadPackage(const MifareReadPackage& package) const { + const std::size_t header_size = sizeof(MifareCommandData); + std::vector serialized_data(header_size); + std::size_t start_index = 0; + + memcpy(serialized_data.data(), &package, header_size); + start_index += header_size; + + for (const auto& data_chunk : package.data_chunks) { + const std::size_t chunk_size = sizeof(MifareReadChunk); + if (data_chunk.command == MifareCmd::None) { + continue; + } + serialized_data.resize(start_index + chunk_size); + memcpy(serialized_data.data() + start_index, &data_chunk, chunk_size); + start_index += chunk_size; + } + + return serialized_data; +} + +std::vector NfcProtocol::SerializeMifareWritePackage(const MifareWritePackage& package) const { + const std::size_t header_size = sizeof(MifareCommandData); + std::vector serialized_data(header_size); + std::size_t start_index = 0; + + memcpy(serialized_data.data(), &package, header_size); + start_index += header_size; + + for (const auto& data_chunk : package.data_chunks) { + const std::size_t chunk_size = sizeof(MifareWriteChunk); + if (data_chunk.command == MifareCmd::None) { + continue; + } + serialized_data.resize(start_index + chunk_size); + memcpy(serialized_data.data() + start_index, &data_chunk, chunk_size); + start_index += chunk_size; + } + + return serialized_data; +} + NFCWritePackage NfcProtocol::MakeAmiiboWritePackage(const TagUUID& tag_uuid, std::span data) const { return { @@ -527,6 +859,46 @@ NFCWritePackage NfcProtocol::MakeAmiiboWritePackage(const TagUUID& tag_uuid, }; } +MifareReadPackage NfcProtocol::MakeMifareReadPackage( + const MifareUUID& tag_uuid, std::span read_request) const { + MifareReadPackage package{ + .command_data{ + .unknown1 = 0xd0, + .unknown2 = 0x07, + .number_of_short_bytes = static_cast( + ((read_request.size() * sizeof(MifareReadChunk)) + sizeof(MifareUUID)) / 2), + .uid = tag_uuid, + }, + .data_chunks = {}, + }; + + for (std::size_t i = 0; i < read_request.size() && i < package.data_chunks.size(); ++i) { + package.data_chunks[i] = read_request[i]; + } + + return package; +} + +MifareWritePackage NfcProtocol::MakeMifareWritePackage( + const MifareUUID& tag_uuid, std::span read_request) const { + MifareWritePackage package{ + .command_data{ + .unknown1 = 0xd0, + .unknown2 = 0x07, + .number_of_short_bytes = static_cast( + ((read_request.size() * sizeof(MifareReadChunk)) + sizeof(MifareUUID) + 2) / 2), + .uid = tag_uuid, + }, + .data_chunks = {}, + }; + + for (std::size_t i = 0; i < read_request.size() && i < package.data_chunks.size(); ++i) { + package.data_chunks[i] = read_request[i]; + } + + return package; +} + NFCDataChunk NfcProtocol::MakeAmiiboChunk(u8 page, u8 size, std::span data) const { constexpr u8 NFC_PAGE_SIZE = 4; @@ -606,4 +978,8 @@ bool NfcProtocol::IsEnabled() const { return is_enabled; } +bool NfcProtocol::IsPolling() const { + return is_polling; +} + } // namespace InputCommon::Joycon diff --git a/src/input_common/helpers/joycon_protocol/nfc.h b/src/input_common/helpers/joycon_protocol/nfc.h index eb58c427d..0be95e40e 100644 --- a/src/input_common/helpers/joycon_protocol/nfc.h +++ b/src/input_common/helpers/joycon_protocol/nfc.h @@ -25,14 +25,25 @@ public: DriverResult StartNFCPollingMode(); - DriverResult ScanAmiibo(std::vector& data); + DriverResult StopNFCPollingMode(); + + DriverResult GetTagInfo(Joycon::TagInfo& tag_info); + + DriverResult ReadAmiibo(std::vector& data); DriverResult WriteAmiibo(std::span data); + DriverResult ReadMifare(std::span read_request, + std::span out_data); + + DriverResult WriteMifare(std::span write_request); + bool HasAmiibo(); bool IsEnabled() const; + bool IsPolling() const; + private: // Number of times the function will be delayed until it outputs valid data static constexpr std::size_t AMIIBO_UPDATE_DELAY = 15; @@ -51,6 +62,13 @@ private: DriverResult WriteAmiiboData(const TagUUID& tag_uuid, std::span data); + DriverResult GetMifareData(const MifareUUID& tag_uuid, + std::span read_request, + std::span out_data); + + DriverResult WriteMifareData(const MifareUUID& tag_uuid, + std::span write_request); + DriverResult SendStartPollingRequest(MCUCommandResponse& output, bool is_second_attempt = false); @@ -65,17 +83,31 @@ private: DriverResult SendWriteDataAmiiboRequest(MCUCommandResponse& output, u8 block_id, bool is_last_packet, std::span data); + DriverResult SendReadDataMifareRequest(MCUCommandResponse& output, u8 block_id, + bool is_last_packet, std::span data); + std::vector SerializeWritePackage(const NFCWritePackage& package) const; + std::vector SerializeMifareReadPackage(const MifareReadPackage& package) const; + + std::vector SerializeMifareWritePackage(const MifareWritePackage& package) const; + NFCWritePackage MakeAmiiboWritePackage(const TagUUID& tag_uuid, std::span data) const; NFCDataChunk MakeAmiiboChunk(u8 page, u8 size, std::span data) const; + MifareReadPackage MakeMifareReadPackage(const MifareUUID& tag_uuid, + std::span read_request) const; + + MifareWritePackage MakeMifareWritePackage(const MifareUUID& tag_uuid, + std::span read_request) const; + NFCReadBlockCommand GetReadBlockCommand(NFCPages pages) const; TagUUID GetTagUUID(std::span data) const; bool is_enabled{}; + bool is_polling{}; std::size_t update_counter{}; }; diff --git a/src/input_common/helpers/joycon_protocol/poller.cpp b/src/input_common/helpers/joycon_protocol/poller.cpp index dca797f7a..1aab9e12a 100644 --- a/src/input_common/helpers/joycon_protocol/poller.cpp +++ b/src/input_common/helpers/joycon_protocol/poller.cpp @@ -70,8 +70,8 @@ void JoyconPoller::UpdateColor(const Color& color) { callbacks.on_color_data(color); } -void JoyconPoller::UpdateAmiibo(const std::vector& amiibo_data) { - callbacks.on_amiibo_data(amiibo_data); +void JoyconPoller::UpdateAmiibo(const Joycon::TagInfo& tag_info) { + callbacks.on_amiibo_data(tag_info); } void JoyconPoller::UpdateCamera(const std::vector& camera_data, IrsResolution format) { diff --git a/src/input_common/helpers/joycon_protocol/poller.h b/src/input_common/helpers/joycon_protocol/poller.h index 0fa72c6db..3746abe5d 100644 --- a/src/input_common/helpers/joycon_protocol/poller.h +++ b/src/input_common/helpers/joycon_protocol/poller.h @@ -36,8 +36,8 @@ public: void UpdateColor(const Color& color); void UpdateRing(s16 value, const RingStatus& ring_status); - void UpdateAmiibo(const std::vector& amiibo_data); - void UpdateCamera(const std::vector& amiibo_data, IrsResolution format); + void UpdateAmiibo(const Joycon::TagInfo& tag_info); + void UpdateCamera(const std::vector& camera_data, IrsResolution format); private: void UpdateActiveLeftPadInput(const InputReportActive& input, diff --git a/src/input_common/input_engine.h b/src/input_common/input_engine.h index 50b5a3dc8..c2d0cbb34 100644 --- a/src/input_common/input_engine.h +++ b/src/input_common/input_engine.h @@ -143,12 +143,46 @@ public: return Common::Input::NfcState::NotSupported; } + // Start scanning for nfc tags + virtual Common::Input::NfcState StartNfcPolling( + [[maybe_unused]] const PadIdentifier& identifier_) { + return Common::Input::NfcState::NotSupported; + } + + // Start scanning for nfc tags + virtual Common::Input::NfcState StopNfcPolling( + [[maybe_unused]] const PadIdentifier& identifier_) { + return Common::Input::NfcState::NotSupported; + } + + // Reads data from amiibo tag + virtual Common::Input::NfcState ReadAmiiboData( + [[maybe_unused]] const PadIdentifier& identifier_, + [[maybe_unused]] std::vector& out_data) { + return Common::Input::NfcState::NotSupported; + } + // Writes data to an nfc tag virtual Common::Input::NfcState WriteNfcData([[maybe_unused]] const PadIdentifier& identifier, [[maybe_unused]] const std::vector& data) { return Common::Input::NfcState::NotSupported; } + // Reads data from mifare tag + virtual Common::Input::NfcState ReadMifareData( + [[maybe_unused]] const PadIdentifier& identifier_, + [[maybe_unused]] const Common::Input::MifareRequest& request, + [[maybe_unused]] Common::Input::MifareRequest& out_data) { + return Common::Input::NfcState::NotSupported; + } + + // Write data to mifare tag + virtual Common::Input::NfcState WriteMifareData( + [[maybe_unused]] const PadIdentifier& identifier_, + [[maybe_unused]] const Common::Input::MifareRequest& request) { + return Common::Input::NfcState::NotSupported; + } + // Returns the engine name [[nodiscard]] const std::string& GetEngineName() const; diff --git a/src/input_common/input_poller.cpp b/src/input_common/input_poller.cpp index 380a01542..870e76ab0 100644 --- a/src/input_common/input_poller.cpp +++ b/src/input_common/input_poller.cpp @@ -792,8 +792,7 @@ public: const Common::Input::CallbackStatus status{ .type = Common::Input::InputType::Nfc, - .nfc_status = nfc_status.state, - .raw_data = nfc_status.data, + .nfc_status = nfc_status, }; TriggerOnChange(status); @@ -836,10 +835,31 @@ public: return input_engine->SupportsNfc(identifier); } + Common::Input::NfcState StartNfcPolling() { + return input_engine->StartNfcPolling(identifier); + } + + Common::Input::NfcState StopNfcPolling() { + return input_engine->StopNfcPolling(identifier); + } + + Common::Input::NfcState ReadAmiiboData(std::vector& out_data) { + return input_engine->ReadAmiiboData(identifier, out_data); + } + Common::Input::NfcState WriteNfcData(const std::vector& data) override { return input_engine->WriteNfcData(identifier, data); } + Common::Input::NfcState ReadMifareData(const Common::Input::MifareRequest& request, + Common::Input::MifareRequest& out_data) { + return input_engine->ReadMifareData(identifier, request, out_data); + } + + Common::Input::NfcState WriteMifareData(const Common::Input::MifareRequest& request) { + return input_engine->WriteMifareData(identifier, request); + } + private: const PadIdentifier identifier; InputEngine* input_engine; diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 013715b44..cba7c3cce 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -3836,7 +3836,7 @@ void GMainWindow::OnLoadAmiibo() { auto* virtual_amiibo = input_subsystem->GetVirtualAmiibo(); // Remove amiibo if one is connected - if (virtual_amiibo->GetCurrentState() == InputCommon::VirtualAmiibo::State::AmiiboIsOpen) { + if (virtual_amiibo->GetCurrentState() == InputCommon::VirtualAmiibo::State::TagNearby) { virtual_amiibo->CloseAmiibo(); QMessageBox::warning(this, tr("Amiibo"), tr("The current amiibo has been removed")); return; @@ -3864,7 +3864,7 @@ void GMainWindow::LoadAmiibo(const QString& filename) { auto* virtual_amiibo = input_subsystem->GetVirtualAmiibo(); const QString title = tr("Error loading Amiibo data"); // Remove amiibo if one is connected - if (virtual_amiibo->GetCurrentState() == InputCommon::VirtualAmiibo::State::AmiiboIsOpen) { + if (virtual_amiibo->GetCurrentState() == InputCommon::VirtualAmiibo::State::TagNearby) { virtual_amiibo->CloseAmiibo(); QMessageBox::warning(this, tr("Amiibo"), tr("The current amiibo has been removed")); return; -- cgit v1.2.3 From 5da70f719703084482933e103e561cc98163f370 Mon Sep 17 00:00:00 2001 From: Kelebek1 Date: Tue, 23 May 2023 14:45:54 +0100 Subject: Remove memory allocations in some hot paths --- src/audio_core/device/audio_buffers.h | 8 +-- src/audio_core/device/device_session.cpp | 12 ++--- src/audio_core/device/device_session.h | 7 +-- src/audio_core/in/audio_in_system.cpp | 5 +- src/audio_core/out/audio_out_system.cpp | 4 +- .../renderer/command/data_source/decode.cpp | 23 ++++----- .../renderer/command/effect/compressor.cpp | 8 +-- src/audio_core/renderer/command/effect/delay.cpp | 14 ++--- .../renderer/command/effect/i3dl2_reverb.cpp | 4 +- .../renderer/command/effect/light_limiter.cpp | 12 ++--- src/audio_core/renderer/command/effect/reverb.cpp | 12 ++--- .../renderer/command/sink/circular_buffer.cpp | 4 +- src/audio_core/renderer/command/sink/device.cpp | 5 +- src/audio_core/renderer/mix/mix_context.cpp | 6 +-- src/audio_core/renderer/nodes/node_states.cpp | 4 +- src/audio_core/renderer/nodes/node_states.h | 2 +- src/audio_core/renderer/system.cpp | 1 + src/audio_core/sink/null_sink.h | 2 +- src/audio_core/sink/sink_stream.cpp | 15 +++--- src/audio_core/sink/sink_stream.h | 5 +- src/common/ring_buffer.h | 3 +- src/common/scratch_buffer.h | 9 ++++ src/core/hle/kernel/k_synchronization_object.cpp | 3 +- src/core/hle/kernel/k_thread.cpp | 8 ++- src/core/hle/kernel/k_thread.h | 3 +- src/core/hle/kernel/svc/svc_ipc.cpp | 7 +-- src/core/hle/kernel/svc/svc_synchronization.cpp | 10 ++-- src/core/hle/kernel/svc/svc_thread.cpp | 2 +- src/core/hle/service/audio/audin_u.cpp | 16 +++--- src/core/hle/service/audio/audout_u.cpp | 15 ++---- src/core/hle/service/audio/audren_u.cpp | 22 ++++---- src/core/hle/service/audio/audren_u.h | 1 + src/core/hle/service/audio/hwopus.cpp | 9 ++-- src/core/hle/service/nvdrv/devices/nvdevice.h | 6 +-- .../hle/service/nvdrv/devices/nvdisp_disp0.cpp | 6 +-- src/core/hle/service/nvdrv/devices/nvdisp_disp0.h | 8 +-- .../hle/service/nvdrv/devices/nvhost_as_gpu.cpp | 31 ++++++------ src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h | 30 ++++++----- src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp | 19 ++++--- src/core/hle/service/nvdrv/devices/nvhost_ctrl.h | 21 ++++---- .../hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp | 32 ++++++------ .../hle/service/nvdrv/devices/nvhost_ctrl_gpu.h | 38 +++++++------- src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp | 59 +++++++++++----------- src/core/hle/service/nvdrv/devices/nvhost_gpu.h | 36 ++++++------- .../hle/service/nvdrv/devices/nvhost_nvdec.cpp | 6 +-- src/core/hle/service/nvdrv/devices/nvhost_nvdec.h | 8 +-- .../service/nvdrv/devices/nvhost_nvdec_common.cpp | 15 +++--- .../service/nvdrv/devices/nvhost_nvdec_common.h | 12 ++--- .../hle/service/nvdrv/devices/nvhost_nvjpg.cpp | 8 +-- src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h | 10 ++-- src/core/hle/service/nvdrv/devices/nvhost_vic.cpp | 6 +-- src/core/hle/service/nvdrv/devices/nvhost_vic.h | 8 +-- src/core/hle/service/nvdrv/devices/nvmap.cpp | 20 ++++---- src/core/hle/service/nvdrv/devices/nvmap.h | 20 ++++---- src/core/hle/service/nvdrv/nvdrv.cpp | 8 +-- src/core/hle/service/nvdrv/nvdrv.h | 8 +-- src/core/hle/service/nvdrv/nvdrv_interface.cpp | 24 ++++----- src/core/hle/service/nvdrv/nvdrv_interface.h | 3 ++ src/core/hle/service/nvnflinger/parcel.h | 7 +-- .../backend/glsl/glsl_emit_context.cpp | 2 +- src/shader_recompiler/backend/spirv/emit_spirv.cpp | 2 +- .../backend/spirv/spirv_emit_context.cpp | 2 +- src/shader_recompiler/runtime_info.h | 3 +- src/video_core/buffer_cache/buffer_cache.h | 4 +- src/video_core/buffer_cache/buffer_cache_base.h | 4 +- src/video_core/cdma_pusher.h | 1 - src/video_core/dma_pusher.h | 8 +-- src/video_core/engines/maxwell_dma.cpp | 35 +++++++------ src/video_core/host1x/codecs/h264.cpp | 4 +- src/video_core/memory_manager.cpp | 13 ++--- src/video_core/memory_manager.h | 15 ++++-- src/video_core/renderer_opengl/gl_shader_cache.cpp | 4 +- src/video_core/renderer_vulkan/vk_buffer_cache.cpp | 2 +- .../renderer_vulkan/vk_pipeline_cache.cpp | 10 +++- .../renderer_vulkan/vk_texture_cache.cpp | 27 +++++----- src/video_core/shader_cache.cpp | 4 +- src/video_core/texture_cache/image_base.h | 5 +- src/video_core/texture_cache/texture_cache.h | 14 ++--- src/video_core/texture_cache/texture_cache_base.h | 4 +- src/video_core/texture_cache/util.cpp | 48 ++++++++++-------- src/video_core/texture_cache/util.h | 31 ++++++------ src/video_core/transform_feedback.cpp | 8 +-- src/video_core/transform_feedback.h | 2 +- src/video_core/vulkan_common/vulkan_device.cpp | 1 + 84 files changed, 503 insertions(+), 460 deletions(-) (limited to 'src') diff --git a/src/audio_core/device/audio_buffers.h b/src/audio_core/device/audio_buffers.h index 15082f6c6..5d8ed0ef7 100644 --- a/src/audio_core/device/audio_buffers.h +++ b/src/audio_core/device/audio_buffers.h @@ -7,6 +7,7 @@ #include #include #include +#include #include "audio_buffer.h" #include "audio_core/device/device_session.h" @@ -48,7 +49,7 @@ public: * * @param out_buffers - The buffers which were registered. */ - void RegisterBuffers(std::vector& out_buffers) { + void RegisterBuffers(boost::container::static_vector& out_buffers) { std::scoped_lock l{lock}; const s32 to_register{std::min(std::min(appended_count, BufferAppendLimit), BufferAppendLimit - registered_count)}; @@ -162,7 +163,8 @@ public: * @param max_buffers - Maximum number of buffers to released. * @return The number of buffers released. */ - u32 GetRegisteredAppendedBuffers(std::vector& buffers_flushed, u32 max_buffers) { + u32 GetRegisteredAppendedBuffers( + boost::container::static_vector& buffers_flushed, u32 max_buffers) { std::scoped_lock l{lock}; if (registered_count + appended_count == 0) { return 0; @@ -270,7 +272,7 @@ public: */ bool FlushBuffers(u32& buffers_released) { std::scoped_lock l{lock}; - std::vector buffers_flushed{}; + boost::container::static_vector buffers_flushed{}; buffers_released = GetRegisteredAppendedBuffers(buffers_flushed, append_limit); diff --git a/src/audio_core/device/device_session.cpp b/src/audio_core/device/device_session.cpp index b5c0ef0e6..86811fcb8 100644 --- a/src/audio_core/device/device_session.cpp +++ b/src/audio_core/device/device_session.cpp @@ -79,7 +79,7 @@ void DeviceSession::ClearBuffers() { } } -void DeviceSession::AppendBuffers(std::span buffers) const { +void DeviceSession::AppendBuffers(std::span buffers) { for (const auto& buffer : buffers) { Sink::SinkBuffer new_buffer{ .frames = buffer.size / (channel_count * sizeof(s16)), @@ -88,13 +88,13 @@ void DeviceSession::AppendBuffers(std::span buffers) const { .consumed = false, }; + tmp_samples.resize_destructive(buffer.size / sizeof(s16)); if (type == Sink::StreamType::In) { - std::vector samples{}; - stream->AppendBuffer(new_buffer, samples); + stream->AppendBuffer(new_buffer, tmp_samples); } else { - std::vector samples(buffer.size / sizeof(s16)); - system.ApplicationMemory().ReadBlockUnsafe(buffer.samples, samples.data(), buffer.size); - stream->AppendBuffer(new_buffer, samples); + system.ApplicationMemory().ReadBlockUnsafe(buffer.samples, tmp_samples.data(), + buffer.size); + stream->AppendBuffer(new_buffer, tmp_samples); } } } diff --git a/src/audio_core/device/device_session.h b/src/audio_core/device/device_session.h index 75f766c68..7d52f362d 100644 --- a/src/audio_core/device/device_session.h +++ b/src/audio_core/device/device_session.h @@ -10,6 +10,7 @@ #include "audio_core/common/common.h" #include "audio_core/sink/sink.h" +#include "common/scratch_buffer.h" #include "core/hle/service/audio/errors.h" namespace Core { @@ -62,7 +63,7 @@ public: * * @param buffers - The buffers to play. */ - void AppendBuffers(std::span buffers) const; + void AppendBuffers(std::span buffers); /** * (Audio In only) Pop samples from the backend, and write them back to this buffer's address. @@ -146,8 +147,8 @@ private: std::shared_ptr thread_event; /// Is this session initialised? bool initialized{}; - /// Buffer queue - std::vector buffer_queue{}; + /// Temporary sample buffer + Common::ScratchBuffer tmp_samples{}; }; } // namespace AudioCore diff --git a/src/audio_core/in/audio_in_system.cpp b/src/audio_core/in/audio_in_system.cpp index e23e51758..579129121 100644 --- a/src/audio_core/in/audio_in_system.cpp +++ b/src/audio_core/in/audio_in_system.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include + #include "audio_core/audio_event.h" #include "audio_core/audio_manager.h" #include "audio_core/in/audio_in_system.h" @@ -89,7 +90,7 @@ Result System::Start() { session->Start(); state = State::Started; - std::vector buffers_to_flush{}; + boost::container::static_vector buffers_to_flush{}; buffers.RegisterBuffers(buffers_to_flush); session->AppendBuffers(buffers_to_flush); session->SetRingSize(static_cast(buffers_to_flush.size())); @@ -134,7 +135,7 @@ bool System::AppendBuffer(const AudioInBuffer& buffer, const u64 tag) { void System::RegisterBuffers() { if (state == State::Started) { - std::vector registered_buffers{}; + boost::container::static_vector registered_buffers{}; buffers.RegisterBuffers(registered_buffers); session->AppendBuffers(registered_buffers); } diff --git a/src/audio_core/out/audio_out_system.cpp b/src/audio_core/out/audio_out_system.cpp index bd13f7219..0adf64bd3 100644 --- a/src/audio_core/out/audio_out_system.cpp +++ b/src/audio_core/out/audio_out_system.cpp @@ -89,7 +89,7 @@ Result System::Start() { session->Start(); state = State::Started; - std::vector buffers_to_flush{}; + boost::container::static_vector buffers_to_flush{}; buffers.RegisterBuffers(buffers_to_flush); session->AppendBuffers(buffers_to_flush); session->SetRingSize(static_cast(buffers_to_flush.size())); @@ -134,7 +134,7 @@ bool System::AppendBuffer(const AudioOutBuffer& buffer, u64 tag) { void System::RegisterBuffers() { if (state == State::Started) { - std::vector registered_buffers{}; + boost::container::static_vector registered_buffers{}; buffers.RegisterBuffers(registered_buffers); session->AppendBuffers(registered_buffers); } diff --git a/src/audio_core/renderer/command/data_source/decode.cpp b/src/audio_core/renderer/command/data_source/decode.cpp index ff5d31bd6..f45933203 100644 --- a/src/audio_core/renderer/command/data_source/decode.cpp +++ b/src/audio_core/renderer/command/data_source/decode.cpp @@ -8,6 +8,7 @@ #include "audio_core/renderer/command/resample/resample.h" #include "common/fixed_point.h" #include "common/logging/log.h" +#include "common/scratch_buffer.h" #include "core/memory.h" namespace AudioCore::AudioRenderer { @@ -27,6 +28,7 @@ constexpr std::array PitchBySrcQuality = {4, 8, 4}; template static u32 DecodePcm(Core::Memory::Memory& memory, std::span out_buffer, const DecodeArg& req) { + std::array tmp_samples{}; constexpr s32 min{std::numeric_limits::min()}; constexpr s32 max{std::numeric_limits::max()}; @@ -49,18 +51,17 @@ static u32 DecodePcm(Core::Memory::Memory& memory, std::span out_buffer, const u64 size{channel_count * samples_to_decode}; const u64 size_bytes{size * sizeof(T)}; - std::vector samples(size); - memory.ReadBlockUnsafe(source, samples.data(), size_bytes); + memory.ReadBlockUnsafe(source, tmp_samples.data(), size_bytes); if constexpr (std::is_floating_point_v) { for (u32 i = 0; i < samples_to_decode; i++) { - auto sample{static_cast(samples[i * channel_count + req.target_channel] * + auto sample{static_cast(tmp_samples[i * channel_count + req.target_channel] * std::numeric_limits::max())}; out_buffer[i] = static_cast(std::clamp(sample, min, max)); } } else { for (u32 i = 0; i < samples_to_decode; i++) { - out_buffer[i] = samples[i * channel_count + req.target_channel]; + out_buffer[i] = tmp_samples[i * channel_count + req.target_channel]; } } } break; @@ -73,17 +74,16 @@ static u32 DecodePcm(Core::Memory::Memory& memory, std::span out_buffer, } const VAddr source{req.buffer + ((req.start_offset + req.offset) * sizeof(T))}; - std::vector samples(samples_to_decode); - memory.ReadBlockUnsafe(source, samples.data(), samples_to_decode * sizeof(T)); + memory.ReadBlockUnsafe(source, tmp_samples.data(), samples_to_decode * sizeof(T)); if constexpr (std::is_floating_point_v) { for (u32 i = 0; i < samples_to_decode; i++) { - auto sample{static_cast(samples[i * channel_count + req.target_channel] * + auto sample{static_cast(tmp_samples[i * channel_count + req.target_channel] * std::numeric_limits::max())}; out_buffer[i] = static_cast(std::clamp(sample, min, max)); } } else { - std::memcpy(out_buffer.data(), samples.data(), samples_to_decode * sizeof(s16)); + std::memcpy(out_buffer.data(), tmp_samples.data(), samples_to_decode * sizeof(s16)); } break; } @@ -101,6 +101,7 @@ static u32 DecodePcm(Core::Memory::Memory& memory, std::span out_buffer, */ static u32 DecodeAdpcm(Core::Memory::Memory& memory, std::span out_buffer, const DecodeArg& req) { + std::array wavebuffer{}; constexpr u32 SamplesPerFrame{14}; constexpr u32 NibblesPerFrame{16}; @@ -138,9 +139,7 @@ static u32 DecodeAdpcm(Core::Memory::Memory& memory, std::span out_buffer, } const auto size{std::max((samples_to_process / 8U) * SamplesPerFrame, 8U)}; - std::vector wavebuffer(size); - memory.ReadBlockUnsafe(req.buffer + position_in_frame / 2, wavebuffer.data(), - wavebuffer.size()); + memory.ReadBlockUnsafe(req.buffer + position_in_frame / 2, wavebuffer.data(), size); auto context{req.adpcm_context}; auto header{context->header}; @@ -258,7 +257,7 @@ void DecodeFromWaveBuffers(Core::Memory::Memory& memory, const DecodeFromWaveBuf u32 offset{voice_state.offset}; auto output_buffer{args.output}; - std::vector temp_buffer(TempBufferSize, 0); + std::array temp_buffer{}; while (remaining_sample_count > 0) { const auto samples_to_write{std::min(remaining_sample_count, max_remaining_sample_count)}; diff --git a/src/audio_core/renderer/command/effect/compressor.cpp b/src/audio_core/renderer/command/effect/compressor.cpp index 7229618e8..ee9b68d5b 100644 --- a/src/audio_core/renderer/command/effect/compressor.cpp +++ b/src/audio_core/renderer/command/effect/compressor.cpp @@ -44,8 +44,8 @@ static void InitializeCompressorEffect(const CompressorInfo::ParameterVersion2& static void ApplyCompressorEffect(const CompressorInfo::ParameterVersion2& params, CompressorInfo::State& state, bool enabled, - std::vector> input_buffers, - std::vector> output_buffers, u32 sample_count) { + std::span> input_buffers, + std::span> output_buffers, u32 sample_count) { if (enabled) { auto state_00{state.unk_00}; auto state_04{state.unk_04}; @@ -124,8 +124,8 @@ void CompressorCommand::Dump([[maybe_unused]] const ADSP::CommandListProcessor& } void CompressorCommand::Process(const ADSP::CommandListProcessor& processor) { - std::vector> input_buffers(parameter.channel_count); - std::vector> output_buffers(parameter.channel_count); + std::array, MaxChannels> input_buffers{}; + std::array, MaxChannels> output_buffers{}; for (s16 i = 0; i < parameter.channel_count; i++) { input_buffers[i] = processor.mix_buffers.subspan(inputs[i] * processor.sample_count, diff --git a/src/audio_core/renderer/command/effect/delay.cpp b/src/audio_core/renderer/command/effect/delay.cpp index a4e408d40..e536cbb1e 100644 --- a/src/audio_core/renderer/command/effect/delay.cpp +++ b/src/audio_core/renderer/command/effect/delay.cpp @@ -51,7 +51,7 @@ static void InitializeDelayEffect(const DelayInfo::ParameterVersion1& params, state.delay_lines[channel].sample_count_max = sample_count_max.to_int_floor(); state.delay_lines[channel].sample_count = sample_count.to_int_floor(); state.delay_lines[channel].buffer.resize(state.delay_lines[channel].sample_count, 0); - if (state.delay_lines[channel].buffer.size() == 0) { + if (state.delay_lines[channel].sample_count == 0) { state.delay_lines[channel].buffer.push_back(0); } state.delay_lines[channel].buffer_pos = 0; @@ -74,8 +74,8 @@ static void InitializeDelayEffect(const DelayInfo::ParameterVersion1& params, */ template static void ApplyDelay(const DelayInfo::ParameterVersion1& params, DelayInfo::State& state, - std::vector>& inputs, - std::vector>& outputs, const u32 sample_count) { + std::span> inputs, std::span> outputs, + const u32 sample_count) { for (u32 sample_index = 0; sample_index < sample_count; sample_index++) { std::array, NumChannels> input_samples{}; for (u32 channel = 0; channel < NumChannels; channel++) { @@ -153,8 +153,8 @@ static void ApplyDelay(const DelayInfo::ParameterVersion1& params, DelayInfo::St * @param sample_count - Number of samples to process. */ static void ApplyDelayEffect(const DelayInfo::ParameterVersion1& params, DelayInfo::State& state, - const bool enabled, std::vector>& inputs, - std::vector>& outputs, const u32 sample_count) { + const bool enabled, std::span> inputs, + std::span> outputs, const u32 sample_count) { if (!IsChannelCountValid(params.channel_count)) { LOG_ERROR(Service_Audio, "Invalid delay channels {}", params.channel_count); @@ -208,8 +208,8 @@ void DelayCommand::Dump([[maybe_unused]] const ADSP::CommandListProcessor& proce } void DelayCommand::Process(const ADSP::CommandListProcessor& processor) { - std::vector> input_buffers(parameter.channel_count); - std::vector> output_buffers(parameter.channel_count); + std::array, MaxChannels> input_buffers{}; + std::array, MaxChannels> output_buffers{}; for (s16 i = 0; i < parameter.channel_count; i++) { input_buffers[i] = processor.mix_buffers.subspan(inputs[i] * processor.sample_count, diff --git a/src/audio_core/renderer/command/effect/i3dl2_reverb.cpp b/src/audio_core/renderer/command/effect/i3dl2_reverb.cpp index 27d8b9844..d2bfb67cc 100644 --- a/src/audio_core/renderer/command/effect/i3dl2_reverb.cpp +++ b/src/audio_core/renderer/command/effect/i3dl2_reverb.cpp @@ -408,8 +408,8 @@ void I3dl2ReverbCommand::Dump([[maybe_unused]] const ADSP::CommandListProcessor& } void I3dl2ReverbCommand::Process(const ADSP::CommandListProcessor& processor) { - std::vector> input_buffers(parameter.channel_count); - std::vector> output_buffers(parameter.channel_count); + std::array, MaxChannels> input_buffers{}; + std::array, MaxChannels> output_buffers{}; for (u32 i = 0; i < parameter.channel_count; i++) { input_buffers[i] = processor.mix_buffers.subspan(inputs[i] * processor.sample_count, diff --git a/src/audio_core/renderer/command/effect/light_limiter.cpp b/src/audio_core/renderer/command/effect/light_limiter.cpp index e8fb0e2fc..4161a9821 100644 --- a/src/audio_core/renderer/command/effect/light_limiter.cpp +++ b/src/audio_core/renderer/command/effect/light_limiter.cpp @@ -47,8 +47,8 @@ static void InitializeLightLimiterEffect(const LightLimiterInfo::ParameterVersio */ static void ApplyLightLimiterEffect(const LightLimiterInfo::ParameterVersion2& params, LightLimiterInfo::State& state, const bool enabled, - std::vector>& inputs, - std::vector>& outputs, const u32 sample_count, + std::span> inputs, + std::span> outputs, const u32 sample_count, LightLimiterInfo::StatisticsInternal* statistics) { constexpr s64 min{std::numeric_limits::min()}; constexpr s64 max{std::numeric_limits::max()}; @@ -147,8 +147,8 @@ void LightLimiterVersion1Command::Dump([[maybe_unused]] const ADSP::CommandListP } void LightLimiterVersion1Command::Process(const ADSP::CommandListProcessor& processor) { - std::vector> input_buffers(parameter.channel_count); - std::vector> output_buffers(parameter.channel_count); + std::array, MaxChannels> input_buffers{}; + std::array, MaxChannels> output_buffers{}; for (u32 i = 0; i < parameter.channel_count; i++) { input_buffers[i] = processor.mix_buffers.subspan(inputs[i] * processor.sample_count, @@ -190,8 +190,8 @@ void LightLimiterVersion2Command::Dump([[maybe_unused]] const ADSP::CommandListP } void LightLimiterVersion2Command::Process(const ADSP::CommandListProcessor& processor) { - std::vector> input_buffers(parameter.channel_count); - std::vector> output_buffers(parameter.channel_count); + std::array, MaxChannels> input_buffers{}; + std::array, MaxChannels> output_buffers{}; for (u32 i = 0; i < parameter.channel_count; i++) { input_buffers[i] = processor.mix_buffers.subspan(inputs[i] * processor.sample_count, diff --git a/src/audio_core/renderer/command/effect/reverb.cpp b/src/audio_core/renderer/command/effect/reverb.cpp index 8b9b65214..fc2f15a5e 100644 --- a/src/audio_core/renderer/command/effect/reverb.cpp +++ b/src/audio_core/renderer/command/effect/reverb.cpp @@ -250,8 +250,8 @@ static Common::FixedPoint<50, 14> Axfx2AllPassTick(ReverbInfo::ReverbDelayLine& */ template static void ApplyReverbEffect(const ReverbInfo::ParameterVersion2& params, ReverbInfo::State& state, - std::vector>& inputs, - std::vector>& outputs, const u32 sample_count) { + std::span> inputs, + std::span> outputs, const u32 sample_count) { static constexpr std::array OutTapIndexes1Ch{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; @@ -369,8 +369,8 @@ static void ApplyReverbEffect(const ReverbInfo::ParameterVersion2& params, Rever * @param sample_count - Number of samples to process. */ static void ApplyReverbEffect(const ReverbInfo::ParameterVersion2& params, ReverbInfo::State& state, - const bool enabled, std::vector>& inputs, - std::vector>& outputs, const u32 sample_count) { + const bool enabled, std::span> inputs, + std::span> outputs, const u32 sample_count) { if (enabled) { switch (params.channel_count) { case 0: @@ -412,8 +412,8 @@ void ReverbCommand::Dump([[maybe_unused]] const ADSP::CommandListProcessor& proc } void ReverbCommand::Process(const ADSP::CommandListProcessor& processor) { - std::vector> input_buffers(parameter.channel_count); - std::vector> output_buffers(parameter.channel_count); + std::array, MaxChannels> input_buffers{}; + std::array, MaxChannels> output_buffers{}; for (u32 i = 0; i < parameter.channel_count; i++) { input_buffers[i] = processor.mix_buffers.subspan(inputs[i] * processor.sample_count, diff --git a/src/audio_core/renderer/command/sink/circular_buffer.cpp b/src/audio_core/renderer/command/sink/circular_buffer.cpp index ded5afc94..e2ce59792 100644 --- a/src/audio_core/renderer/command/sink/circular_buffer.cpp +++ b/src/audio_core/renderer/command/sink/circular_buffer.cpp @@ -24,7 +24,7 @@ void CircularBufferSinkCommand::Process(const ADSP::CommandListProcessor& proces constexpr s32 min{std::numeric_limits::min()}; constexpr s32 max{std::numeric_limits::max()}; - std::vector output(processor.sample_count); + std::array output{}; for (u32 channel = 0; channel < input_count; channel++) { auto input{processor.mix_buffers.subspan(inputs[channel] * processor.sample_count, processor.sample_count)}; @@ -33,7 +33,7 @@ void CircularBufferSinkCommand::Process(const ADSP::CommandListProcessor& proces } processor.memory->WriteBlockUnsafe(address + pos, output.data(), - output.size() * sizeof(s16)); + processor.sample_count * sizeof(s16)); pos += static_cast(processor.sample_count * sizeof(s16)); if (pos >= size) { pos = 0; diff --git a/src/audio_core/renderer/command/sink/device.cpp b/src/audio_core/renderer/command/sink/device.cpp index e88372a75..5f74dd7ad 100644 --- a/src/audio_core/renderer/command/sink/device.cpp +++ b/src/audio_core/renderer/command/sink/device.cpp @@ -33,8 +33,7 @@ void DeviceSinkCommand::Process(const ADSP::CommandListProcessor& processor) { .consumed{false}, }; - std::vector samples(out_buffer.frames * input_count); - + std::array samples{}; for (u32 channel = 0; channel < input_count; channel++) { const auto offset{inputs[channel] * out_buffer.frames}; @@ -45,7 +44,7 @@ void DeviceSinkCommand::Process(const ADSP::CommandListProcessor& processor) { } out_buffer.tag = reinterpret_cast(samples.data()); - stream->AppendBuffer(out_buffer, samples); + stream->AppendBuffer(out_buffer, {samples.data(), out_buffer.frames * input_count}); if (stream->IsPaused()) { stream->Start(); diff --git a/src/audio_core/renderer/mix/mix_context.cpp b/src/audio_core/renderer/mix/mix_context.cpp index 35b748ede..3a18ae7c2 100644 --- a/src/audio_core/renderer/mix/mix_context.cpp +++ b/src/audio_core/renderer/mix/mix_context.cpp @@ -125,10 +125,10 @@ bool MixContext::TSortInfo(const SplitterContext& splitter_context) { return false; } - std::vector sorted_results{node_states.GetSortedResuls()}; - const auto result_size{std::min(count, static_cast(sorted_results.size()))}; + auto sorted_results{node_states.GetSortedResuls()}; + const auto result_size{std::min(count, static_cast(sorted_results.second))}; for (s32 i = 0; i < result_size; i++) { - sorted_mix_infos[i] = &mix_infos[sorted_results[i]]; + sorted_mix_infos[i] = &mix_infos[sorted_results.first[i]]; } CalcMixBufferOffset(); diff --git a/src/audio_core/renderer/nodes/node_states.cpp b/src/audio_core/renderer/nodes/node_states.cpp index 1821a51e6..b7a44a54c 100644 --- a/src/audio_core/renderer/nodes/node_states.cpp +++ b/src/audio_core/renderer/nodes/node_states.cpp @@ -134,8 +134,8 @@ u32 NodeStates::GetNodeCount() const { return node_count; } -std::vector NodeStates::GetSortedResuls() const { - return {results.rbegin(), results.rbegin() + result_pos}; +std::pair::reverse_iterator, size_t> NodeStates::GetSortedResuls() const { + return {results.rbegin(), result_pos}; } } // namespace AudioCore::AudioRenderer diff --git a/src/audio_core/renderer/nodes/node_states.h b/src/audio_core/renderer/nodes/node_states.h index 94b1d1254..e768cd4b5 100644 --- a/src/audio_core/renderer/nodes/node_states.h +++ b/src/audio_core/renderer/nodes/node_states.h @@ -175,7 +175,7 @@ public: * * @return Vector of nodes in reverse order. */ - std::vector GetSortedResuls() const; + std::pair::reverse_iterator, size_t> GetSortedResuls() const; private: /// Number of nodes in the graph diff --git a/src/audio_core/renderer/system.cpp b/src/audio_core/renderer/system.cpp index 53b258c4f..a23627472 100644 --- a/src/audio_core/renderer/system.cpp +++ b/src/audio_core/renderer/system.cpp @@ -444,6 +444,7 @@ Result System::Update(std::span input, std::span performance, std: std::scoped_lock l{lock}; const auto start_time{core.CoreTiming().GetClockTicks()}; + std::memset(output.data(), 0, output.size()); InfoUpdater info_updater(input, output, process_handle, behavior); diff --git a/src/audio_core/sink/null_sink.h b/src/audio_core/sink/null_sink.h index 1215d3cd2..b6b43c93e 100644 --- a/src/audio_core/sink/null_sink.h +++ b/src/audio_core/sink/null_sink.h @@ -20,7 +20,7 @@ public: explicit NullSinkStreamImpl(Core::System& system_, StreamType type_) : SinkStream{system_, type_} {} ~NullSinkStreamImpl() override {} - void AppendBuffer(SinkBuffer&, std::vector&) override {} + void AppendBuffer(SinkBuffer&, std::span) override {} std::vector ReleaseBuffer(u64) override { return {}; } diff --git a/src/audio_core/sink/sink_stream.cpp b/src/audio_core/sink/sink_stream.cpp index 9a718a9cc..404dcd0e9 100644 --- a/src/audio_core/sink/sink_stream.cpp +++ b/src/audio_core/sink/sink_stream.cpp @@ -18,7 +18,7 @@ namespace AudioCore::Sink { -void SinkStream::AppendBuffer(SinkBuffer& buffer, std::vector& samples) { +void SinkStream::AppendBuffer(SinkBuffer& buffer, std::span samples) { if (type == StreamType::In) { queue.enqueue(buffer); queued_buffers++; @@ -66,15 +66,16 @@ void SinkStream::AppendBuffer(SinkBuffer& buffer, std::vector& samples) { static_cast(std::clamp(right_sample, min, max)); } - samples.resize(samples.size() / system_channels * device_channels); + samples = samples.subspan(0, samples.size() / system_channels * device_channels); } else if (system_channels == 2 && device_channels == 6) { // We need moar samples! Not all games will provide 6 channel audio. // TODO: Implement some upmixing here. Currently just passthrough, with other // channels left as silence. - std::vector new_samples(samples.size() / system_channels * device_channels, 0); + auto new_size = samples.size() / system_channels * device_channels; + tmp_samples.resize_destructive(new_size); - for (u32 read_index = 0, write_index = 0; read_index < samples.size(); + for (u32 read_index = 0, write_index = 0; read_index < new_size; read_index += system_channels, write_index += device_channels) { const auto left_sample{static_cast(std::clamp( static_cast( @@ -82,7 +83,7 @@ void SinkStream::AppendBuffer(SinkBuffer& buffer, std::vector& samples) { volume), min, max))}; - new_samples[write_index + static_cast(Channels::FrontLeft)] = left_sample; + tmp_samples[write_index + static_cast(Channels::FrontLeft)] = left_sample; const auto right_sample{static_cast(std::clamp( static_cast( @@ -90,9 +91,9 @@ void SinkStream::AppendBuffer(SinkBuffer& buffer, std::vector& samples) { volume), min, max))}; - new_samples[write_index + static_cast(Channels::FrontRight)] = right_sample; + tmp_samples[write_index + static_cast(Channels::FrontRight)] = right_sample; } - samples = std::move(new_samples); + samples = std::span(tmp_samples); } else if (volume != 1.0f) { for (u32 i = 0; i < samples.size(); i++) { diff --git a/src/audio_core/sink/sink_stream.h b/src/audio_core/sink/sink_stream.h index 41cbadc9c..98d72ace1 100644 --- a/src/audio_core/sink/sink_stream.h +++ b/src/audio_core/sink/sink_stream.h @@ -16,6 +16,7 @@ #include "common/polyfill_thread.h" #include "common/reader_writer_queue.h" #include "common/ring_buffer.h" +#include "common/scratch_buffer.h" #include "common/thread.h" namespace Core { @@ -170,7 +171,7 @@ public: * @param buffer - Audio buffer information to be queued. * @param samples - The s16 samples to be queue for playback. */ - virtual void AppendBuffer(SinkBuffer& buffer, std::vector& samples); + virtual void AppendBuffer(SinkBuffer& buffer, std::span samples); /** * Release a buffer. Audio In only, will fill a buffer with recorded samples. @@ -255,6 +256,8 @@ private: /// Signalled when ring buffer entries are consumed std::condition_variable_any release_cv; std::mutex release_mutex; + /// Temporary buffer for appending samples when upmixing + Common::ScratchBuffer tmp_samples{}; }; using SinkStreamPtr = std::unique_ptr; diff --git a/src/common/ring_buffer.h b/src/common/ring_buffer.h index 4c328ab44..416680d44 100644 --- a/src/common/ring_buffer.h +++ b/src/common/ring_buffer.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -53,7 +54,7 @@ public: return push_count; } - std::size_t Push(const std::vector& input) { + std::size_t Push(const std::span input) { return Push(input.data(), input.size()); } diff --git a/src/common/scratch_buffer.h b/src/common/scratch_buffer.h index a69a5a7af..6fe907953 100644 --- a/src/common/scratch_buffer.h +++ b/src/common/scratch_buffer.h @@ -3,6 +3,9 @@ #pragma once +#include + +#include "common/concepts.h" #include "common/make_unique_for_overwrite.h" namespace Common { @@ -16,6 +19,12 @@ namespace Common { template class ScratchBuffer { public: + using iterator = T*; + using const_iterator = const T*; + using value_type = T; + using element_type = T; + using iterator_category = std::contiguous_iterator_tag; + ScratchBuffer() = default; explicit ScratchBuffer(size_t initial_capacity) diff --git a/src/core/hle/kernel/k_synchronization_object.cpp b/src/core/hle/kernel/k_synchronization_object.cpp index b7da3eee7..3e5b735b1 100644 --- a/src/core/hle/kernel/k_synchronization_object.cpp +++ b/src/core/hle/kernel/k_synchronization_object.cpp @@ -3,6 +3,7 @@ #include "common/assert.h" #include "common/common_types.h" +#include "common/scratch_buffer.h" #include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" #include "core/hle/kernel/k_synchronization_object.h" @@ -75,7 +76,7 @@ Result KSynchronizationObject::Wait(KernelCore& kernel, s32* out_index, KSynchronizationObject** objects, const s32 num_objects, s64 timeout) { // Allocate space on stack for thread nodes. - std::vector thread_nodes(num_objects); + std::array thread_nodes; // Prepare for wait. KThread* thread = GetCurrentThreadPointer(kernel); diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index 908811e2c..adb6ec581 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp @@ -909,7 +909,7 @@ Result KThread::SetActivity(Svc::ThreadActivity activity) { R_SUCCEED(); } -Result KThread::GetThreadContext3(std::vector& out) { +Result KThread::GetThreadContext3(Common::ScratchBuffer& out) { // Lock ourselves. KScopedLightLock lk{m_activity_pause_lock}; @@ -927,15 +927,13 @@ Result KThread::GetThreadContext3(std::vector& out) { // Mask away mode bits, interrupt bits, IL bit, and other reserved bits. auto context = GetContext64(); context.pstate &= 0xFF0FFE20; - - out.resize(sizeof(context)); + out.resize_destructive(sizeof(context)); std::memcpy(out.data(), std::addressof(context), sizeof(context)); } else { // Mask away mode bits, interrupt bits, IL bit, and other reserved bits. auto context = GetContext32(); context.cpsr &= 0xFF0FFE20; - - out.resize(sizeof(context)); + out.resize_destructive(sizeof(context)); std::memcpy(out.data(), std::addressof(context), sizeof(context)); } } diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index 37fe5db77..dd662b3f8 100644 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h @@ -15,6 +15,7 @@ #include "common/intrusive_list.h" #include "common/intrusive_red_black_tree.h" +#include "common/scratch_buffer.h" #include "common/spin_lock.h" #include "core/arm/arm_interface.h" #include "core/hle/kernel/k_affinity_mask.h" @@ -567,7 +568,7 @@ public: void RemoveWaiter(KThread* thread); - Result GetThreadContext3(std::vector& out); + Result GetThreadContext3(Common::ScratchBuffer& out); KThread* RemoveUserWaiterByKey(bool* out_has_waiters, KProcessAddress key) { return this->RemoveWaiterByKey(out_has_waiters, key, false); diff --git a/src/core/hle/kernel/svc/svc_ipc.cpp b/src/core/hle/kernel/svc/svc_ipc.cpp index ea03068aa..60247df2e 100644 --- a/src/core/hle/kernel/svc/svc_ipc.cpp +++ b/src/core/hle/kernel/svc/svc_ipc.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "common/scope_exit.h" +#include "common/scratch_buffer.h" #include "core/core.h" #include "core/hle/kernel/k_client_session.h" #include "core/hle/kernel/k_process.h" @@ -45,11 +46,11 @@ Result ReplyAndReceive(Core::System& system, s32* out_index, uint64_t handles_ad handles_addr, static_cast(sizeof(Handle) * num_handles)), ResultInvalidPointer); - std::vector handles(num_handles); + std::array handles; GetCurrentMemory(kernel).ReadBlock(handles_addr, handles.data(), sizeof(Handle) * num_handles); // Convert handle list to object table. - std::vector objs(num_handles); + std::array objs; R_UNLESS(handle_table.GetMultipleObjects(objs.data(), handles.data(), num_handles), ResultInvalidHandle); @@ -80,7 +81,7 @@ Result ReplyAndReceive(Core::System& system, s32* out_index, uint64_t handles_ad // Wait for an object. s32 index; Result result = KSynchronizationObject::Wait(kernel, std::addressof(index), objs.data(), - static_cast(objs.size()), timeout_ns); + num_handles, timeout_ns); if (result == ResultTimedOut) { R_RETURN(result); } diff --git a/src/core/hle/kernel/svc/svc_synchronization.cpp b/src/core/hle/kernel/svc/svc_synchronization.cpp index 04d65f0bd..53df5bcd8 100644 --- a/src/core/hle/kernel/svc/svc_synchronization.cpp +++ b/src/core/hle/kernel/svc/svc_synchronization.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "common/scope_exit.h" +#include "common/scratch_buffer.h" #include "core/core.h" #include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_readable_event.h" @@ -54,7 +55,7 @@ static Result WaitSynchronization(Core::System& system, int32_t* out_index, cons // Get the synchronization context. auto& kernel = system.Kernel(); auto& handle_table = GetCurrentProcess(kernel).GetHandleTable(); - std::vector objs(num_handles); + std::array objs; // Copy user handles. if (num_handles > 0) { @@ -72,8 +73,8 @@ static Result WaitSynchronization(Core::System& system, int32_t* out_index, cons }); // Wait on the objects. - Result res = KSynchronizationObject::Wait(kernel, out_index, objs.data(), - static_cast(objs.size()), timeout_ns); + Result res = + KSynchronizationObject::Wait(kernel, out_index, objs.data(), num_handles, timeout_ns); R_SUCCEED_IF(res == ResultSessionClosed); R_RETURN(res); @@ -87,8 +88,7 @@ Result WaitSynchronization(Core::System& system, int32_t* out_index, u64 user_ha // Ensure number of handles is valid. R_UNLESS(0 <= num_handles && num_handles <= Svc::ArgumentHandleCountMax, ResultOutOfRange); - - std::vector handles(num_handles); + std::array handles; if (num_handles > 0) { GetCurrentMemory(system.Kernel()) .ReadBlock(user_handles, handles.data(), num_handles * sizeof(Handle)); diff --git a/src/core/hle/kernel/svc/svc_thread.cpp b/src/core/hle/kernel/svc/svc_thread.cpp index 37b54079c..36b94e6bf 100644 --- a/src/core/hle/kernel/svc/svc_thread.cpp +++ b/src/core/hle/kernel/svc/svc_thread.cpp @@ -174,7 +174,7 @@ Result GetThreadContext3(Core::System& system, u64 out_context, Handle thread_ha } // Get the thread context. - std::vector context; + static thread_local Common::ScratchBuffer context; R_TRY(thread->GetThreadContext3(context)); // Copy the thread context to user space. diff --git a/src/core/hle/service/audio/audin_u.cpp b/src/core/hle/service/audio/audin_u.cpp index f0640c64f..c8d574993 100644 --- a/src/core/hle/service/audio/audin_u.cpp +++ b/src/core/hle/service/audio/audin_u.cpp @@ -5,6 +5,7 @@ #include "audio_core/renderer/audio_device.h" #include "common/common_funcs.h" #include "common/logging/log.h" +#include "common/settings.h" #include "common/string_util.h" #include "core/core.h" #include "core/hle/kernel/k_event.h" @@ -123,19 +124,13 @@ private: void GetReleasedAudioInBuffer(HLERequestContext& ctx) { const auto write_buffer_size = ctx.GetWriteBufferNumElements(); - std::vector released_buffers(write_buffer_size); + tmp_buffer.resize_destructive(write_buffer_size); + tmp_buffer[0] = 0; - const auto count = impl->GetReleasedBuffers(released_buffers); + const auto count = impl->GetReleasedBuffers(tmp_buffer); - [[maybe_unused]] std::string tags{}; - for (u32 i = 0; i < count; i++) { - tags += fmt::format("{:08X}, ", released_buffers[i]); - } - [[maybe_unused]] auto sessionid{impl->GetSystem().GetSessionId()}; - LOG_TRACE(Service_Audio, "called. Session {} released {} buffers: {}", sessionid, count, - tags); + ctx.WriteBuffer(tmp_buffer); - ctx.WriteBuffer(released_buffers); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); rb.Push(count); @@ -200,6 +195,7 @@ private: KernelHelpers::ServiceContext service_context; Kernel::KEvent* event; std::shared_ptr impl; + Common::ScratchBuffer tmp_buffer; }; AudInU::AudInU(Core::System& system_) diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp index 3e62fa4fc..032c8c11f 100644 --- a/src/core/hle/service/audio/audout_u.cpp +++ b/src/core/hle/service/audio/audout_u.cpp @@ -123,19 +123,13 @@ private: void GetReleasedAudioOutBuffers(HLERequestContext& ctx) { const auto write_buffer_size = ctx.GetWriteBufferNumElements(); - std::vector released_buffers(write_buffer_size); + tmp_buffer.resize_destructive(write_buffer_size); + tmp_buffer[0] = 0; - const auto count = impl->GetReleasedBuffers(released_buffers); + const auto count = impl->GetReleasedBuffers(tmp_buffer); - [[maybe_unused]] std::string tags{}; - for (u32 i = 0; i < count; i++) { - tags += fmt::format("{:08X}, ", released_buffers[i]); - } - [[maybe_unused]] const auto sessionid{impl->GetSystem().GetSessionId()}; - LOG_TRACE(Service_Audio, "called. Session {} released {} buffers: {}", sessionid, count, - tags); + ctx.WriteBuffer(tmp_buffer); - ctx.WriteBuffer(released_buffers); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); rb.Push(count); @@ -211,6 +205,7 @@ private: KernelHelpers::ServiceContext service_context; Kernel::KEvent* event; std::shared_ptr impl; + Common::ScratchBuffer tmp_buffer; }; AudOutU::AudOutU(Core::System& system_) diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp index 7086d4750..12845c23a 100644 --- a/src/core/hle/service/audio/audren_u.cpp +++ b/src/core/hle/service/audio/audren_u.cpp @@ -116,28 +116,26 @@ private: // These buffers are written manually to avoid an issue with WriteBuffer throwing errors for // checking size 0. Performance size is 0 for most games. - std::vector output{}; - std::vector performance{}; auto is_buffer_b{ctx.BufferDescriptorB()[0].Size() != 0}; if (is_buffer_b) { const auto buffersB{ctx.BufferDescriptorB()}; - output.resize(buffersB[0].Size(), 0); - performance.resize(buffersB[1].Size(), 0); + tmp_output.resize_destructive(buffersB[0].Size()); + tmp_performance.resize_destructive(buffersB[1].Size()); } else { const auto buffersC{ctx.BufferDescriptorC()}; - output.resize(buffersC[0].Size(), 0); - performance.resize(buffersC[1].Size(), 0); + tmp_output.resize_destructive(buffersC[0].Size()); + tmp_performance.resize_destructive(buffersC[1].Size()); } - auto result = impl->RequestUpdate(input, performance, output); + auto result = impl->RequestUpdate(input, tmp_performance, tmp_output); if (result.IsSuccess()) { if (is_buffer_b) { - ctx.WriteBufferB(output.data(), output.size(), 0); - ctx.WriteBufferB(performance.data(), performance.size(), 1); + ctx.WriteBufferB(tmp_output.data(), tmp_output.size(), 0); + ctx.WriteBufferB(tmp_performance.data(), tmp_performance.size(), 1); } else { - ctx.WriteBufferC(output.data(), output.size(), 0); - ctx.WriteBufferC(performance.data(), performance.size(), 1); + ctx.WriteBufferC(tmp_output.data(), tmp_output.size(), 0); + ctx.WriteBufferC(tmp_performance.data(), tmp_performance.size(), 1); } } else { LOG_ERROR(Service_Audio, "RequestUpdate failed error 0x{:02X}!", result.description); @@ -235,6 +233,8 @@ private: Kernel::KEvent* rendered_event; Manager& manager; std::unique_ptr impl; + Common::ScratchBuffer tmp_output; + Common::ScratchBuffer tmp_performance; }; class IAudioDevice final : public ServiceFramework { diff --git a/src/core/hle/service/audio/audren_u.h b/src/core/hle/service/audio/audren_u.h index 24ce37e87..d8e9c8719 100644 --- a/src/core/hle/service/audio/audren_u.h +++ b/src/core/hle/service/audio/audren_u.h @@ -4,6 +4,7 @@ #pragma once #include "audio_core/audio_render_manager.h" +#include "common/scratch_buffer.h" #include "core/hle/service/kernel_helpers.h" #include "core/hle/service/service.h" diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp index 451ac224a..c835f6cb7 100644 --- a/src/core/hle/service/audio/hwopus.cpp +++ b/src/core/hle/service/audio/hwopus.cpp @@ -68,13 +68,13 @@ private: ExtraBehavior extra_behavior) { u32 consumed = 0; u32 sample_count = 0; - std::vector samples(ctx.GetWriteBufferNumElements()); + tmp_samples.resize_destructive(ctx.GetWriteBufferNumElements()); if (extra_behavior == ExtraBehavior::ResetContext) { ResetDecoderContext(); } - if (!DecodeOpusData(consumed, sample_count, ctx.ReadBuffer(), samples, performance)) { + if (!DecodeOpusData(consumed, sample_count, ctx.ReadBuffer(), tmp_samples, performance)) { LOG_ERROR(Audio, "Failed to decode opus data"); IPC::ResponseBuilder rb{ctx, 2}; // TODO(ogniK): Use correct error code @@ -90,11 +90,11 @@ private: if (performance) { rb.Push(*performance); } - ctx.WriteBuffer(samples); + ctx.WriteBuffer(tmp_samples); } bool DecodeOpusData(u32& consumed, u32& sample_count, std::span input, - std::vector& output, u64* out_performance_time) const { + std::span output, u64* out_performance_time) const { const auto start_time = std::chrono::steady_clock::now(); const std::size_t raw_output_sz = output.size() * sizeof(opus_int16); if (sizeof(OpusPacketHeader) > input.size()) { @@ -154,6 +154,7 @@ private: OpusDecoderPtr decoder; u32 sample_rate; u32 channel_count; + Common::ScratchBuffer tmp_samples; }; class IHardwareOpusDecoderManager final : public ServiceFramework { diff --git a/src/core/hle/service/nvdrv/devices/nvdevice.h b/src/core/hle/service/nvdrv/devices/nvdevice.h index ab1f30f9e..a04538d5d 100644 --- a/src/core/hle/service/nvdrv/devices/nvdevice.h +++ b/src/core/hle/service/nvdrv/devices/nvdevice.h @@ -34,7 +34,7 @@ public: * @returns The result code of the ioctl. */ virtual NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span input, - std::vector& output) = 0; + std::span output) = 0; /** * Handles an ioctl2 request. @@ -45,7 +45,7 @@ public: * @returns The result code of the ioctl. */ virtual NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span input, - std::span inline_input, std::vector& output) = 0; + std::span inline_input, std::span output) = 0; /** * Handles an ioctl3 request. @@ -56,7 +56,7 @@ public: * @returns The result code of the ioctl. */ virtual NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span input, - std::vector& output, std::vector& inline_output) = 0; + std::span output, std::span inline_output) = 0; /** * Called once a device is opened diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp index 0fe242e9d..05a43d8dc 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp @@ -18,19 +18,19 @@ nvdisp_disp0::nvdisp_disp0(Core::System& system_, NvCore::Container& core) nvdisp_disp0::~nvdisp_disp0() = default; NvResult nvdisp_disp0::Ioctl1(DeviceFD fd, Ioctl command, std::span input, - std::vector& output) { + std::span output) { UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); return NvResult::NotImplemented; } NvResult nvdisp_disp0::Ioctl2(DeviceFD fd, Ioctl command, std::span input, - std::span inline_input, std::vector& output) { + std::span inline_input, std::span output) { UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); return NvResult::NotImplemented; } NvResult nvdisp_disp0::Ioctl3(DeviceFD fd, Ioctl command, std::span input, - std::vector& output, std::vector& inline_output) { + std::span output, std::span inline_output) { UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); return NvResult::NotImplemented; } diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h index bcd0e3ed5..daee05fe8 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h @@ -26,11 +26,11 @@ public: ~nvdisp_disp0() override; NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span input, - std::vector& output) override; + std::span output) override; NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span input, - std::span inline_input, std::vector& output) override; - NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span input, std::vector& output, - std::vector& inline_output) override; + std::span inline_input, std::span output) override; + NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span input, std::span output, + std::span inline_output) override; void OnOpen(DeviceFD fd) override; void OnClose(DeviceFD fd) override; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp index 681bd0867..07e570a9f 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp @@ -28,7 +28,7 @@ nvhost_as_gpu::nvhost_as_gpu(Core::System& system_, Module& module_, NvCore::Con nvhost_as_gpu::~nvhost_as_gpu() = default; NvResult nvhost_as_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span input, - std::vector& output) { + std::span output) { switch (command.group) { case 'A': switch (command.cmd) { @@ -61,13 +61,13 @@ NvResult nvhost_as_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span i } NvResult nvhost_as_gpu::Ioctl2(DeviceFD fd, Ioctl command, std::span input, - std::span inline_input, std::vector& output) { + std::span inline_input, std::span output) { UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); return NvResult::NotImplemented; } NvResult nvhost_as_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span input, - std::vector& output, std::vector& inline_output) { + std::span output, std::span inline_output) { switch (command.group) { case 'A': switch (command.cmd) { @@ -87,7 +87,7 @@ NvResult nvhost_as_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span i void nvhost_as_gpu::OnOpen(DeviceFD fd) {} void nvhost_as_gpu::OnClose(DeviceFD fd) {} -NvResult nvhost_as_gpu::AllocAsEx(std::span input, std::vector& output) { +NvResult nvhost_as_gpu::AllocAsEx(std::span input, std::span output) { IoctlAllocAsEx params{}; std::memcpy(¶ms, input.data(), input.size()); @@ -141,7 +141,7 @@ NvResult nvhost_as_gpu::AllocAsEx(std::span input, std::vector& ou return NvResult::Success; } -NvResult nvhost_as_gpu::AllocateSpace(std::span input, std::vector& output) { +NvResult nvhost_as_gpu::AllocateSpace(std::span input, std::span output) { IoctlAllocSpace params{}; std::memcpy(¶ms, input.data(), input.size()); @@ -220,7 +220,7 @@ void nvhost_as_gpu::FreeMappingLocked(u64 offset) { mapping_map.erase(offset); } -NvResult nvhost_as_gpu::FreeSpace(std::span input, std::vector& output) { +NvResult nvhost_as_gpu::FreeSpace(std::span input, std::span output) { IoctlFreeSpace params{}; std::memcpy(¶ms, input.data(), input.size()); @@ -266,15 +266,14 @@ NvResult nvhost_as_gpu::FreeSpace(std::span input, std::vector& ou return NvResult::Success; } -NvResult nvhost_as_gpu::Remap(std::span input, std::vector& output) { +NvResult nvhost_as_gpu::Remap(std::span input, std::span output) { const auto num_entries = input.size() / sizeof(IoctlRemapEntry); LOG_DEBUG(Service_NVDRV, "called, num_entries=0x{:X}", num_entries); - std::vector entries(num_entries); - std::memcpy(entries.data(), input.data(), input.size()); - std::scoped_lock lock(mutex); + entries.resize_destructive(num_entries); + std::memcpy(entries.data(), input.data(), input.size()); if (!vm.initialised) { return NvResult::BadValue; @@ -320,7 +319,7 @@ NvResult nvhost_as_gpu::Remap(std::span input, std::vector& output return NvResult::Success; } -NvResult nvhost_as_gpu::MapBufferEx(std::span input, std::vector& output) { +NvResult nvhost_as_gpu::MapBufferEx(std::span input, std::span output) { IoctlMapBufferEx params{}; std::memcpy(¶ms, input.data(), input.size()); @@ -424,7 +423,7 @@ NvResult nvhost_as_gpu::MapBufferEx(std::span input, std::vector& return NvResult::Success; } -NvResult nvhost_as_gpu::UnmapBuffer(std::span input, std::vector& output) { +NvResult nvhost_as_gpu::UnmapBuffer(std::span input, std::span output) { IoctlUnmapBuffer params{}; std::memcpy(¶ms, input.data(), input.size()); @@ -463,7 +462,7 @@ NvResult nvhost_as_gpu::UnmapBuffer(std::span input, std::vector& return NvResult::Success; } -NvResult nvhost_as_gpu::BindChannel(std::span input, std::vector& output) { +NvResult nvhost_as_gpu::BindChannel(std::span input, std::span output) { IoctlBindChannel params{}; std::memcpy(¶ms, input.data(), input.size()); LOG_DEBUG(Service_NVDRV, "called, fd={:X}", params.fd); @@ -492,7 +491,7 @@ void nvhost_as_gpu::GetVARegionsImpl(IoctlGetVaRegions& params) { }; } -NvResult nvhost_as_gpu::GetVARegions(std::span input, std::vector& output) { +NvResult nvhost_as_gpu::GetVARegions(std::span input, std::span output) { IoctlGetVaRegions params{}; std::memcpy(¶ms, input.data(), input.size()); @@ -511,8 +510,8 @@ NvResult nvhost_as_gpu::GetVARegions(std::span input, std::vector& return NvResult::Success; } -NvResult nvhost_as_gpu::GetVARegions(std::span input, std::vector& output, - std::vector& inline_output) { +NvResult nvhost_as_gpu::GetVARegions(std::span input, std::span output, + std::span inline_output) { IoctlGetVaRegions params{}; std::memcpy(¶ms, input.data(), input.size()); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h index 1aba8d579..2af3e1260 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h @@ -15,6 +15,7 @@ #include "common/address_space.h" #include "common/common_funcs.h" #include "common/common_types.h" +#include "common/scratch_buffer.h" #include "common/swap.h" #include "core/hle/service/nvdrv/core/nvmap.h" #include "core/hle/service/nvdrv/devices/nvdevice.h" @@ -48,11 +49,11 @@ public: ~nvhost_as_gpu() override; NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span input, - std::vector& output) override; + std::span output) override; NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span input, - std::span inline_input, std::vector& output) override; - NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span input, std::vector& output, - std::vector& inline_output) override; + std::span inline_input, std::span output) override; + NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span input, std::span output, + std::span inline_output) override; void OnOpen(DeviceFD fd) override; void OnClose(DeviceFD fd) override; @@ -138,18 +139,18 @@ private: static_assert(sizeof(IoctlGetVaRegions) == 16 + sizeof(VaRegion) * 2, "IoctlGetVaRegions is incorrect size"); - NvResult AllocAsEx(std::span input, std::vector& output); - NvResult AllocateSpace(std::span input, std::vector& output); - NvResult Remap(std::span input, std::vector& output); - NvResult MapBufferEx(std::span input, std::vector& output); - NvResult UnmapBuffer(std::span input, std::vector& output); - NvResult FreeSpace(std::span input, std::vector& output); - NvResult BindChannel(std::span input, std::vector& output); + NvResult AllocAsEx(std::span input, std::span output); + NvResult AllocateSpace(std::span input, std::span output); + NvResult Remap(std::span input, std::span output); + NvResult MapBufferEx(std::span input, std::span output); + NvResult UnmapBuffer(std::span input, std::span output); + NvResult FreeSpace(std::span input, std::span output); + NvResult BindChannel(std::span input, std::span output); void GetVARegionsImpl(IoctlGetVaRegions& params); - NvResult GetVARegions(std::span input, std::vector& output); - NvResult GetVARegions(std::span input, std::vector& output, - std::vector& inline_output); + NvResult GetVARegions(std::span input, std::span output); + NvResult GetVARegions(std::span input, std::span output, + std::span inline_output); void FreeMappingLocked(u64 offset); @@ -212,6 +213,7 @@ private: bool initialised{}; } vm; std::shared_ptr gmmu; + Common::ScratchBuffer entries; // s32 channel{}; // u32 big_page_size{VM::DEFAULT_BIG_PAGE_SIZE}; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index e12025560..4d55554b4 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp @@ -35,7 +35,7 @@ nvhost_ctrl::~nvhost_ctrl() { } NvResult nvhost_ctrl::Ioctl1(DeviceFD fd, Ioctl command, std::span input, - std::vector& output) { + std::span output) { switch (command.group) { case 0x0: switch (command.cmd) { @@ -64,13 +64,13 @@ NvResult nvhost_ctrl::Ioctl1(DeviceFD fd, Ioctl command, std::span inp } NvResult nvhost_ctrl::Ioctl2(DeviceFD fd, Ioctl command, std::span input, - std::span inline_input, std::vector& output) { + std::span inline_input, std::span output) { UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); return NvResult::NotImplemented; } NvResult nvhost_ctrl::Ioctl3(DeviceFD fd, Ioctl command, std::span input, - std::vector& output, std::vector& inline_outpu) { + std::span output, std::span inline_outpu) { UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); return NvResult::NotImplemented; } @@ -79,7 +79,7 @@ void nvhost_ctrl::OnOpen(DeviceFD fd) {} void nvhost_ctrl::OnClose(DeviceFD fd) {} -NvResult nvhost_ctrl::NvOsGetConfigU32(std::span input, std::vector& output) { +NvResult nvhost_ctrl::NvOsGetConfigU32(std::span input, std::span output) { IocGetConfigParams params{}; std::memcpy(¶ms, input.data(), sizeof(params)); LOG_TRACE(Service_NVDRV, "called, setting={}!{}", params.domain_str.data(), @@ -87,7 +87,7 @@ NvResult nvhost_ctrl::NvOsGetConfigU32(std::span input, std::vector input, std::vector& output, +NvResult nvhost_ctrl::IocCtrlEventWait(std::span input, std::span output, bool is_allocation) { IocCtrlEventWaitParams params{}; std::memcpy(¶ms, input.data(), sizeof(params)); @@ -231,7 +231,7 @@ NvResult nvhost_ctrl::FreeEvent(u32 slot) { return NvResult::Success; } -NvResult nvhost_ctrl::IocCtrlEventRegister(std::span input, std::vector& output) { +NvResult nvhost_ctrl::IocCtrlEventRegister(std::span input, std::span output) { IocCtrlEventRegisterParams params{}; std::memcpy(¶ms, input.data(), sizeof(params)); const u32 event_id = params.user_event_id; @@ -252,7 +252,7 @@ NvResult nvhost_ctrl::IocCtrlEventRegister(std::span input, std::vecto return NvResult::Success; } -NvResult nvhost_ctrl::IocCtrlEventUnregister(std::span input, std::vector& output) { +NvResult nvhost_ctrl::IocCtrlEventUnregister(std::span input, std::span output) { IocCtrlEventUnregisterParams params{}; std::memcpy(¶ms, input.data(), sizeof(params)); const u32 event_id = params.user_event_id & 0x00FF; @@ -262,8 +262,7 @@ NvResult nvhost_ctrl::IocCtrlEventUnregister(std::span input, std::vec return FreeEvent(event_id); } -NvResult nvhost_ctrl::IocCtrlEventUnregisterBatch(std::span input, - std::vector& output) { +NvResult nvhost_ctrl::IocCtrlEventUnregisterBatch(std::span input, std::span output) { IocCtrlEventUnregisterBatchParams params{}; std::memcpy(¶ms, input.data(), sizeof(params)); u64 event_mask = params.user_events; @@ -281,7 +280,7 @@ NvResult nvhost_ctrl::IocCtrlEventUnregisterBatch(std::span input, return NvResult::Success; } -NvResult nvhost_ctrl::IocCtrlClearEventWait(std::span input, std::vector& output) { +NvResult nvhost_ctrl::IocCtrlClearEventWait(std::span input, std::span output) { IocCtrlEventClearParams params{}; std::memcpy(¶ms, input.data(), sizeof(params)); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h index dd2e7888a..2efed4862 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h @@ -26,11 +26,11 @@ public: ~nvhost_ctrl() override; NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span input, - std::vector& output) override; + std::span output) override; NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span input, - std::span inline_input, std::vector& output) override; - NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span input, std::vector& output, - std::vector& inline_output) override; + std::span inline_input, std::span output) override; + NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span input, std::span output, + std::span inline_output) override; void OnOpen(DeviceFD fd) override; void OnClose(DeviceFD fd) override; @@ -186,13 +186,12 @@ private: static_assert(sizeof(IocCtrlEventUnregisterBatchParams) == 8, "IocCtrlEventKill is incorrect size"); - NvResult NvOsGetConfigU32(std::span input, std::vector& output); - NvResult IocCtrlEventWait(std::span input, std::vector& output, - bool is_allocation); - NvResult IocCtrlEventRegister(std::span input, std::vector& output); - NvResult IocCtrlEventUnregister(std::span input, std::vector& output); - NvResult IocCtrlEventUnregisterBatch(std::span input, std::vector& output); - NvResult IocCtrlClearEventWait(std::span input, std::vector& output); + NvResult NvOsGetConfigU32(std::span input, std::span output); + NvResult IocCtrlEventWait(std::span input, std::span output, bool is_allocation); + NvResult IocCtrlEventRegister(std::span input, std::span output); + NvResult IocCtrlEventUnregister(std::span input, std::span output); + NvResult IocCtrlEventUnregisterBatch(std::span input, std::span output); + NvResult IocCtrlClearEventWait(std::span input, std::span output); NvResult FreeEvent(u32 slot); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp index be3c083db..6081d92e9 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp @@ -22,7 +22,7 @@ nvhost_ctrl_gpu::~nvhost_ctrl_gpu() { } NvResult nvhost_ctrl_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span input, - std::vector& output) { + std::span output) { switch (command.group) { case 'G': switch (command.cmd) { @@ -54,13 +54,13 @@ NvResult nvhost_ctrl_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span } NvResult nvhost_ctrl_gpu::Ioctl2(DeviceFD fd, Ioctl command, std::span input, - std::span inline_input, std::vector& output) { + std::span inline_input, std::span output) { UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); return NvResult::NotImplemented; } NvResult nvhost_ctrl_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span input, - std::vector& output, std::vector& inline_output) { + std::span output, std::span inline_output) { switch (command.group) { case 'G': switch (command.cmd) { @@ -82,7 +82,7 @@ NvResult nvhost_ctrl_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span void nvhost_ctrl_gpu::OnOpen(DeviceFD fd) {} void nvhost_ctrl_gpu::OnClose(DeviceFD fd) {} -NvResult nvhost_ctrl_gpu::GetCharacteristics(std::span input, std::vector& output) { +NvResult nvhost_ctrl_gpu::GetCharacteristics(std::span input, std::span output) { LOG_DEBUG(Service_NVDRV, "called"); IoctlCharacteristics params{}; std::memcpy(¶ms, input.data(), input.size()); @@ -127,8 +127,8 @@ NvResult nvhost_ctrl_gpu::GetCharacteristics(std::span input, std::vec return NvResult::Success; } -NvResult nvhost_ctrl_gpu::GetCharacteristics(std::span input, std::vector& output, - std::vector& inline_output) { +NvResult nvhost_ctrl_gpu::GetCharacteristics(std::span input, std::span output, + std::span inline_output) { LOG_DEBUG(Service_NVDRV, "called"); IoctlCharacteristics params{}; std::memcpy(¶ms, input.data(), input.size()); @@ -175,7 +175,7 @@ NvResult nvhost_ctrl_gpu::GetCharacteristics(std::span input, std::vec return NvResult::Success; } -NvResult nvhost_ctrl_gpu::GetTPCMasks(std::span input, std::vector& output) { +NvResult nvhost_ctrl_gpu::GetTPCMasks(std::span input, std::span output) { IoctlGpuGetTpcMasksArgs params{}; std::memcpy(¶ms, input.data(), input.size()); LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size=0x{:X}", params.mask_buffer_size); @@ -186,8 +186,8 @@ NvResult nvhost_ctrl_gpu::GetTPCMasks(std::span input, std::vector return NvResult::Success; } -NvResult nvhost_ctrl_gpu::GetTPCMasks(std::span input, std::vector& output, - std::vector& inline_output) { +NvResult nvhost_ctrl_gpu::GetTPCMasks(std::span input, std::span output, + std::span inline_output) { IoctlGpuGetTpcMasksArgs params{}; std::memcpy(¶ms, input.data(), input.size()); LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size=0x{:X}", params.mask_buffer_size); @@ -199,7 +199,7 @@ NvResult nvhost_ctrl_gpu::GetTPCMasks(std::span input, std::vector return NvResult::Success; } -NvResult nvhost_ctrl_gpu::GetActiveSlotMask(std::span input, std::vector& output) { +NvResult nvhost_ctrl_gpu::GetActiveSlotMask(std::span input, std::span output) { LOG_DEBUG(Service_NVDRV, "called"); IoctlActiveSlotMask params{}; @@ -212,7 +212,7 @@ NvResult nvhost_ctrl_gpu::GetActiveSlotMask(std::span input, std::vect return NvResult::Success; } -NvResult nvhost_ctrl_gpu::ZCullGetCtxSize(std::span input, std::vector& output) { +NvResult nvhost_ctrl_gpu::ZCullGetCtxSize(std::span input, std::span output) { LOG_DEBUG(Service_NVDRV, "called"); IoctlZcullGetCtxSize params{}; @@ -224,7 +224,7 @@ NvResult nvhost_ctrl_gpu::ZCullGetCtxSize(std::span input, std::vector return NvResult::Success; } -NvResult nvhost_ctrl_gpu::ZCullGetInfo(std::span input, std::vector& output) { +NvResult nvhost_ctrl_gpu::ZCullGetInfo(std::span input, std::span output) { LOG_DEBUG(Service_NVDRV, "called"); IoctlNvgpuGpuZcullGetInfoArgs params{}; @@ -247,7 +247,7 @@ NvResult nvhost_ctrl_gpu::ZCullGetInfo(std::span input, std::vector input, std::vector& output) { +NvResult nvhost_ctrl_gpu::ZBCSetTable(std::span input, std::span output) { LOG_WARNING(Service_NVDRV, "(STUBBED) called"); IoctlZbcSetTable params{}; @@ -263,7 +263,7 @@ NvResult nvhost_ctrl_gpu::ZBCSetTable(std::span input, std::vector return NvResult::Success; } -NvResult nvhost_ctrl_gpu::ZBCQueryTable(std::span input, std::vector& output) { +NvResult nvhost_ctrl_gpu::ZBCQueryTable(std::span input, std::span output) { LOG_WARNING(Service_NVDRV, "(STUBBED) called"); IoctlZbcQueryTable params{}; @@ -273,7 +273,7 @@ NvResult nvhost_ctrl_gpu::ZBCQueryTable(std::span input, std::vector input, std::vector& output) { +NvResult nvhost_ctrl_gpu::FlushL2(std::span input, std::span output) { LOG_WARNING(Service_NVDRV, "(STUBBED) called"); IoctlFlushL2 params{}; @@ -283,7 +283,7 @@ NvResult nvhost_ctrl_gpu::FlushL2(std::span input, std::vector& ou return NvResult::Success; } -NvResult nvhost_ctrl_gpu::GetGpuTime(std::span input, std::vector& output) { +NvResult nvhost_ctrl_gpu::GetGpuTime(std::span input, std::span output) { LOG_DEBUG(Service_NVDRV, "called"); IoctlGetGpuTime params{}; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h index b9333d9d3..97995551c 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h @@ -22,11 +22,11 @@ public: ~nvhost_ctrl_gpu() override; NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span input, - std::vector& output) override; + std::span output) override; NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span input, - std::span inline_input, std::vector& output) override; - NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span input, std::vector& output, - std::vector& inline_output) override; + std::span inline_input, std::span output) override; + NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span input, std::span output, + std::span inline_output) override; void OnOpen(DeviceFD fd) override; void OnClose(DeviceFD fd) override; @@ -151,21 +151,21 @@ private: }; static_assert(sizeof(IoctlGetGpuTime) == 0x10, "IoctlGetGpuTime is incorrect size"); - NvResult GetCharacteristics(std::span input, std::vector& output); - NvResult GetCharacteristics(std::span input, std::vector& output, - std::vector& inline_output); - - NvResult GetTPCMasks(std::span input, std::vector& output); - NvResult GetTPCMasks(std::span input, std::vector& output, - std::vector& inline_output); - - NvResult GetActiveSlotMask(std::span input, std::vector& output); - NvResult ZCullGetCtxSize(std::span input, std::vector& output); - NvResult ZCullGetInfo(std::span input, std::vector& output); - NvResult ZBCSetTable(std::span input, std::vector& output); - NvResult ZBCQueryTable(std::span input, std::vector& output); - NvResult FlushL2(std::span input, std::vector& output); - NvResult GetGpuTime(std::span input, std::vector& output); + NvResult GetCharacteristics(std::span input, std::span output); + NvResult GetCharacteristics(std::span input, std::span output, + std::span inline_output); + + NvResult GetTPCMasks(std::span input, std::span output); + NvResult GetTPCMasks(std::span input, std::span output, + std::span inline_output); + + NvResult GetActiveSlotMask(std::span input, std::span output); + NvResult ZCullGetCtxSize(std::span input, std::span output); + NvResult ZCullGetInfo(std::span input, std::span output); + NvResult ZBCSetTable(std::span input, std::span output); + NvResult ZBCQueryTable(std::span input, std::span output); + NvResult FlushL2(std::span input, std::span output); + NvResult GetGpuTime(std::span input, std::span output); EventInterface& events_interface; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index 453a965dc..46a25fcab 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp @@ -47,7 +47,7 @@ nvhost_gpu::~nvhost_gpu() { } NvResult nvhost_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span input, - std::vector& output) { + std::span output) { switch (command.group) { case 0x0: switch (command.cmd) { @@ -99,7 +99,7 @@ NvResult nvhost_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span inpu }; NvResult nvhost_gpu::Ioctl2(DeviceFD fd, Ioctl command, std::span input, - std::span inline_input, std::vector& output) { + std::span inline_input, std::span output) { switch (command.group) { case 'H': switch (command.cmd) { @@ -113,7 +113,7 @@ NvResult nvhost_gpu::Ioctl2(DeviceFD fd, Ioctl command, std::span inpu } NvResult nvhost_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span input, - std::vector& output, std::vector& inline_output) { + std::span output, std::span inline_output) { UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); return NvResult::NotImplemented; } @@ -121,7 +121,7 @@ NvResult nvhost_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span inpu void nvhost_gpu::OnOpen(DeviceFD fd) {} void nvhost_gpu::OnClose(DeviceFD fd) {} -NvResult nvhost_gpu::SetNVMAPfd(std::span input, std::vector& output) { +NvResult nvhost_gpu::SetNVMAPfd(std::span input, std::span output) { IoctlSetNvmapFD params{}; std::memcpy(¶ms, input.data(), input.size()); LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); @@ -130,7 +130,7 @@ NvResult nvhost_gpu::SetNVMAPfd(std::span input, std::vector& outp return NvResult::Success; } -NvResult nvhost_gpu::SetClientData(std::span input, std::vector& output) { +NvResult nvhost_gpu::SetClientData(std::span input, std::span output) { LOG_DEBUG(Service_NVDRV, "called"); IoctlClientData params{}; @@ -139,7 +139,7 @@ NvResult nvhost_gpu::SetClientData(std::span input, std::vector& o return NvResult::Success; } -NvResult nvhost_gpu::GetClientData(std::span input, std::vector& output) { +NvResult nvhost_gpu::GetClientData(std::span input, std::span output) { LOG_DEBUG(Service_NVDRV, "called"); IoctlClientData params{}; @@ -149,7 +149,7 @@ NvResult nvhost_gpu::GetClientData(std::span input, std::vector& o return NvResult::Success; } -NvResult nvhost_gpu::ZCullBind(std::span input, std::vector& output) { +NvResult nvhost_gpu::ZCullBind(std::span input, std::span output) { std::memcpy(&zcull_params, input.data(), input.size()); LOG_DEBUG(Service_NVDRV, "called, gpu_va={:X}, mode={:X}", zcull_params.gpu_va, zcull_params.mode); @@ -158,7 +158,7 @@ NvResult nvhost_gpu::ZCullBind(std::span input, std::vector& outpu return NvResult::Success; } -NvResult nvhost_gpu::SetErrorNotifier(std::span input, std::vector& output) { +NvResult nvhost_gpu::SetErrorNotifier(std::span input, std::span output) { IoctlSetErrorNotifier params{}; std::memcpy(¶ms, input.data(), input.size()); LOG_WARNING(Service_NVDRV, "(STUBBED) called, offset={:X}, size={:X}, mem={:X}", params.offset, @@ -168,14 +168,14 @@ NvResult nvhost_gpu::SetErrorNotifier(std::span input, std::vector return NvResult::Success; } -NvResult nvhost_gpu::SetChannelPriority(std::span input, std::vector& output) { +NvResult nvhost_gpu::SetChannelPriority(std::span input, std::span output) { std::memcpy(&channel_priority, input.data(), input.size()); LOG_DEBUG(Service_NVDRV, "(STUBBED) called, priority={:X}", channel_priority); return NvResult::Success; } -NvResult nvhost_gpu::AllocGPFIFOEx2(std::span input, std::vector& output) { +NvResult nvhost_gpu::AllocGPFIFOEx2(std::span input, std::span output) { IoctlAllocGpfifoEx2 params{}; std::memcpy(¶ms, input.data(), input.size()); LOG_WARNING(Service_NVDRV, @@ -197,7 +197,7 @@ NvResult nvhost_gpu::AllocGPFIFOEx2(std::span input, std::vector& return NvResult::Success; } -NvResult nvhost_gpu::AllocateObjectContext(std::span input, std::vector& output) { +NvResult nvhost_gpu::AllocateObjectContext(std::span input, std::span output) { IoctlAllocObjCtx params{}; std::memcpy(¶ms, input.data(), input.size()); LOG_WARNING(Service_NVDRV, "(STUBBED) called, class_num={:X}, flags={:X}", params.class_num, @@ -208,7 +208,8 @@ NvResult nvhost_gpu::AllocateObjectContext(std::span input, std::vecto return NvResult::Success; } -static std::vector BuildWaitCommandList(NvFence fence) { +static boost::container::small_vector BuildWaitCommandList( + NvFence fence) { return { Tegra::BuildCommandHeader(Tegra::BufferMethods::SyncpointPayload, 1, Tegra::SubmissionMode::Increasing), @@ -219,35 +220,35 @@ static std::vector BuildWaitCommandList(NvFence fence) { }; } -static std::vector BuildIncrementCommandList(NvFence fence) { - std::vector result{ +static boost::container::small_vector BuildIncrementCommandList( + NvFence fence) { + boost::container::small_vector result{ Tegra::BuildCommandHeader(Tegra::BufferMethods::SyncpointPayload, 1, Tegra::SubmissionMode::Increasing), {}}; for (u32 count = 0; count < 2; ++count) { - result.emplace_back(Tegra::BuildCommandHeader(Tegra::BufferMethods::SyncpointOperation, 1, - Tegra::SubmissionMode::Increasing)); - result.emplace_back( + result.push_back(Tegra::BuildCommandHeader(Tegra::BufferMethods::SyncpointOperation, 1, + Tegra::SubmissionMode::Increasing)); + result.push_back( BuildFenceAction(Tegra::Engines::Puller::FenceOperation::Increment, fence.id)); } return result; } -static std::vector BuildIncrementWithWfiCommandList(NvFence fence) { - std::vector result{ +static boost::container::small_vector BuildIncrementWithWfiCommandList( + NvFence fence) { + boost::container::small_vector result{ Tegra::BuildCommandHeader(Tegra::BufferMethods::WaitForIdle, 1, Tegra::SubmissionMode::Increasing), {}}; - const std::vector increment{BuildIncrementCommandList(fence)}; - - result.insert(result.end(), increment.begin(), increment.end()); - + auto increment_list{BuildIncrementCommandList(fence)}; + result.insert(result.end(), increment_list.begin(), increment_list.end()); return result; } -NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector& output, +NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::span output, Tegra::CommandList&& entries) { LOG_TRACE(Service_NVDRV, "called, gpfifo={:X}, num_entries={:X}, flags={:X}", params.address, params.num_entries, params.flags.raw); @@ -293,7 +294,7 @@ NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector return NvResult::Success; } -NvResult nvhost_gpu::SubmitGPFIFOBase(std::span input, std::vector& output, +NvResult nvhost_gpu::SubmitGPFIFOBase(std::span input, std::span output, bool kickoff) { if (input.size() < sizeof(IoctlSubmitGpfifo)) { UNIMPLEMENTED(); @@ -315,7 +316,7 @@ NvResult nvhost_gpu::SubmitGPFIFOBase(std::span input, std::vector } NvResult nvhost_gpu::SubmitGPFIFOBase(std::span input, std::span input_inline, - std::vector& output) { + std::span output) { if (input.size() < sizeof(IoctlSubmitGpfifo)) { UNIMPLEMENTED(); return NvResult::InvalidSize; @@ -327,7 +328,7 @@ NvResult nvhost_gpu::SubmitGPFIFOBase(std::span input, std::span input, std::vector& output) { +NvResult nvhost_gpu::GetWaitbase(std::span input, std::span output) { IoctlGetWaitbase params{}; std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase)); LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown); @@ -337,7 +338,7 @@ NvResult nvhost_gpu::GetWaitbase(std::span input, std::vector& out return NvResult::Success; } -NvResult nvhost_gpu::ChannelSetTimeout(std::span input, std::vector& output) { +NvResult nvhost_gpu::ChannelSetTimeout(std::span input, std::span output) { IoctlChannelSetTimeout params{}; std::memcpy(¶ms, input.data(), sizeof(IoctlChannelSetTimeout)); LOG_INFO(Service_NVDRV, "called, timeout=0x{:X}", params.timeout); @@ -345,7 +346,7 @@ NvResult nvhost_gpu::ChannelSetTimeout(std::span input, std::vector input, std::vector& output) { +NvResult nvhost_gpu::ChannelSetTimeslice(std::span input, std::span output) { IoctlSetTimeslice params{}; std::memcpy(¶ms, input.data(), sizeof(IoctlSetTimeslice)); LOG_INFO(Service_NVDRV, "called, timeslice=0x{:X}", params.timeslice); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h index 3ca58202d..529c20526 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h @@ -41,11 +41,11 @@ public: ~nvhost_gpu() override; NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span input, - std::vector& output) override; + std::span output) override; NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span input, - std::span inline_input, std::vector& output) override; - NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span input, std::vector& output, - std::vector& inline_output) override; + std::span inline_input, std::span output) override; + NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span input, std::span output, + std::span inline_output) override; void OnOpen(DeviceFD fd) override; void OnClose(DeviceFD fd) override; @@ -186,23 +186,23 @@ private: u32_le channel_priority{}; u32_le channel_timeslice{}; - NvResult SetNVMAPfd(std::span input, std::vector& output); - NvResult SetClientData(std::span input, std::vector& output); - NvResult GetClientData(std::span input, std::vector& output); - NvResult ZCullBind(std::span input, std::vector& output); - NvResult SetErrorNotifier(std::span input, std::vector& output); - NvResult SetChannelPriority(std::span input, std::vector& output); - NvResult AllocGPFIFOEx2(std::span input, std::vector& output); - NvResult AllocateObjectContext(std::span input, std::vector& output); - NvResult SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector& output, + NvResult SetNVMAPfd(std::span input, std::span output); + NvResult SetClientData(std::span input, std::span output); + NvResult GetClientData(std::span input, std::span output); + NvResult ZCullBind(std::span input, std::span output); + NvResult SetErrorNotifier(std::span input, std::span output); + NvResult SetChannelPriority(std::span input, std::span output); + NvResult AllocGPFIFOEx2(std::span input, std::span output); + NvResult AllocateObjectContext(std::span input, std::span output); + NvResult SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::span output, Tegra::CommandList&& entries); - NvResult SubmitGPFIFOBase(std::span input, std::vector& output, + NvResult SubmitGPFIFOBase(std::span input, std::span output, bool kickoff = false); NvResult SubmitGPFIFOBase(std::span input, std::span input_inline, - std::vector& output); - NvResult GetWaitbase(std::span input, std::vector& output); - NvResult ChannelSetTimeout(std::span input, std::vector& output); - NvResult ChannelSetTimeslice(std::span input, std::vector& output); + std::span output); + NvResult GetWaitbase(std::span input, std::span output); + NvResult ChannelSetTimeout(std::span input, std::span output); + NvResult ChannelSetTimeslice(std::span input, std::span output); EventInterface& events_interface; NvCore::Container& core; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp index dc45169ad..a174442a6 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp @@ -16,7 +16,7 @@ nvhost_nvdec::nvhost_nvdec(Core::System& system_, NvCore::Container& core_) nvhost_nvdec::~nvhost_nvdec() = default; NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, std::span input, - std::vector& output) { + std::span output) { switch (command.group) { case 0x0: switch (command.cmd) { @@ -56,13 +56,13 @@ NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, std::span in } NvResult nvhost_nvdec::Ioctl2(DeviceFD fd, Ioctl command, std::span input, - std::span inline_input, std::vector& output) { + std::span inline_input, std::span output) { UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); return NvResult::NotImplemented; } NvResult nvhost_nvdec::Ioctl3(DeviceFD fd, Ioctl command, std::span input, - std::vector& output, std::vector& inline_output) { + std::span output, std::span inline_output) { UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); return NvResult::NotImplemented; } diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h index 0d615bbcb..ad2233c49 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h @@ -14,11 +14,11 @@ public: ~nvhost_nvdec() override; NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span input, - std::vector& output) override; + std::span output) override; NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span input, - std::span inline_input, std::vector& output) override; - NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span input, std::vector& output, - std::vector& inline_output) override; + std::span inline_input, std::span output) override; + NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span input, std::span output, + std::span inline_output) override; void OnOpen(DeviceFD fd) override; void OnClose(DeviceFD fd) override; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp index 1ab51f10b..61649aa4a 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp @@ -36,7 +36,7 @@ std::size_t SliceVectors(std::span input, std::vector& dst, std::si // Writes the data in src to an offset into the dst vector. The offset is specified in bytes // Returns the number of bytes written into dst. template -std::size_t WriteVectors(std::vector& dst, const std::vector& src, std::size_t offset) { +std::size_t WriteVectors(std::span dst, const std::vector& src, std::size_t offset) { if (src.empty()) { return 0; } @@ -72,8 +72,7 @@ NvResult nvhost_nvdec_common::SetNVMAPfd(std::span input) { return NvResult::Success; } -NvResult nvhost_nvdec_common::Submit(DeviceFD fd, std::span input, - std::vector& output) { +NvResult nvhost_nvdec_common::Submit(DeviceFD fd, std::span input, std::span output) { IoctlSubmit params{}; std::memcpy(¶ms, input.data(), sizeof(IoctlSubmit)); LOG_DEBUG(Service_NVDRV, "called NVDEC Submit, cmd_buffer_count={}", params.cmd_buffer_count); @@ -121,7 +120,7 @@ NvResult nvhost_nvdec_common::Submit(DeviceFD fd, std::span input, return NvResult::Success; } -NvResult nvhost_nvdec_common::GetSyncpoint(std::span input, std::vector& output) { +NvResult nvhost_nvdec_common::GetSyncpoint(std::span input, std::span output) { IoctlGetSyncpoint params{}; std::memcpy(¶ms, input.data(), sizeof(IoctlGetSyncpoint)); LOG_DEBUG(Service_NVDRV, "called GetSyncpoint, id={}", params.param); @@ -133,7 +132,7 @@ NvResult nvhost_nvdec_common::GetSyncpoint(std::span input, std::vecto return NvResult::Success; } -NvResult nvhost_nvdec_common::GetWaitbase(std::span input, std::vector& output) { +NvResult nvhost_nvdec_common::GetWaitbase(std::span input, std::span output) { IoctlGetWaitbase params{}; LOG_CRITICAL(Service_NVDRV, "called WAITBASE"); std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase)); @@ -142,7 +141,7 @@ NvResult nvhost_nvdec_common::GetWaitbase(std::span input, std::vector return NvResult::Success; } -NvResult nvhost_nvdec_common::MapBuffer(std::span input, std::vector& output) { +NvResult nvhost_nvdec_common::MapBuffer(std::span input, std::span output) { IoctlMapBuffer params{}; std::memcpy(¶ms, input.data(), sizeof(IoctlMapBuffer)); std::vector cmd_buffer_handles(params.num_entries); @@ -159,7 +158,7 @@ NvResult nvhost_nvdec_common::MapBuffer(std::span input, std::vector input, std::vector& output) { +NvResult nvhost_nvdec_common::UnmapBuffer(std::span input, std::span output) { IoctlMapBuffer params{}; std::memcpy(¶ms, input.data(), sizeof(IoctlMapBuffer)); std::vector cmd_buffer_handles(params.num_entries); @@ -173,7 +172,7 @@ NvResult nvhost_nvdec_common::UnmapBuffer(std::span input, std::vector return NvResult::Success; } -NvResult nvhost_nvdec_common::SetSubmitTimeout(std::span input, std::vector& output) { +NvResult nvhost_nvdec_common::SetSubmitTimeout(std::span input, std::span output) { std::memcpy(&submit_timeout, input.data(), input.size()); LOG_WARNING(Service_NVDRV, "(STUBBED) called"); return NvResult::Success; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h index 5af26a26f..9bb573bfe 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h @@ -108,12 +108,12 @@ protected: /// Ioctl command implementations NvResult SetNVMAPfd(std::span input); - NvResult Submit(DeviceFD fd, std::span input, std::vector& output); - NvResult GetSyncpoint(std::span input, std::vector& output); - NvResult GetWaitbase(std::span input, std::vector& output); - NvResult MapBuffer(std::span input, std::vector& output); - NvResult UnmapBuffer(std::span input, std::vector& output); - NvResult SetSubmitTimeout(std::span input, std::vector& output); + NvResult Submit(DeviceFD fd, std::span input, std::span output); + NvResult GetSyncpoint(std::span input, std::span output); + NvResult GetWaitbase(std::span input, std::span output); + NvResult MapBuffer(std::span input, std::span output); + NvResult UnmapBuffer(std::span input, std::span output); + NvResult SetSubmitTimeout(std::span input, std::span output); Kernel::KEvent* QueryEvent(u32 event_id) override; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp index 39f30e7c8..a05c8cdae 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp @@ -13,7 +13,7 @@ nvhost_nvjpg::nvhost_nvjpg(Core::System& system_) : nvdevice{system_} {} nvhost_nvjpg::~nvhost_nvjpg() = default; NvResult nvhost_nvjpg::Ioctl1(DeviceFD fd, Ioctl command, std::span input, - std::vector& output) { + std::span output) { switch (command.group) { case 'H': switch (command.cmd) { @@ -32,13 +32,13 @@ NvResult nvhost_nvjpg::Ioctl1(DeviceFD fd, Ioctl command, std::span in } NvResult nvhost_nvjpg::Ioctl2(DeviceFD fd, Ioctl command, std::span input, - std::span inline_input, std::vector& output) { + std::span inline_input, std::span output) { UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); return NvResult::NotImplemented; } NvResult nvhost_nvjpg::Ioctl3(DeviceFD fd, Ioctl command, std::span input, - std::vector& output, std::vector& inline_output) { + std::span output, std::span inline_output) { UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); return NvResult::NotImplemented; } @@ -46,7 +46,7 @@ NvResult nvhost_nvjpg::Ioctl3(DeviceFD fd, Ioctl command, std::span in void nvhost_nvjpg::OnOpen(DeviceFD fd) {} void nvhost_nvjpg::OnClose(DeviceFD fd) {} -NvResult nvhost_nvjpg::SetNVMAPfd(std::span input, std::vector& output) { +NvResult nvhost_nvjpg::SetNVMAPfd(std::span input, std::span output) { IoctlSetNvmapFD params{}; std::memcpy(¶ms, input.data(), input.size()); LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h index 41b57e872..5623e0d47 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h @@ -16,11 +16,11 @@ public: ~nvhost_nvjpg() override; NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span input, - std::vector& output) override; + std::span output) override; NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span input, - std::span inline_input, std::vector& output) override; - NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span input, std::vector& output, - std::vector& inline_output) override; + std::span inline_input, std::span output) override; + NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span input, std::span output, + std::span inline_output) override; void OnOpen(DeviceFD fd) override; void OnClose(DeviceFD fd) override; @@ -33,7 +33,7 @@ private: s32_le nvmap_fd{}; - NvResult SetNVMAPfd(std::span input, std::vector& output); + NvResult SetNVMAPfd(std::span input, std::span output); }; } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp index b0ea402a7..c0b8684c3 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp @@ -16,7 +16,7 @@ nvhost_vic::nvhost_vic(Core::System& system_, NvCore::Container& core_) nvhost_vic::~nvhost_vic() = default; NvResult nvhost_vic::Ioctl1(DeviceFD fd, Ioctl command, std::span input, - std::vector& output) { + std::span output) { switch (command.group) { case 0x0: switch (command.cmd) { @@ -56,13 +56,13 @@ NvResult nvhost_vic::Ioctl1(DeviceFD fd, Ioctl command, std::span inpu } NvResult nvhost_vic::Ioctl2(DeviceFD fd, Ioctl command, std::span input, - std::span inline_input, std::vector& output) { + std::span inline_input, std::span output) { UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); return NvResult::NotImplemented; } NvResult nvhost_vic::Ioctl3(DeviceFD fd, Ioctl command, std::span input, - std::vector& output, std::vector& inline_output) { + std::span output, std::span inline_output) { UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); return NvResult::NotImplemented; } diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.h b/src/core/hle/service/nvdrv/devices/nvhost_vic.h index b5e350a83..cadbcb0a5 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.h @@ -13,11 +13,11 @@ public: ~nvhost_vic(); NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span input, - std::vector& output) override; + std::span output) override; NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span input, - std::span inline_input, std::vector& output) override; - NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span input, std::vector& output, - std::vector& inline_output) override; + std::span inline_input, std::span output) override; + NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span input, std::span output, + std::span inline_output) override; void OnOpen(DeviceFD fd) override; void OnClose(DeviceFD fd) override; diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp index 07417f045..e7f7e273b 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.cpp +++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp @@ -26,7 +26,7 @@ nvmap::nvmap(Core::System& system_, NvCore::Container& container_) nvmap::~nvmap() = default; NvResult nvmap::Ioctl1(DeviceFD fd, Ioctl command, std::span input, - std::vector& output) { + std::span output) { switch (command.group) { case 0x1: switch (command.cmd) { @@ -55,13 +55,13 @@ NvResult nvmap::Ioctl1(DeviceFD fd, Ioctl command, std::span input, } NvResult nvmap::Ioctl2(DeviceFD fd, Ioctl command, std::span input, - std::span inline_input, std::vector& output) { + std::span inline_input, std::span output) { UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); return NvResult::NotImplemented; } -NvResult nvmap::Ioctl3(DeviceFD fd, Ioctl command, std::span input, - std::vector& output, std::vector& inline_output) { +NvResult nvmap::Ioctl3(DeviceFD fd, Ioctl command, std::span input, std::span output, + std::span inline_output) { UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); return NvResult::NotImplemented; } @@ -69,7 +69,7 @@ NvResult nvmap::Ioctl3(DeviceFD fd, Ioctl command, std::span input, void nvmap::OnOpen(DeviceFD fd) {} void nvmap::OnClose(DeviceFD fd) {} -NvResult nvmap::IocCreate(std::span input, std::vector& output) { +NvResult nvmap::IocCreate(std::span input, std::span output) { IocCreateParams params; std::memcpy(¶ms, input.data(), sizeof(params)); LOG_DEBUG(Service_NVDRV, "called, size=0x{:08X}", params.size); @@ -89,7 +89,7 @@ NvResult nvmap::IocCreate(std::span input, std::vector& output) { return NvResult::Success; } -NvResult nvmap::IocAlloc(std::span input, std::vector& output) { +NvResult nvmap::IocAlloc(std::span input, std::span output) { IocAllocParams params; std::memcpy(¶ms, input.data(), sizeof(params)); LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.address); @@ -137,7 +137,7 @@ NvResult nvmap::IocAlloc(std::span input, std::vector& output) { return result; } -NvResult nvmap::IocGetId(std::span input, std::vector& output) { +NvResult nvmap::IocGetId(std::span input, std::span output) { IocGetIdParams params; std::memcpy(¶ms, input.data(), sizeof(params)); @@ -161,7 +161,7 @@ NvResult nvmap::IocGetId(std::span input, std::vector& output) { return NvResult::Success; } -NvResult nvmap::IocFromId(std::span input, std::vector& output) { +NvResult nvmap::IocFromId(std::span input, std::span output) { IocFromIdParams params; std::memcpy(¶ms, input.data(), sizeof(params)); @@ -192,7 +192,7 @@ NvResult nvmap::IocFromId(std::span input, std::vector& output) { return NvResult::Success; } -NvResult nvmap::IocParam(std::span input, std::vector& output) { +NvResult nvmap::IocParam(std::span input, std::span output) { enum class ParamTypes { Size = 1, Alignment = 2, Base = 3, Heap = 4, Kind = 5, Compr = 6 }; IocParamParams params; @@ -241,7 +241,7 @@ NvResult nvmap::IocParam(std::span input, std::vector& output) { return NvResult::Success; } -NvResult nvmap::IocFree(std::span input, std::vector& output) { +NvResult nvmap::IocFree(std::span input, std::span output) { IocFreeParams params; std::memcpy(¶ms, input.data(), sizeof(params)); diff --git a/src/core/hle/service/nvdrv/devices/nvmap.h b/src/core/hle/service/nvdrv/devices/nvmap.h index 82bd3b118..40c65b430 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.h +++ b/src/core/hle/service/nvdrv/devices/nvmap.h @@ -27,11 +27,11 @@ public: nvmap& operator=(const nvmap&) = delete; NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span input, - std::vector& output) override; + std::span output) override; NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span input, - std::span inline_input, std::vector& output) override; - NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span input, std::vector& output, - std::vector& inline_output) override; + std::span inline_input, std::span output) override; + NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span input, std::span output, + std::span inline_output) override; void OnOpen(DeviceFD fd) override; void OnClose(DeviceFD fd) override; @@ -106,12 +106,12 @@ private: }; static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size"); - NvResult IocCreate(std::span input, std::vector& output); - NvResult IocAlloc(std::span input, std::vector& output); - NvResult IocGetId(std::span input, std::vector& output); - NvResult IocFromId(std::span input, std::vector& output); - NvResult IocParam(std::span input, std::vector& output); - NvResult IocFree(std::span input, std::vector& output); + NvResult IocCreate(std::span input, std::span output); + NvResult IocAlloc(std::span input, std::span output); + NvResult IocGetId(std::span input, std::span output); + NvResult IocFromId(std::span input, std::span output); + NvResult IocParam(std::span input, std::span output); + NvResult IocFree(std::span input, std::span output); NvCore::Container& container; NvCore::NvMap& file; diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index 3d774eec4..9e46ee8dd 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp @@ -130,7 +130,7 @@ DeviceFD Module::Open(const std::string& device_name) { } NvResult Module::Ioctl1(DeviceFD fd, Ioctl command, std::span input, - std::vector& output) { + std::span output) { if (fd < 0) { LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); return NvResult::InvalidState; @@ -147,7 +147,7 @@ NvResult Module::Ioctl1(DeviceFD fd, Ioctl command, std::span input, } NvResult Module::Ioctl2(DeviceFD fd, Ioctl command, std::span input, - std::span inline_input, std::vector& output) { + std::span inline_input, std::span output) { if (fd < 0) { LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); return NvResult::InvalidState; @@ -163,8 +163,8 @@ NvResult Module::Ioctl2(DeviceFD fd, Ioctl command, std::span input, return itr->second->Ioctl2(fd, command, input, inline_input, output); } -NvResult Module::Ioctl3(DeviceFD fd, Ioctl command, std::span input, - std::vector& output, std::vector& inline_output) { +NvResult Module::Ioctl3(DeviceFD fd, Ioctl command, std::span input, std::span output, + std::span inline_output) { if (fd < 0) { LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); return NvResult::InvalidState; diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index 668be742b..d8622b3ca 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h @@ -80,13 +80,13 @@ public: DeviceFD Open(const std::string& device_name); /// Sends an ioctl command to the specified file descriptor. - NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span input, std::vector& output); + NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span input, std::span output); NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span input, - std::span inline_input, std::vector& output); + std::span inline_input, std::span output); - NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span input, std::vector& output, - std::vector& inline_output); + NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span input, std::span output, + std::span inline_output); /// Closes a device file descriptor and returns operation success. NvResult Close(DeviceFD fd); diff --git a/src/core/hle/service/nvdrv/nvdrv_interface.cpp b/src/core/hle/service/nvdrv/nvdrv_interface.cpp index d010a1e03..348207e25 100644 --- a/src/core/hle/service/nvdrv/nvdrv_interface.cpp +++ b/src/core/hle/service/nvdrv/nvdrv_interface.cpp @@ -63,12 +63,12 @@ void NVDRV::Ioctl1(HLERequestContext& ctx) { } // Check device - std::vector output_buffer(ctx.GetWriteBufferSize(0)); + tmp_output.resize_destructive(ctx.GetWriteBufferSize(0)); const auto input_buffer = ctx.ReadBuffer(0); - const auto nv_result = nvdrv->Ioctl1(fd, command, input_buffer, output_buffer); + const auto nv_result = nvdrv->Ioctl1(fd, command, input_buffer, tmp_output); if (command.is_out != 0) { - ctx.WriteBuffer(output_buffer); + ctx.WriteBuffer(tmp_output); } IPC::ResponseBuilder rb{ctx, 3}; @@ -90,12 +90,12 @@ void NVDRV::Ioctl2(HLERequestContext& ctx) { const auto input_buffer = ctx.ReadBuffer(0); const auto input_inlined_buffer = ctx.ReadBuffer(1); - std::vector output_buffer(ctx.GetWriteBufferSize(0)); + tmp_output.resize_destructive(ctx.GetWriteBufferSize(0)); const auto nv_result = - nvdrv->Ioctl2(fd, command, input_buffer, input_inlined_buffer, output_buffer); + nvdrv->Ioctl2(fd, command, input_buffer, input_inlined_buffer, tmp_output); if (command.is_out != 0) { - ctx.WriteBuffer(output_buffer); + ctx.WriteBuffer(tmp_output); } IPC::ResponseBuilder rb{ctx, 3}; @@ -116,14 +116,12 @@ void NVDRV::Ioctl3(HLERequestContext& ctx) { } const auto input_buffer = ctx.ReadBuffer(0); - std::vector output_buffer(ctx.GetWriteBufferSize(0)); - std::vector output_buffer_inline(ctx.GetWriteBufferSize(1)); - - const auto nv_result = - nvdrv->Ioctl3(fd, command, input_buffer, output_buffer, output_buffer_inline); + tmp_output.resize_destructive(ctx.GetWriteBufferSize(0)); + tmp_output_inline.resize_destructive(ctx.GetWriteBufferSize(1)); + const auto nv_result = nvdrv->Ioctl3(fd, command, input_buffer, tmp_output, tmp_output_inline); if (command.is_out != 0) { - ctx.WriteBuffer(output_buffer, 0); - ctx.WriteBuffer(output_buffer_inline, 1); + ctx.WriteBuffer(tmp_output, 0); + ctx.WriteBuffer(tmp_output_inline, 1); } IPC::ResponseBuilder rb{ctx, 3}; diff --git a/src/core/hle/service/nvdrv/nvdrv_interface.h b/src/core/hle/service/nvdrv/nvdrv_interface.h index 881ea1a6b..4b593ff90 100644 --- a/src/core/hle/service/nvdrv/nvdrv_interface.h +++ b/src/core/hle/service/nvdrv/nvdrv_interface.h @@ -4,6 +4,7 @@ #pragma once #include +#include "common/scratch_buffer.h" #include "core/hle/service/nvdrv/nvdrv.h" #include "core/hle/service/service.h" @@ -33,6 +34,8 @@ private: u64 pid{}; bool is_initialized{}; + Common::ScratchBuffer tmp_output; + Common::ScratchBuffer tmp_output_inline; }; } // namespace Service::Nvidia diff --git a/src/core/hle/service/nvnflinger/parcel.h b/src/core/hle/service/nvnflinger/parcel.h index fb56d75d7..23ba315a0 100644 --- a/src/core/hle/service/nvnflinger/parcel.h +++ b/src/core/hle/service/nvnflinger/parcel.h @@ -6,6 +6,7 @@ #include #include #include +#include #include "common/alignment.h" #include "common/assert.h" @@ -167,7 +168,7 @@ public: private: template requires(std::is_trivially_copyable_v) - void WriteImpl(const T& val, std::vector& buffer) { + void WriteImpl(const T& val, boost::container::small_vector& buffer) { const size_t aligned_size = Common::AlignUp(sizeof(T), 4); const size_t old_size = buffer.size(); buffer.resize(old_size + aligned_size); @@ -176,8 +177,8 @@ private: } private: - std::vector m_data_buffer; - std::vector m_object_buffer; + boost::container::small_vector m_data_buffer; + boost::container::small_vector m_object_buffer; }; } // namespace Service::android diff --git a/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp b/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp index c3c2281bb..9ff4028c2 100644 --- a/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp +++ b/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp @@ -479,7 +479,7 @@ void EmitContext::DefineGenericOutput(size_t index, u32 invocations) { const u32 remainder{4 - element}; const TransformFeedbackVarying* xfb_varying{}; const size_t xfb_varying_index{base_index + element}; - if (xfb_varying_index < runtime_info.xfb_varyings.size()) { + if (xfb_varying_index < runtime_info.xfb_count) { xfb_varying = &runtime_info.xfb_varyings[xfb_varying_index]; xfb_varying = xfb_varying->components > 0 ? xfb_varying : nullptr; } diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.cpp b/src/shader_recompiler/backend/spirv/emit_spirv.cpp index 0f86a8004..34592a01f 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv.cpp @@ -387,7 +387,7 @@ void SetupSignedNanCapabilities(const Profile& profile, const IR::Program& progr } void SetupTransformFeedbackCapabilities(EmitContext& ctx, Id main_func) { - if (ctx.runtime_info.xfb_varyings.empty()) { + if (ctx.runtime_info.xfb_count == 0) { return; } ctx.AddCapability(spv::Capability::TransformFeedback); diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp index fd15f47ea..bec5db173 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp @@ -160,7 +160,7 @@ void DefineGenericOutput(EmitContext& ctx, size_t index, std::optional invo const u32 remainder{4 - element}; const TransformFeedbackVarying* xfb_varying{}; const size_t xfb_varying_index{base_attr_index + element}; - if (xfb_varying_index < ctx.runtime_info.xfb_varyings.size()) { + if (xfb_varying_index < ctx.runtime_info.xfb_count) { xfb_varying = &ctx.runtime_info.xfb_varyings[xfb_varying_index]; xfb_varying = xfb_varying->components > 0 ? xfb_varying : nullptr; } diff --git a/src/shader_recompiler/runtime_info.h b/src/shader_recompiler/runtime_info.h index 3b63c249f..619c0b138 100644 --- a/src/shader_recompiler/runtime_info.h +++ b/src/shader_recompiler/runtime_info.h @@ -84,7 +84,8 @@ struct RuntimeInfo { bool glasm_use_storage_buffers{}; /// Transform feedback state for each varying - std::vector xfb_varyings; + std::array xfb_varyings{}; + u32 xfb_count{0}; }; } // namespace Shader diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h index 45977d578..58a45ab67 100644 --- a/src/video_core/buffer_cache/buffer_cache.h +++ b/src/video_core/buffer_cache/buffer_cache.h @@ -207,7 +207,7 @@ bool BufferCache

::DMACopy(GPUVAddr src_address, GPUVAddr dest_address, u64 am if (has_new_downloads) { memory_tracker.MarkRegionAsGpuModified(*cpu_dest_address, amount); } - tmp_buffer.resize(amount); + tmp_buffer.resize_destructive(amount); cpu_memory.ReadBlockUnsafe(*cpu_src_address, tmp_buffer.data(), amount); cpu_memory.WriteBlockUnsafe(*cpu_dest_address, tmp_buffer.data(), amount); return true; @@ -1279,7 +1279,7 @@ template typename BufferCache

::OverlapResult BufferCache

::ResolveOverlaps(VAddr cpu_addr, u32 wanted_size) { static constexpr int STREAM_LEAP_THRESHOLD = 16; - std::vector overlap_ids; + boost::container::small_vector overlap_ids; VAddr begin = cpu_addr; VAddr end = cpu_addr + wanted_size; int stream_score = 0; diff --git a/src/video_core/buffer_cache/buffer_cache_base.h b/src/video_core/buffer_cache/buffer_cache_base.h index 63a120f7a..fe6068cfe 100644 --- a/src/video_core/buffer_cache/buffer_cache_base.h +++ b/src/video_core/buffer_cache/buffer_cache_base.h @@ -229,7 +229,7 @@ class BufferCache : public VideoCommon::ChannelSetupCaches; struct OverlapResult { - std::vector ids; + boost::container::small_vector ids; VAddr begin; VAddr end; bool has_stream_leap = false; @@ -582,7 +582,7 @@ private: BufferId inline_buffer_id; std::array> CACHING_PAGEBITS)> page_table; - std::vector tmp_buffer; + Common::ScratchBuffer tmp_buffer; }; } // namespace VideoCommon diff --git a/src/video_core/cdma_pusher.h b/src/video_core/cdma_pusher.h index 83112dfce..7d660af47 100644 --- a/src/video_core/cdma_pusher.h +++ b/src/video_core/cdma_pusher.h @@ -63,7 +63,6 @@ struct ChCommand { }; using ChCommandHeaderList = std::vector; -using ChCommandList = std::vector; struct ThiRegisters { u32_le increment_syncpt{}; diff --git a/src/video_core/dma_pusher.h b/src/video_core/dma_pusher.h index 1cdb690ed..8a2784cdc 100644 --- a/src/video_core/dma_pusher.h +++ b/src/video_core/dma_pusher.h @@ -6,6 +6,7 @@ #include #include #include +#include #include #include "common/bit_field.h" @@ -102,11 +103,12 @@ inline CommandHeader BuildCommandHeader(BufferMethods method, u32 arg_count, Sub struct CommandList final { CommandList() = default; explicit CommandList(std::size_t size) : command_lists(size) {} - explicit CommandList(std::vector&& prefetch_command_list_) + explicit CommandList( + boost::container::small_vector&& prefetch_command_list_) : prefetch_command_list{std::move(prefetch_command_list_)} {} - std::vector command_lists; - std::vector prefetch_command_list; + boost::container::small_vector command_lists; + boost::container::small_vector prefetch_command_list; }; /** diff --git a/src/video_core/engines/maxwell_dma.cpp b/src/video_core/engines/maxwell_dma.cpp index ebe5536de..bc1eb41e7 100644 --- a/src/video_core/engines/maxwell_dma.cpp +++ b/src/video_core/engines/maxwell_dma.cpp @@ -108,9 +108,11 @@ void MaxwellDMA::Launch() { if (regs.launch_dma.remap_enable != 0 && is_const_a_dst) { ASSERT(regs.remap_const.component_size_minus_one == 3); accelerate.BufferClear(regs.offset_out, regs.line_length_in, regs.remap_consta_value); - std::vector tmp_buffer(regs.line_length_in, regs.remap_consta_value); + read_buffer.resize_destructive(regs.line_length_in * sizeof(u32)); + std::span span(reinterpret_cast(read_buffer.data()), regs.line_length_in); + std::ranges::fill(span, regs.remap_consta_value); memory_manager.WriteBlockUnsafe(regs.offset_out, - reinterpret_cast(tmp_buffer.data()), + reinterpret_cast(read_buffer.data()), regs.line_length_in * sizeof(u32)); } else { memory_manager.FlushCaching(); @@ -126,32 +128,32 @@ void MaxwellDMA::Launch() { UNIMPLEMENTED_IF(regs.line_length_in % 16 != 0); UNIMPLEMENTED_IF(regs.offset_in % 16 != 0); UNIMPLEMENTED_IF(regs.offset_out % 16 != 0); - std::vector tmp_buffer(16); + read_buffer.resize_destructive(16); for (u32 offset = 0; offset < regs.line_length_in; offset += 16) { memory_manager.ReadBlockUnsafe( convert_linear_2_blocklinear_addr(regs.offset_in + offset), - tmp_buffer.data(), tmp_buffer.size()); - memory_manager.WriteBlockCached(regs.offset_out + offset, tmp_buffer.data(), - tmp_buffer.size()); + read_buffer.data(), read_buffer.size()); + memory_manager.WriteBlockCached(regs.offset_out + offset, read_buffer.data(), + read_buffer.size()); } } else if (is_src_pitch && !is_dst_pitch) { UNIMPLEMENTED_IF(regs.line_length_in % 16 != 0); UNIMPLEMENTED_IF(regs.offset_in % 16 != 0); UNIMPLEMENTED_IF(regs.offset_out % 16 != 0); - std::vector tmp_buffer(16); + read_buffer.resize_destructive(16); for (u32 offset = 0; offset < regs.line_length_in; offset += 16) { - memory_manager.ReadBlockUnsafe(regs.offset_in + offset, tmp_buffer.data(), - tmp_buffer.size()); + memory_manager.ReadBlockUnsafe(regs.offset_in + offset, read_buffer.data(), + read_buffer.size()); memory_manager.WriteBlockCached( convert_linear_2_blocklinear_addr(regs.offset_out + offset), - tmp_buffer.data(), tmp_buffer.size()); + read_buffer.data(), read_buffer.size()); } } else { if (!accelerate.BufferCopy(regs.offset_in, regs.offset_out, regs.line_length_in)) { - std::vector tmp_buffer(regs.line_length_in); - memory_manager.ReadBlockUnsafe(regs.offset_in, tmp_buffer.data(), + read_buffer.resize_destructive(regs.line_length_in); + memory_manager.ReadBlockUnsafe(regs.offset_in, read_buffer.data(), regs.line_length_in); - memory_manager.WriteBlockCached(regs.offset_out, tmp_buffer.data(), + memory_manager.WriteBlockCached(regs.offset_out, read_buffer.data(), regs.line_length_in); } } @@ -171,7 +173,8 @@ void MaxwellDMA::CopyBlockLinearToPitch() { src_operand.address = regs.offset_in; DMA::BufferOperand dst_operand; - dst_operand.pitch = regs.pitch_out; + u32 abs_pitch_out = std::abs(static_cast(regs.pitch_out)); + dst_operand.pitch = abs_pitch_out; dst_operand.width = regs.line_length_in; dst_operand.height = regs.line_count; dst_operand.address = regs.offset_out; @@ -218,7 +221,7 @@ void MaxwellDMA::CopyBlockLinearToPitch() { const size_t src_size = CalculateSize(true, bytes_per_pixel, width, height, depth, block_height, block_depth); - const size_t dst_size = static_cast(regs.pitch_out) * regs.line_count; + const size_t dst_size = static_cast(abs_pitch_out) * regs.line_count; read_buffer.resize_destructive(src_size); write_buffer.resize_destructive(dst_size); @@ -227,7 +230,7 @@ void MaxwellDMA::CopyBlockLinearToPitch() { UnswizzleSubrect(write_buffer, read_buffer, bytes_per_pixel, width, height, depth, x_offset, src_params.origin.y, x_elements, regs.line_count, block_height, block_depth, - regs.pitch_out); + abs_pitch_out); memory_manager.WriteBlockCached(regs.offset_out, write_buffer.data(), dst_size); } diff --git a/src/video_core/host1x/codecs/h264.cpp b/src/video_core/host1x/codecs/h264.cpp index 6ce179167..ce827eb6c 100644 --- a/src/video_core/host1x/codecs/h264.cpp +++ b/src/video_core/host1x/codecs/h264.cpp @@ -4,6 +4,7 @@ #include #include +#include "common/scratch_buffer.h" #include "common/settings.h" #include "video_core/host1x/codecs/h264.h" #include "video_core/host1x/host1x.h" @@ -188,7 +189,8 @@ void H264BitWriter::WriteBit(bool state) { } void H264BitWriter::WriteScalingList(std::span list, s32 start, s32 count) { - std::vector scan(count); + static Common::ScratchBuffer scan{}; + scan.resize_destructive(count); if (count == 16) { std::memcpy(scan.data(), zig_zag_scan.data(), scan.size()); } else { diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp index b2f7e160a..45141e488 100644 --- a/src/video_core/memory_manager.cpp +++ b/src/video_core/memory_manager.cpp @@ -587,7 +587,7 @@ void MemoryManager::InvalidateRegion(GPUVAddr gpu_addr, size_t size, void MemoryManager::CopyBlock(GPUVAddr gpu_dest_addr, GPUVAddr gpu_src_addr, std::size_t size, VideoCommon::CacheType which) { - std::vector tmp_buffer(size); + tmp_buffer.resize_destructive(size); ReadBlock(gpu_src_addr, tmp_buffer.data(), size, which); // The output block must be flushed in case it has data modified from the GPU. @@ -670,9 +670,9 @@ bool MemoryManager::IsFullyMappedRange(GPUVAddr gpu_addr, std::size_t size) cons return result; } -std::vector> MemoryManager::GetSubmappedRange( - GPUVAddr gpu_addr, std::size_t size) const { - std::vector> result{}; +boost::container::small_vector, 32> +MemoryManager::GetSubmappedRange(GPUVAddr gpu_addr, std::size_t size) const { + boost::container::small_vector, 32> result{}; GetSubmappedRangeImpl(gpu_addr, size, result); return result; } @@ -680,8 +680,9 @@ std::vector> MemoryManager::GetSubmappedRange( template void MemoryManager::GetSubmappedRangeImpl( GPUVAddr gpu_addr, std::size_t size, - std::vector, std::size_t>>& - result) const { + boost::container::small_vector< + std::pair, std::size_t>, 32>& result) + const { std::optional, std::size_t>> last_segment{}; std::optional old_page_addr{}; diff --git a/src/video_core/memory_manager.h b/src/video_core/memory_manager.h index 794535122..4202c26ff 100644 --- a/src/video_core/memory_manager.h +++ b/src/video_core/memory_manager.h @@ -8,10 +8,12 @@ #include #include #include +#include #include "common/common_types.h" #include "common/multi_level_page_table.h" #include "common/range_map.h" +#include "common/scratch_buffer.h" #include "common/virtual_buffer.h" #include "video_core/cache_types.h" #include "video_core/pte_kind.h" @@ -107,8 +109,8 @@ public: * if the region is continuous, a single pair will be returned. If it's unmapped, an empty * vector will be returned; */ - std::vector> GetSubmappedRange(GPUVAddr gpu_addr, - std::size_t size) const; + boost::container::small_vector, 32> GetSubmappedRange( + GPUVAddr gpu_addr, std::size_t size) const; GPUVAddr Map(GPUVAddr gpu_addr, VAddr cpu_addr, std::size_t size, PTEKind kind = PTEKind::INVALID, bool is_big_pages = true); @@ -165,7 +167,8 @@ private: template void GetSubmappedRangeImpl( GPUVAddr gpu_addr, std::size_t size, - std::vector, std::size_t>>& + boost::container::small_vector< + std::pair, std::size_t>, 32>& result) const; Core::System& system; @@ -215,8 +218,8 @@ private: Common::VirtualBuffer big_page_table_cpu; std::vector big_page_continuous; - std::vector> page_stash{}; - std::vector> page_stash2{}; + boost::container::small_vector, 32> page_stash{}; + boost::container::small_vector, 32> page_stash2{}; mutable std::mutex guard; @@ -226,6 +229,8 @@ private: std::unique_ptr accumulator; static std::atomic unique_identifier_generator; + + Common::ScratchBuffer tmp_buffer; }; } // namespace Tegra diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index 3f077311e..0329ed820 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp @@ -85,7 +85,9 @@ Shader::RuntimeInfo MakeRuntimeInfo(const GraphicsPipelineKey& key, case Shader::Stage::VertexB: case Shader::Stage::Geometry: if (!use_assembly_shaders && key.xfb_enabled != 0) { - info.xfb_varyings = VideoCommon::MakeTransformFeedbackVaryings(key.xfb_state); + auto [varyings, count] = VideoCommon::MakeTransformFeedbackVaryings(key.xfb_state); + info.xfb_varyings = varyings; + info.xfb_count = count; } break; case Shader::Stage::TessellationEval: diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp index e30fcb1ed..f47301ad5 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp @@ -361,7 +361,7 @@ void BufferCacheRuntime::CopyBuffer(VkBuffer dst_buffer, VkBuffer src_buffer, .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT, }; // Measuring a popular game, this number never exceeds the specified size once data is warmed up - boost::container::small_vector vk_copies(copies.size()); + boost::container::small_vector vk_copies(copies.size()); std::ranges::transform(copies, vk_copies.begin(), MakeBufferCopy); scheduler.RequestOutsideRenderPassOperationContext(); scheduler.Record([src_buffer, dst_buffer, vk_copies, barrier](vk::CommandBuffer cmdbuf) { diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index a2cfb2105..9f316113c 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -167,7 +167,10 @@ Shader::RuntimeInfo MakeRuntimeInfo(std::span program info.fixed_state_point_size = point_size; } if (key.state.xfb_enabled) { - info.xfb_varyings = VideoCommon::MakeTransformFeedbackVaryings(key.state.xfb_state); + auto [varyings, count] = + VideoCommon::MakeTransformFeedbackVaryings(key.state.xfb_state); + info.xfb_varyings = varyings; + info.xfb_count = count; } info.convert_depth_mode = gl_ndc; } @@ -214,7 +217,10 @@ Shader::RuntimeInfo MakeRuntimeInfo(std::span program info.fixed_state_point_size = point_size; } if (key.state.xfb_enabled != 0) { - info.xfb_varyings = VideoCommon::MakeTransformFeedbackVaryings(key.state.xfb_state); + auto [varyings, count] = + VideoCommon::MakeTransformFeedbackVaryings(key.state.xfb_state); + info.xfb_varyings = varyings; + info.xfb_count = count; } info.convert_depth_mode = gl_ndc; break; diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index f025f618b..f3cef09dd 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -330,9 +330,9 @@ constexpr VkBorderColor ConvertBorderColor(const std::array& color) { }; } -[[maybe_unused]] [[nodiscard]] std::vector TransformBufferCopies( - std::span copies, size_t buffer_offset) { - std::vector result(copies.size()); +[[maybe_unused]] [[nodiscard]] boost::container::small_vector +TransformBufferCopies(std::span copies, size_t buffer_offset) { + boost::container::small_vector result(copies.size()); std::ranges::transform( copies, result.begin(), [buffer_offset](const VideoCommon::BufferCopy& copy) { return VkBufferCopy{ @@ -344,7 +344,7 @@ constexpr VkBorderColor ConvertBorderColor(const std::array& color) { return result; } -[[nodiscard]] std::vector TransformBufferImageCopies( +[[nodiscard]] boost::container::small_vector TransformBufferImageCopies( std::span copies, size_t buffer_offset, VkImageAspectFlags aspect_mask) { struct Maker { VkBufferImageCopy operator()(const BufferImageCopy& copy) const { @@ -377,14 +377,14 @@ constexpr VkBorderColor ConvertBorderColor(const std::array& color) { VkImageAspectFlags aspect_mask; }; if (aspect_mask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { - std::vector result(copies.size() * 2); + boost::container::small_vector result(copies.size() * 2); std::ranges::transform(copies, result.begin(), Maker{buffer_offset, VK_IMAGE_ASPECT_DEPTH_BIT}); std::ranges::transform(copies, result.begin() + copies.size(), Maker{buffer_offset, VK_IMAGE_ASPECT_STENCIL_BIT}); return result; } else { - std::vector result(copies.size()); + boost::container::small_vector result(copies.size()); std::ranges::transform(copies, result.begin(), Maker{buffer_offset, aspect_mask}); return result; } @@ -867,8 +867,8 @@ void TextureCacheRuntime::BarrierFeedbackLoop() { void TextureCacheRuntime::ReinterpretImage(Image& dst, Image& src, std::span copies) { - std::vector vk_in_copies(copies.size()); - std::vector vk_out_copies(copies.size()); + boost::container::small_vector vk_in_copies(copies.size()); + boost::container::small_vector vk_out_copies(copies.size()); const VkImageAspectFlags src_aspect_mask = src.AspectMask(); const VkImageAspectFlags dst_aspect_mask = dst.AspectMask(); @@ -1157,7 +1157,7 @@ void TextureCacheRuntime::ConvertImage(Framebuffer* dst, ImageView& dst_view, Im void TextureCacheRuntime::CopyImage(Image& dst, Image& src, std::span copies) { - std::vector vk_copies(copies.size()); + boost::container::small_vector vk_copies(copies.size()); const VkImageAspectFlags aspect_mask = dst.AspectMask(); ASSERT(aspect_mask == src.AspectMask()); @@ -1332,7 +1332,7 @@ void Image::UploadMemory(VkBuffer buffer, VkDeviceSize offset, ScaleDown(true); } scheduler->RequestOutsideRenderPassOperationContext(); - std::vector vk_copies = TransformBufferImageCopies(copies, offset, aspect_mask); + auto vk_copies = TransformBufferImageCopies(copies, offset, aspect_mask); const VkBuffer src_buffer = buffer; const VkImage vk_image = *original_image; const VkImageAspectFlags vk_aspect_mask = aspect_mask; @@ -1367,8 +1367,9 @@ void Image::DownloadMemory(std::span buffers_span, std::span buffers_vector{}; - boost::container::small_vector, 1> vk_copies; + boost::container::small_vector buffers_vector{}; + boost::container::small_vector, 8> + vk_copies; for (size_t index = 0; index < buffers_span.size(); index++) { buffers_vector.emplace_back(buffers_span[index]); vk_copies.emplace_back( @@ -1858,7 +1859,7 @@ Framebuffer::~Framebuffer() = default; void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime, std::span color_buffers, ImageView* depth_buffer, bool is_rescaled) { - std::vector attachments; + boost::container::small_vector attachments; RenderPassKey renderpass_key{}; s32 num_layers = 1; diff --git a/src/video_core/shader_cache.cpp b/src/video_core/shader_cache.cpp index c5213875b..4db948b6d 100644 --- a/src/video_core/shader_cache.cpp +++ b/src/video_core/shader_cache.cpp @@ -151,11 +151,9 @@ void ShaderCache::RemovePendingShaders() { marked_for_removal.erase(std::unique(marked_for_removal.begin(), marked_for_removal.end()), marked_for_removal.end()); - std::vector removed_shaders; - removed_shaders.reserve(marked_for_removal.size()); + boost::container::small_vector removed_shaders; std::scoped_lock lock{lookup_mutex}; - for (Entry* const entry : marked_for_removal) { removed_shaders.push_back(entry->data); diff --git a/src/video_core/texture_cache/image_base.h b/src/video_core/texture_cache/image_base.h index 1b8a17ee8..55d49d017 100644 --- a/src/video_core/texture_cache/image_base.h +++ b/src/video_core/texture_cache/image_base.h @@ -6,6 +6,7 @@ #include #include #include +#include #include "common/common_funcs.h" #include "common/common_types.h" @@ -108,8 +109,8 @@ struct ImageBase { std::vector image_view_infos; std::vector image_view_ids; - std::vector slice_offsets; - std::vector slice_subresources; + boost::container::small_vector slice_offsets; + boost::container::small_vector slice_subresources; std::vector aliased_images; std::vector overlapping_images; diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index d58bb69ff..d3f03a995 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -526,7 +526,7 @@ void TextureCache

::WriteMemory(VAddr cpu_addr, size_t size) { template void TextureCache

::DownloadMemory(VAddr cpu_addr, size_t size) { - std::vector images; + boost::container::small_vector images; ForEachImageInRegion(cpu_addr, size, [&images](ImageId image_id, ImageBase& image) { if (!image.IsSafeDownload()) { return; @@ -579,7 +579,7 @@ std::optional TextureCache

::GetFlushArea(V template void TextureCache

::UnmapMemory(VAddr cpu_addr, size_t size) { - std::vector deleted_images; + boost::container::small_vector deleted_images; ForEachImageInRegion(cpu_addr, size, [&](ImageId id, Image&) { deleted_images.push_back(id); }); for (const ImageId id : deleted_images) { Image& image = slot_images[id]; @@ -593,7 +593,7 @@ void TextureCache

::UnmapMemory(VAddr cpu_addr, size_t size) { template void TextureCache

::UnmapGPUMemory(size_t as_id, GPUVAddr gpu_addr, size_t size) { - std::vector deleted_images; + boost::container::small_vector deleted_images; ForEachImageInRegionGPU(as_id, gpu_addr, size, [&](ImageId id, Image&) { deleted_images.push_back(id); }); for (const ImageId id : deleted_images) { @@ -1101,7 +1101,7 @@ ImageId TextureCache

::FindImage(const ImageInfo& info, GPUVAddr gpu_addr, const bool native_bgr = runtime.HasNativeBgr(); const bool flexible_formats = True(options & RelaxedOptions::Format); ImageId image_id{}; - boost::container::small_vector image_ids; + boost::container::small_vector image_ids; const auto lambda = [&](ImageId existing_image_id, ImageBase& existing_image) { if (True(existing_image.flags & ImageFlagBits::Remapped)) { return false; @@ -1622,7 +1622,7 @@ ImageId TextureCache

::FindDMAImage(const ImageInfo& info, GPUVAddr gpu_addr) } } ImageId image_id{}; - boost::container::small_vector image_ids; + boost::container::small_vector image_ids; const auto lambda = [&](ImageId existing_image_id, ImageBase& existing_image) { if (True(existing_image.flags & ImageFlagBits::Remapped)) { return false; @@ -1942,7 +1942,7 @@ void TextureCache

::RegisterImage(ImageId image_id) { image.map_view_id = map_id; return; } - std::vector sparse_maps{}; + boost::container::small_vector sparse_maps; ForEachSparseSegment( image, [this, image_id, &sparse_maps](GPUVAddr gpu_addr, VAddr cpu_addr, size_t size) { auto map_id = slot_map_views.insert(gpu_addr, cpu_addr, size, image_id); @@ -2217,7 +2217,7 @@ void TextureCache

::MarkModification(ImageBase& image) noexcept { template void TextureCache

::SynchronizeAliases(ImageId image_id) { - boost::container::small_vector aliased_images; + boost::container::small_vector aliased_images; Image& image = slot_images[image_id]; bool any_rescaled = True(image.flags & ImageFlagBits::Rescaled); bool any_modified = True(image.flags & ImageFlagBits::GpuModified); diff --git a/src/video_core/texture_cache/texture_cache_base.h b/src/video_core/texture_cache/texture_cache_base.h index 44232b961..e9ec91265 100644 --- a/src/video_core/texture_cache/texture_cache_base.h +++ b/src/video_core/texture_cache/texture_cache_base.h @@ -56,7 +56,7 @@ struct ImageViewInOut { struct AsyncDecodeContext { ImageId image_id; Common::ScratchBuffer decoded_data; - std::vector copies; + boost::container::small_vector copies; std::mutex mutex; std::atomic_bool complete; }; @@ -429,7 +429,7 @@ private: std::unordered_map, Common::IdentityHash> page_table; std::unordered_map, Common::IdentityHash> sparse_page_table; - std::unordered_map> sparse_views; + std::unordered_map> sparse_views; VAddr virtual_invalid_space{}; diff --git a/src/video_core/texture_cache/util.cpp b/src/video_core/texture_cache/util.cpp index 95a5b47d8..f781cb7a0 100644 --- a/src/video_core/texture_cache/util.cpp +++ b/src/video_core/texture_cache/util.cpp @@ -329,13 +329,13 @@ template [[nodiscard]] std::optional ResolveOverlapRightAddress3D( const ImageInfo& new_info, GPUVAddr gpu_addr, const ImageBase& overlap, bool strict_size) { - const std::vector slice_offsets = CalculateSliceOffsets(new_info); + const auto slice_offsets = CalculateSliceOffsets(new_info); const u32 diff = static_cast(overlap.gpu_addr - gpu_addr); const auto it = std::ranges::find(slice_offsets, diff); if (it == slice_offsets.end()) { return std::nullopt; } - const std::vector subresources = CalculateSliceSubresources(new_info); + const auto subresources = CalculateSliceSubresources(new_info); const SubresourceBase base = subresources[std::distance(slice_offsets.begin(), it)]; const ImageInfo& info = overlap.info; if (!IsBlockLinearSizeCompatible(new_info, info, base.level, 0, strict_size)) { @@ -655,9 +655,9 @@ LevelArray CalculateMipLevelSizes(const ImageInfo& info) noexcept { return sizes; } -std::vector CalculateSliceOffsets(const ImageInfo& info) { +boost::container::small_vector CalculateSliceOffsets(const ImageInfo& info) { ASSERT(info.type == ImageType::e3D); - std::vector offsets; + boost::container::small_vector offsets; offsets.reserve(NumSlices(info)); const LevelInfo level_info = MakeLevelInfo(info); @@ -679,9 +679,10 @@ std::vector CalculateSliceOffsets(const ImageInfo& info) { return offsets; } -std::vector CalculateSliceSubresources(const ImageInfo& info) { +boost::container::small_vector CalculateSliceSubresources( + const ImageInfo& info) { ASSERT(info.type == ImageType::e3D); - std::vector subresources; + boost::container::small_vector subresources; subresources.reserve(NumSlices(info)); for (s32 level = 0; level < info.resources.levels; ++level) { const s32 depth = AdjustMipSize(info.size.depth, level); @@ -723,8 +724,10 @@ ImageViewType RenderTargetImageViewType(const ImageInfo& info) noexcept { } } -std::vector MakeShrinkImageCopies(const ImageInfo& dst, const ImageInfo& src, - SubresourceBase base, u32 up_scale, u32 down_shift) { +boost::container::small_vector MakeShrinkImageCopies(const ImageInfo& dst, + const ImageInfo& src, + SubresourceBase base, + u32 up_scale, u32 down_shift) { ASSERT(dst.resources.levels >= src.resources.levels); const bool is_dst_3d = dst.type == ImageType::e3D; @@ -733,7 +736,7 @@ std::vector MakeShrinkImageCopies(const ImageInfo& dst, const ImageIn ASSERT(src.resources.levels == 1); } const bool both_2d{src.type == ImageType::e2D && dst.type == ImageType::e2D}; - std::vector copies; + boost::container::small_vector copies; copies.reserve(src.resources.levels); for (s32 level = 0; level < src.resources.levels; ++level) { ImageCopy& copy = copies.emplace_back(); @@ -770,9 +773,10 @@ std::vector MakeShrinkImageCopies(const ImageInfo& dst, const ImageIn return copies; } -std::vector MakeReinterpretImageCopies(const ImageInfo& src, u32 up_scale, - u32 down_shift) { - std::vector copies; +boost::container::small_vector MakeReinterpretImageCopies(const ImageInfo& src, + u32 up_scale, + u32 down_shift) { + boost::container::small_vector copies; copies.reserve(src.resources.levels); const bool is_3d = src.type == ImageType::e3D; for (s32 level = 0; level < src.resources.levels; ++level) { @@ -824,9 +828,11 @@ bool IsValidEntry(const Tegra::MemoryManager& gpu_memory, const TICEntry& config return gpu_memory.GpuToCpuAddress(address, guest_size_bytes).has_value(); } -std::vector UnswizzleImage(Tegra::MemoryManager& gpu_memory, GPUVAddr gpu_addr, - const ImageInfo& info, std::span input, - std::span output) { +boost::container::small_vector UnswizzleImage(Tegra::MemoryManager& gpu_memory, + GPUVAddr gpu_addr, + const ImageInfo& info, + std::span input, + std::span output) { const size_t guest_size_bytes = input.size_bytes(); const u32 bpp_log2 = BytesPerBlockLog2(info.format); const Extent3D size = info.size; @@ -861,7 +867,7 @@ std::vector UnswizzleImage(Tegra::MemoryManager& gpu_memory, GP info.tile_width_spacing); size_t guest_offset = 0; u32 host_offset = 0; - std::vector copies(num_levels); + boost::container::small_vector copies(num_levels); for (s32 level = 0; level < num_levels; ++level) { const Extent3D level_size = AdjustMipSize(size, level); @@ -978,7 +984,7 @@ void ConvertImage(std::span input, const ImageInfo& info, std::span FullDownloadCopies(const ImageInfo& info) { +boost::container::small_vector FullDownloadCopies(const ImageInfo& info) { const Extent3D size = info.size; const u32 bytes_per_block = BytesPerBlock(info.format); if (info.type == ImageType::Linear) { @@ -1006,7 +1012,7 @@ std::vector FullDownloadCopies(const ImageInfo& info) { u32 host_offset = 0; - std::vector copies(num_levels); + boost::container::small_vector copies(num_levels); for (s32 level = 0; level < num_levels; ++level) { const Extent3D level_size = AdjustMipSize(size, level); const u32 num_blocks_per_layer = NumBlocks(level_size, tile_size); @@ -1042,10 +1048,10 @@ Extent3D MipBlockSize(const ImageInfo& info, u32 level) { return AdjustMipBlockSize(num_tiles, level_info.block, level); } -std::vector FullUploadSwizzles(const ImageInfo& info) { +boost::container::small_vector FullUploadSwizzles(const ImageInfo& info) { const Extent2D tile_size = DefaultBlockSize(info.format); if (info.type == ImageType::Linear) { - return std::vector{SwizzleParameters{ + return {SwizzleParameters{ .num_tiles = AdjustTileSize(info.size, tile_size), .block = {}, .buffer_offset = 0, @@ -1057,7 +1063,7 @@ std::vector FullUploadSwizzles(const ImageInfo& info) { const s32 num_levels = info.resources.levels; u32 guest_offset = 0; - std::vector params(num_levels); + boost::container::small_vector params(num_levels); for (s32 level = 0; level < num_levels; ++level) { const Extent3D level_size = AdjustMipSize(size, level); const Extent3D num_tiles = AdjustTileSize(level_size, tile_size); diff --git a/src/video_core/texture_cache/util.h b/src/video_core/texture_cache/util.h index 84aa6880d..ab45a43c4 100644 --- a/src/video_core/texture_cache/util.h +++ b/src/video_core/texture_cache/util.h @@ -5,6 +5,7 @@ #include #include +#include #include "common/common_types.h" #include "common/scratch_buffer.h" @@ -40,9 +41,10 @@ struct OverlapResult { [[nodiscard]] LevelArray CalculateMipLevelSizes(const ImageInfo& info) noexcept; -[[nodiscard]] std::vector CalculateSliceOffsets(const ImageInfo& info); +[[nodiscard]] boost::container::small_vector CalculateSliceOffsets(const ImageInfo& info); -[[nodiscard]] std::vector CalculateSliceSubresources(const ImageInfo& info); +[[nodiscard]] boost::container::small_vector CalculateSliceSubresources( + const ImageInfo& info); [[nodiscard]] u32 CalculateLevelStrideAlignment(const ImageInfo& info, u32 level); @@ -51,21 +53,18 @@ struct OverlapResult { [[nodiscard]] ImageViewType RenderTargetImageViewType(const ImageInfo& info) noexcept; -[[nodiscard]] std::vector MakeShrinkImageCopies(const ImageInfo& dst, - const ImageInfo& src, - SubresourceBase base, u32 up_scale = 1, - u32 down_shift = 0); +[[nodiscard]] boost::container::small_vector MakeShrinkImageCopies( + const ImageInfo& dst, const ImageInfo& src, SubresourceBase base, u32 up_scale = 1, + u32 down_shift = 0); -[[nodiscard]] std::vector MakeReinterpretImageCopies(const ImageInfo& src, - u32 up_scale = 1, - u32 down_shift = 0); +[[nodiscard]] boost::container::small_vector MakeReinterpretImageCopies( + const ImageInfo& src, u32 up_scale = 1, u32 down_shift = 0); [[nodiscard]] bool IsValidEntry(const Tegra::MemoryManager& gpu_memory, const TICEntry& config); -[[nodiscard]] std::vector UnswizzleImage(Tegra::MemoryManager& gpu_memory, - GPUVAddr gpu_addr, const ImageInfo& info, - std::span input, - std::span output); +[[nodiscard]] boost::container::small_vector UnswizzleImage( + Tegra::MemoryManager& gpu_memory, GPUVAddr gpu_addr, const ImageInfo& info, + std::span input, std::span output); [[nodiscard]] BufferCopy UploadBufferCopy(Tegra::MemoryManager& gpu_memory, GPUVAddr gpu_addr, const ImageBase& image, std::span output); @@ -73,13 +72,15 @@ struct OverlapResult { void ConvertImage(std::span input, const ImageInfo& info, std::span output, std::span copies); -[[nodiscard]] std::vector FullDownloadCopies(const ImageInfo& info); +[[nodiscard]] boost::container::small_vector FullDownloadCopies( + const ImageInfo& info); [[nodiscard]] Extent3D MipSize(Extent3D size, u32 level); [[nodiscard]] Extent3D MipBlockSize(const ImageInfo& info, u32 level); -[[nodiscard]] std::vector FullUploadSwizzles(const ImageInfo& info); +[[nodiscard]] boost::container::small_vector FullUploadSwizzles( + const ImageInfo& info); void SwizzleImage(Tegra::MemoryManager& gpu_memory, GPUVAddr gpu_addr, const ImageInfo& info, std::span copies, std::span memory, diff --git a/src/video_core/transform_feedback.cpp b/src/video_core/transform_feedback.cpp index 155599316..1f353d2df 100644 --- a/src/video_core/transform_feedback.cpp +++ b/src/video_core/transform_feedback.cpp @@ -13,7 +13,7 @@ namespace VideoCommon { -std::vector MakeTransformFeedbackVaryings( +std::pair, u32> MakeTransformFeedbackVaryings( const TransformFeedbackState& state) { static constexpr std::array VECTORS{ 28U, // gl_Position @@ -62,7 +62,8 @@ std::vector MakeTransformFeedbackVaryings( 216U, // gl_TexCoord[6] 220U, // gl_TexCoord[7] }; - std::vector xfb(256); + std::array xfb{}; + u32 count{0}; for (size_t buffer = 0; buffer < state.layouts.size(); ++buffer) { const auto& locations = state.varyings[buffer]; const auto& layout = state.layouts[buffer]; @@ -103,11 +104,12 @@ std::vector MakeTransformFeedbackVaryings( } } xfb[attribute] = varying; + count = std::max(count, attribute); highest = std::max(highest, (base_offset + varying.components) * 4); } UNIMPLEMENTED_IF(highest != layout.stride); } - return xfb; + return {xfb, count + 1}; } } // namespace VideoCommon diff --git a/src/video_core/transform_feedback.h b/src/video_core/transform_feedback.h index d13eb16c3..401b1352a 100644 --- a/src/video_core/transform_feedback.h +++ b/src/video_core/transform_feedback.h @@ -24,7 +24,7 @@ struct TransformFeedbackState { varyings; }; -std::vector MakeTransformFeedbackVaryings( +std::pair, u32> MakeTransformFeedbackVaryings( const TransformFeedbackState& state); } // namespace VideoCommon diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index fa9cde75b..b11abe311 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -316,6 +316,7 @@ NvidiaArchitecture GetNvidiaArchitecture(vk::PhysicalDevice physical, std::vector ExtensionListForVulkan( const std::set>& extensions) { std::vector output; + output.reserve(extensions.size()); for (const auto& extension : extensions) { output.push_back(extension.c_str()); } -- cgit v1.2.3 From 1586f1c0b174bec6b1db7de48b46ff75e29f3bb2 Mon Sep 17 00:00:00 2001 From: Liam Date: Tue, 20 Jun 2023 11:41:38 -0400 Subject: general: remove atomic signal and wait --- src/common/thread.h | 2 +- src/core/hle/service/nvnflinger/nvnflinger.cpp | 14 ++++---------- src/core/hle/service/nvnflinger/nvnflinger.h | 3 ++- src/core/hle/service/server_manager.cpp | 7 ++----- src/core/hle/service/server_manager.h | 4 ++-- .../renderer_vulkan/vk_master_semaphore.cpp | 22 +++++++++------------- .../renderer_vulkan/vk_master_semaphore.h | 1 + src/yuzu/bootmanager.cpp | 6 ++---- src/yuzu/bootmanager.h | 7 +++---- 9 files changed, 26 insertions(+), 40 deletions(-) (limited to 'src') diff --git a/src/common/thread.h b/src/common/thread.h index 8ae169b4e..c6976fb6c 100644 --- a/src/common/thread.h +++ b/src/common/thread.h @@ -55,7 +55,7 @@ public: is_set = false; } - [[nodiscard]] bool IsSet() { + [[nodiscard]] bool IsSet() const { return is_set; } diff --git a/src/core/hle/service/nvnflinger/nvnflinger.cpp b/src/core/hle/service/nvnflinger/nvnflinger.cpp index b41c6240c..5f55cd31e 100644 --- a/src/core/hle/service/nvnflinger/nvnflinger.cpp +++ b/src/core/hle/service/nvnflinger/nvnflinger.cpp @@ -43,14 +43,10 @@ void Nvnflinger::SplitVSync(std::stop_token stop_token) { Common::SetCurrentThreadPriority(Common::ThreadPriority::High); while (!stop_token.stop_requested()) { - vsync_signal.wait(false); - vsync_signal.store(false); - - guard->lock(); + vsync_signal.Wait(); + const auto lock_guard = Lock(); Compose(); - - guard->unlock(); } } @@ -69,9 +65,8 @@ Nvnflinger::Nvnflinger(Core::System& system_, HosBinderDriverServer& hos_binder_ "ScreenComposition", [this](std::uintptr_t, s64 time, std::chrono::nanoseconds ns_late) -> std::optional { - vsync_signal.store(true); { const auto lock_guard = Lock(); } - vsync_signal.notify_one(); + vsync_signal.Set(); return std::chrono::nanoseconds(GetNextTicks()); }); @@ -97,8 +92,7 @@ Nvnflinger::~Nvnflinger() { if (system.IsMulticore()) { system.CoreTiming().UnscheduleEvent(multi_composition_event, {}); vsync_thread.request_stop(); - vsync_signal.store(true); - vsync_signal.notify_all(); + vsync_signal.Set(); } else { system.CoreTiming().UnscheduleEvent(single_composition_event, {}); } diff --git a/src/core/hle/service/nvnflinger/nvnflinger.h b/src/core/hle/service/nvnflinger/nvnflinger.h index a043cceb2..ef236303a 100644 --- a/src/core/hle/service/nvnflinger/nvnflinger.h +++ b/src/core/hle/service/nvnflinger/nvnflinger.h @@ -12,6 +12,7 @@ #include "common/common_types.h" #include "common/polyfill_thread.h" +#include "common/thread.h" #include "core/hle/result.h" #include "core/hle/service/kernel_helpers.h" @@ -143,7 +144,7 @@ private: Core::System& system; - std::atomic vsync_signal; + Common::Event vsync_signal; std::jthread vsync_thread; diff --git a/src/core/hle/service/server_manager.cpp b/src/core/hle/service/server_manager.cpp index 156bc27d8..d1e99b184 100644 --- a/src/core/hle/service/server_manager.cpp +++ b/src/core/hle/service/server_manager.cpp @@ -44,7 +44,7 @@ ServerManager::~ServerManager() { m_event->Signal(); // Wait for processing to stop. - m_stopped.wait(false); + m_stopped.Wait(); m_threads.clear(); // Clean up ports. @@ -182,10 +182,7 @@ void ServerManager::StartAdditionalHostThreads(const char* name, size_t num_thre } Result ServerManager::LoopProcess() { - SCOPE_EXIT({ - m_stopped.store(true); - m_stopped.notify_all(); - }); + SCOPE_EXIT({ m_stopped.Set(); }); R_RETURN(this->LoopProcessImpl()); } diff --git a/src/core/hle/service/server_manager.h b/src/core/hle/service/server_manager.h index fdb8af2ff..58b0a0832 100644 --- a/src/core/hle/service/server_manager.h +++ b/src/core/hle/service/server_manager.h @@ -3,7 +3,6 @@ #pragma once -#include #include #include #include @@ -12,6 +11,7 @@ #include #include "common/polyfill_thread.h" +#include "common/thread.h" #include "core/hle/result.h" #include "core/hle/service/mutex.h" @@ -82,7 +82,7 @@ private: std::list m_deferrals{}; // Host state tracking - std::atomic m_stopped{}; + Common::Event m_stopped{}; std::vector m_threads{}; std::stop_source m_stop_source{}; }; diff --git a/src/video_core/renderer_vulkan/vk_master_semaphore.cpp b/src/video_core/renderer_vulkan/vk_master_semaphore.cpp index 5eeda08d2..6b288b994 100644 --- a/src/video_core/renderer_vulkan/vk_master_semaphore.cpp +++ b/src/video_core/renderer_vulkan/vk_master_semaphore.cpp @@ -75,15 +75,9 @@ void MasterSemaphore::Refresh() { void MasterSemaphore::Wait(u64 tick) { if (!semaphore) { - // If we don't support timeline semaphores, use an atomic wait - while (true) { - u64 current_value = gpu_tick.load(std::memory_order_relaxed); - if (current_value >= tick) { - return; - } - gpu_tick.wait(current_value); - } - + // If we don't support timeline semaphores, wait for the value normally + std::unique_lock lk{free_mutex}; + free_cv.wait(lk, [&] { return gpu_tick.load(std::memory_order_relaxed) >= tick; }); return; } @@ -198,11 +192,13 @@ void MasterSemaphore::WaitThread(std::stop_token token) { fence.Wait(); fence.Reset(); - gpu_tick.store(host_tick); - gpu_tick.notify_all(); - std::scoped_lock lock{free_mutex}; - free_queue.push_front(std::move(fence)); + { + std::scoped_lock lock{free_mutex}; + free_queue.push_front(std::move(fence)); + gpu_tick.store(host_tick); + } + free_cv.notify_one(); } } diff --git a/src/video_core/renderer_vulkan/vk_master_semaphore.h b/src/video_core/renderer_vulkan/vk_master_semaphore.h index 1e7c90215..3f599d7bd 100644 --- a/src/video_core/renderer_vulkan/vk_master_semaphore.h +++ b/src/video_core/renderer_vulkan/vk_master_semaphore.h @@ -72,6 +72,7 @@ private: std::atomic current_tick{1}; ///< Current logical tick. std::mutex wait_mutex; std::mutex free_mutex; + std::condition_variable free_cv; std::condition_variable_any wait_cv; std::queue wait_queue; ///< Queue for the fences to be waited on by the wait thread. std::deque free_queue; ///< Holds available fences for submission. diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index cc6b6a25a..bdd1497b5 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -105,14 +105,12 @@ void EmuThread::run() { std::unique_lock lk{m_should_run_mutex}; if (m_should_run) { m_system.Run(); - m_is_running.store(true); - m_is_running.notify_all(); + m_stopped.Reset(); Common::CondvarWait(m_should_run_cv, lk, stop_token, [&] { return !m_should_run; }); } else { m_system.Pause(); - m_is_running.store(false); - m_is_running.notify_all(); + m_stopped.Set(); EmulationPaused(lk); Common::CondvarWait(m_should_run_cv, lk, stop_token, [&] { return m_should_run; }); diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index b7b9d4141..87b23df12 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h @@ -3,7 +3,6 @@ #pragma once -#include #include #include #include @@ -88,7 +87,7 @@ public: // Wait until paused, if pausing. if (!should_run) { - m_is_running.wait(true); + m_stopped.Wait(); } } @@ -97,7 +96,7 @@ public: * @return True if the emulation thread is running, otherwise false */ bool IsRunning() const { - return m_is_running.load() || m_should_run; + return m_should_run; } /** @@ -118,7 +117,7 @@ private: std::stop_source m_stop_source; std::mutex m_should_run_mutex; std::condition_variable_any m_should_run_cv; - std::atomic m_is_running{false}; + Common::Event m_stopped; bool m_should_run{true}; signals: -- cgit v1.2.3 From 75fb29e08e3891ecfc5d96d54603cda806ebd426 Mon Sep 17 00:00:00 2001 From: GPUCode Date: Thu, 22 Jun 2023 20:03:12 +0300 Subject: vulkan_common: Remove required flags * Allows VMA to fallback to system RAM instead of crashing --- src/video_core/vulkan_common/vulkan_memory_allocator.cpp | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) (limited to 'src') diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp index 20d36680c..70db41343 100644 --- a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp +++ b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp @@ -59,20 +59,6 @@ struct Range { return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; } -[[nodiscard]] VkMemoryPropertyFlags MemoryUsageRequiredVmaFlags(MemoryUsage usage) { - switch (usage) { - case MemoryUsage::DeviceLocal: - return VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - case MemoryUsage::Upload: - case MemoryUsage::Stream: - return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; - case MemoryUsage::Download: - return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT; - } - ASSERT_MSG(false, "Invalid memory usage={}", usage); - return {}; -} - [[nodiscard]] VkMemoryPropertyFlags MemoryUsagePreferedVmaFlags(MemoryUsage usage) { return usage != MemoryUsage::DeviceLocal ? VK_MEMORY_PROPERTY_HOST_COHERENT_BIT : VkMemoryPropertyFlagBits{}; @@ -259,7 +245,7 @@ vk::Buffer MemoryAllocator::CreateBuffer(const VkBufferCreateInfo& ci, MemoryUsa .flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT | MemoryUsageVmaFlags(usage), .usage = MemoryUsageVma(usage), - .requiredFlags = MemoryUsageRequiredVmaFlags(usage), + .requiredFlags = 0, .preferredFlags = MemoryUsagePreferedVmaFlags(usage), .memoryTypeBits = 0, .pool = VK_NULL_HANDLE, -- cgit v1.2.3 From c133509368f1054690a39a117e9d9ea34f187b8d Mon Sep 17 00:00:00 2001 From: GPUCode Date: Thu, 22 Jun 2023 20:17:52 +0300 Subject: android: Log settings --- src/android/app/src/main/jni/native.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp index 632aa50b3..f4fed0886 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp @@ -237,6 +237,7 @@ public: m_software_keyboard = android_keyboard.get(); m_system.SetShuttingDown(false); m_system.ApplySettings(); + Settings::LogSettings(); m_system.HIDCore().ReloadInputDevices(); m_system.SetAppletFrontendSet({ nullptr, // Amiibo Settings -- cgit v1.2.3 From 1dd166f76653bee7f7c2a0a89929ee9232680536 Mon Sep 17 00:00:00 2001 From: Liam Date: Thu, 22 Jun 2023 22:05:08 -0400 Subject: vfs_real: lock concurrent accesses --- src/core/file_sys/vfs_real.cpp | 55 +++++++++++++++++++++++++++--------------- src/core/file_sys/vfs_real.h | 15 +++++++----- 2 files changed, 45 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/core/file_sys/vfs_real.cpp b/src/core/file_sys/vfs_real.cpp index fcc81a664..b0515ec05 100644 --- a/src/core/file_sys/vfs_real.cpp +++ b/src/core/file_sys/vfs_real.cpp @@ -76,6 +76,7 @@ VfsEntryType RealVfsFilesystem::GetEntryType(std::string_view path_) const { VirtualFile RealVfsFilesystem::OpenFileFromEntry(std::string_view path_, std::optional size, Mode perms) { const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault); + std::scoped_lock lk{list_lock}; if (auto it = cache.find(path); it != cache.end()) { if (auto file = it->second.lock(); file) { @@ -88,7 +89,7 @@ VirtualFile RealVfsFilesystem::OpenFileFromEntry(std::string_view path_, std::op } auto reference = std::make_unique(); - this->InsertReferenceIntoList(*reference); + this->InsertReferenceIntoListLocked(*reference); auto file = std::shared_ptr( new RealVfsFile(*this, std::move(reference), path, perms, size)); @@ -103,7 +104,10 @@ VirtualFile RealVfsFilesystem::OpenFile(std::string_view path_, Mode perms) { VirtualFile RealVfsFilesystem::CreateFile(std::string_view path_, Mode perms) { const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault); - cache.erase(path); + { + std::scoped_lock lk{list_lock}; + cache.erase(path); + } // Current usages of CreateFile expect to delete the contents of an existing file. if (FS::IsFile(path)) { @@ -133,8 +137,11 @@ VirtualFile RealVfsFilesystem::CopyFile(std::string_view old_path_, std::string_ VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_view new_path_) { const auto old_path = FS::SanitizePath(old_path_, FS::DirectorySeparator::PlatformDefault); const auto new_path = FS::SanitizePath(new_path_, FS::DirectorySeparator::PlatformDefault); - cache.erase(old_path); - cache.erase(new_path); + { + std::scoped_lock lk{list_lock}; + cache.erase(old_path); + cache.erase(new_path); + } if (!FS::RenameFile(old_path, new_path)) { return nullptr; } @@ -143,7 +150,10 @@ VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_ bool RealVfsFilesystem::DeleteFile(std::string_view path_) { const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault); - cache.erase(path); + { + std::scoped_lock lk{list_lock}; + cache.erase(path); + } return FS::RemoveFile(path); } @@ -182,14 +192,17 @@ bool RealVfsFilesystem::DeleteDirectory(std::string_view path_) { return FS::RemoveDirRecursively(path); } -void RealVfsFilesystem::RefreshReference(const std::string& path, Mode perms, - FileReference& reference) { +std::unique_lock RealVfsFilesystem::RefreshReference(const std::string& path, + Mode perms, + FileReference& reference) { + std::unique_lock lk{list_lock}; + // Temporarily remove from list. - this->RemoveReferenceFromList(reference); + this->RemoveReferenceFromListLocked(reference); // Restore file if needed. if (!reference.file) { - this->EvictSingleReference(); + this->EvictSingleReferenceLocked(); reference.file = FS::FileOpen(path, ModeFlagsToFileAccessMode(perms), FS::FileType::BinaryFile); @@ -199,12 +212,16 @@ void RealVfsFilesystem::RefreshReference(const std::string& path, Mode perms, } // Reinsert into list. - this->InsertReferenceIntoList(reference); + this->InsertReferenceIntoListLocked(reference); + + return lk; } void RealVfsFilesystem::DropReference(std::unique_ptr&& reference) { + std::scoped_lock lk{list_lock}; + // Remove from list. - this->RemoveReferenceFromList(*reference); + this->RemoveReferenceFromListLocked(*reference); // Close the file. if (reference->file) { @@ -213,14 +230,14 @@ void RealVfsFilesystem::DropReference(std::unique_ptr&& reference } } -void RealVfsFilesystem::EvictSingleReference() { +void RealVfsFilesystem::EvictSingleReferenceLocked() { if (num_open_files < MaxOpenFiles || open_references.empty()) { return; } // Get and remove from list. auto& reference = open_references.back(); - this->RemoveReferenceFromList(reference); + this->RemoveReferenceFromListLocked(reference); // Close the file. if (reference.file) { @@ -229,10 +246,10 @@ void RealVfsFilesystem::EvictSingleReference() { } // Reinsert into closed list. - this->InsertReferenceIntoList(reference); + this->InsertReferenceIntoListLocked(reference); } -void RealVfsFilesystem::InsertReferenceIntoList(FileReference& reference) { +void RealVfsFilesystem::InsertReferenceIntoListLocked(FileReference& reference) { if (reference.file) { open_references.push_front(reference); } else { @@ -240,7 +257,7 @@ void RealVfsFilesystem::InsertReferenceIntoList(FileReference& reference) { } } -void RealVfsFilesystem::RemoveReferenceFromList(FileReference& reference) { +void RealVfsFilesystem::RemoveReferenceFromListLocked(FileReference& reference) { if (reference.file) { open_references.erase(open_references.iterator_to(reference)); } else { @@ -271,7 +288,7 @@ std::size_t RealVfsFile::GetSize() const { bool RealVfsFile::Resize(std::size_t new_size) { size.reset(); - base.RefreshReference(path, perms, *reference); + auto lk = base.RefreshReference(path, perms, *reference); return reference->file ? reference->file->SetSize(new_size) : false; } @@ -288,7 +305,7 @@ bool RealVfsFile::IsReadable() const { } std::size_t RealVfsFile::Read(u8* data, std::size_t length, std::size_t offset) const { - base.RefreshReference(path, perms, *reference); + auto lk = base.RefreshReference(path, perms, *reference); if (!reference->file || !reference->file->Seek(static_cast(offset))) { return 0; } @@ -297,7 +314,7 @@ std::size_t RealVfsFile::Read(u8* data, std::size_t length, std::size_t offset) std::size_t RealVfsFile::Write(const u8* data, std::size_t length, std::size_t offset) { size.reset(); - base.RefreshReference(path, perms, *reference); + auto lk = base.RefreshReference(path, perms, *reference); if (!reference->file || !reference->file->Seek(static_cast(offset))) { return 0; } diff --git a/src/core/file_sys/vfs_real.h b/src/core/file_sys/vfs_real.h index 67f4c4422..26ea7df62 100644 --- a/src/core/file_sys/vfs_real.h +++ b/src/core/file_sys/vfs_real.h @@ -4,6 +4,7 @@ #pragma once #include +#include #include #include #include "common/intrusive_list.h" @@ -48,22 +49,24 @@ private: std::map, std::less<>> cache; ReferenceListType open_references; ReferenceListType closed_references; + std::mutex list_lock; size_t num_open_files{}; private: friend class RealVfsFile; - void RefreshReference(const std::string& path, Mode perms, FileReference& reference); + std::unique_lock RefreshReference(const std::string& path, Mode perms, + FileReference& reference); void DropReference(std::unique_ptr&& reference); - void EvictSingleReference(); - -private: - void InsertReferenceIntoList(FileReference& reference); - void RemoveReferenceFromList(FileReference& reference); private: friend class RealVfsDirectory; VirtualFile OpenFileFromEntry(std::string_view path, std::optional size, Mode perms = Mode::Read); + +private: + void EvictSingleReferenceLocked(); + void InsertReferenceIntoListLocked(FileReference& reference); + void RemoveReferenceFromListLocked(FileReference& reference); }; // An implementation of VfsFile that represents a file on the user's computer. -- cgit v1.2.3 From a58a1403ba62f27f67ece97eadc0136834afbe29 Mon Sep 17 00:00:00 2001 From: Abandoned Cart Date: Fri, 23 Jun 2023 09:48:02 -0400 Subject: android: Parameter types from Android Studio Android Studio marked these parameters as errors because it is an instance, not a class, that is being passed from Java. --- src/android/app/src/main/jni/native.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp index d576aac50..5d6d61f68 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp @@ -528,23 +528,24 @@ static Core::SystemResultStatus RunEmulation(const std::string& filepath) { extern "C" { -void Java_org_yuzu_yuzu_1emu_NativeLibrary_surfaceChanged(JNIEnv* env, jclass clazz, jobject surf) { +void Java_org_yuzu_yuzu_1emu_NativeLibrary_surfaceChanged(JNIEnv* env, jobject instance, + jobject surf) { EmulationSession::GetInstance().SetNativeWindow(ANativeWindow_fromSurface(env, surf)); EmulationSession::GetInstance().SurfaceChanged(); } -void Java_org_yuzu_yuzu_1emu_NativeLibrary_surfaceDestroyed(JNIEnv* env, jclass clazz) { +void Java_org_yuzu_yuzu_1emu_NativeLibrary_surfaceDestroyed(JNIEnv* env, jobject instance) { ANativeWindow_release(EmulationSession::GetInstance().NativeWindow()); EmulationSession::GetInstance().SetNativeWindow(nullptr); EmulationSession::GetInstance().SurfaceChanged(); } -void Java_org_yuzu_yuzu_1emu_NativeLibrary_setAppDirectory(JNIEnv* env, jclass clazz, +void Java_org_yuzu_yuzu_1emu_NativeLibrary_setAppDirectory(JNIEnv* env, jobject instance, jstring j_directory) { Common::FS::SetAppDirectory(GetJString(env, j_directory)); } -int Java_org_yuzu_yuzu_1emu_NativeLibrary_installFileToNand(JNIEnv* env, jclass clazz, +int Java_org_yuzu_yuzu_1emu_NativeLibrary_installFileToNand(JNIEnv* env, jobject instance, jstring j_file) { return EmulationSession::GetInstance().InstallFileToNand(GetJString(env, j_file)); } -- cgit v1.2.3 From b53945a99f009076d6e48d368e5aa043ca04bf7b Mon Sep 17 00:00:00 2001 From: Abandoned Cart Date: Fri, 23 Jun 2023 12:43:27 -0400 Subject: android: define [[maybe_unused]] (const) auto --- src/android/app/src/main/jni/native.cpp | 84 +++++++++++++++++---------------- 1 file changed, 43 insertions(+), 41 deletions(-) (limited to 'src') diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp index 5d6d61f68..8bc6a4a04 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp @@ -60,6 +60,9 @@ #include "video_core/rasterizer_interface.h" #include "video_core/renderer_base.h" +#define jconst [[maybe_unused]] const auto +#define jauto [[maybe_unused]] auto + namespace { class EmulationSession final { @@ -99,8 +102,8 @@ public: } int InstallFileToNand(std::string filename) { - const auto copy_func = [](const FileSys::VirtualFile& src, const FileSys::VirtualFile& dest, - std::size_t block_size) { + jconst copy_func = [](const FileSys::VirtualFile& src, const FileSys::VirtualFile& dest, + std::size_t block_size) { if (src == nullptr || dest == nullptr) { return false; } @@ -109,10 +112,10 @@ public: } using namespace Common::Literals; - std::vector buffer(1_MiB); + [[maybe_unused]] std::vector buffer(1_MiB); for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) { - const auto read = src->Read(buffer.data(), buffer.size(), i); + jconst read = src->Read(buffer.data(), buffer.size(), i); dest->Write(buffer.data(), read, i); } return true; @@ -129,14 +132,14 @@ public: m_system.SetContentProvider(std::make_unique()); m_system.GetFileSystemController().CreateFactories(*m_vfs); - std::shared_ptr nsp; + [[maybe_unused]] std::shared_ptr nsp; if (filename.ends_with("nsp")) { nsp = std::make_shared(m_vfs->OpenFile(filename, FileSys::Mode::Read)); if (nsp->IsExtractedType()) { return InstallError; } } else if (filename.ends_with("xci")) { - const auto xci = + jconst xci = std::make_shared(m_vfs->OpenFile(filename, FileSys::Mode::Read)); nsp = xci->GetSecurePartitionNSP(); } else { @@ -151,7 +154,7 @@ public: return InstallError; } - const auto res = m_system.GetFileSystemController().GetUserNANDContents()->InstallEntry( + jconst res = m_system.GetFileSystemController().GetUserNANDContents()->InstallEntry( *nsp, true, copy_func); switch (res) { @@ -234,7 +237,7 @@ public: m_system.SetFilesystem(m_vfs); // Initialize system. - auto android_keyboard = std::make_unique(); + jauto android_keyboard = std::make_unique(); m_software_keyboard = android_keyboard.get(); m_system.SetShuttingDown(false); m_system.ApplySettings(); @@ -332,7 +335,7 @@ public: while (true) { { - std::unique_lock lock(m_mutex); + [[maybe_unused]] std::unique_lock lock(m_mutex); if (m_cv.wait_for(lock, std::chrono::milliseconds(800), [&]() { return !m_is_running; })) { // Emulation halted. @@ -364,7 +367,7 @@ public: } bool IsHandheldOnly() { - const auto npad_style_set = m_system.HIDCore().GetSupportedStyleTag(); + jconst npad_style_set = m_system.HIDCore().GetSupportedStyleTag(); if (npad_style_set.fullkey == 1) { return false; @@ -377,17 +380,17 @@ public: return !Settings::values.use_docked_mode.GetValue(); } - void SetDeviceType(int index, int type) { - auto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index); + void SetDeviceType([[maybe_unused]] int index, int type) { + jauto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index); controller->SetNpadStyleIndex(static_cast(type)); } - void OnGamepadConnectEvent(int index) { - auto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index); + void OnGamepadConnectEvent([[maybe_unused]] int index) { + jauto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index); // Ensure that player1 is configured correctly and handheld disconnected if (controller->GetNpadIdType() == Core::HID::NpadIdType::Player1) { - auto handheld = + jauto handheld = m_system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); if (controller->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::Handheld) { @@ -399,7 +402,8 @@ public: // Ensure that handheld is configured correctly and player 1 disconnected if (controller->GetNpadIdType() == Core::HID::NpadIdType::Handheld) { - auto player1 = m_system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); + jauto player1 = + m_system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); if (controller->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::Handheld) { player1->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld); @@ -413,8 +417,8 @@ public: } } - void OnGamepadDisconnectEvent(int index) { - auto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index); + void OnGamepadDisconnectEvent([[maybe_unused]] int index) { + jauto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index); controller->Disconnect(); } @@ -430,7 +434,7 @@ private: }; RomMetadata GetRomMetadata(const std::string& path) { - if (auto search = m_rom_metadata_cache.find(path); search != m_rom_metadata_cache.end()) { + if (jauto search = m_rom_metadata_cache.find(path); search != m_rom_metadata_cache.end()) { return search->second; } @@ -438,14 +442,14 @@ private: } RomMetadata CacheRomMetadata(const std::string& path) { - const auto file = Core::GetGameFileFromPath(m_vfs, path); - auto loader = Loader::GetLoader(EmulationSession::GetInstance().System(), file, 0, 0); + jconst file = Core::GetGameFileFromPath(m_vfs, path); + jauto loader = Loader::GetLoader(EmulationSession::GetInstance().System(), file, 0, 0); RomMetadata entry; loader->ReadTitle(entry.title); loader->ReadIcon(entry.icon); if (loader->GetFileType() == Loader::FileType::NRO) { - auto loader_nro = dynamic_cast(loader.get()); + jauto loader_nro = dynamic_cast(loader.get()); entry.isHomebrew = loader_nro->IsHomebrew(); } else { entry.isHomebrew = false; @@ -516,7 +520,7 @@ static Core::SystemResultStatus RunEmulation(const std::string& filepath) { SCOPE_EXIT({ EmulationSession::GetInstance().ShutdownEmulation(); }); - const auto result = EmulationSession::GetInstance().InitializeEmulation(filepath); + jconst result = EmulationSession::GetInstance().InitializeEmulation(filepath); if (result != Core::SystemResultStatus::Success) { return result; } @@ -529,7 +533,7 @@ static Core::SystemResultStatus RunEmulation(const std::string& filepath) { extern "C" { void Java_org_yuzu_yuzu_1emu_NativeLibrary_surfaceChanged(JNIEnv* env, jobject instance, - jobject surf) { + [[maybe_unused]] jobject surf) { EmulationSession::GetInstance().SetNativeWindow(ANativeWindow_fromSurface(env, surf)); EmulationSession::GetInstance().SurfaceChanged(); } @@ -541,12 +545,12 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_surfaceDestroyed(JNIEnv* env, jobject } void Java_org_yuzu_yuzu_1emu_NativeLibrary_setAppDirectory(JNIEnv* env, jobject instance, - jstring j_directory) { + [[maybe_unused]] jstring j_directory) { Common::FS::SetAppDirectory(GetJString(env, j_directory)); } int Java_org_yuzu_yuzu_1emu_NativeLibrary_installFileToNand(JNIEnv* env, jobject instance, - jstring j_file) { + [[maybe_unused]] jstring j_file) { return EmulationSession::GetInstance().InstallFileToNand(GetJString(env, j_file)); } @@ -571,7 +575,7 @@ void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeGpuDriver(JNIEnv* e } jboolean JNICALL Java_org_yuzu_yuzu_1emu_utils_GpuDriverHelper_supportsCustomDriverLoading( - JNIEnv* env, [[maybe_unused]] jobject instance) { + JNIEnv* env, jobject instance) { #ifdef ARCHITECTURE_arm64 // If the KGSL device exists custom drivers can be loaded using adrenotools return SupportsCustomDriver(); @@ -649,8 +653,8 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadDisconnectEvent(JNIEnv* return static_cast(true); } jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadButtonEvent(JNIEnv* env, jclass clazz, - [[maybe_unused]] jint j_device, - jint j_button, jint action) { + jint j_device, jint j_button, + jint action) { if (EmulationSession::GetInstance().IsRunning()) { // Ensure gamepad is connected EmulationSession::GetInstance().OnGamepadConnectEvent(j_device); @@ -719,8 +723,8 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchReleased(JNIEnv* env, jclass c } jbyteArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getIcon(JNIEnv* env, jclass clazz, - [[maybe_unused]] jstring j_filename) { - auto icon_data = EmulationSession::GetInstance().GetRomIcon(GetJString(env, j_filename)); + jstring j_filename) { + jauto icon_data = EmulationSession::GetInstance().GetRomIcon(GetJString(env, j_filename)); jbyteArray icon = env->NewByteArray(static_cast(icon_data.size())); env->SetByteArrayRegion(icon, 0, env->GetArrayLength(icon), reinterpret_cast(icon_data.data())); @@ -728,8 +732,8 @@ jbyteArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getIcon(JNIEnv* env, jclass cla } jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getTitle(JNIEnv* env, jclass clazz, - [[maybe_unused]] jstring j_filename) { - auto title = EmulationSession::GetInstance().GetRomTitle(GetJString(env, j_filename)); + jstring j_filename) { + jauto title = EmulationSession::GetInstance().GetRomTitle(GetJString(env, j_filename)); return env->NewStringUTF(title.c_str()); } @@ -744,22 +748,21 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getGameId(JNIEnv* env, jclass claz } jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getRegions(JNIEnv* env, jclass clazz, - [[maybe_unused]] jstring j_filename) { + jstring j_filename) { return env->NewStringUTF(""); } jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getCompany(JNIEnv* env, jclass clazz, - [[maybe_unused]] jstring j_filename) { + jstring j_filename) { return env->NewStringUTF(""); } jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isHomebrew(JNIEnv* env, jclass clazz, - [[maybe_unused]] jstring j_filename) { + jstring j_filename) { return EmulationSession::GetInstance().GetIsHomebrew(GetJString(env, j_filename)); } -void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeEmulation - [[maybe_unused]] (JNIEnv* env, jclass clazz) { +void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeEmulation(JNIEnv* env, jclass clazz) { // Create the default config.ini. Config{}; // Initialize the emulated system. @@ -771,8 +774,7 @@ jint Java_org_yuzu_yuzu_1emu_NativeLibrary_defaultCPUCore(JNIEnv* env, jclass cl } void Java_org_yuzu_yuzu_1emu_NativeLibrary_run__Ljava_lang_String_2Ljava_lang_String_2Z( - JNIEnv* env, jclass clazz, [[maybe_unused]] jstring j_file, - [[maybe_unused]] jstring j_savestate, [[maybe_unused]] jboolean j_delete_savestate) {} + JNIEnv* env, jclass clazz, jstring j_file, jstring j_savestate, jboolean j_delete_savestate) {} void Java_org_yuzu_yuzu_1emu_NativeLibrary_reloadSettings(JNIEnv* env, jclass clazz) { Config{}; @@ -817,7 +819,7 @@ jdoubleArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getPerfStats(JNIEnv* env, jcl jdoubleArray j_stats = env->NewDoubleArray(4); if (EmulationSession::GetInstance().IsRunning()) { - const auto results = EmulationSession::GetInstance().PerfStats(); + jconst results = EmulationSession::GetInstance().PerfStats(); // Converting the structure into an array makes it easier to pass it to the frontend double stats[4] = {results.system_fps, results.average_game_fps, results.frametime, -- cgit v1.2.3 From 482fbded9b2dd2d5dd0ac55d66d456d7ffefaaa2 Mon Sep 17 00:00:00 2001 From: zeltermann <136022354+zeltermann@users.noreply.github.com> Date: Fri, 9 Jun 2023 11:42:23 +0700 Subject: Only use SDL wakelock on Linux SDL has internally fixed shenanigans related to wakelocking through DBus from inside sandboxes from around August 2022, so we can now remove the workaround we used since 2021. --- src/input_common/drivers/sdl_driver.cpp | 4 +++ src/yuzu/main.cpp | 58 +++++---------------------------- src/yuzu/main.h | 2 -- 3 files changed, 12 insertions(+), 52 deletions(-) (limited to 'src') diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp index 9a0439bb5..ab64a64a2 100644 --- a/src/input_common/drivers/sdl_driver.cpp +++ b/src/input_common/drivers/sdl_driver.cpp @@ -483,6 +483,10 @@ void SDLDriver::CloseJoysticks() { } SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_engine_)) { + // Set our application name. Currently passed to DBus by SDL and visible to the user through + // their desktop environment. + SDL_SetHint(SDL_HINT_APP_NAME, "yuzu"); + if (!Settings::values.enable_raw_input) { // Disable raw input. When enabled this setting causes SDL to die when a web applet opens SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT, "0"); diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 45a39451d..2133f7343 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -447,6 +447,14 @@ GMainWindow::GMainWindow(std::unique_ptr config_, bool has_broken_vulkan #if defined(HAVE_SDL2) && !defined(_WIN32) SDL_InitSubSystem(SDL_INIT_VIDEO); + + // Set a screensaver inhibition reason string. Currently passed to DBus by SDL and visible to + // the user through their desktop environment. + //: TRANSLATORS: This string is shown to the user to explain why yuzu needs to prevent the + //: computer from sleeping + QByteArray wakelock_reason = tr("Running a game").toLatin1(); + SDL_SetHint(SDL_HINT_SCREENSAVER_INHIBIT_ACTIVITY_NAME, wakelock_reason.data()); + // SDL disables the screen saver by default, and setting the hint // SDL_HINT_VIDEO_ALLOW_SCREENSAVER doesn't seem to work, so we just enable the screen saver // for now. @@ -1623,45 +1631,6 @@ void GMainWindow::OnPrepareForSleep(bool prepare_sleep) { } #ifdef __unix__ -static std::optional HoldWakeLockLinux(u32 window_id = 0) { - if (!QDBusConnection::sessionBus().isConnected()) { - return {}; - } - // reference: https://flatpak.github.io/xdg-desktop-portal/#gdbus-org.freedesktop.portal.Inhibit - QDBusInterface xdp(QString::fromLatin1("org.freedesktop.portal.Desktop"), - QString::fromLatin1("/org/freedesktop/portal/desktop"), - QString::fromLatin1("org.freedesktop.portal.Inhibit")); - if (!xdp.isValid()) { - LOG_WARNING(Frontend, "Couldn't connect to XDP D-Bus endpoint"); - return {}; - } - QVariantMap options = {}; - //: TRANSLATORS: This string is shown to the user to explain why yuzu needs to prevent the - //: computer from sleeping - options.insert(QString::fromLatin1("reason"), - QCoreApplication::translate("GMainWindow", "yuzu is running a game")); - // 0x4: Suspend lock; 0x8: Idle lock - QDBusReply reply = - xdp.call(QString::fromLatin1("Inhibit"), - QString::fromLatin1("x11:") + QString::number(window_id, 16), 12U, options); - - if (reply.isValid()) { - return reply.value(); - } - LOG_WARNING(Frontend, "Couldn't read Inhibit reply from XDP: {}", - reply.error().message().toStdString()); - return {}; -} - -static void ReleaseWakeLockLinux(QDBusObjectPath lock) { - if (!QDBusConnection::sessionBus().isConnected()) { - return; - } - QDBusInterface unlocker(QString::fromLatin1("org.freedesktop.portal.Desktop"), lock.path(), - QString::fromLatin1("org.freedesktop.portal.Request")); - unlocker.call(QString::fromLatin1("Close")); -} - std::array GMainWindow::sig_interrupt_fds{0, 0, 0}; void GMainWindow::SetupSigInterrupts() { @@ -1714,12 +1683,6 @@ void GMainWindow::PreventOSSleep() { SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED); #elif defined(HAVE_SDL2) SDL_DisableScreenSaver(); -#ifdef __unix__ - auto reply = HoldWakeLockLinux(winId()); - if (reply) { - wake_lock = std::move(reply.value()); - } -#endif #endif } @@ -1728,11 +1691,6 @@ void GMainWindow::AllowOSSleep() { SetThreadExecutionState(ES_CONTINUOUS); #elif defined(HAVE_SDL2) SDL_EnableScreenSaver(); -#ifdef __unix__ - if (!wake_lock.path().isEmpty()) { - ReleaseWakeLockLinux(wake_lock); - } -#endif #endif } diff --git a/src/yuzu/main.h b/src/yuzu/main.h index e0e775d87..2cfb96257 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -504,8 +504,6 @@ private: #ifdef __unix__ QSocketNotifier* sig_interrupt_notifier; static std::array sig_interrupt_fds; - - QDBusObjectPath wake_lock{}; #endif protected: -- cgit v1.2.3 From 474fa13a1a4781b7a97d0f4ac379e2a3f76f4a06 Mon Sep 17 00:00:00 2001 From: german77 Date: Sat, 24 Jun 2023 14:06:34 -0600 Subject: input_common: Make use of new SDL features --- src/input_common/drivers/sdl_driver.cpp | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp index 9a0439bb5..3cc639ba7 100644 --- a/src/input_common/drivers/sdl_driver.cpp +++ b/src/input_common/drivers/sdl_driver.cpp @@ -150,6 +150,8 @@ public: if (sdl_controller) { const auto type = SDL_GameControllerGetType(sdl_controller.get()); return (type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO) || + (type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT) || + (type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT) || (type == SDL_CONTROLLER_TYPE_PS5); } return false; @@ -228,9 +230,8 @@ public: return false; } - Common::Input::BatteryLevel GetBatteryLevel() { - const auto level = SDL_JoystickCurrentPowerLevel(sdl_joystick.get()); - switch (level) { + Common::Input::BatteryLevel GetBatteryLevel(SDL_JoystickPowerLevel battery_level) { + switch (battery_level) { case SDL_JOYSTICK_POWER_EMPTY: return Common::Input::BatteryLevel::Empty; case SDL_JOYSTICK_POWER_LOW: @@ -378,7 +379,6 @@ void SDLDriver::InitJoystick(int joystick_index) { if (joystick_map.find(guid) == joystick_map.end()) { auto joystick = std::make_shared(guid, 0, sdl_joystick, sdl_gamecontroller); PreSetController(joystick->GetPadIdentifier()); - SetBattery(joystick->GetPadIdentifier(), joystick->GetBatteryLevel()); joystick->EnableMotion(); joystick_map[guid].emplace_back(std::move(joystick)); return; @@ -398,7 +398,6 @@ void SDLDriver::InitJoystick(int joystick_index) { const int port = static_cast(joystick_guid_list.size()); auto joystick = std::make_shared(guid, port, sdl_joystick, sdl_gamecontroller); PreSetController(joystick->GetPadIdentifier()); - SetBattery(joystick->GetPadIdentifier(), joystick->GetBatteryLevel()); joystick->EnableMotion(); joystick_guid_list.emplace_back(std::move(joystick)); } @@ -438,8 +437,6 @@ void SDLDriver::HandleGameControllerEvent(const SDL_Event& event) { if (const auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) { const PadIdentifier identifier = joystick->GetPadIdentifier(); SetButton(identifier, event.jbutton.button, true); - // Battery doesn't trigger an event so just update every button press - SetBattery(identifier, joystick->GetBatteryLevel()); } break; } @@ -466,6 +463,13 @@ void SDLDriver::HandleGameControllerEvent(const SDL_Event& event) { } break; } + case SDL_JOYBATTERYUPDATED: { + if (auto joystick = GetSDLJoystickBySDLID(event.jbattery.which)) { + const PadIdentifier identifier = joystick->GetPadIdentifier(); + SetBattery(identifier, joystick->GetBatteryLevel(event.jbattery.level)); + } + break; + } case SDL_JOYDEVICEREMOVED: LOG_DEBUG(Input, "Controller removed with Instance_ID {}", event.jdevice.which); CloseJoystick(SDL_JoystickFromInstanceID(event.jdevice.which)); @@ -501,6 +505,9 @@ SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_en SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "0"); } else { SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "1"); + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOYCON_HOME_LED, "0"); + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_COMBINE_JOY_CONS, "0"); + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_VERTICAL_JOY_CONS, "1"); } // Disable hidapi drivers for pro controllers when the custom joycon driver is enabled @@ -508,8 +515,11 @@ SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_en SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH, "0"); } else { SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH, "1"); + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH_HOME_LED, "0"); } + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH_PLAYER_LED, "1"); + // Disable hidapi driver for xbox. Already default on Windows, this causes conflict with native // driver on Linux. SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_XBOX, "0"); @@ -789,7 +799,9 @@ ButtonMapping SDLDriver::GetButtonMappingForDevice(const Common::ParamPackage& p // This list also excludes Screenshot since there's not really a mapping for that ButtonBindings switch_to_sdl_button; - if (SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO) { + if (SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO || + SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT || + SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT) { switch_to_sdl_button = GetNintendoButtonBinding(joystick); } else { switch_to_sdl_button = GetDefaultButtonBinding(); -- cgit v1.2.3 From 5aa208e26417a455abced9c067f75e1b81f2cb80 Mon Sep 17 00:00:00 2001 From: german77 Date: Sat, 24 Jun 2023 18:48:45 -0600 Subject: input_common: Dont try to read/write data from 3rd party controllers --- src/core/hid/emulated_controller.cpp | 5 +++ src/input_common/helpers/joycon_driver.cpp | 42 +++++++++++++++++----- src/input_common/helpers/joycon_driver.h | 1 + .../helpers/joycon_protocol/common_protocol.cpp | 8 ++--- 4 files changed, 42 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index c937495f9..190f7c906 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -1250,6 +1250,11 @@ Common::Input::DriverResult EmulatedController::SetPollingMode( const auto virtual_nfc_result = nfc_output_device->SetPollingMode(polling_mode); const auto mapped_nfc_result = right_output_device->SetPollingMode(polling_mode); + // Restore previous state + if (mapped_nfc_result != Common::Input::DriverResult::Success) { + right_output_device->SetPollingMode(Common::Input::PollingMode::Active); + } + if (virtual_nfc_result == Common::Input::DriverResult::Success) { return virtual_nfc_result; } diff --git a/src/input_common/helpers/joycon_driver.cpp b/src/input_common/helpers/joycon_driver.cpp index 2c8c66951..ec984a647 100644 --- a/src/input_common/helpers/joycon_driver.cpp +++ b/src/input_common/helpers/joycon_driver.cpp @@ -72,6 +72,7 @@ DriverResult JoyconDriver::InitializeDevice() { nfc_enabled = false; passive_enabled = false; irs_enabled = false; + input_only_device = false; gyro_sensitivity = Joycon::GyroSensitivity::DPS2000; gyro_performance = Joycon::GyroPerformance::HZ833; accelerometer_sensitivity = Joycon::AccelerometerSensitivity::G8; @@ -86,16 +87,23 @@ DriverResult JoyconDriver::InitializeDevice() { rumble_protocol = std::make_unique(hidapi_handle); // Get fixed joycon info - generic_protocol->GetVersionNumber(version); - generic_protocol->SetLowPowerMode(false); - generic_protocol->GetColor(color); - if (handle_device_type == ControllerType::Pro) { - // Some 3rd party controllers aren't pro controllers - generic_protocol->GetControllerType(device_type); - } else { - device_type = handle_device_type; + if (generic_protocol->GetVersionNumber(version) != DriverResult::Success) { + // If this command fails the device doesn't accept configuration commands + input_only_device = true; } - generic_protocol->GetSerialNumber(serial_number); + + if (!input_only_device) { + generic_protocol->SetLowPowerMode(false); + generic_protocol->GetColor(color); + if (handle_device_type == ControllerType::Pro) { + // Some 3rd party controllers aren't pro controllers + generic_protocol->GetControllerType(device_type); + } else { + device_type = handle_device_type; + } + generic_protocol->GetSerialNumber(serial_number); + } + supported_features = GetSupportedFeatures(); // Get Calibration data @@ -261,6 +269,10 @@ DriverResult JoyconDriver::SetPollingMode() { generic_protocol->EnableImu(false); } + if (input_only_device) { + return DriverResult::NotSupported; + } + if (irs_protocol->IsEnabled()) { irs_protocol->DisableIrs(); } @@ -282,6 +294,7 @@ DriverResult JoyconDriver::SetPollingMode() { } irs_protocol->DisableIrs(); LOG_ERROR(Input, "Error enabling IRS"); + return result; } if (nfc_enabled && supported_features.nfc) { @@ -291,6 +304,7 @@ DriverResult JoyconDriver::SetPollingMode() { } nfc_protocol->DisableNfc(); LOG_ERROR(Input, "Error enabling NFC"); + return result; } if (hidbus_enabled && supported_features.hidbus) { @@ -305,6 +319,7 @@ DriverResult JoyconDriver::SetPollingMode() { ring_connected = false; ring_protocol->DisableRingCon(); LOG_ERROR(Input, "Error enabling Ringcon"); + return result; } if (passive_enabled && supported_features.passive) { @@ -333,6 +348,10 @@ JoyconDriver::SupportedFeatures JoyconDriver::GetSupportedFeatures() { .vibration = true, }; + if (input_only_device) { + return features; + } + if (device_type == ControllerType::Right) { features.nfc = true; features.irs = true; @@ -517,6 +536,11 @@ DriverResult JoyconDriver::StopNfcPolling() { const auto result = nfc_protocol->StopNFCPollingMode(); disable_input_thread = false; + if (amiibo_detected) { + amiibo_detected = false; + joycon_poller->UpdateAmiibo({}); + } + return result; } diff --git a/src/input_common/helpers/joycon_driver.h b/src/input_common/helpers/joycon_driver.h index bc7025a21..45b32d2f8 100644 --- a/src/input_common/helpers/joycon_driver.h +++ b/src/input_common/helpers/joycon_driver.h @@ -120,6 +120,7 @@ private: // Hardware configuration u8 leds{}; ReportMode mode{}; + bool input_only_device{}; bool passive_enabled{}; // Low power mode, Ideal for multiple controllers at the same time bool hidbus_enabled{}; // External device support bool irs_enabled{}; // Infrared camera input diff --git a/src/input_common/helpers/joycon_protocol/common_protocol.cpp b/src/input_common/helpers/joycon_protocol/common_protocol.cpp index 51669261a..88f4cec1c 100644 --- a/src/input_common/helpers/joycon_protocol/common_protocol.cpp +++ b/src/input_common/helpers/joycon_protocol/common_protocol.cpp @@ -73,7 +73,7 @@ DriverResult JoyconCommonProtocol::SendRawData(std::span buffer) { DriverResult JoyconCommonProtocol::GetSubCommandResponse(SubCommand sc, SubCommandResponse& output) { constexpr int timeout_mili = 66; - constexpr int MaxTries = 15; + constexpr int MaxTries = 3; int tries = 0; do { @@ -113,9 +113,7 @@ DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span buffer) { @@ -158,7 +156,7 @@ DriverResult JoyconCommonProtocol::SendVibrationReport(std::span buffe DriverResult JoyconCommonProtocol::ReadRawSPI(SpiAddress addr, std::span output) { constexpr std::size_t HeaderSize = 5; - constexpr std::size_t MaxTries = 10; + constexpr std::size_t MaxTries = 5; std::size_t tries = 0; SubCommandResponse response{}; std::array buffer{}; -- cgit v1.2.3 From bf641e2964d513e9b9e3495c7d68d1c18c5b806e Mon Sep 17 00:00:00 2001 From: german77 Date: Sat, 24 Jun 2023 18:59:40 -0600 Subject: core: hid: Allow to read bin files while switch controller is available --- src/core/hid/emulated_controller.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 190f7c906..1ebc32c1e 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -1334,16 +1334,22 @@ bool EmulatedController::StartNfcPolling() { auto& nfc_output_device = output_devices[static_cast(DeviceIndex::Right)]; auto& nfc_virtual_output_device = output_devices[3]; - return nfc_output_device->StartNfcPolling() == Common::Input::NfcState::Success || - nfc_virtual_output_device->StartNfcPolling() == Common::Input::NfcState::Success; + const auto device_result = nfc_output_device->StartNfcPolling(); + const auto virtual_device_result = nfc_virtual_output_device->StartNfcPolling(); + + return device_result == Common::Input::NfcState::Success || + virtual_device_result == Common::Input::NfcState::Success; } bool EmulatedController::StopNfcPolling() { auto& nfc_output_device = output_devices[static_cast(DeviceIndex::Right)]; auto& nfc_virtual_output_device = output_devices[3]; - return nfc_output_device->StopNfcPolling() == Common::Input::NfcState::Success || - nfc_virtual_output_device->StopNfcPolling() == Common::Input::NfcState::Success; + const auto device_result = nfc_output_device->StopNfcPolling(); + const auto virtual_device_result = nfc_virtual_output_device->StopNfcPolling(); + + return device_result == Common::Input::NfcState::Success || + virtual_device_result == Common::Input::NfcState::Success; } bool EmulatedController::ReadAmiiboData(std::vector& data) { -- cgit v1.2.3 From b6025cf62f895dba08530eb7d832cec3c89a9e51 Mon Sep 17 00:00:00 2001 From: Kirill Ignatev Date: Sun, 25 Jun 2023 11:52:15 -0400 Subject: Clarify Ring-Con configuration message in UI Not obvious how left controller should be set up Mention that it should be left physical dual emulated --- src/yuzu/configuration/configure_ringcon.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/yuzu/configuration/configure_ringcon.ui b/src/yuzu/configuration/configure_ringcon.ui index 514dff372..0c50b9258 100644 --- a/src/yuzu/configuration/configure_ringcon.ui +++ b/src/yuzu/configuration/configure_ringcon.ui @@ -23,7 +23,7 @@ - If you want to use this controller configure player 1 as right controller and player 2 as dual joycon before starting the game to allow this controller to be detected properly. + To use Ring-Con configure player 1 as right JoyCon both physical and emulated, and player 2 as left JoyCon physical and dual (!) JoyCon emulated before starting the game. true -- cgit v1.2.3 From b6e89bdf2c871d2d793c78781babe4f0c0636514 Mon Sep 17 00:00:00 2001 From: Kirill Ignatev Date: Sun, 25 Jun 2023 12:51:16 -0400 Subject: Hyphenate Joy-Con and clarify further --- src/yuzu/configuration/configure_ringcon.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/yuzu/configuration/configure_ringcon.ui b/src/yuzu/configuration/configure_ringcon.ui index 0c50b9258..38ecccc3d 100644 --- a/src/yuzu/configuration/configure_ringcon.ui +++ b/src/yuzu/configuration/configure_ringcon.ui @@ -23,7 +23,7 @@ - To use Ring-Con configure player 1 as right JoyCon both physical and emulated, and player 2 as left JoyCon physical and dual (!) JoyCon emulated before starting the game. + To use Ring-Con, configure player 1 as right Joy-Con (both physical and emulated), and player 2 as left Joy-Con (left physical and dual emulated) before starting the game. true -- cgit v1.2.3 From 82107b33a2251eb4f55ab2006a8fc0cb47cc39e8 Mon Sep 17 00:00:00 2001 From: ameerj <52414509+ameerj@users.noreply.github.com> Date: Sun, 25 Jun 2023 18:43:23 -0400 Subject: OpenGL: Add Local Memory warmup shader --- src/video_core/host_shaders/CMakeLists.txt | 1 + .../host_shaders/opengl_lmem_warmup.comp | 47 ++++++++++++++++++++++ src/video_core/renderer_opengl/gl_rasterizer.cpp | 2 + .../renderer_opengl/gl_shader_manager.cpp | 10 ++++- src/video_core/renderer_opengl/gl_shader_manager.h | 3 ++ 5 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 src/video_core/host_shaders/opengl_lmem_warmup.comp (limited to 'src') diff --git a/src/video_core/host_shaders/CMakeLists.txt b/src/video_core/host_shaders/CMakeLists.txt index 2442c3c29..e61d9af80 100644 --- a/src/video_core/host_shaders/CMakeLists.txt +++ b/src/video_core/host_shaders/CMakeLists.txt @@ -33,6 +33,7 @@ set(SHADER_FILES opengl_fidelityfx_fsr.frag opengl_fidelityfx_fsr_easu.frag opengl_fidelityfx_fsr_rcas.frag + opengl_lmem_warmup.comp opengl_present.frag opengl_present.vert opengl_present_scaleforce.frag diff --git a/src/video_core/host_shaders/opengl_lmem_warmup.comp b/src/video_core/host_shaders/opengl_lmem_warmup.comp new file mode 100644 index 000000000..518268477 --- /dev/null +++ b/src/video_core/host_shaders/opengl_lmem_warmup.comp @@ -0,0 +1,47 @@ +// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +// This shader is a workaround for a quirk in NVIDIA OpenGL drivers +// Shaders using local memory see a great performance benefit if a shader that was dispatched +// before it had more local memory allocated. +// This shader allocates the maximum local memory allowed on NVIDIA drivers to ensure that +// subsequent shaders see the performance boost. + +// NOTE: This shader does no actual meaningful work and returns immediately, +// it is simply a means to have the driver expect a shader using lots of local memory. + +#version 450 + +layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; + +layout(location = 0) uniform uint uniform_data; + +layout(binding = 0, rgba8) uniform writeonly restrict image2DArray dest_image; + +#define MAX_LMEM_SIZE 4080 // Size chosen to avoid errors in Nvidia's GLSL compiler +#define NUM_LMEM_CONSTANTS 1 +#define ARRAY_SIZE MAX_LMEM_SIZE - NUM_LMEM_CONSTANTS + +uint lmem_0[ARRAY_SIZE]; +const uvec4 constant_values[NUM_LMEM_CONSTANTS] = uvec4[](uvec4(0)); + +void main() { + const uint global_id = gl_GlobalInvocationID.x; + if (global_id <= 128) { + // Since the shader is called with a dispatch of 1x1x1 + // This should always be the case, and this shader will not actually execute + return; + } + for (uint t = 0; t < uniform_data; t++) { + const uint offset = (t * uniform_data); + lmem_0[offset] = t; + } + const uint offset = (gl_GlobalInvocationID.y * uniform_data + gl_GlobalInvocationID.x); + const uint value = lmem_0[offset]; + const uint const_value = constant_values[offset / 4][offset % 4]; + const uvec4 color = uvec4(value + const_value); + + // A "side-effect" is needed so the variables don't get optimized out, + // but this should never execute so there should be no clobbering of previously bound state. + imageStore(dest_image, ivec3(gl_GlobalInvocationID), color); +} diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index fc711c44a..d03288516 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -222,6 +222,7 @@ void RasterizerOpenGL::PrepareDraw(bool is_indexed, Func&& draw_func) { gpu.TickWork(); std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex}; + program_manager.LocalMemoryWarmup(); pipeline->SetEngine(maxwell3d, gpu_memory); pipeline->Configure(is_indexed); @@ -371,6 +372,7 @@ void RasterizerOpenGL::DispatchCompute() { if (!pipeline) { return; } + program_manager.LocalMemoryWarmup(); pipeline->SetEngine(kepler_compute, gpu_memory); pipeline->Configure(); const auto& qmd{kepler_compute->launch_description}; diff --git a/src/video_core/renderer_opengl/gl_shader_manager.cpp b/src/video_core/renderer_opengl/gl_shader_manager.cpp index 98841ae65..2f6ba6823 100644 --- a/src/video_core/renderer_opengl/gl_shader_manager.cpp +++ b/src/video_core/renderer_opengl/gl_shader_manager.cpp @@ -3,7 +3,9 @@ #include +#include "video_core/host_shaders/opengl_lmem_warmup_comp.h" #include "video_core/renderer_opengl/gl_shader_manager.h" +#include "video_core/renderer_opengl/gl_shader_util.h" namespace OpenGL { @@ -12,7 +14,8 @@ static constexpr std::array ASSEMBLY_PROGRAM_ENUMS{ GL_GEOMETRY_PROGRAM_NV, GL_FRAGMENT_PROGRAM_NV, }; -ProgramManager::ProgramManager(const Device& device) { +ProgramManager::ProgramManager(const Device& device) + : lmem_warmup_program(CreateProgram(HostShaders::OPENGL_LMEM_WARMUP_COMP, GL_COMPUTE_SHADER)) { glCreateProgramPipelines(1, &pipeline.handle); if (device.UseAssemblyShaders()) { glEnable(GL_COMPUTE_PROGRAM_NV); @@ -98,6 +101,11 @@ void ProgramManager::BindAssemblyPrograms(std::span current_programs{}; GLuint current_assembly_compute_program = 0; + OGLProgram lmem_warmup_program; }; } // namespace OpenGL -- cgit v1.2.3 From b198339580f1a54c4c670eb58593eb64e2ef945c Mon Sep 17 00:00:00 2001 From: ameerj <52414509+ameerj@users.noreply.github.com> Date: Sun, 25 Jun 2023 18:43:52 -0400 Subject: emit_glasm: Fix lmem size computation --- src/shader_recompiler/backend/glasm/emit_glasm.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/shader_recompiler/backend/glasm/emit_glasm.cpp b/src/shader_recompiler/backend/glasm/emit_glasm.cpp index fd4a61a4d..b795c0179 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm.cpp @@ -461,7 +461,7 @@ std::string EmitGLASM(const Profile& profile, const RuntimeInfo& runtime_info, I header += fmt::format("R{},", index); } if (program.local_memory_size > 0) { - header += fmt::format("lmem[{}],", program.local_memory_size); + header += fmt::format("lmem[{}],", Common::DivCeil(program.local_memory_size, 4U)); } if (program.info.uses_fswzadd) { header += "FSWZA[4],FSWZB[4],"; -- cgit v1.2.3 From 405eae3734dd6bfb259df0afceecf4de1f1262ce Mon Sep 17 00:00:00 2001 From: ameerj <52414509+ameerj@users.noreply.github.com> Date: Sun, 25 Jun 2023 18:59:33 -0400 Subject: shaders: Track local memory usage --- src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp | 4 ++++ src/shader_recompiler/shader_info.h | 1 + src/video_core/renderer_opengl/gl_compute_pipeline.cpp | 1 + src/video_core/renderer_opengl/gl_compute_pipeline.h | 5 +++++ src/video_core/renderer_opengl/gl_graphics_pipeline.cpp | 1 + src/video_core/renderer_opengl/gl_graphics_pipeline.h | 5 +++++ src/video_core/renderer_opengl/gl_rasterizer.cpp | 8 ++++++-- 7 files changed, 23 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp index 5a4195217..70292686f 100644 --- a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp +++ b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp @@ -424,6 +424,10 @@ void VisitUsages(Info& info, IR::Inst& inst) { info.used_constant_buffer_types |= IR::Type::U32 | IR::Type::U32x2; info.used_storage_buffer_types |= IR::Type::U32 | IR::Type::U32x2 | IR::Type::U32x4; break; + case IR::Opcode::LoadLocal: + case IR::Opcode::WriteLocal: + info.uses_local_memory = true; + break; default: break; } diff --git a/src/shader_recompiler/shader_info.h b/src/shader_recompiler/shader_info.h index d308db942..b4b4afd37 100644 --- a/src/shader_recompiler/shader_info.h +++ b/src/shader_recompiler/shader_info.h @@ -172,6 +172,7 @@ struct Info { bool stores_indexed_attributes{}; bool stores_global_memory{}; + bool uses_local_memory{}; bool uses_fp16{}; bool uses_fp64{}; diff --git a/src/video_core/renderer_opengl/gl_compute_pipeline.cpp b/src/video_core/renderer_opengl/gl_compute_pipeline.cpp index 3151c0db8..f9ca55c36 100644 --- a/src/video_core/renderer_opengl/gl_compute_pipeline.cpp +++ b/src/video_core/renderer_opengl/gl_compute_pipeline.cpp @@ -63,6 +63,7 @@ ComputePipeline::ComputePipeline(const Device& device, TextureCache& texture_cac writes_global_memory = !use_storage_buffers && std::ranges::any_of(info.storage_buffers_descriptors, [](const auto& desc) { return desc.is_written; }); + uses_local_memory = info.uses_local_memory; if (force_context_flush) { std::scoped_lock lock{built_mutex}; built_fence.Create(); diff --git a/src/video_core/renderer_opengl/gl_compute_pipeline.h b/src/video_core/renderer_opengl/gl_compute_pipeline.h index 9bcc72b59..c26b4fa5e 100644 --- a/src/video_core/renderer_opengl/gl_compute_pipeline.h +++ b/src/video_core/renderer_opengl/gl_compute_pipeline.h @@ -59,6 +59,10 @@ public: return writes_global_memory; } + [[nodiscard]] bool UsesLocalMemory() const noexcept { + return uses_local_memory; + } + void SetEngine(Tegra::Engines::KeplerCompute* kepler_compute_, Tegra::MemoryManager* gpu_memory_) { kepler_compute = kepler_compute_; @@ -84,6 +88,7 @@ private: bool use_storage_buffers{}; bool writes_global_memory{}; + bool uses_local_memory{}; std::mutex built_mutex; std::condition_variable built_condvar; diff --git a/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp b/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp index c58f760b8..23a48c6fe 100644 --- a/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp +++ b/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp @@ -215,6 +215,7 @@ GraphicsPipeline::GraphicsPipeline(const Device& device, TextureCache& texture_c writes_global_memory |= std::ranges::any_of( info.storage_buffers_descriptors, [](const auto& desc) { return desc.is_written; }); + uses_local_memory |= info.uses_local_memory; } ASSERT(num_textures <= MAX_TEXTURES); ASSERT(num_images <= MAX_IMAGES); diff --git a/src/video_core/renderer_opengl/gl_graphics_pipeline.h b/src/video_core/renderer_opengl/gl_graphics_pipeline.h index 7bab3be0a..7b3d7eae8 100644 --- a/src/video_core/renderer_opengl/gl_graphics_pipeline.h +++ b/src/video_core/renderer_opengl/gl_graphics_pipeline.h @@ -98,6 +98,10 @@ public: return writes_global_memory; } + [[nodiscard]] bool UsesLocalMemory() const noexcept { + return uses_local_memory; + } + [[nodiscard]] bool IsBuilt() noexcept; template @@ -146,6 +150,7 @@ private: bool use_storage_buffers{}; bool writes_global_memory{}; + bool uses_local_memory{}; static constexpr std::size_t XFB_ENTRY_STRIDE = 3; GLsizei num_xfb_attribs{}; diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index d03288516..edf527f2d 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -222,7 +222,9 @@ void RasterizerOpenGL::PrepareDraw(bool is_indexed, Func&& draw_func) { gpu.TickWork(); std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex}; - program_manager.LocalMemoryWarmup(); + if (pipeline->UsesLocalMemory()) { + program_manager.LocalMemoryWarmup(); + } pipeline->SetEngine(maxwell3d, gpu_memory); pipeline->Configure(is_indexed); @@ -372,7 +374,9 @@ void RasterizerOpenGL::DispatchCompute() { if (!pipeline) { return; } - program_manager.LocalMemoryWarmup(); + if (pipeline->UsesLocalMemory()) { + program_manager.LocalMemoryWarmup(); + } pipeline->SetEngine(kepler_compute, gpu_memory); pipeline->Configure(); const auto& qmd{kepler_compute->launch_description}; -- cgit v1.2.3 From 4f160633d369b702a45ace9b6ff133312761c5f8 Mon Sep 17 00:00:00 2001 From: ameerj <52414509+ameerj@users.noreply.github.com> Date: Sun, 25 Jun 2023 19:06:51 -0400 Subject: OpenGL: Limit lmem warmup to NVIDIA :frog: --- src/video_core/renderer_opengl/gl_device.cpp | 1 + src/video_core/renderer_opengl/gl_device.h | 5 +++++ src/video_core/renderer_opengl/gl_shader_manager.cpp | 13 +++++++++---- 3 files changed, 15 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/video_core/renderer_opengl/gl_device.cpp b/src/video_core/renderer_opengl/gl_device.cpp index 03d234f2f..33e63c17d 100644 --- a/src/video_core/renderer_opengl/gl_device.cpp +++ b/src/video_core/renderer_opengl/gl_device.cpp @@ -194,6 +194,7 @@ Device::Device(Core::Frontend::EmuWindow& emu_window) { has_bool_ref_bug = true; } } + has_lmem_perf_bug = is_nvidia; strict_context_required = emu_window.StrictContextRequired(); // Blocks AMD and Intel OpenGL drivers on Windows from using asynchronous shader compilation. diff --git a/src/video_core/renderer_opengl/gl_device.h b/src/video_core/renderer_opengl/gl_device.h index ad27264e5..a5a6bbbba 100644 --- a/src/video_core/renderer_opengl/gl_device.h +++ b/src/video_core/renderer_opengl/gl_device.h @@ -192,6 +192,10 @@ public: return supports_conditional_barriers; } + bool HasLmemPerfBug() const { + return has_lmem_perf_bug; + } + private: static bool TestVariableAoffi(); static bool TestPreciseBug(); @@ -238,6 +242,7 @@ private: bool can_report_memory{}; bool strict_context_required{}; bool supports_conditional_barriers{}; + bool has_lmem_perf_bug{}; std::string vendor_name; }; diff --git a/src/video_core/renderer_opengl/gl_shader_manager.cpp b/src/video_core/renderer_opengl/gl_shader_manager.cpp index 2f6ba6823..03d4b9d06 100644 --- a/src/video_core/renderer_opengl/gl_shader_manager.cpp +++ b/src/video_core/renderer_opengl/gl_shader_manager.cpp @@ -14,12 +14,15 @@ static constexpr std::array ASSEMBLY_PROGRAM_ENUMS{ GL_GEOMETRY_PROGRAM_NV, GL_FRAGMENT_PROGRAM_NV, }; -ProgramManager::ProgramManager(const Device& device) - : lmem_warmup_program(CreateProgram(HostShaders::OPENGL_LMEM_WARMUP_COMP, GL_COMPUTE_SHADER)) { +ProgramManager::ProgramManager(const Device& device) { glCreateProgramPipelines(1, &pipeline.handle); if (device.UseAssemblyShaders()) { glEnable(GL_COMPUTE_PROGRAM_NV); } + if (device.HasLmemPerfBug()) { + lmem_warmup_program = + CreateProgram(HostShaders::OPENGL_LMEM_WARMUP_COMP, GL_COMPUTE_SHADER); + } } void ProgramManager::BindComputeProgram(GLuint program) { @@ -102,8 +105,10 @@ void ProgramManager::BindAssemblyPrograms(std::span Date: Wed, 21 Jun 2023 05:48:04 +0100 Subject: Use safe reads in DMA engine --- src/video_core/engines/maxwell_dma.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/video_core/engines/maxwell_dma.cpp b/src/video_core/engines/maxwell_dma.cpp index bc1eb41e7..a290d6ea7 100644 --- a/src/video_core/engines/maxwell_dma.cpp +++ b/src/video_core/engines/maxwell_dma.cpp @@ -130,7 +130,7 @@ void MaxwellDMA::Launch() { UNIMPLEMENTED_IF(regs.offset_out % 16 != 0); read_buffer.resize_destructive(16); for (u32 offset = 0; offset < regs.line_length_in; offset += 16) { - memory_manager.ReadBlockUnsafe( + memory_manager.ReadBlock( convert_linear_2_blocklinear_addr(regs.offset_in + offset), read_buffer.data(), read_buffer.size()); memory_manager.WriteBlockCached(regs.offset_out + offset, read_buffer.data(), @@ -142,8 +142,8 @@ void MaxwellDMA::Launch() { UNIMPLEMENTED_IF(regs.offset_out % 16 != 0); read_buffer.resize_destructive(16); for (u32 offset = 0; offset < regs.line_length_in; offset += 16) { - memory_manager.ReadBlockUnsafe(regs.offset_in + offset, read_buffer.data(), - read_buffer.size()); + memory_manager.ReadBlock(regs.offset_in + offset, read_buffer.data(), + read_buffer.size()); memory_manager.WriteBlockCached( convert_linear_2_blocklinear_addr(regs.offset_out + offset), read_buffer.data(), read_buffer.size()); @@ -151,8 +151,9 @@ void MaxwellDMA::Launch() { } else { if (!accelerate.BufferCopy(regs.offset_in, regs.offset_out, regs.line_length_in)) { read_buffer.resize_destructive(regs.line_length_in); - memory_manager.ReadBlockUnsafe(regs.offset_in, read_buffer.data(), - regs.line_length_in); + memory_manager.ReadBlock(regs.offset_in, read_buffer.data(), + regs.line_length_in, + VideoCommon::CacheType::NoBufferCache); memory_manager.WriteBlockCached(regs.offset_out, read_buffer.data(), regs.line_length_in); } -- cgit v1.2.3 From b6c6dcc5760ebaf08460c176c42d1c4729e2eb21 Mon Sep 17 00:00:00 2001 From: GPUCode Date: Sun, 25 Jun 2023 15:08:38 +0300 Subject: externals: Use cmake subdirectory --- src/video_core/vulkan_common/vulkan_device.cpp | 2 -- src/video_core/vulkan_common/vulkan_memory_allocator.cpp | 2 -- src/video_core/vulkan_common/vulkan_wrapper.cpp | 2 -- 3 files changed, 6 deletions(-) (limited to 'src') diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 94dd1aa14..31226084f 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -22,8 +22,6 @@ #include #endif -#define VMA_STATIC_VULKAN_FUNCTIONS 0 -#define VMA_DYNAMIC_VULKAN_FUNCTIONS 1 #include namespace Vulkan { diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp index 70db41343..a2ef0efa4 100644 --- a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp +++ b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp @@ -15,8 +15,6 @@ #include "video_core/vulkan_common/vulkan_memory_allocator.h" #include "video_core/vulkan_common/vulkan_wrapper.h" -#define VMA_STATIC_VULKAN_FUNCTIONS 0 -#define VMA_DYNAMIC_VULKAN_FUNCTIONS 1 #include namespace Vulkan { diff --git a/src/video_core/vulkan_common/vulkan_wrapper.cpp b/src/video_core/vulkan_common/vulkan_wrapper.cpp index c01a9478e..28fcb21a0 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.cpp +++ b/src/video_core/vulkan_common/vulkan_wrapper.cpp @@ -12,8 +12,6 @@ #include "video_core/vulkan_common/vulkan_wrapper.h" -#define VMA_STATIC_VULKAN_FUNCTIONS 0 -#define VMA_DYNAMIC_VULKAN_FUNCTIONS 1 #include namespace Vulkan::vk { -- cgit v1.2.3 From 0f31039831688d347d12853fea991014cfb954ba Mon Sep 17 00:00:00 2001 From: Charles Lombardo Date: Tue, 20 Jun 2023 17:23:20 -0400 Subject: android: Clean up file extension checks --- .../org/yuzu/yuzu_emu/fragments/SearchFragment.kt | 6 +--- .../src/main/java/org/yuzu/yuzu_emu/model/Game.kt | 2 +- .../java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt | 4 +-- .../main/java/org/yuzu/yuzu_emu/utils/FileUtil.kt | 34 +++++----------------- .../java/org/yuzu/yuzu_emu/utils/GameHelper.kt | 23 +++++---------- 5 files changed, 19 insertions(+), 50 deletions(-) (limited to 'src') diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SearchFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SearchFragment.kt index dd6c895fd..f54dccc69 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SearchFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SearchFragment.kt @@ -29,7 +29,6 @@ import org.yuzu.yuzu_emu.layout.AutofitGridLayoutManager import org.yuzu.yuzu_emu.model.Game import org.yuzu.yuzu_emu.model.GamesViewModel import org.yuzu.yuzu_emu.model.HomeViewModel -import org.yuzu.yuzu_emu.utils.FileUtil class SearchFragment : Fragment() { private var _binding: FragmentSearchBinding? = null @@ -128,10 +127,7 @@ class SearchFragment : Fragment() { R.id.chip_homebrew -> baseList.filter { it.isHomebrew } - R.id.chip_retail -> baseList.filter { - FileUtil.hasExtension(it.path, "xci") || - FileUtil.hasExtension(it.path, "nsp") - } + R.id.chip_retail -> baseList.filter { !it.isHomebrew } else -> baseList } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt index 6a048e39f..6527c64ab 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt @@ -43,7 +43,7 @@ class Game( companion object { val extensions: Set = HashSet( - listOf(".xci", ".nsp", ".nca", ".nro") + listOf("xci", "nsp", "nca", "nro") ) } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt index cc1d87f1b..d5eb8c2eb 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt @@ -294,7 +294,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider { return@registerForActivityResult } - if (!FileUtil.hasExtension(result, "keys")) { + if (FileUtil.getExtension(result) != "keys") { MessageDialogFragment.newInstance( R.string.reading_keys_failure, R.string.install_prod_keys_failure_extension_description @@ -391,7 +391,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider { return@registerForActivityResult } - if (!FileUtil.hasExtension(result, "bin")) { + if (FileUtil.getExtension(result) != "bin") { MessageDialogFragment.newInstance( R.string.reading_keys_failure, R.string.install_amiibo_keys_failure_extension_description diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.kt index 9f3bbe56f..142af5f26 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.kt @@ -7,7 +7,6 @@ import android.content.Context import android.database.Cursor import android.net.Uri import android.provider.DocumentsContract -import android.provider.OpenableColumns import androidx.documentfile.provider.DocumentFile import java.io.BufferedInputStream import java.io.File @@ -185,19 +184,18 @@ object FileUtil { /** * Get file display name from given path - * @param path content uri path + * @param uri content uri * @return String display name */ - fun getFilename(context: Context, path: String): String { - val resolver = context.contentResolver + fun getFilename(uri: Uri): String { + val resolver = YuzuApplication.appContext.contentResolver val columns = arrayOf( DocumentsContract.Document.COLUMN_DISPLAY_NAME ) var filename = "" var c: Cursor? = null try { - val mUri = Uri.parse(path) - c = resolver.query(mUri, columns, null, null, null) + c = resolver.query(uri, columns, null, null, null) c!!.moveToNext() filename = c.getString(0) } catch (e: Exception) { @@ -326,25 +324,9 @@ object FileUtil { } } - fun hasExtension(path: String, extension: String): Boolean = - path.substring(path.lastIndexOf(".") + 1).contains(extension) - - fun hasExtension(uri: Uri, extension: String): Boolean { - val fileName: String? - val cursor = YuzuApplication.appContext.contentResolver.query(uri, null, null, null, null) - val nameIndex = cursor?.getColumnIndex(OpenableColumns.DISPLAY_NAME) - cursor?.moveToFirst() - - if (nameIndex == null) { - return false - } - - fileName = cursor.getString(nameIndex) - cursor.close() - - if (fileName == null) { - return false - } - return fileName.substring(fileName.lastIndexOf(".") + 1).contains(extension) + fun getExtension(uri: Uri): String { + val fileName = getFilename(uri) + return fileName.substring(fileName.lastIndexOf(".") + 1) + .lowercase() } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt index ee9f3e570..f8e7eeca7 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt @@ -6,7 +6,6 @@ package org.yuzu.yuzu_emu.utils import android.content.SharedPreferences import android.net.Uri import androidx.preference.PreferenceManager -import java.util.* import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import org.yuzu.yuzu_emu.NativeLibrary @@ -33,15 +32,9 @@ object GameHelper { val children = FileUtil.listFiles(context, gamesUri) for (file in children) { if (!file.isDirectory) { - val filename = file.uri.toString() - val extensionStart = filename.lastIndexOf('.') - if (extensionStart > 0) { - val fileExtension = filename.substring(extensionStart) - - // Check that the file has an extension we care about before trying to read out of it. - if (Game.extensions.contains(fileExtension.lowercase(Locale.getDefault()))) { - games.add(getGame(filename)) - } + // Check that the file has an extension we care about before trying to read out of it. + if (Game.extensions.contains(FileUtil.getExtension(file.uri))) { + games.add(getGame(file.uri)) } } } @@ -59,21 +52,19 @@ object GameHelper { return games.toList() } - private fun getGame(filePath: String): Game { + private fun getGame(uri: Uri): Game { + val filePath = uri.toString() var name = NativeLibrary.getTitle(filePath) // If the game's title field is empty, use the filename. if (name.isEmpty()) { - name = filePath.substring(filePath.lastIndexOf("/") + 1) + name = FileUtil.getFilename(uri) } var gameId = NativeLibrary.getGameId(filePath) // If the game's ID field is empty, use the filename without extension. if (gameId.isEmpty()) { - gameId = filePath.substring( - filePath.lastIndexOf("/") + 1, - filePath.lastIndexOf(".") - ) + gameId = name.substring(0, name.lastIndexOf(".")) } val newGame = Game( -- cgit v1.2.3 From 9074a70b0180057d0cebcd667ad7fc813f1aca8c Mon Sep 17 00:00:00 2001 From: Charles Lombardo Date: Mon, 26 Jun 2023 20:55:28 -0400 Subject: android: Fix size check for content uris Fix for checking file size for android content uris --- src/common/fs/fs.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src') diff --git a/src/common/fs/fs.cpp b/src/common/fs/fs.cpp index 1baf6d746..36e67c145 100644 --- a/src/common/fs/fs.cpp +++ b/src/common/fs/fs.cpp @@ -605,6 +605,12 @@ fs::file_type GetEntryType(const fs::path& path) { } u64 GetSize(const fs::path& path) { +#ifdef ANDROID + if (Android::IsContentUri(path)) { + return Android::GetSize(path); + } +#endif + std::error_code ec; const auto file_size = fs::file_size(path, ec); -- cgit v1.2.3 From 30544fbfa53fb5866d104c3a0000419eada51558 Mon Sep 17 00:00:00 2001 From: german77 Date: Tue, 27 Jun 2023 15:55:23 -0600 Subject: yuzu: Fix clang format --- src/yuzu/configuration/configure_general.cpp | 6 ++++-- src/yuzu/main.cpp | 21 +++++++++++---------- 2 files changed, 15 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp index d74e663d4..2f55159f5 100644 --- a/src/yuzu/configuration/configure_general.cpp +++ b/src/yuzu/configuration/configure_general.cpp @@ -41,7 +41,8 @@ void ConfigureGeneral::SetConfiguration() { ui->toggle_background_pause->setChecked(UISettings::values.pause_when_in_background.GetValue()); ui->toggle_hide_mouse->setChecked(UISettings::values.hide_mouse.GetValue()); ui->toggle_controller_applet_disabled->setEnabled(runtime_lock); - ui->toggle_controller_applet_disabled->setChecked(UISettings::values.controller_applet_disabled.GetValue()); + ui->toggle_controller_applet_disabled->setChecked( + UISettings::values.controller_applet_disabled.GetValue()); ui->toggle_speed_limit->setChecked(Settings::values.use_speed_limit.GetValue()); ui->speed_limit->setValue(Settings::values.speed_limit.GetValue()); @@ -84,7 +85,8 @@ void ConfigureGeneral::ApplyConfiguration() { UISettings::values.select_user_on_boot = ui->toggle_user_on_boot->isChecked(); UISettings::values.pause_when_in_background = ui->toggle_background_pause->isChecked(); UISettings::values.hide_mouse = ui->toggle_hide_mouse->isChecked(); - UISettings::values.controller_applet_disabled = ui->toggle_controller_applet_disabled->isChecked(); + UISettings::values.controller_applet_disabled = + ui->toggle_controller_applet_disabled->isChecked(); // Guard if during game and set to game-specific value if (Settings::values.use_speed_limit.UsingGlobal()) { diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 24e59f646..e8418b302 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -1707,16 +1707,17 @@ bool GMainWindow::LoadROM(const QString& filename, u64 program_id, std::size_t p system->SetFilesystem(vfs); system->SetAppletFrontendSet({ - std::make_unique(*this), // Amiibo Settings - (UISettings::values.controller_applet_disabled.GetValue() == true) ? nullptr : - std::make_unique(*this), // Controller Selector - std::make_unique(*this), // Error Display - nullptr, // Mii Editor - nullptr, // Parental Controls - nullptr, // Photo Viewer - std::make_unique(*this), // Profile Selector - std::make_unique(*this), // Software Keyboard - std::make_unique(*this), // Web Browser + std::make_unique(*this), // Amiibo Settings + (UISettings::values.controller_applet_disabled.GetValue() == true) + ? nullptr + : std::make_unique(*this), // Controller Selector + std::make_unique(*this), // Error Display + nullptr, // Mii Editor + nullptr, // Parental Controls + nullptr, // Photo Viewer + std::make_unique(*this), // Profile Selector + std::make_unique(*this), // Software Keyboard + std::make_unique(*this), // Web Browser }); const Core::SystemResultStatus result{ -- cgit v1.2.3 From 32475efbc4326a3e7a97883f39b21b91fd14af60 Mon Sep 17 00:00:00 2001 From: lat9nq <22451773+lat9nq@users.noreply.github.com> Date: Tue, 27 Jun 2023 23:34:16 +0200 Subject: settings: Catch runtime_error, fallback time zone Windows will let you select time zones that will fail in their own C++ implementation library. Evidently from the stack trace, we get a runtime error to work with, so catch it and use the fallback. --- src/common/settings.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/common/settings.cpp b/src/common/settings.cpp index 66dffc9bf..a1df69140 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp @@ -1,6 +1,8 @@ // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include +#include #if __cpp_lib_chrono >= 201907L #include #endif @@ -25,9 +27,19 @@ std::string GetTimeZoneString() { if (time_zone_index == 0) { // Auto #if __cpp_lib_chrono >= 201907L const struct std::chrono::tzdb& time_zone_data = std::chrono::get_tzdb(); - const std::chrono::time_zone* current_zone = time_zone_data.current_zone(); - std::string_view current_zone_name = current_zone->name(); - location_name = current_zone_name; + try { + const std::chrono::time_zone* current_zone = time_zone_data.current_zone(); + std::string_view current_zone_name = current_zone->name(); + location_name = current_zone_name; + } catch (std::runtime_error& runtime_error) { + // VCRUNTIME will throw a runtime_error if the operating system's selected time zone + // cannot be found + location_name = Common::TimeZone::FindSystemTimeZone(); + LOG_WARNING(Common, + "Error occurred when trying to determine system time zone:\n{}\nFalling " + "back to hour offset \"{}\"", + runtime_error.what(), location_name); + } #else location_name = Common::TimeZone::FindSystemTimeZone(); #endif -- cgit v1.2.3 From e3c548d081cb9ad34f8eb8975a6ecb92e27fec6d Mon Sep 17 00:00:00 2001 From: Merry Date: Tue, 27 Jun 2023 23:51:49 +0100 Subject: arm_dynarmic_32: Remove disabling of block linking on arm64 --- src/core/arm/dynarmic/arm_dynarmic_32.cpp | 5 ----- 1 file changed, 5 deletions(-) (limited to 'src') diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index 5acf9008d..3b82fb73c 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -322,11 +322,6 @@ std::shared_ptr ARM_Dynarmic_32::MakeJit(Common::PageTable* } } -#ifdef ARCHITECTURE_arm64 - // TODO: remove when fixed in dynarmic - config.optimizations &= ~Dynarmic::OptimizationFlag::BlockLinking; -#endif - return std::make_unique(config); } -- cgit v1.2.3 From 21675c9b68741d15b678598aa555536bfc6a6f76 Mon Sep 17 00:00:00 2001 From: lat9nq <22451773+lat9nq@users.noreply.github.com> Date: Tue, 27 Jun 2023 19:13:54 -0400 Subject: settings: Clean up includes Adds since we are looking at C++ implementation version details. Also moves exception header includes into the if preprocessor command since we only use it there. --- src/common/settings.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/common/settings.cpp b/src/common/settings.cpp index a1df69140..6cbbea1b2 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp @@ -1,10 +1,11 @@ // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include -#include +#include #if __cpp_lib_chrono >= 201907L #include +#include +#include #endif #include -- cgit v1.2.3 From 72e7f5b4dd08e9ea46ee049d8f2564a8808273d4 Mon Sep 17 00:00:00 2001 From: GPUCode Date: Sat, 3 Jun 2023 09:21:52 +0300 Subject: renderer_vulkan: Add suport for debug report callback --- src/video_core/renderer_vulkan/renderer_vulkan.cpp | 18 ++++++- src/video_core/renderer_vulkan/renderer_vulkan.h | 5 +- .../vulkan_common/vulkan_debug_callback.cpp | 40 ++++++++++++--- .../vulkan_common/vulkan_debug_callback.h | 4 +- src/video_core/vulkan_common/vulkan_device.cpp | 2 +- src/video_core/vulkan_common/vulkan_instance.cpp | 58 ++++++++++++---------- src/video_core/vulkan_common/vulkan_wrapper.cpp | 14 ++++++ src/video_core/vulkan_common/vulkan_wrapper.h | 9 ++++ 8 files changed, 113 insertions(+), 37 deletions(-) (limited to 'src') diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index ddf28ca28..454bb66a4 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -12,6 +12,7 @@ #include #include "common/logging/log.h" +#include "common/polyfill_ranges.h" #include "common/scope_exit.h" #include "common/settings.h" #include "common/telemetry.h" @@ -65,6 +66,21 @@ std::string BuildCommaSeparatedExtensions( return fmt::format("{}", fmt::join(available_extensions, ",")); } +DebugCallback MakeDebugCallback(const vk::Instance& instance, const vk::InstanceDispatch& dld) { + if (!Settings::values.renderer_debug) { + return DebugCallback{}; + } + const std::optional properties = vk::EnumerateInstanceExtensionProperties(dld); + const auto it = std::ranges::find_if(*properties, [](const auto& prop) { + return std::strcmp(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, prop.extensionName) == 0; + }); + if (it != properties->end()) { + return CreateDebugUtilsCallback(instance); + } else { + return CreateDebugReportCallback(instance); + } +} + } // Anonymous namespace Device CreateDevice(const vk::Instance& instance, const vk::InstanceDispatch& dld, @@ -87,7 +103,7 @@ RendererVulkan::RendererVulkan(Core::TelemetrySession& telemetry_session_, cpu_memory(cpu_memory_), gpu(gpu_), library(OpenLibrary(context.get())), instance(CreateInstance(*library, dld, VK_API_VERSION_1_1, render_window.GetWindowInfo().type, Settings::values.renderer_debug.GetValue())), - debug_callback(Settings::values.renderer_debug ? CreateDebugCallback(instance) : nullptr), + debug_callback(MakeDebugCallback(instance, dld)), surface(CreateSurface(instance, render_window.GetWindowInfo())), device(CreateDevice(instance, dld, *surface)), memory_allocator(device), state_tracker(), scheduler(device, state_tracker), diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h index b2e8cbd1b..ca22c0baa 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.h +++ b/src/video_core/renderer_vulkan/renderer_vulkan.h @@ -5,6 +5,7 @@ #include #include +#include #include "common/dynamic_library.h" #include "video_core/renderer_base.h" @@ -33,6 +34,8 @@ class GPU; namespace Vulkan { +using DebugCallback = std::variant; + Device CreateDevice(const vk::Instance& instance, const vk::InstanceDispatch& dld, VkSurfaceKHR surface); @@ -71,7 +74,7 @@ private: vk::InstanceDispatch dld; vk::Instance instance; - vk::DebugUtilsMessenger debug_callback; + DebugCallback debug_callback; vk::SurfaceKHR surface; ScreenInfo screen_info; diff --git a/src/video_core/vulkan_common/vulkan_debug_callback.cpp b/src/video_core/vulkan_common/vulkan_debug_callback.cpp index 9de484c29..67e8065a4 100644 --- a/src/video_core/vulkan_common/vulkan_debug_callback.cpp +++ b/src/video_core/vulkan_common/vulkan_debug_callback.cpp @@ -7,10 +7,10 @@ namespace Vulkan { namespace { -VkBool32 Callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, - VkDebugUtilsMessageTypeFlagsEXT type, - const VkDebugUtilsMessengerCallbackDataEXT* data, - [[maybe_unused]] void* user_data) { +VkBool32 DebugUtilCallback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, + VkDebugUtilsMessageTypeFlagsEXT type, + const VkDebugUtilsMessengerCallbackDataEXT* data, + [[maybe_unused]] void* user_data) { // Skip logging known false-positive validation errors switch (static_cast(data->messageIdNumber)) { #ifdef ANDROID @@ -62,9 +62,26 @@ VkBool32 Callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, } return VK_FALSE; } + +VkBool32 DebugReportCallback(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, + uint64_t object, size_t location, int32_t messageCode, + const char* pLayerPrefix, const char* pMessage, void* pUserData) { + const VkDebugReportFlagBitsEXT severity = static_cast(flags); + const std::string_view message{pMessage}; + if (severity & VK_DEBUG_REPORT_ERROR_BIT_EXT) { + LOG_CRITICAL(Render_Vulkan, "{}", message); + } else if (severity & VK_DEBUG_REPORT_WARNING_BIT_EXT) { + LOG_WARNING(Render_Vulkan, "{}", message); + } else if (severity & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) { + LOG_INFO(Render_Vulkan, "{}", message); + } else if (severity & VK_DEBUG_REPORT_DEBUG_BIT_EXT) { + LOG_DEBUG(Render_Vulkan, "{}", message); + } + return VK_FALSE; +} } // Anonymous namespace -vk::DebugUtilsMessenger CreateDebugCallback(const vk::Instance& instance) { +vk::DebugUtilsMessenger CreateDebugUtilsCallback(const vk::Instance& instance) { return instance.CreateDebugUtilsMessenger(VkDebugUtilsMessengerCreateInfoEXT{ .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, .pNext = nullptr, @@ -76,7 +93,18 @@ vk::DebugUtilsMessenger CreateDebugCallback(const vk::Instance& instance) { .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT, - .pfnUserCallback = Callback, + .pfnUserCallback = DebugUtilCallback, + .pUserData = nullptr, + }); +} + +vk::DebugReportCallback CreateDebugReportCallback(const vk::Instance& instance) { + return instance.CreateDebugReportCallback({ + .sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT, + .pNext = nullptr, + .flags = VK_DEBUG_REPORT_DEBUG_BIT_EXT | VK_DEBUG_REPORT_INFORMATION_BIT_EXT | + VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT, + .pfnCallback = DebugReportCallback, .pUserData = nullptr, }); } diff --git a/src/video_core/vulkan_common/vulkan_debug_callback.h b/src/video_core/vulkan_common/vulkan_debug_callback.h index 71b1f69ec..a8af7b406 100644 --- a/src/video_core/vulkan_common/vulkan_debug_callback.h +++ b/src/video_core/vulkan_common/vulkan_debug_callback.h @@ -7,6 +7,8 @@ namespace Vulkan { -vk::DebugUtilsMessenger CreateDebugCallback(const vk::Instance& instance); +vk::DebugUtilsMessenger CreateDebugUtilsCallback(const vk::Instance& instance); + +vk::DebugReportCallback CreateDebugReportCallback(const vk::Instance& instance); } // namespace Vulkan diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index e4ca65b58..9743a82f5 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -349,7 +349,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR const bool is_s8gen2 = device_id == 0x43050a01; const bool is_arm = driver_id == VK_DRIVER_ID_ARM_PROPRIETARY; - if ((is_mvk || is_qualcomm || is_turnip) && !is_suitable) { + if ((is_mvk || is_qualcomm || is_turnip || is_arm) && !is_suitable) { LOG_WARNING(Render_Vulkan, "Unsuitable driver, continuing anyway"); } else if (!is_suitable) { throw vk::Exception(VK_ERROR_INCOMPATIBLE_DRIVER); diff --git a/src/video_core/vulkan_common/vulkan_instance.cpp b/src/video_core/vulkan_common/vulkan_instance.cpp index b6d83e446..7624a9b32 100644 --- a/src/video_core/vulkan_common/vulkan_instance.cpp +++ b/src/video_core/vulkan_common/vulkan_instance.cpp @@ -31,10 +31,34 @@ namespace Vulkan { namespace { + +[[nodiscard]] bool AreExtensionsSupported(const vk::InstanceDispatch& dld, + std::span extensions) { + const std::optional properties = vk::EnumerateInstanceExtensionProperties(dld); + if (!properties) { + LOG_ERROR(Render_Vulkan, "Failed to query extension properties"); + return false; + } + for (const char* extension : extensions) { + const auto it = std::ranges::find_if(*properties, [extension](const auto& prop) { + return std::strcmp(extension, prop.extensionName) == 0; + }); + if (it == properties->end()) { + LOG_ERROR(Render_Vulkan, "Required instance extension {} is not available", extension); + return false; + } + } + return true; +} + [[nodiscard]] std::vector RequiredExtensions( - Core::Frontend::WindowSystemType window_type, bool enable_validation) { + const vk::InstanceDispatch& dld, Core::Frontend::WindowSystemType window_type, + bool enable_validation) { std::vector extensions; extensions.reserve(6); +#ifdef __APPLE__ + extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME); +#endif switch (window_type) { case Core::Frontend::WindowSystemType::Headless: break; @@ -66,35 +90,14 @@ namespace { extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME); } if (enable_validation) { - extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); + const bool debug_utils = + AreExtensionsSupported(dld, std::array{VK_EXT_DEBUG_UTILS_EXTENSION_NAME}); + extensions.push_back(debug_utils ? VK_EXT_DEBUG_UTILS_EXTENSION_NAME + : VK_EXT_DEBUG_REPORT_EXTENSION_NAME); } - extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); - -#ifdef __APPLE__ - extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME); -#endif return extensions; } -[[nodiscard]] bool AreExtensionsSupported(const vk::InstanceDispatch& dld, - std::span extensions) { - const std::optional properties = vk::EnumerateInstanceExtensionProperties(dld); - if (!properties) { - LOG_ERROR(Render_Vulkan, "Failed to query extension properties"); - return false; - } - for (const char* extension : extensions) { - const auto it = std::ranges::find_if(*properties, [extension](const auto& prop) { - return std::strcmp(extension, prop.extensionName) == 0; - }); - if (it == properties->end()) { - LOG_ERROR(Render_Vulkan, "Required instance extension {} is not available", extension); - return false; - } - } - return true; -} - [[nodiscard]] std::vector Layers(bool enable_validation) { std::vector layers; if (enable_validation) { @@ -138,7 +141,8 @@ vk::Instance CreateInstance(const Common::DynamicLibrary& library, vk::InstanceD LOG_ERROR(Render_Vulkan, "Failed to load Vulkan function pointers"); throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED); } - const std::vector extensions = RequiredExtensions(window_type, enable_validation); + const std::vector extensions = + RequiredExtensions(dld, window_type, enable_validation); if (!AreExtensionsSupported(dld, extensions)) { throw vk::Exception(VK_ERROR_EXTENSION_NOT_PRESENT); } diff --git a/src/video_core/vulkan_common/vulkan_wrapper.cpp b/src/video_core/vulkan_common/vulkan_wrapper.cpp index 28fcb21a0..2fa29793a 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.cpp +++ b/src/video_core/vulkan_common/vulkan_wrapper.cpp @@ -259,7 +259,9 @@ bool Load(VkInstance instance, InstanceDispatch& dld) noexcept { // These functions may fail to load depending on the enabled extensions. // Don't return a failure on these. X(vkCreateDebugUtilsMessengerEXT); + X(vkCreateDebugReportCallbackEXT); X(vkDestroyDebugUtilsMessengerEXT); + X(vkDestroyDebugReportCallbackEXT); X(vkDestroySurfaceKHR); X(vkGetPhysicalDeviceFeatures2); X(vkGetPhysicalDeviceProperties2); @@ -481,6 +483,11 @@ void Destroy(VkInstance instance, VkDebugUtilsMessengerEXT handle, dld.vkDestroyDebugUtilsMessengerEXT(instance, handle, nullptr); } +void Destroy(VkInstance instance, VkDebugReportCallbackEXT handle, + const InstanceDispatch& dld) noexcept { + dld.vkDestroyDebugReportCallbackEXT(instance, handle, nullptr); +} + void Destroy(VkInstance instance, VkSurfaceKHR handle, const InstanceDispatch& dld) noexcept { dld.vkDestroySurfaceKHR(instance, handle, nullptr); } @@ -549,6 +556,13 @@ DebugUtilsMessenger Instance::CreateDebugUtilsMessenger( return DebugUtilsMessenger(object, handle, *dld); } +DebugReportCallback Instance::CreateDebugReportCallback( + const VkDebugReportCallbackCreateInfoEXT& create_info) const { + VkDebugReportCallbackEXT object; + Check(dld->vkCreateDebugReportCallbackEXT(handle, &create_info, nullptr, &object)); + return DebugReportCallback(object, handle, *dld); +} + void Image::SetObjectNameEXT(const char* name) const { SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_IMAGE, name); } diff --git a/src/video_core/vulkan_common/vulkan_wrapper.h b/src/video_core/vulkan_common/vulkan_wrapper.h index 44fce47a5..b5e70fcd4 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.h +++ b/src/video_core/vulkan_common/vulkan_wrapper.h @@ -164,8 +164,10 @@ struct InstanceDispatch { PFN_vkEnumerateInstanceLayerProperties vkEnumerateInstanceLayerProperties{}; PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT{}; + PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallbackEXT{}; PFN_vkCreateDevice vkCreateDevice{}; PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT{}; + PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallbackEXT{}; PFN_vkDestroyDevice vkDestroyDevice{}; PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR{}; PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties{}; @@ -366,6 +368,7 @@ void Destroy(VkDevice, VkSwapchainKHR, const DeviceDispatch&) noexcept; void Destroy(VkDevice, VkSemaphore, const DeviceDispatch&) noexcept; void Destroy(VkDevice, VkShaderModule, const DeviceDispatch&) noexcept; void Destroy(VkInstance, VkDebugUtilsMessengerEXT, const InstanceDispatch&) noexcept; +void Destroy(VkInstance, VkDebugReportCallbackEXT, const InstanceDispatch&) noexcept; void Destroy(VkInstance, VkSurfaceKHR, const InstanceDispatch&) noexcept; VkResult Free(VkDevice, VkDescriptorPool, Span, const DeviceDispatch&) noexcept; @@ -581,6 +584,7 @@ private: }; using DebugUtilsMessenger = Handle; +using DebugReportCallback = Handle; using DescriptorSetLayout = Handle; using DescriptorUpdateTemplate = Handle; using Pipeline = Handle; @@ -613,6 +617,11 @@ public: DebugUtilsMessenger CreateDebugUtilsMessenger( const VkDebugUtilsMessengerCreateInfoEXT& create_info) const; + /// Creates a debug report callback. + /// @throw Exception on creation failure. + DebugReportCallback CreateDebugReportCallback( + const VkDebugReportCallbackCreateInfoEXT& create_info) const; + /// Returns dispatch table. const InstanceDispatch& Dispatch() const noexcept { return *dld; -- cgit v1.2.3 From a9b44d37e101c646b00ca73dffa06edcb7627dcd Mon Sep 17 00:00:00 2001 From: GPUCode Date: Mon, 5 Jun 2023 18:58:21 +0300 Subject: renderer_vulkan: Don't add transform feedback flag if unsupported --- src/video_core/renderer_vulkan/vk_buffer_cache.cpp | 3 ++- .../renderer_vulkan/vk_staging_buffer_pool.cpp | 16 ++++++++++------ 2 files changed, 12 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp index 660f7c9ff..b72f95235 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp @@ -590,7 +590,8 @@ void BufferCacheRuntime::ReserveNullBuffer() { .pNext = nullptr, .flags = 0, .size = 4, - .usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, + .usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT | + VK_BUFFER_USAGE_TRANSFER_DST_BIT, .sharingMode = VK_SHARING_MODE_EXCLUSIVE, .queueFamilyIndexCount = 0, .pQueueFamilyIndices = nullptr, diff --git a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp index 62b251a9b..ce92f66ab 100644 --- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp +++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp @@ -38,18 +38,20 @@ size_t Region(size_t iterator) noexcept { StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& memory_allocator_, Scheduler& scheduler_) : device{device_}, memory_allocator{memory_allocator_}, scheduler{scheduler_} { - const VkBufferCreateInfo stream_ci = { + VkBufferCreateInfo stream_ci = { .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, .pNext = nullptr, .flags = 0, .size = STREAM_BUFFER_SIZE, .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | - VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | - VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT, + VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, .sharingMode = VK_SHARING_MODE_EXCLUSIVE, .queueFamilyIndexCount = 0, .pQueueFamilyIndices = nullptr, }; + if (device.IsExtTransformFeedbackSupported()) { + stream_ci.usage |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT; + } stream_buffer = memory_allocator.CreateBuffer(stream_ci, MemoryUsage::Stream); if (device.HasDebuggingToolAttached()) { stream_buffer.SetObjectNameEXT("Stream Buffer"); @@ -164,19 +166,21 @@ std::optional StagingBufferPool::TryGetReservedBuffer(size_t s StagingBufferRef StagingBufferPool::CreateStagingBuffer(size_t size, MemoryUsage usage, bool deferred) { const u32 log2 = Common::Log2Ceil64(size); - const VkBufferCreateInfo buffer_ci = { + VkBufferCreateInfo buffer_ci = { .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, .pNext = nullptr, .flags = 0, .size = 1ULL << log2, .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | - VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | - VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT, + VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, .sharingMode = VK_SHARING_MODE_EXCLUSIVE, .queueFamilyIndexCount = 0, .pQueueFamilyIndices = nullptr, }; + if (device.IsExtTransformFeedbackSupported()) { + buffer_ci.usage |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT; + } vk::Buffer buffer = memory_allocator.CreateBuffer(buffer_ci, usage); if (device.HasDebuggingToolAttached()) { ++buffer_index; -- cgit v1.2.3 From c339af37a73de144fbbad706e43aefe278640cd7 Mon Sep 17 00:00:00 2001 From: GPUCode Date: Mon, 5 Jun 2023 19:03:16 +0300 Subject: renderer_vulkan: Respect viewport limit --- src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp | 5 +++-- src/video_core/renderer_vulkan/vk_rasterizer.cpp | 16 ++++++++++++---- src/video_core/vulkan_common/vulkan_device.h | 4 ++++ 3 files changed, 19 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index c1595642e..ad35cacac 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -652,13 +652,14 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) { .pNext = nullptr, .negativeOneToOne = key.state.ndc_minus_one_to_one.Value() != 0 ? VK_TRUE : VK_FALSE, }; + const u32 num_viewports = std::min(device.GetMaxViewports(), Maxwell::NumViewports); VkPipelineViewportStateCreateInfo viewport_ci{ .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, .pNext = nullptr, .flags = 0, - .viewportCount = Maxwell::NumViewports, + .viewportCount = num_viewports, .pViewports = nullptr, - .scissorCount = Maxwell::NumViewports, + .scissorCount = num_viewports, .pScissors = nullptr, }; if (device.IsNvViewportSwizzleSupported()) { diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 84e3a30cc..268b955fb 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -925,7 +925,7 @@ void RasterizerVulkan::UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& reg } const bool is_rescaling{texture_cache.IsRescaling()}; const float scale = is_rescaling ? Settings::values.resolution_info.up_factor : 1.0f; - const std::array viewports{ + const std::array viewport_list{ GetViewportState(device, regs, 0, scale), GetViewportState(device, regs, 1, scale), GetViewportState(device, regs, 2, scale), GetViewportState(device, regs, 3, scale), GetViewportState(device, regs, 4, scale), GetViewportState(device, regs, 5, scale), @@ -935,7 +935,11 @@ void RasterizerVulkan::UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& reg GetViewportState(device, regs, 12, scale), GetViewportState(device, regs, 13, scale), GetViewportState(device, regs, 14, scale), GetViewportState(device, regs, 15, scale), }; - scheduler.Record([viewports](vk::CommandBuffer cmdbuf) { cmdbuf.SetViewport(0, viewports); }); + scheduler.Record([this, viewport_list](vk::CommandBuffer cmdbuf) { + const u32 num_viewports = std::min(device.GetMaxViewports(), Maxwell::NumViewports); + const vk::Span viewports(viewport_list.data(), num_viewports); + cmdbuf.SetViewport(0, viewports); + }); } void RasterizerVulkan::UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs) { @@ -948,7 +952,7 @@ void RasterizerVulkan::UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs up_scale = Settings::values.resolution_info.up_scale; down_shift = Settings::values.resolution_info.down_shift; } - const std::array scissors{ + const std::array scissor_list{ GetScissorState(regs, 0, up_scale, down_shift), GetScissorState(regs, 1, up_scale, down_shift), GetScissorState(regs, 2, up_scale, down_shift), @@ -966,7 +970,11 @@ void RasterizerVulkan::UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs GetScissorState(regs, 14, up_scale, down_shift), GetScissorState(regs, 15, up_scale, down_shift), }; - scheduler.Record([scissors](vk::CommandBuffer cmdbuf) { cmdbuf.SetScissor(0, scissors); }); + scheduler.Record([this, scissor_list](vk::CommandBuffer cmdbuf) { + const u32 num_scissors = std::min(device.GetMaxViewports(), Maxwell::NumViewports); + const vk::Span scissors(scissor_list.data(), num_scissors); + cmdbuf.SetScissor(0, scissors); + }); } void RasterizerVulkan::UpdateDepthBias(Tegra::Engines::Maxwell3D::Regs& regs) { diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index b84af3dfb..8a05a4fab 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h @@ -588,6 +588,10 @@ public: return properties.properties.limits.maxVertexInputBindings; } + u32 GetMaxViewports() const { + return properties.properties.limits.maxViewports; + } + bool SupportsConditionalBarriers() const { return supports_conditional_barriers; } -- cgit v1.2.3 From 1522b956583aab463bd1576652d1794fe989437d Mon Sep 17 00:00:00 2001 From: GPUCode Date: Mon, 5 Jun 2023 19:04:22 +0300 Subject: renderer_vulkan: Bump minimum SPIRV version * 1.3 is guaranteed on all 1.1 drivers --- src/video_core/vulkan_common/vulkan_device.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index 8a05a4fab..13ca24ef5 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h @@ -518,7 +518,7 @@ public: if (extensions.spirv_1_4) { return 0x00010400U; } - return 0x00010000U; + return 0x00010300U; } /// Returns true when a known debugging tool is attached. -- cgit v1.2.3 From 220a42896d350399f1f2d77432aa571ade3c9cdd Mon Sep 17 00:00:00 2001 From: GPUCode Date: Mon, 5 Jun 2023 19:07:05 +0300 Subject: renderer_vulkan: Don't assume debug tool with debug renderer * Causes crashes because mali drivers don't support debug utils --- src/video_core/vulkan_common/vulkan_device.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index 13ca24ef5..7be631122 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h @@ -523,7 +523,7 @@ public: /// Returns true when a known debugging tool is attached. bool HasDebuggingToolAttached() const { - return has_renderdoc || has_nsight_graphics || Settings::values.renderer_debug.GetValue(); + return has_renderdoc || has_nsight_graphics; } /// @returns True if compute pipelines can cause crashing. -- cgit v1.2.3 From b8c96cee5f2eb0bd5ba9ef46746daec78ee3bb44 Mon Sep 17 00:00:00 2001 From: GPUCode Date: Mon, 5 Jun 2023 19:27:36 +0300 Subject: renderer_vulkan: Add more feature checking --- src/video_core/renderer_vulkan/vk_pipeline_cache.cpp | 7 ++++--- src/video_core/vulkan_common/vulkan_device.cpp | 4 ++++ src/video_core/vulkan_common/vulkan_device.h | 16 ++++++++++++++++ 3 files changed, 24 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 9f316113c..d600c4e61 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -309,7 +309,7 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device .support_int16 = device.IsShaderInt16Supported(), .support_int64 = device.IsShaderInt64Supported(), .support_vertex_instance_id = false, - .support_float_controls = true, + .support_float_controls = device.IsKhrShaderFloatControlsSupported(), .support_separate_denorm_behavior = float_control.denormBehaviorIndependence == VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL, .support_separate_rounding_mode = @@ -325,12 +325,13 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device .support_fp64_signed_zero_nan_preserve = float_control.shaderSignedZeroInfNanPreserveFloat64 != VK_FALSE, .support_explicit_workgroup_layout = device.IsKhrWorkgroupMemoryExplicitLayoutSupported(), - .support_vote = true, + .support_vote = device.IsSubgroupFeatureSupported(VK_SUBGROUP_FEATURE_VOTE_BIT), .support_viewport_index_layer_non_geometry = device.IsExtShaderViewportIndexLayerSupported(), .support_viewport_mask = device.IsNvViewportArray2Supported(), .support_typeless_image_loads = device.IsFormatlessImageLoadSupported(), - .support_demote_to_helper_invocation = true, + .support_demote_to_helper_invocation = + device.IsExtShaderDemoteToHelperInvocationSupported(), .support_int64_atomics = device.IsExtShaderAtomicInt64Supported(), .support_derivative_control = true, .support_geometry_shader_passthrough = device.IsNvGeometryShaderPassthroughSupported(), diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 9743a82f5..70436cf1c 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -905,6 +905,10 @@ bool Device::GetSuitability(bool requires_swapchain) { properties.driver.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES; SetNext(next, properties.driver); + // Retrieve subgroup properties. + properties.subgroup_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES; + SetNext(next, properties.subgroup_properties); + // Retrieve relevant extension properties. if (extensions.shader_float_controls) { properties.float_controls.sType = diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index 7be631122..e05d04db3 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h @@ -323,6 +323,11 @@ public: return properties.subgroup_size_control.requiredSubgroupSizeStages & stage; } + /// Returns true if the device supports the provided subgroup feature. + bool IsSubgroupFeatureSupported(VkSubgroupFeatureFlagBits feature) const { + return properties.subgroup_properties.supportedOperations & feature; + } + /// Returns the maximum number of push descriptors. u32 MaxPushDescriptors() const { return properties.push_descriptor.maxPushDescriptors; @@ -388,6 +393,11 @@ public: return extensions.swapchain_mutable_format; } + /// Returns true if VK_KHR_shader_float_controls is enabled. + bool IsKhrShaderFloatControlsSupported() const { + return extensions.shader_float_controls; + } + /// Returns true if the device supports VK_KHR_workgroup_memory_explicit_layout. bool IsKhrWorkgroupMemoryExplicitLayoutSupported() const { return extensions.workgroup_memory_explicit_layout; @@ -487,6 +497,11 @@ public: return extensions.shader_stencil_export; } + /// Returns true if the device supports VK_EXT_shader_demote_to_helper_invocation + bool IsExtShaderDemoteToHelperInvocationSupported() const { + return extensions.shader_demote_to_helper_invocation; + } + /// Returns true if the device supports VK_EXT_conservative_rasterization. bool IsExtConservativeRasterizationSupported() const { return extensions.conservative_rasterization; @@ -684,6 +699,7 @@ private: struct Properties { VkPhysicalDeviceDriverProperties driver{}; + VkPhysicalDeviceSubgroupProperties subgroup_properties{}; VkPhysicalDeviceFloatControlsProperties float_controls{}; VkPhysicalDevicePushDescriptorPropertiesKHR push_descriptor{}; VkPhysicalDeviceSubgroupSizeControlProperties subgroup_size_control{}; -- cgit v1.2.3 From eac46ad7ceca5e35b396a8b80bfc38dc6ef1a4fe Mon Sep 17 00:00:00 2001 From: GPUCode Date: Tue, 6 Jun 2023 23:10:06 +0300 Subject: video_core: Add BCn decoding support --- src/video_core/CMakeLists.txt | 6 +- src/video_core/renderer_vulkan/maxwell_to_vk.cpp | 20 ++++ src/video_core/renderer_vulkan/vk_rasterizer.cpp | 7 ++ .../renderer_vulkan/vk_texture_cache.cpp | 4 + src/video_core/surface.cpp | 22 ++++ src/video_core/surface.h | 2 + src/video_core/texture_cache/decode_bc.cpp | 129 +++++++++++++++++++++ src/video_core/texture_cache/decode_bc.h | 19 +++ src/video_core/texture_cache/decode_bc4.cpp | 96 --------------- src/video_core/texture_cache/decode_bc4.h | 15 --- src/video_core/texture_cache/util.cpp | 24 ++-- src/video_core/textures/bcn.cpp | 1 - src/video_core/textures/bcn.h | 9 +- src/video_core/vulkan_common/vulkan_device.h | 15 ++- 14 files changed, 235 insertions(+), 134 deletions(-) create mode 100644 src/video_core/texture_cache/decode_bc.cpp create mode 100644 src/video_core/texture_cache/decode_bc.h delete mode 100644 src/video_core/texture_cache/decode_bc4.cpp delete mode 100644 src/video_core/texture_cache/decode_bc4.h (limited to 'src') diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index e9e6f278d..3b2fe01da 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -220,8 +220,8 @@ add_library(video_core STATIC surface.h texture_cache/accelerated_swizzle.cpp texture_cache/accelerated_swizzle.h - texture_cache/decode_bc4.cpp - texture_cache/decode_bc4.h + texture_cache/decode_bc.cpp + texture_cache/decode_bc.h texture_cache/descriptor_table.h texture_cache/formatter.cpp texture_cache/formatter.h @@ -279,7 +279,7 @@ add_library(video_core STATIC create_target_directory_groups(video_core) target_link_libraries(video_core PUBLIC common core) -target_link_libraries(video_core PUBLIC glad shader_recompiler stb) +target_link_libraries(video_core PUBLIC glad shader_recompiler stb bc_decoder) if (YUZU_USE_BUNDLED_FFMPEG AND NOT (WIN32 OR ANDROID)) add_dependencies(video_core ffmpeg-build) diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp index 9a0b10568..a8540339d 100644 --- a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp +++ b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp @@ -259,6 +259,26 @@ FormatInfo SurfaceFormat(const Device& device, FormatType format_type, bool with break; } } + // Transcode on hardware that doesn't support BCn natively + if (!device.IsOptimalBcnSupported() && VideoCore::Surface::IsPixelFormatBCn(pixel_format)) { + const bool is_srgb = with_srgb && VideoCore::Surface::IsPixelFormatSRGB(pixel_format); + if (pixel_format == PixelFormat::BC4_SNORM) { + tuple.format = VK_FORMAT_R8_SNORM; + } else if (pixel_format == PixelFormat::BC4_UNORM) { + tuple.format = VK_FORMAT_R8_UNORM; + } else if (pixel_format == PixelFormat::BC5_SNORM) { + tuple.format = VK_FORMAT_R8G8_SNORM; + } else if (pixel_format == PixelFormat::BC5_UNORM) { + tuple.format = VK_FORMAT_R8G8_UNORM; + } else if (pixel_format == PixelFormat::BC6H_SFLOAT || + pixel_format == PixelFormat::BC6H_UFLOAT) { + tuple.format = VK_FORMAT_R16G16B16A16_SFLOAT; + } else if (is_srgb) { + tuple.format = VK_FORMAT_A8B8G8R8_SRGB_PACK32; + } else { + tuple.format = VK_FORMAT_A8B8G8R8_UNORM_PACK32; + } + } const bool attachable = (tuple.usage & Attachable) != 0; const bool storage = (tuple.usage & Storage) != 0; diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 268b955fb..f7c0d939a 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -315,7 +315,14 @@ void RasterizerVulkan::Clear(u32 layer_count) { FlushWork(); gpu_memory->FlushCaching(); +#if ANDROID + if (Settings::IsGPULevelHigh()) { + // This is problematic on Android, disable on GPU Normal. + query_cache.UpdateCounters(); + } +#else query_cache.UpdateCounters(); +#endif auto& regs = maxwell3d->regs; const bool use_color = regs.clear_surface.R || regs.clear_surface.G || regs.clear_surface.B || diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index ce6acc30c..8385b5509 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -1279,6 +1279,10 @@ Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info_, GPUVAddr gpu flags |= VideoCommon::ImageFlagBits::Converted; flags |= VideoCommon::ImageFlagBits::CostlyLoad; } + if (IsPixelFormatBCn(info.format) && !runtime->device.IsOptimalBcnSupported()) { + flags |= VideoCommon::ImageFlagBits::Converted; + flags |= VideoCommon::ImageFlagBits::CostlyLoad; + } if (runtime->device.HasDebuggingToolAttached()) { original_image.SetObjectNameEXT(VideoCommon::Name(*this).c_str()); } diff --git a/src/video_core/surface.cpp b/src/video_core/surface.cpp index cb51529e4..e16cd5e73 100644 --- a/src/video_core/surface.cpp +++ b/src/video_core/surface.cpp @@ -269,6 +269,28 @@ bool IsPixelFormatASTC(PixelFormat format) { } } +bool IsPixelFormatBCn(PixelFormat format) { + switch (format) { + case PixelFormat::BC1_RGBA_UNORM: + case PixelFormat::BC2_UNORM: + case PixelFormat::BC3_UNORM: + case PixelFormat::BC4_UNORM: + case PixelFormat::BC4_SNORM: + case PixelFormat::BC5_UNORM: + case PixelFormat::BC5_SNORM: + case PixelFormat::BC1_RGBA_SRGB: + case PixelFormat::BC2_SRGB: + case PixelFormat::BC3_SRGB: + case PixelFormat::BC7_UNORM: + case PixelFormat::BC6H_UFLOAT: + case PixelFormat::BC6H_SFLOAT: + case PixelFormat::BC7_SRGB: + return true; + default: + return false; + } +} + bool IsPixelFormatSRGB(PixelFormat format) { switch (format) { case PixelFormat::A8B8G8R8_SRGB: diff --git a/src/video_core/surface.h b/src/video_core/surface.h index 0225d3287..9b9c4d9bc 100644 --- a/src/video_core/surface.h +++ b/src/video_core/surface.h @@ -501,6 +501,8 @@ SurfaceType GetFormatType(PixelFormat pixel_format); bool IsPixelFormatASTC(PixelFormat format); +bool IsPixelFormatBCn(PixelFormat format); + bool IsPixelFormatSRGB(PixelFormat format); bool IsPixelFormatInteger(PixelFormat format); diff --git a/src/video_core/texture_cache/decode_bc.cpp b/src/video_core/texture_cache/decode_bc.cpp new file mode 100644 index 000000000..3e26474a3 --- /dev/null +++ b/src/video_core/texture_cache/decode_bc.cpp @@ -0,0 +1,129 @@ +// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#include +#include +#include + +#include "common/common_types.h" +#include "video_core/texture_cache/decode_bc.h" + +namespace VideoCommon { + +namespace { +constexpr u32 BLOCK_SIZE = 4; + +using VideoCore::Surface::PixelFormat; + +constexpr bool IsSigned(PixelFormat pixel_format) { + switch (pixel_format) { + case PixelFormat::BC4_SNORM: + case PixelFormat::BC4_UNORM: + case PixelFormat::BC5_SNORM: + case PixelFormat::BC5_UNORM: + case PixelFormat::BC6H_SFLOAT: + case PixelFormat::BC6H_UFLOAT: + return true; + default: + return false; + } +} + +constexpr u32 BlockSize(PixelFormat pixel_format) { + switch (pixel_format) { + case PixelFormat::BC1_RGBA_SRGB: + case PixelFormat::BC1_RGBA_UNORM: + case PixelFormat::BC4_SNORM: + case PixelFormat::BC4_UNORM: + return 8; + default: + return 16; + } +} +} // Anonymous namespace + +u32 ConvertedBytesPerBlock(VideoCore::Surface::PixelFormat pixel_format) { + switch (pixel_format) { + case PixelFormat::BC4_SNORM: + case PixelFormat::BC4_UNORM: + return 1; + case PixelFormat::BC5_SNORM: + case PixelFormat::BC5_UNORM: + return 2; + case PixelFormat::BC6H_SFLOAT: + case PixelFormat::BC6H_UFLOAT: + return 8; + default: + return 4; + } +} + +template +void DecompressBlocks(std::span input, std::span output, Extent3D extent, + bool is_signed = false) { + const u32 out_bpp = ConvertedBytesPerBlock(pixel_format); + const u32 block_width = std::min(extent.width, BLOCK_SIZE); + const u32 block_height = std::min(extent.height, BLOCK_SIZE); + const u32 pitch = extent.width * out_bpp; + size_t input_offset = 0; + size_t output_offset = 0; + for (u32 slice = 0; slice < extent.depth; ++slice) { + for (u32 y = 0; y < extent.height; y += block_height) { + size_t row_offset = 0; + for (u32 x = 0; x < extent.width; + x += block_width, row_offset += block_width * out_bpp) { + const u8* src = input.data() + input_offset; + u8* const dst = output.data() + output_offset + row_offset; + if constexpr (IsSigned(pixel_format)) { + decompress(src, dst, x, y, extent.width, extent.height, is_signed); + } else { + decompress(src, dst, x, y, extent.width, extent.height); + } + input_offset += BlockSize(pixel_format); + } + output_offset += block_height * pitch; + } + } +} + +void DecompressBCn(std::span input, std::span output, Extent3D extent, + VideoCore::Surface::PixelFormat pixel_format) { + switch (pixel_format) { + case PixelFormat::BC1_RGBA_UNORM: + case PixelFormat::BC1_RGBA_SRGB: + DecompressBlocks(input, output, extent); + break; + case PixelFormat::BC2_UNORM: + case PixelFormat::BC2_SRGB: + DecompressBlocks(input, output, extent); + break; + case PixelFormat::BC3_UNORM: + case PixelFormat::BC3_SRGB: + DecompressBlocks(input, output, extent); + break; + case PixelFormat::BC4_SNORM: + case PixelFormat::BC4_UNORM: + DecompressBlocks( + input, output, extent, pixel_format == PixelFormat::BC4_SNORM); + break; + case PixelFormat::BC5_SNORM: + case PixelFormat::BC5_UNORM: + DecompressBlocks( + input, output, extent, pixel_format == PixelFormat::BC5_SNORM); + break; + case PixelFormat::BC6H_SFLOAT: + case PixelFormat::BC6H_UFLOAT: + DecompressBlocks( + input, output, extent, pixel_format == PixelFormat::BC6H_SFLOAT); + break; + case PixelFormat::BC7_SRGB: + case PixelFormat::BC7_UNORM: + DecompressBlocks(input, output, extent); + break; + default: + LOG_WARNING(HW_GPU, "Unimplemented BCn decompression {}", pixel_format); + } +} + +} // namespace VideoCommon diff --git a/src/video_core/texture_cache/decode_bc.h b/src/video_core/texture_cache/decode_bc.h new file mode 100644 index 000000000..41d1ec0a3 --- /dev/null +++ b/src/video_core/texture_cache/decode_bc.h @@ -0,0 +1,19 @@ +// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include + +#include "common/common_types.h" +#include "video_core/surface.h" +#include "video_core/texture_cache/types.h" + +namespace VideoCommon { + +[[nodiscard]] u32 ConvertedBytesPerBlock(VideoCore::Surface::PixelFormat pixel_format); + +void DecompressBCn(std::span input, std::span output, Extent3D extent, + VideoCore::Surface::PixelFormat pixel_format); + +} // namespace VideoCommon diff --git a/src/video_core/texture_cache/decode_bc4.cpp b/src/video_core/texture_cache/decode_bc4.cpp deleted file mode 100644 index ef98afdca..000000000 --- a/src/video_core/texture_cache/decode_bc4.cpp +++ /dev/null @@ -1,96 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include -#include -#include - -#include "common/assert.h" -#include "common/common_types.h" -#include "video_core/texture_cache/decode_bc4.h" -#include "video_core/texture_cache/types.h" - -namespace VideoCommon { - -// https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_texture_compression_rgtc.txt -[[nodiscard]] constexpr u32 DecompressBlock(u64 bits, u32 x, u32 y) { - const u32 code_offset = 16 + 3 * (4 * y + x); - const u32 code = (bits >> code_offset) & 7; - const u32 red0 = (bits >> 0) & 0xff; - const u32 red1 = (bits >> 8) & 0xff; - if (red0 > red1) { - switch (code) { - case 0: - return red0; - case 1: - return red1; - case 2: - return (6 * red0 + 1 * red1) / 7; - case 3: - return (5 * red0 + 2 * red1) / 7; - case 4: - return (4 * red0 + 3 * red1) / 7; - case 5: - return (3 * red0 + 4 * red1) / 7; - case 6: - return (2 * red0 + 5 * red1) / 7; - case 7: - return (1 * red0 + 6 * red1) / 7; - } - } else { - switch (code) { - case 0: - return red0; - case 1: - return red1; - case 2: - return (4 * red0 + 1 * red1) / 5; - case 3: - return (3 * red0 + 2 * red1) / 5; - case 4: - return (2 * red0 + 3 * red1) / 5; - case 5: - return (1 * red0 + 4 * red1) / 5; - case 6: - return 0; - case 7: - return 0xff; - } - } - return 0; -} - -void DecompressBC4(std::span input, Extent3D extent, std::span output) { - UNIMPLEMENTED_IF_MSG(extent.width % 4 != 0, "Unaligned width={}", extent.width); - UNIMPLEMENTED_IF_MSG(extent.height % 4 != 0, "Unaligned height={}", extent.height); - static constexpr u32 BLOCK_SIZE = 4; - size_t input_offset = 0; - for (u32 slice = 0; slice < extent.depth; ++slice) { - for (u32 block_y = 0; block_y < extent.height / 4; ++block_y) { - for (u32 block_x = 0; block_x < extent.width / 4; ++block_x) { - u64 bits; - std::memcpy(&bits, &input[input_offset], sizeof(bits)); - input_offset += sizeof(bits); - - for (u32 y = 0; y < BLOCK_SIZE; ++y) { - for (u32 x = 0; x < BLOCK_SIZE; ++x) { - const u32 linear_z = slice; - const u32 linear_y = block_y * BLOCK_SIZE + y; - const u32 linear_x = block_x * BLOCK_SIZE + x; - const u32 offset_z = linear_z * extent.width * extent.height; - const u32 offset_y = linear_y * extent.width; - const u32 offset_x = linear_x; - const u32 output_offset = (offset_z + offset_y + offset_x) * 4ULL; - const u32 color = DecompressBlock(bits, x, y); - output[output_offset + 0] = static_cast(color); - output[output_offset + 1] = 0; - output[output_offset + 2] = 0; - output[output_offset + 3] = 0xff; - } - } - } - } - } -} - -} // namespace VideoCommon diff --git a/src/video_core/texture_cache/decode_bc4.h b/src/video_core/texture_cache/decode_bc4.h deleted file mode 100644 index ab2f735be..000000000 --- a/src/video_core/texture_cache/decode_bc4.h +++ /dev/null @@ -1,15 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include - -#include "common/common_types.h" -#include "video_core/texture_cache/types.h" - -namespace VideoCommon { - -void DecompressBC4(std::span data, Extent3D extent, std::span output); - -} // namespace VideoCommon diff --git a/src/video_core/texture_cache/util.cpp b/src/video_core/texture_cache/util.cpp index f781cb7a0..9a618a57a 100644 --- a/src/video_core/texture_cache/util.cpp +++ b/src/video_core/texture_cache/util.cpp @@ -24,7 +24,7 @@ #include "video_core/engines/maxwell_3d.h" #include "video_core/memory_manager.h" #include "video_core/surface.h" -#include "video_core/texture_cache/decode_bc4.h" +#include "video_core/texture_cache/decode_bc.h" #include "video_core/texture_cache/format_lookup_table.h" #include "video_core/texture_cache/formatter.h" #include "video_core/texture_cache/samples_helper.h" @@ -61,8 +61,6 @@ using VideoCore::Surface::PixelFormatFromDepthFormat; using VideoCore::Surface::PixelFormatFromRenderTargetFormat; using VideoCore::Surface::SurfaceType; -constexpr u32 CONVERTED_BYTES_PER_BLOCK = BytesPerBlock(PixelFormat::A8B8G8R8_UNORM); - struct LevelInfo { Extent3D size; Extent3D block; @@ -612,7 +610,8 @@ u32 CalculateConvertedSizeBytes(const ImageInfo& info) noexcept { } return output_size; } - return NumBlocksPerLayer(info, TILE_SIZE) * info.resources.layers * CONVERTED_BYTES_PER_BLOCK; + return NumBlocksPerLayer(info, TILE_SIZE) * info.resources.layers * + ConvertedBytesPerBlock(info.format); } u32 CalculateLayerStride(const ImageInfo& info) noexcept { @@ -945,7 +944,8 @@ void ConvertImage(std::span input, const ImageInfo& info, std::span input, const ImageInfo& info, std::span input, const ImageInfo& info, std::span(copy.buffer_size); } else { - DecompressBC4(input_offset, copy.image_extent, output.subspan(output_offset)); - + const Extent3D image_extent{ + .width = copy.image_extent.width, + .height = copy.image_extent.height * copy.image_subresource.num_layers, + .depth = copy.image_extent.depth, + }; + DecompressBCn(input_offset, output.subspan(output_offset), image_extent, info.format); output_offset += copy.image_extent.width * copy.image_extent.height * - copy.image_subresource.num_layers * CONVERTED_BYTES_PER_BLOCK; + copy.image_subresource.num_layers * + ConvertedBytesPerBlock(info.format); } } } diff --git a/src/video_core/textures/bcn.cpp b/src/video_core/textures/bcn.cpp index 671212a49..16ddbe320 100644 --- a/src/video_core/textures/bcn.cpp +++ b/src/video_core/textures/bcn.cpp @@ -3,7 +3,6 @@ #include #include - #include "common/alignment.h" #include "video_core/textures/bcn.h" #include "video_core/textures/workers.h" diff --git a/src/video_core/textures/bcn.h b/src/video_core/textures/bcn.h index 6464af885..d5d2a16c9 100644 --- a/src/video_core/textures/bcn.h +++ b/src/video_core/textures/bcn.h @@ -4,14 +4,13 @@ #pragma once #include -#include + +#include "common/common_types.h" namespace Tegra::Texture::BCN { -void CompressBC1(std::span data, uint32_t width, uint32_t height, uint32_t depth, - std::span output); +void CompressBC1(std::span data, u32 width, u32 height, u32 depth, std::span output); -void CompressBC3(std::span data, uint32_t width, uint32_t height, uint32_t depth, - std::span output); +void CompressBC3(std::span data, u32 width, u32 height, u32 depth, std::span output); } // namespace Tegra::Texture::BCN diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index e05d04db3..1f17265d5 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h @@ -293,6 +293,11 @@ public: return features.features.textureCompressionASTC_LDR; } + /// Returns true if BCn is natively supported. + bool IsOptimalBcnSupported() const { + return features.features.textureCompressionBC; + } + /// Returns true if descriptor aliasing is natively supported. bool IsDescriptorAliasingSupported() const { return GetDriverID() != VK_DRIVER_ID_QUALCOMM_PROPRIETARY; @@ -423,6 +428,11 @@ public: return extensions.sampler_filter_minmax; } + /// Returns true if the device supports VK_EXT_shader_stencil_export. + bool IsExtShaderStencilExportSupported() const { + return extensions.shader_stencil_export; + } + /// Returns true if the device supports VK_EXT_depth_range_unrestricted. bool IsExtDepthRangeUnrestrictedSupported() const { return extensions.depth_range_unrestricted; @@ -492,11 +502,6 @@ public: return extensions.vertex_input_dynamic_state; } - /// Returns true if the device supports VK_EXT_shader_stencil_export. - bool IsExtShaderStencilExportSupported() const { - return extensions.shader_stencil_export; - } - /// Returns true if the device supports VK_EXT_shader_demote_to_helper_invocation bool IsExtShaderDemoteToHelperInvocationSupported() const { return extensions.shader_demote_to_helper_invocation; -- cgit v1.2.3 From ddcc95833660c57647d3e99dad76ecfa3b86ee8d Mon Sep 17 00:00:00 2001 From: GPUCode Date: Thu, 15 Jun 2023 12:17:46 +0300 Subject: renderer_vulkan: Prevent crashes when blitting depth stencil --- src/video_core/renderer_vulkan/blit_image.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp index cf2964a3f..28d4b15a0 100644 --- a/src/video_core/renderer_vulkan/blit_image.cpp +++ b/src/video_core/renderer_vulkan/blit_image.cpp @@ -495,6 +495,9 @@ void BlitImageHelper::BlitDepthStencil(const Framebuffer* dst_framebuffer, const Region2D& dst_region, const Region2D& src_region, Tegra::Engines::Fermi2D::Filter filter, Tegra::Engines::Fermi2D::Operation operation) { + if (!device.IsExtShaderStencilExportSupported()) { + return; + } ASSERT(filter == Tegra::Engines::Fermi2D::Filter::Point); ASSERT(operation == Tegra::Engines::Fermi2D::Operation::SrcCopy); const BlitImagePipelineKey key{ -- cgit v1.2.3 From 4303ed614d0d758d9e9bcdef8afee3274769d2fb Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Wed, 28 Jun 2023 01:07:10 -0400 Subject: x64: Add detection of monitorx instructions monitorx introduces 2 instructions: MONITORX and MWAITX. --- src/common/telemetry.cpp | 1 + src/common/x64/cpu_detect.cpp | 1 + src/common/x64/cpu_detect.h | 1 + 3 files changed, 3 insertions(+) (limited to 'src') diff --git a/src/common/telemetry.cpp b/src/common/telemetry.cpp index 91352912d..929ed67e4 100644 --- a/src/common/telemetry.cpp +++ b/src/common/telemetry.cpp @@ -93,6 +93,7 @@ void AppendCPUInfo(FieldCollection& fc) { add_field("CPU_Extension_x64_GFNI", caps.gfni); add_field("CPU_Extension_x64_INVARIANT_TSC", caps.invariant_tsc); add_field("CPU_Extension_x64_LZCNT", caps.lzcnt); + add_field("CPU_Extension_x64_MONITORX", caps.monitorx); add_field("CPU_Extension_x64_MOVBE", caps.movbe); add_field("CPU_Extension_x64_PCLMULQDQ", caps.pclmulqdq); add_field("CPU_Extension_x64_POPCNT", caps.popcnt); diff --git a/src/common/x64/cpu_detect.cpp b/src/common/x64/cpu_detect.cpp index c998b1197..780120a5b 100644 --- a/src/common/x64/cpu_detect.cpp +++ b/src/common/x64/cpu_detect.cpp @@ -168,6 +168,7 @@ static CPUCaps Detect() { __cpuid(cpu_id, 0x80000001); caps.lzcnt = Common::Bit<5>(cpu_id[2]); caps.fma4 = Common::Bit<16>(cpu_id[2]); + caps.monitorx = Common::Bit<29>(cpu_id[2]); } if (max_ex_fn >= 0x80000007) { diff --git a/src/common/x64/cpu_detect.h b/src/common/x64/cpu_detect.h index 8253944d6..756459417 100644 --- a/src/common/x64/cpu_detect.h +++ b/src/common/x64/cpu_detect.h @@ -63,6 +63,7 @@ struct CPUCaps { bool gfni : 1; bool invariant_tsc : 1; bool lzcnt : 1; + bool monitorx : 1; bool movbe : 1; bool pclmulqdq : 1; bool popcnt : 1; -- cgit v1.2.3 From 3d868baaa44152e7a4bd8c64905443fd9a08adce Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Wed, 28 Jun 2023 01:07:59 -0400 Subject: x64: cpu_wait: Make use of MWAITX in MicroSleep MWAITX is equivalent to UMWAIT on Intel's Alder Lake CPUs. We can emulate TPAUSE by using MONITORX in conjunction with MWAITX to wait for 100K cycles. --- src/common/x64/cpu_wait.cpp | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/common/x64/cpu_wait.cpp b/src/common/x64/cpu_wait.cpp index c53dd4945..11b9c4d83 100644 --- a/src/common/x64/cpu_wait.cpp +++ b/src/common/x64/cpu_wait.cpp @@ -13,24 +13,30 @@ namespace Common::X64 { +namespace { + +// 100,000 cycles is a reasonable amount of time to wait to save on CPU resources. +// For reference: +// At 1 GHz, 100K cycles is 100us +// At 2 GHz, 100K cycles is 50us +// At 4 GHz, 100K cycles is 25us +constexpr auto PauseCycles = 100'000U; + +} // Anonymous namespace + #ifdef _MSC_VER __forceinline static void TPAUSE() { - // 100,000 cycles is a reasonable amount of time to wait to save on CPU resources. - // For reference: - // At 1 GHz, 100K cycles is 100us - // At 2 GHz, 100K cycles is 50us - // At 4 GHz, 100K cycles is 25us - static constexpr auto PauseCycles = 100'000; _tpause(0, FencedRDTSC() + PauseCycles); } + +__forceinline static void MWAITX() { + // monitor_var should be aligned to a cache line. + alignas(64) u64 monitor_var{}; + _mm_monitorx(&monitor_var, 0, 0); + _mm_mwaitx(/* extensions*/ 2, /* hints */ 0, /* cycles */ PauseCycles); +} #else static void TPAUSE() { - // 100,000 cycles is a reasonable amount of time to wait to save on CPU resources. - // For reference: - // At 1 GHz, 100K cycles is 100us - // At 2 GHz, 100K cycles is 50us - // At 4 GHz, 100K cycles is 25us - static constexpr auto PauseCycles = 100'000; const auto tsc = FencedRDTSC() + PauseCycles; const auto eax = static_cast(tsc & 0xFFFFFFFF); const auto edx = static_cast(tsc >> 32); @@ -40,9 +46,12 @@ static void TPAUSE() { void MicroSleep() { static const bool has_waitpkg = GetCPUCaps().waitpkg; + static const bool has_monitorx = GetCPUCaps().monitorx; if (has_waitpkg) { TPAUSE(); + } else if (has_monitorx) { + MWAITX(); } else { std::this_thread::yield(); } -- cgit v1.2.3 From 2b68a3cbbf144b97aa524eb1dd17aad34cdf1a67 Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Wed, 28 Jun 2023 01:19:41 -0400 Subject: x64: cpu_wait: Remove magic values --- src/common/x64/cpu_wait.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/common/x64/cpu_wait.cpp b/src/common/x64/cpu_wait.cpp index 11b9c4d83..ea16c8490 100644 --- a/src/common/x64/cpu_wait.cpp +++ b/src/common/x64/cpu_wait.cpp @@ -26,21 +26,26 @@ constexpr auto PauseCycles = 100'000U; #ifdef _MSC_VER __forceinline static void TPAUSE() { - _tpause(0, FencedRDTSC() + PauseCycles); + static constexpr auto RequestC02State = 0U; + _tpause(RequestC02State, FencedRDTSC() + PauseCycles); } __forceinline static void MWAITX() { + static constexpr auto EnableWaitTimeFlag = 1U << 1; + static constexpr auto RequestC1State = 0U; + // monitor_var should be aligned to a cache line. alignas(64) u64 monitor_var{}; _mm_monitorx(&monitor_var, 0, 0); - _mm_mwaitx(/* extensions*/ 2, /* hints */ 0, /* cycles */ PauseCycles); + _mm_mwaitx(EnableWaitTimeFlag, RequestC1State, PauseCycles); } #else static void TPAUSE() { + static constexpr auto RequestC02State = 0U; const auto tsc = FencedRDTSC() + PauseCycles; const auto eax = static_cast(tsc & 0xFFFFFFFF); const auto edx = static_cast(tsc >> 32); - asm volatile("tpause %0" : : "r"(0), "d"(edx), "a"(eax)); + asm volatile("tpause %0" : : "r"(RequestC02State), "d"(edx), "a"(eax)); } #endif -- cgit v1.2.3 From 295fc7d0f8f0b6158307c5c9b11a60516f9eb221 Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Wed, 28 Jun 2023 01:35:16 -0400 Subject: x64: cpu_wait: Implement MWAITX for non-MSVC compilers --- src/common/x64/cpu_wait.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'src') diff --git a/src/common/x64/cpu_wait.cpp b/src/common/x64/cpu_wait.cpp index ea16c8490..41d385f59 100644 --- a/src/common/x64/cpu_wait.cpp +++ b/src/common/x64/cpu_wait.cpp @@ -47,6 +47,16 @@ static void TPAUSE() { const auto edx = static_cast(tsc >> 32); asm volatile("tpause %0" : : "r"(RequestC02State), "d"(edx), "a"(eax)); } + +static void MWAITX() { + static constexpr auto EnableWaitTimeFlag = 1U << 1; + static constexpr auto RequestC1State = 0U; + + // monitor_var should be aligned to a cache line. + alignas(64) u64 monitor_var{}; + asm volatile("monitorx" : : "a"(&monitor_var), "c"(0), "d"(0)); + asm volatile("mwaitx" : : "a"(RequestC1State), "b"(PauseCycles), "c"(EnableWaitTimeFlag)); +} #endif void MicroSleep() { -- cgit v1.2.3 From df9685a21c105962e90dbd95133c5a1bcef7886f Mon Sep 17 00:00:00 2001 From: german77 Date: Wed, 28 Jun 2023 00:20:38 -0600 Subject: input_common: Remove duplicated DriverResult enum --- src/common/input.h | 2 + src/input_common/drivers/joycon.cpp | 35 ++-- src/input_common/drivers/joycon.h | 3 +- src/input_common/helpers/joycon_driver.cpp | 129 ++++++------ src/input_common/helpers/joycon_driver.h | 48 +++-- .../helpers/joycon_protocol/calibration.cpp | 53 ++--- .../helpers/joycon_protocol/calibration.h | 15 +- .../helpers/joycon_protocol/common_protocol.cpp | 102 ++++----- .../helpers/joycon_protocol/common_protocol.h | 44 ++-- .../helpers/joycon_protocol/generic_functions.cpp | 52 ++--- .../helpers/joycon_protocol/generic_functions.h | 41 ++-- src/input_common/helpers/joycon_protocol/irs.cpp | 70 +++---- src/input_common/helpers/joycon_protocol/irs.h | 22 +- .../helpers/joycon_protocol/joycon_types.h | 17 -- src/input_common/helpers/joycon_protocol/nfc.cpp | 231 +++++++++++---------- src/input_common/helpers/joycon_protocol/nfc.h | 66 +++--- .../helpers/joycon_protocol/ringcon.cpp | 42 ++-- src/input_common/helpers/joycon_protocol/ringcon.h | 14 +- .../helpers/joycon_protocol/rumble.cpp | 5 +- src/input_common/helpers/joycon_protocol/rumble.h | 8 +- src/yuzu/configuration/configure_ringcon.cpp | 3 + 21 files changed, 523 insertions(+), 479 deletions(-) (limited to 'src') diff --git a/src/common/input.h b/src/common/input.h index ea30770ae..2c4ccea22 100644 --- a/src/common/input.h +++ b/src/common/input.h @@ -75,8 +75,10 @@ enum class DriverResult { ErrorWritingData, NoDeviceDetected, InvalidHandle, + InvalidParameters, NotSupported, Disabled, + Delayed, Unknown, }; diff --git a/src/input_common/drivers/joycon.cpp b/src/input_common/drivers/joycon.cpp index 52494e0d9..0aca5a3a3 100644 --- a/src/input_common/drivers/joycon.cpp +++ b/src/input_common/drivers/joycon.cpp @@ -102,12 +102,12 @@ bool Joycons::IsDeviceNew(SDL_hid_device_info* device_info) const { Joycon::SerialNumber serial_number{}; const auto result = Joycon::JoyconDriver::GetDeviceType(device_info, type); - if (result != Joycon::DriverResult::Success) { + if (result != Common::Input::DriverResult::Success) { return false; } const auto result2 = Joycon::JoyconDriver::GetSerialNumber(device_info, serial_number); - if (result2 != Joycon::DriverResult::Success) { + if (result2 != Common::Input::DriverResult::Success) { return false; } @@ -171,10 +171,10 @@ void Joycons::RegisterNewDevice(SDL_hid_device_info* device_info) { LOG_WARNING(Input, "No free handles available"); return; } - if (result == Joycon::DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { result = handle->RequestDeviceAccess(device_info); } - if (result == Joycon::DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { LOG_WARNING(Input, "Initialize device"); const std::size_t port = handle->GetDevicePort(); @@ -273,8 +273,7 @@ Common::Input::DriverResult Joycons::SetLeds(const PadIdentifier& identifier, led_config += led_status.led_3 ? 4 : 0; led_config += led_status.led_4 ? 8 : 0; - return static_cast( - handle->SetLedConfig(static_cast(led_config))); + return handle->SetLedConfig(static_cast(led_config)); } Common::Input::DriverResult Joycons::SetCameraFormat(const PadIdentifier& identifier, @@ -283,8 +282,8 @@ Common::Input::DriverResult Joycons::SetCameraFormat(const PadIdentifier& identi if (handle == nullptr) { return Common::Input::DriverResult::InvalidHandle; } - return static_cast(handle->SetIrsConfig( - Joycon::IrsMode::ImageTransfer, static_cast(camera_format))); + return handle->SetIrsConfig(Joycon::IrsMode::ImageTransfer, + static_cast(camera_format)); }; Common::Input::NfcState Joycons::SupportsNfc(const PadIdentifier& identifier_) const { @@ -351,7 +350,7 @@ Common::Input::NfcState Joycons::ReadMifareData(const PadIdentifier& identifier, std::vector read_data(read_request.size()); const auto result = handle->ReadMifareData(read_request, read_data); - if (result == Joycon::DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { for (std::size_t i = 0; i < read_request.size(); i++) { data.data[i] = { .command = static_cast(command), @@ -402,15 +401,15 @@ Common::Input::DriverResult Joycons::SetPollingMode(const PadIdentifier& identif switch (polling_mode) { case Common::Input::PollingMode::Active: - return static_cast(handle->SetActiveMode()); + return handle->SetActiveMode(); case Common::Input::PollingMode::Passive: - return static_cast(handle->SetPassiveMode()); + return handle->SetPassiveMode(); case Common::Input::PollingMode::IR: - return static_cast(handle->SetIrMode()); + return handle->SetIrMode(); case Common::Input::PollingMode::NFC: - return static_cast(handle->SetNfcMode()); + return handle->SetNfcMode(); case Common::Input::PollingMode::Ring: - return static_cast(handle->SetRingConMode()); + return handle->SetRingConMode(); default: return Common::Input::DriverResult::NotSupported; } @@ -828,13 +827,13 @@ std::string Joycons::JoyconName(Joycon::ControllerType type) const { } } -Common::Input::NfcState Joycons::TranslateDriverResult(Joycon::DriverResult result) const { +Common::Input::NfcState Joycons::TranslateDriverResult(Common::Input::DriverResult result) const { switch (result) { - case Joycon::DriverResult::Success: + case Common::Input::DriverResult::Success: return Common::Input::NfcState::Success; - case Joycon::DriverResult::Disabled: + case Common::Input::DriverResult::Disabled: return Common::Input::NfcState::WrongDeviceState; - case Joycon::DriverResult::NotSupported: + case Common::Input::DriverResult::NotSupported: return Common::Input::NfcState::NotSupported; default: return Common::Input::NfcState::Unknown; diff --git a/src/input_common/drivers/joycon.h b/src/input_common/drivers/joycon.h index 4c323d7d6..112e970e1 100644 --- a/src/input_common/drivers/joycon.h +++ b/src/input_common/drivers/joycon.h @@ -17,7 +17,6 @@ struct Color; struct MotionData; struct TagInfo; enum class ControllerType : u8; -enum class DriverResult; enum class IrsResolution; class JoyconDriver; } // namespace InputCommon::Joycon @@ -112,7 +111,7 @@ private: /// Returns the name of the device in text format std::string JoyconName(Joycon::ControllerType type) const; - Common::Input::NfcState TranslateDriverResult(Joycon::DriverResult result) const; + Common::Input::NfcState TranslateDriverResult(Common::Input::DriverResult result) const; std::jthread scan_thread; diff --git a/src/input_common/helpers/joycon_driver.cpp b/src/input_common/helpers/joycon_driver.cpp index ec984a647..cf51f3481 100644 --- a/src/input_common/helpers/joycon_driver.cpp +++ b/src/input_common/helpers/joycon_driver.cpp @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include "common/input.h" #include "common/logging/log.h" #include "common/scope_exit.h" #include "common/swap.h" @@ -28,13 +29,13 @@ void JoyconDriver::Stop() { input_thread = {}; } -DriverResult JoyconDriver::RequestDeviceAccess(SDL_hid_device_info* device_info) { +Common::Input::DriverResult JoyconDriver::RequestDeviceAccess(SDL_hid_device_info* device_info) { std::scoped_lock lock{mutex}; handle_device_type = ControllerType::None; GetDeviceType(device_info, handle_device_type); if (handle_device_type == ControllerType::None) { - return DriverResult::UnsupportedControllerType; + return Common::Input::DriverResult::UnsupportedControllerType; } hidapi_handle->handle = @@ -43,15 +44,15 @@ DriverResult JoyconDriver::RequestDeviceAccess(SDL_hid_device_info* device_info) if (!hidapi_handle->handle) { LOG_ERROR(Input, "Yuzu can't gain access to this device: ID {:04X}:{:04X}.", device_info->vendor_id, device_info->product_id); - return DriverResult::HandleInUse; + return Common::Input::DriverResult::HandleInUse; } SDL_hid_set_nonblocking(hidapi_handle->handle, 1); - return DriverResult::Success; + return Common::Input::DriverResult::Success; } -DriverResult JoyconDriver::InitializeDevice() { +Common::Input::DriverResult JoyconDriver::InitializeDevice() { if (!hidapi_handle->handle) { - return DriverResult::InvalidHandle; + return Common::Input::DriverResult::InvalidHandle; } std::scoped_lock lock{mutex}; disable_input_thread = true; @@ -87,7 +88,7 @@ DriverResult JoyconDriver::InitializeDevice() { rumble_protocol = std::make_unique(hidapi_handle); // Get fixed joycon info - if (generic_protocol->GetVersionNumber(version) != DriverResult::Success) { + if (generic_protocol->GetVersionNumber(version) != Common::Input::DriverResult::Success) { // If this command fails the device doesn't accept configuration commands input_only_device = true; } @@ -129,7 +130,7 @@ DriverResult JoyconDriver::InitializeDevice() { } disable_input_thread = false; - return DriverResult::Success; + return Common::Input::DriverResult::Success; } void JoyconDriver::InputThread(std::stop_token stop_token) { @@ -229,7 +230,7 @@ void JoyconDriver::OnNewData(std::span buffer) { if (!amiibo_detected) { Joycon::TagInfo tag_info; const auto result = nfc_protocol->GetTagInfo(tag_info); - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { joycon_poller->UpdateAmiibo(tag_info); amiibo_detected = true; } @@ -255,7 +256,7 @@ void JoyconDriver::OnNewData(std::span buffer) { } } -DriverResult JoyconDriver::SetPollingMode() { +Common::Input::DriverResult JoyconDriver::SetPollingMode() { SCOPE_EXIT({ disable_input_thread = false; }); disable_input_thread = true; @@ -270,7 +271,7 @@ DriverResult JoyconDriver::SetPollingMode() { } if (input_only_device) { - return DriverResult::NotSupported; + return Common::Input::DriverResult::NotSupported; } if (irs_protocol->IsEnabled()) { @@ -289,7 +290,7 @@ DriverResult JoyconDriver::SetPollingMode() { if (irs_enabled && supported_features.irs) { auto result = irs_protocol->EnableIrs(); - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { return result; } irs_protocol->DisableIrs(); @@ -299,7 +300,7 @@ DriverResult JoyconDriver::SetPollingMode() { if (nfc_enabled && supported_features.nfc) { auto result = nfc_protocol->EnableNfc(); - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { return result; } nfc_protocol->DisableNfc(); @@ -309,10 +310,10 @@ DriverResult JoyconDriver::SetPollingMode() { if (hidbus_enabled && supported_features.hidbus) { auto result = ring_protocol->EnableRingCon(); - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { result = ring_protocol->StartRingconPolling(); } - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { ring_connected = true; return result; } @@ -324,7 +325,7 @@ DriverResult JoyconDriver::SetPollingMode() { if (passive_enabled && supported_features.passive) { const auto result = generic_protocol->EnablePassiveMode(); - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { return result; } LOG_ERROR(Input, "Error enabling passive mode"); @@ -332,7 +333,7 @@ DriverResult JoyconDriver::SetPollingMode() { // Default Mode const auto result = generic_protocol->EnableActiveMode(); - if (result != DriverResult::Success) { + if (result != Common::Input::DriverResult::Success) { LOG_ERROR(Input, "Error enabling active mode"); } // Switch calls this function after enabling active mode @@ -396,26 +397,26 @@ bool JoyconDriver::IsPayloadCorrect(int status, std::span buffer) { return true; } -DriverResult JoyconDriver::SetVibration(const VibrationValue& vibration) { +Common::Input::DriverResult JoyconDriver::SetVibration(const VibrationValue& vibration) { std::scoped_lock lock{mutex}; if (disable_input_thread) { - return DriverResult::HandleInUse; + return Common::Input::DriverResult::HandleInUse; } return rumble_protocol->SendVibration(vibration); } -DriverResult JoyconDriver::SetLedConfig(u8 led_pattern) { +Common::Input::DriverResult JoyconDriver::SetLedConfig(u8 led_pattern) { std::scoped_lock lock{mutex}; if (disable_input_thread) { - return DriverResult::HandleInUse; + return Common::Input::DriverResult::HandleInUse; } return generic_protocol->SetLedPattern(led_pattern); } -DriverResult JoyconDriver::SetIrsConfig(IrsMode mode_, IrsResolution format_) { +Common::Input::DriverResult JoyconDriver::SetIrsConfig(IrsMode mode_, IrsResolution format_) { std::scoped_lock lock{mutex}; if (disable_input_thread) { - return DriverResult::HandleInUse; + return Common::Input::DriverResult::HandleInUse; } disable_input_thread = true; const auto result = irs_protocol->SetIrsConfig(mode_, format_); @@ -423,7 +424,7 @@ DriverResult JoyconDriver::SetIrsConfig(IrsMode mode_, IrsResolution format_) { return result; } -DriverResult JoyconDriver::SetPassiveMode() { +Common::Input::DriverResult JoyconDriver::SetPassiveMode() { std::scoped_lock lock{mutex}; motion_enabled = false; hidbus_enabled = false; @@ -433,7 +434,7 @@ DriverResult JoyconDriver::SetPassiveMode() { return SetPollingMode(); } -DriverResult JoyconDriver::SetActiveMode() { +Common::Input::DriverResult JoyconDriver::SetActiveMode() { if (is_ring_disabled_by_irs) { is_ring_disabled_by_irs = false; SetActiveMode(); @@ -449,11 +450,11 @@ DriverResult JoyconDriver::SetActiveMode() { return SetPollingMode(); } -DriverResult JoyconDriver::SetIrMode() { +Common::Input::DriverResult JoyconDriver::SetIrMode() { std::scoped_lock lock{mutex}; if (!supported_features.irs) { - return DriverResult::NotSupported; + return Common::Input::DriverResult::NotSupported; } if (ring_connected) { @@ -468,11 +469,11 @@ DriverResult JoyconDriver::SetIrMode() { return SetPollingMode(); } -DriverResult JoyconDriver::SetNfcMode() { +Common::Input::DriverResult JoyconDriver::SetNfcMode() { std::scoped_lock lock{mutex}; if (!supported_features.nfc) { - return DriverResult::NotSupported; + return Common::Input::DriverResult::NotSupported; } motion_enabled = true; @@ -483,11 +484,11 @@ DriverResult JoyconDriver::SetNfcMode() { return SetPollingMode(); } -DriverResult JoyconDriver::SetRingConMode() { +Common::Input::DriverResult JoyconDriver::SetRingConMode() { std::scoped_lock lock{mutex}; if (!supported_features.hidbus) { - return DriverResult::NotSupported; + return Common::Input::DriverResult::NotSupported; } motion_enabled = true; @@ -499,20 +500,20 @@ DriverResult JoyconDriver::SetRingConMode() { const auto result = SetPollingMode(); if (!ring_connected) { - return DriverResult::NoDeviceDetected; + return Common::Input::DriverResult::NoDeviceDetected; } return result; } -DriverResult JoyconDriver::StartNfcPolling() { +Common::Input::DriverResult JoyconDriver::StartNfcPolling() { std::scoped_lock lock{mutex}; if (!supported_features.nfc) { - return DriverResult::NotSupported; + return Common::Input::DriverResult::NotSupported; } if (!nfc_protocol->IsEnabled()) { - return DriverResult::Disabled; + return Common::Input::DriverResult::Disabled; } disable_input_thread = true; @@ -522,14 +523,14 @@ DriverResult JoyconDriver::StartNfcPolling() { return result; } -DriverResult JoyconDriver::StopNfcPolling() { +Common::Input::DriverResult JoyconDriver::StopNfcPolling() { std::scoped_lock lock{mutex}; if (!supported_features.nfc) { - return DriverResult::NotSupported; + return Common::Input::DriverResult::NotSupported; } if (!nfc_protocol->IsEnabled()) { - return DriverResult::Disabled; + return Common::Input::DriverResult::Disabled; } disable_input_thread = true; @@ -544,17 +545,17 @@ DriverResult JoyconDriver::StopNfcPolling() { return result; } -DriverResult JoyconDriver::ReadAmiiboData(std::vector& out_data) { +Common::Input::DriverResult JoyconDriver::ReadAmiiboData(std::vector& out_data) { std::scoped_lock lock{mutex}; if (!supported_features.nfc) { - return DriverResult::NotSupported; + return Common::Input::DriverResult::NotSupported; } if (!nfc_protocol->IsEnabled()) { - return DriverResult::Disabled; + return Common::Input::DriverResult::Disabled; } if (!amiibo_detected) { - return DriverResult::ErrorWritingData; + return Common::Input::DriverResult::ErrorWritingData; } out_data.resize(0x21C); @@ -565,17 +566,17 @@ DriverResult JoyconDriver::ReadAmiiboData(std::vector& out_data) { return result; } -DriverResult JoyconDriver::WriteNfcData(std::span data) { +Common::Input::DriverResult JoyconDriver::WriteNfcData(std::span data) { std::scoped_lock lock{mutex}; if (!supported_features.nfc) { - return DriverResult::NotSupported; + return Common::Input::DriverResult::NotSupported; } if (!nfc_protocol->IsEnabled()) { - return DriverResult::Disabled; + return Common::Input::DriverResult::Disabled; } if (!amiibo_detected) { - return DriverResult::ErrorWritingData; + return Common::Input::DriverResult::ErrorWritingData; } disable_input_thread = true; @@ -585,18 +586,18 @@ DriverResult JoyconDriver::WriteNfcData(std::span data) { return result; } -DriverResult JoyconDriver::ReadMifareData(std::span data, - std::span out_data) { +Common::Input::DriverResult JoyconDriver::ReadMifareData(std::span data, + std::span out_data) { std::scoped_lock lock{mutex}; if (!supported_features.nfc) { - return DriverResult::NotSupported; + return Common::Input::DriverResult::NotSupported; } if (!nfc_protocol->IsEnabled()) { - return DriverResult::Disabled; + return Common::Input::DriverResult::Disabled; } if (!amiibo_detected) { - return DriverResult::ErrorWritingData; + return Common::Input::DriverResult::ErrorWritingData; } disable_input_thread = true; @@ -606,17 +607,17 @@ DriverResult JoyconDriver::ReadMifareData(std::span data, return result; } -DriverResult JoyconDriver::WriteMifareData(std::span data) { +Common::Input::DriverResult JoyconDriver::WriteMifareData(std::span data) { std::scoped_lock lock{mutex}; if (!supported_features.nfc) { - return DriverResult::NotSupported; + return Common::Input::DriverResult::NotSupported; } if (!nfc_protocol->IsEnabled()) { - return DriverResult::Disabled; + return Common::Input::DriverResult::Disabled; } if (!amiibo_detected) { - return DriverResult::ErrorWritingData; + return Common::Input::DriverResult::ErrorWritingData; } disable_input_thread = true; @@ -675,8 +676,8 @@ void JoyconDriver::SetCallbacks(const JoyconCallbacks& callbacks) { joycon_poller->SetCallbacks(callbacks); } -DriverResult JoyconDriver::GetDeviceType(SDL_hid_device_info* device_info, - ControllerType& controller_type) { +Common::Input::DriverResult JoyconDriver::GetDeviceType(SDL_hid_device_info* device_info, + ControllerType& controller_type) { static constexpr std::array, 6> supported_devices{ std::pair{0x2006, ControllerType::Left}, {0x2007, ControllerType::Right}, @@ -686,25 +687,25 @@ DriverResult JoyconDriver::GetDeviceType(SDL_hid_device_info* device_info, controller_type = ControllerType::None; if (device_info->vendor_id != nintendo_vendor_id) { - return DriverResult::UnsupportedControllerType; + return Common::Input::DriverResult::UnsupportedControllerType; } for (const auto& [product_id, type] : supported_devices) { if (device_info->product_id == static_cast(product_id)) { controller_type = type; - return Joycon::DriverResult::Success; + return Common::Input::DriverResult::Success; } } - return Joycon::DriverResult::UnsupportedControllerType; + return Common::Input::DriverResult::UnsupportedControllerType; } -DriverResult JoyconDriver::GetSerialNumber(SDL_hid_device_info* device_info, - SerialNumber& serial_number) { +Common::Input::DriverResult JoyconDriver::GetSerialNumber(SDL_hid_device_info* device_info, + SerialNumber& serial_number) { if (device_info->serial_number == nullptr) { - return DriverResult::Unknown; + return Common::Input::DriverResult::Unknown; } std::memcpy(&serial_number, device_info->serial_number, 15); - return Joycon::DriverResult::Success; + return Common::Input::DriverResult::Success; } } // namespace InputCommon::Joycon diff --git a/src/input_common/helpers/joycon_driver.h b/src/input_common/helpers/joycon_driver.h index 45b32d2f8..335e12cc3 100644 --- a/src/input_common/helpers/joycon_driver.h +++ b/src/input_common/helpers/joycon_driver.h @@ -11,6 +11,10 @@ #include "input_common/helpers/joycon_protocol/joycon_types.h" +namespace Common::Input { +enum class DriverResult; +} + namespace InputCommon::Joycon { class CalibrationProtocol; class GenericProtocol; @@ -26,8 +30,8 @@ public: ~JoyconDriver(); - DriverResult RequestDeviceAccess(SDL_hid_device_info* device_info); - DriverResult InitializeDevice(); + Common::Input::DriverResult RequestDeviceAccess(SDL_hid_device_info* device_info); + Common::Input::DriverResult InitializeDevice(); void Stop(); bool IsConnected() const; @@ -41,31 +45,31 @@ public: SerialNumber GetSerialNumber() const; SerialNumber GetHandleSerialNumber() const; - DriverResult SetVibration(const VibrationValue& vibration); - DriverResult SetLedConfig(u8 led_pattern); - DriverResult SetIrsConfig(IrsMode mode_, IrsResolution format_); - DriverResult SetPassiveMode(); - DriverResult SetActiveMode(); - DriverResult SetIrMode(); - DriverResult SetNfcMode(); - DriverResult SetRingConMode(); - DriverResult StartNfcPolling(); - DriverResult StopNfcPolling(); - DriverResult ReadAmiiboData(std::vector& out_data); - DriverResult WriteNfcData(std::span data); - DriverResult ReadMifareData(std::span request, - std::span out_data); - DriverResult WriteMifareData(std::span request); + Common::Input::DriverResult SetVibration(const VibrationValue& vibration); + Common::Input::DriverResult SetLedConfig(u8 led_pattern); + Common::Input::DriverResult SetIrsConfig(IrsMode mode_, IrsResolution format_); + Common::Input::DriverResult SetPassiveMode(); + Common::Input::DriverResult SetActiveMode(); + Common::Input::DriverResult SetIrMode(); + Common::Input::DriverResult SetNfcMode(); + Common::Input::DriverResult SetRingConMode(); + Common::Input::DriverResult StartNfcPolling(); + Common::Input::DriverResult StopNfcPolling(); + Common::Input::DriverResult ReadAmiiboData(std::vector& out_data); + Common::Input::DriverResult WriteNfcData(std::span data); + Common::Input::DriverResult ReadMifareData(std::span request, + std::span out_data); + Common::Input::DriverResult WriteMifareData(std::span request); void SetCallbacks(const JoyconCallbacks& callbacks); // Returns device type from hidapi handle - static DriverResult GetDeviceType(SDL_hid_device_info* device_info, - ControllerType& controller_type); + static Common::Input::DriverResult GetDeviceType(SDL_hid_device_info* device_info, + ControllerType& controller_type); // Returns serial number from hidapi handle - static DriverResult GetSerialNumber(SDL_hid_device_info* device_info, - SerialNumber& serial_number); + static Common::Input::DriverResult GetSerialNumber(SDL_hid_device_info* device_info, + SerialNumber& serial_number); private: struct SupportedFeatures { @@ -84,7 +88,7 @@ private: void OnNewData(std::span buffer); /// Updates device configuration to enable or disable features - DriverResult SetPollingMode(); + Common::Input::DriverResult SetPollingMode(); /// Returns true if input thread is valid and doesn't need to be stopped bool IsInputThreadValid() const; diff --git a/src/input_common/helpers/joycon_protocol/calibration.cpp b/src/input_common/helpers/joycon_protocol/calibration.cpp index d8f040f75..1300ecaf5 100644 --- a/src/input_common/helpers/joycon_protocol/calibration.cpp +++ b/src/input_common/helpers/joycon_protocol/calibration.cpp @@ -3,6 +3,7 @@ #include +#include "common/input.h" #include "input_common/helpers/joycon_protocol/calibration.h" #include "input_common/helpers/joycon_protocol/joycon_types.h" @@ -11,28 +12,29 @@ namespace InputCommon::Joycon { CalibrationProtocol::CalibrationProtocol(std::shared_ptr handle) : JoyconCommonProtocol(std::move(handle)) {} -DriverResult CalibrationProtocol::GetLeftJoyStickCalibration(JoyStickCalibration& calibration) { +Common::Input::DriverResult CalibrationProtocol::GetLeftJoyStickCalibration( + JoyStickCalibration& calibration) { ScopedSetBlocking sb(this); - DriverResult result{DriverResult::Success}; + Common::Input::DriverResult result{Common::Input::DriverResult::Success}; JoystickLeftSpiCalibration spi_calibration{}; bool has_user_calibration = false; calibration = {}; - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { result = HasUserCalibration(SpiAddress::USER_LEFT_MAGIC, has_user_calibration); } // Read User defined calibration - if (result == DriverResult::Success && has_user_calibration) { + if (result == Common::Input::DriverResult::Success && has_user_calibration) { result = ReadSPI(SpiAddress::USER_LEFT_DATA, spi_calibration); } // Read Factory calibration - if (result == DriverResult::Success && !has_user_calibration) { + if (result == Common::Input::DriverResult::Success && !has_user_calibration) { result = ReadSPI(SpiAddress::FACT_LEFT_DATA, spi_calibration); } - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { calibration.x.center = GetXAxisCalibrationValue(spi_calibration.center); calibration.y.center = GetYAxisCalibrationValue(spi_calibration.center); calibration.x.min = GetXAxisCalibrationValue(spi_calibration.min); @@ -47,28 +49,29 @@ DriverResult CalibrationProtocol::GetLeftJoyStickCalibration(JoyStickCalibration return result; } -DriverResult CalibrationProtocol::GetRightJoyStickCalibration(JoyStickCalibration& calibration) { +Common::Input::DriverResult CalibrationProtocol::GetRightJoyStickCalibration( + JoyStickCalibration& calibration) { ScopedSetBlocking sb(this); - DriverResult result{DriverResult::Success}; + Common::Input::DriverResult result{Common::Input::DriverResult::Success}; JoystickRightSpiCalibration spi_calibration{}; bool has_user_calibration = false; calibration = {}; - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { result = HasUserCalibration(SpiAddress::USER_RIGHT_MAGIC, has_user_calibration); } // Read User defined calibration - if (result == DriverResult::Success && has_user_calibration) { + if (result == Common::Input::DriverResult::Success && has_user_calibration) { result = ReadSPI(SpiAddress::USER_RIGHT_DATA, spi_calibration); } // Read Factory calibration - if (result == DriverResult::Success && !has_user_calibration) { + if (result == Common::Input::DriverResult::Success && !has_user_calibration) { result = ReadSPI(SpiAddress::FACT_RIGHT_DATA, spi_calibration); } - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { calibration.x.center = GetXAxisCalibrationValue(spi_calibration.center); calibration.y.center = GetYAxisCalibrationValue(spi_calibration.center); calibration.x.min = GetXAxisCalibrationValue(spi_calibration.min); @@ -83,28 +86,28 @@ DriverResult CalibrationProtocol::GetRightJoyStickCalibration(JoyStickCalibratio return result; } -DriverResult CalibrationProtocol::GetImuCalibration(MotionCalibration& calibration) { +Common::Input::DriverResult CalibrationProtocol::GetImuCalibration(MotionCalibration& calibration) { ScopedSetBlocking sb(this); - DriverResult result{DriverResult::Success}; + Common::Input::DriverResult result{Common::Input::DriverResult::Success}; ImuSpiCalibration spi_calibration{}; bool has_user_calibration = false; calibration = {}; - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { result = HasUserCalibration(SpiAddress::USER_IMU_MAGIC, has_user_calibration); } // Read User defined calibration - if (result == DriverResult::Success && has_user_calibration) { + if (result == Common::Input::DriverResult::Success && has_user_calibration) { result = ReadSPI(SpiAddress::USER_IMU_DATA, spi_calibration); } // Read Factory calibration - if (result == DriverResult::Success && !has_user_calibration) { + if (result == Common::Input::DriverResult::Success && !has_user_calibration) { result = ReadSPI(SpiAddress::FACT_IMU_DATA, spi_calibration); } - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { calibration.accelerometer[0].offset = spi_calibration.accelerometer_offset[0]; calibration.accelerometer[1].offset = spi_calibration.accelerometer_offset[1]; calibration.accelerometer[2].offset = spi_calibration.accelerometer_offset[2]; @@ -127,8 +130,8 @@ DriverResult CalibrationProtocol::GetImuCalibration(MotionCalibration& calibrati return result; } -DriverResult CalibrationProtocol::GetRingCalibration(RingCalibration& calibration, - s16 current_value) { +Common::Input::DriverResult CalibrationProtocol::GetRingCalibration(RingCalibration& calibration, + s16 current_value) { constexpr s16 DefaultRingRange{800}; // TODO: Get default calibration form ring itself @@ -144,15 +147,15 @@ DriverResult CalibrationProtocol::GetRingCalibration(RingCalibration& calibratio .max_value = ring_data_max, .min_value = ring_data_min, }; - return DriverResult::Success; + return Common::Input::DriverResult::Success; } -DriverResult CalibrationProtocol::HasUserCalibration(SpiAddress address, - bool& has_user_calibration) { +Common::Input::DriverResult CalibrationProtocol::HasUserCalibration(SpiAddress address, + bool& has_user_calibration) { MagicSpiCalibration spi_magic{}; - const DriverResult result{ReadSPI(address, spi_magic)}; + const Common::Input::DriverResult result{ReadSPI(address, spi_magic)}; has_user_calibration = false; - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { has_user_calibration = spi_magic.first == CalibrationMagic::USR_MAGIC_0 && spi_magic.second == CalibrationMagic::USR_MAGIC_1; } diff --git a/src/input_common/helpers/joycon_protocol/calibration.h b/src/input_common/helpers/joycon_protocol/calibration.h index c6fd0f729..82d94b366 100644 --- a/src/input_common/helpers/joycon_protocol/calibration.h +++ b/src/input_common/helpers/joycon_protocol/calibration.h @@ -12,8 +12,11 @@ #include "input_common/helpers/joycon_protocol/common_protocol.h" -namespace InputCommon::Joycon { +namespace Common::Input { enum class DriverResult; +} + +namespace InputCommon::Joycon { struct JoyStickCalibration; struct IMUCalibration; struct JoyconHandle; @@ -31,30 +34,30 @@ public: * @param is_factory_calibration if true factory values will be returned * @returns JoyStickCalibration of the left joystick */ - DriverResult GetLeftJoyStickCalibration(JoyStickCalibration& calibration); + Common::Input::DriverResult GetLeftJoyStickCalibration(JoyStickCalibration& calibration); /** * Sends a request to obtain the right stick calibration from memory * @param is_factory_calibration if true factory values will be returned * @returns JoyStickCalibration of the right joystick */ - DriverResult GetRightJoyStickCalibration(JoyStickCalibration& calibration); + Common::Input::DriverResult GetRightJoyStickCalibration(JoyStickCalibration& calibration); /** * Sends a request to obtain the motion calibration from memory * @returns ImuCalibration of the motion sensor */ - DriverResult GetImuCalibration(MotionCalibration& calibration); + Common::Input::DriverResult GetImuCalibration(MotionCalibration& calibration); /** * Calculates on run time the proper calibration of the ring controller * @returns RingCalibration of the ring sensor */ - DriverResult GetRingCalibration(RingCalibration& calibration, s16 current_value); + Common::Input::DriverResult GetRingCalibration(RingCalibration& calibration, s16 current_value); private: /// Returns true if the specified address corresponds to the magic value of user calibration - DriverResult HasUserCalibration(SpiAddress address, bool& has_user_calibration); + Common::Input::DriverResult HasUserCalibration(SpiAddress address, bool& has_user_calibration); /// Converts a raw calibration block to an u16 value containing the x axis value u16 GetXAxisCalibrationValue(std::span block) const; diff --git a/src/input_common/helpers/joycon_protocol/common_protocol.cpp b/src/input_common/helpers/joycon_protocol/common_protocol.cpp index 88f4cec1c..e10d15c18 100644 --- a/src/input_common/helpers/joycon_protocol/common_protocol.cpp +++ b/src/input_common/helpers/joycon_protocol/common_protocol.cpp @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include "common/input.h" #include "common/logging/log.h" #include "input_common/helpers/joycon_protocol/common_protocol.h" @@ -21,10 +22,10 @@ void JoyconCommonProtocol::SetNonBlocking() { SDL_hid_set_nonblocking(hidapi_handle->handle, 1); } -DriverResult JoyconCommonProtocol::GetDeviceType(ControllerType& controller_type) { +Common::Input::DriverResult JoyconCommonProtocol::GetDeviceType(ControllerType& controller_type) { const auto result = ReadSPI(SpiAddress::DEVICE_TYPE, controller_type); - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { // Fallback to 3rd party pro controllers if (controller_type == ControllerType::None) { controller_type = ControllerType::Pro; @@ -34,12 +35,13 @@ DriverResult JoyconCommonProtocol::GetDeviceType(ControllerType& controller_type return result; } -DriverResult JoyconCommonProtocol::CheckDeviceAccess(SDL_hid_device_info* device_info) { +Common::Input::DriverResult JoyconCommonProtocol::CheckDeviceAccess( + SDL_hid_device_info* device_info) { ControllerType controller_type{ControllerType::None}; const auto result = GetDeviceType(controller_type); - if (result != DriverResult::Success || controller_type == ControllerType::None) { - return DriverResult::UnsupportedControllerType; + if (result != Common::Input::DriverResult::Success || controller_type == ControllerType::None) { + return Common::Input::DriverResult::UnsupportedControllerType; } hidapi_handle->handle = @@ -48,30 +50,30 @@ DriverResult JoyconCommonProtocol::CheckDeviceAccess(SDL_hid_device_info* device if (!hidapi_handle->handle) { LOG_ERROR(Input, "Yuzu can't gain access to this device: ID {:04X}:{:04X}.", device_info->vendor_id, device_info->product_id); - return DriverResult::HandleInUse; + return Common::Input::DriverResult::HandleInUse; } SetNonBlocking(); - return DriverResult::Success; + return Common::Input::DriverResult::Success; } -DriverResult JoyconCommonProtocol::SetReportMode(ReportMode report_mode) { +Common::Input::DriverResult JoyconCommonProtocol::SetReportMode(ReportMode report_mode) { const std::array buffer{static_cast(report_mode)}; return SendSubCommand(SubCommand::SET_REPORT_MODE, buffer); } -DriverResult JoyconCommonProtocol::SendRawData(std::span buffer) { +Common::Input::DriverResult JoyconCommonProtocol::SendRawData(std::span buffer) { const auto result = SDL_hid_write(hidapi_handle->handle, buffer.data(), buffer.size()); if (result == -1) { - return DriverResult::ErrorWritingData; + return Common::Input::DriverResult::ErrorWritingData; } - return DriverResult::Success; + return Common::Input::DriverResult::Success; } -DriverResult JoyconCommonProtocol::GetSubCommandResponse(SubCommand sc, - SubCommandResponse& output) { +Common::Input::DriverResult JoyconCommonProtocol::GetSubCommandResponse( + SubCommand sc, SubCommandResponse& output) { constexpr int timeout_mili = 66; constexpr int MaxTries = 3; int tries = 0; @@ -84,16 +86,17 @@ DriverResult JoyconCommonProtocol::GetSubCommandResponse(SubCommand sc, LOG_ERROR(Input, "No response from joycon"); } if (tries++ > MaxTries) { - return DriverResult::Timeout; + return Common::Input::DriverResult::Timeout; } } while (output.input_report.report_mode != ReportMode::SUBCMD_REPLY && output.sub_command != sc); - return DriverResult::Success; + return Common::Input::DriverResult::Success; } -DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span buffer, - SubCommandResponse& output) { +Common::Input::DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, + std::span buffer, + SubCommandResponse& output) { SubCommandPacket packet{ .output_report = OutputReport::RUMBLE_AND_SUBCMD, .packet_counter = GetCounter(), @@ -102,26 +105,28 @@ DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span packet.command_data.size()) { - return DriverResult::InvalidParameters; + return Common::Input::DriverResult::InvalidParameters; } memcpy(packet.command_data.data(), buffer.data(), buffer.size()); auto result = SendData(packet); - if (result != DriverResult::Success) { + if (result != Common::Input::DriverResult::Success) { return result; } return GetSubCommandResponse(sc, output); } -DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span buffer) { +Common::Input::DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, + std::span buffer) { SubCommandResponse output{}; return SendSubCommand(sc, buffer, output); } -DriverResult JoyconCommonProtocol::SendMCUCommand(SubCommand sc, std::span buffer) { +Common::Input::DriverResult JoyconCommonProtocol::SendMCUCommand(SubCommand sc, + std::span buffer) { SubCommandPacket packet{ .output_report = OutputReport::MCU_DATA, .packet_counter = GetCounter(), @@ -130,7 +135,7 @@ DriverResult JoyconCommonProtocol::SendMCUCommand(SubCommand sc, std::span packet.command_data.size()) { - return DriverResult::InvalidParameters; + return Common::Input::DriverResult::InvalidParameters; } memcpy(packet.command_data.data(), buffer.data(), buffer.size()); @@ -138,7 +143,7 @@ DriverResult JoyconCommonProtocol::SendMCUCommand(SubCommand sc, std::span buffer) { +Common::Input::DriverResult JoyconCommonProtocol::SendVibrationReport(std::span buffer) { VibrationPacket packet{ .output_report = OutputReport::RUMBLE_ONLY, .packet_counter = GetCounter(), @@ -146,7 +151,7 @@ DriverResult JoyconCommonProtocol::SendVibrationReport(std::span buffe }; if (buffer.size() > packet.vibration_data.size()) { - return DriverResult::InvalidParameters; + return Common::Input::DriverResult::InvalidParameters; } memcpy(packet.vibration_data.data(), buffer.data(), buffer.size()); @@ -154,7 +159,8 @@ DriverResult JoyconCommonProtocol::SendVibrationReport(std::span buffe return SendData(packet); } -DriverResult JoyconCommonProtocol::ReadRawSPI(SpiAddress addr, std::span output) { +Common::Input::DriverResult JoyconCommonProtocol::ReadRawSPI(SpiAddress addr, + std::span output) { constexpr std::size_t HeaderSize = 5; constexpr std::size_t MaxTries = 5; std::size_t tries = 0; @@ -168,36 +174,36 @@ DriverResult JoyconCommonProtocol::ReadRawSPI(SpiAddress addr, std::span out memcpy(buffer.data(), &packet_data, sizeof(ReadSpiPacket)); do { const auto result = SendSubCommand(SubCommand::SPI_FLASH_READ, buffer, response); - if (result != DriverResult::Success) { + if (result != Common::Input::DriverResult::Success) { return result; } if (tries++ > MaxTries) { - return DriverResult::Timeout; + return Common::Input::DriverResult::Timeout; } } while (response.spi_address != addr); if (response.command_data.size() < packet_data.size + HeaderSize) { - return DriverResult::WrongReply; + return Common::Input::DriverResult::WrongReply; } // Remove header from output memcpy(output.data(), response.command_data.data() + HeaderSize, packet_data.size); - return DriverResult::Success; + return Common::Input::DriverResult::Success; } -DriverResult JoyconCommonProtocol::EnableMCU(bool enable) { +Common::Input::DriverResult JoyconCommonProtocol::EnableMCU(bool enable) { const std::array mcu_state{static_cast(enable ? 1 : 0)}; const auto result = SendSubCommand(SubCommand::SET_MCU_STATE, mcu_state); - if (result != DriverResult::Success) { + if (result != Common::Input::DriverResult::Success) { LOG_ERROR(Input, "Failed with error {}", result); } return result; } -DriverResult JoyconCommonProtocol::ConfigureMCU(const MCUConfig& config) { +Common::Input::DriverResult JoyconCommonProtocol::ConfigureMCU(const MCUConfig& config) { LOG_DEBUG(Input, "ConfigureMCU"); std::array config_buffer; memcpy(config_buffer.data(), &config, sizeof(MCUConfig)); @@ -205,15 +211,15 @@ DriverResult JoyconCommonProtocol::ConfigureMCU(const MCUConfig& config) { const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, config_buffer); - if (result != DriverResult::Success) { + if (result != Common::Input::DriverResult::Success) { LOG_ERROR(Input, "Failed with error {}", result); } return result; } -DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode, - MCUCommandResponse& output) { +Common::Input::DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode, + MCUCommandResponse& output) { constexpr int TimeoutMili = 200; constexpr int MaxTries = 9; int tries = 0; @@ -226,17 +232,18 @@ DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode, LOG_ERROR(Input, "No response from joycon attempt {}", tries); } if (tries++ > MaxTries) { - return DriverResult::Timeout; + return Common::Input::DriverResult::Timeout; } } while (output.input_report.report_mode != report_mode || output.mcu_report == MCUReport::EmptyAwaitingCmd); - return DriverResult::Success; + return Common::Input::DriverResult::Success; } -DriverResult JoyconCommonProtocol::SendMCUData(ReportMode report_mode, MCUSubCommand sc, - std::span buffer, - MCUCommandResponse& output) { +Common::Input::DriverResult JoyconCommonProtocol::SendMCUData(ReportMode report_mode, + MCUSubCommand sc, + std::span buffer, + MCUCommandResponse& output) { SubCommandPacket packet{ .output_report = OutputReport::MCU_DATA, .packet_counter = GetCounter(), @@ -245,23 +252,24 @@ DriverResult JoyconCommonProtocol::SendMCUData(ReportMode report_mode, MCUSubCom }; if (buffer.size() > packet.command_data.size()) { - return DriverResult::InvalidParameters; + return Common::Input::DriverResult::InvalidParameters; } memcpy(packet.command_data.data(), buffer.data(), buffer.size()); auto result = SendData(packet); - if (result != DriverResult::Success) { + if (result != Common::Input::DriverResult::Success) { return result; } result = GetMCUDataResponse(report_mode, output); - return DriverResult::Success; + return Common::Input::DriverResult::Success; } -DriverResult JoyconCommonProtocol::WaitSetMCUMode(ReportMode report_mode, MCUMode mode) { +Common::Input::DriverResult JoyconCommonProtocol::WaitSetMCUMode(ReportMode report_mode, + MCUMode mode) { MCUCommandResponse output{}; constexpr std::size_t MaxTries{16}; std::size_t tries{}; @@ -269,17 +277,17 @@ DriverResult JoyconCommonProtocol::WaitSetMCUMode(ReportMode report_mode, MCUMod do { const auto result = SendMCUData(report_mode, MCUSubCommand::SetDeviceMode, {}, output); - if (result != DriverResult::Success) { + if (result != Common::Input::DriverResult::Success) { return result; } if (tries++ > MaxTries) { - return DriverResult::WrongReply; + return Common::Input::DriverResult::WrongReply; } } while (output.mcu_report != MCUReport::StateReport || output.mcu_data[6] != static_cast(mode)); - return DriverResult::Success; + return Common::Input::DriverResult::Success; } // crc-8-ccitt / polynomial 0x07 look up table diff --git a/src/input_common/helpers/joycon_protocol/common_protocol.h b/src/input_common/helpers/joycon_protocol/common_protocol.h index 411ec018a..dd667ca2b 100644 --- a/src/input_common/helpers/joycon_protocol/common_protocol.h +++ b/src/input_common/helpers/joycon_protocol/common_protocol.h @@ -38,30 +38,30 @@ public: * Sends a request to obtain the joycon type from device * @returns controller type of the joycon */ - DriverResult GetDeviceType(ControllerType& controller_type); + Common::Input::DriverResult GetDeviceType(ControllerType& controller_type); /** * Verifies and sets the joycon_handle if device is valid * @param device info from the driver * @returns success if the device is valid */ - DriverResult CheckDeviceAccess(SDL_hid_device_info* device); + Common::Input::DriverResult CheckDeviceAccess(SDL_hid_device_info* device); /** * Sends a request to set the polling mode of the joycon * @param report_mode polling mode to be set */ - DriverResult SetReportMode(Joycon::ReportMode report_mode); + Common::Input::DriverResult SetReportMode(Joycon::ReportMode report_mode); /** * Sends data to the joycon device * @param buffer data to be send */ - DriverResult SendRawData(std::span buffer); + Common::Input::DriverResult SendRawData(std::span buffer); template requires std::is_trivially_copyable_v - DriverResult SendData(const Output& output) { + Common::Input::DriverResult SendData(const Output& output) { std::array buffer; std::memcpy(buffer.data(), &output, sizeof(Output)); return SendRawData(buffer); @@ -72,7 +72,8 @@ public: * @param sub_command type of data to be returned * @returns a buffer containing the response */ - DriverResult GetSubCommandResponse(SubCommand sub_command, SubCommandResponse& output); + Common::Input::DriverResult GetSubCommandResponse(SubCommand sub_command, + SubCommandResponse& output); /** * Sends a sub command to the device and waits for it's reply @@ -80,35 +81,35 @@ public: * @param buffer data to be send * @returns output buffer containing the response */ - DriverResult SendSubCommand(SubCommand sc, std::span buffer, - SubCommandResponse& output); + Common::Input::DriverResult SendSubCommand(SubCommand sc, std::span buffer, + SubCommandResponse& output); /** * Sends a sub command to the device and waits for it's reply and ignores the output * @param sc sub command to be send * @param buffer data to be send */ - DriverResult SendSubCommand(SubCommand sc, std::span buffer); + Common::Input::DriverResult SendSubCommand(SubCommand sc, std::span buffer); /** * Sends a mcu command to the device * @param sc sub command to be send * @param buffer data to be send */ - DriverResult SendMCUCommand(SubCommand sc, std::span buffer); + Common::Input::DriverResult SendMCUCommand(SubCommand sc, std::span buffer); /** * Sends vibration data to the joycon * @param buffer data to be send */ - DriverResult SendVibrationReport(std::span buffer); + Common::Input::DriverResult SendVibrationReport(std::span buffer); /** * Reads the SPI memory stored on the joycon * @param Initial address location * @returns output buffer containing the response */ - DriverResult ReadRawSPI(SpiAddress addr, std::span output); + Common::Input::DriverResult ReadRawSPI(SpiAddress addr, std::span output); /** * Reads the SPI memory stored on the joycon @@ -117,37 +118,38 @@ public: */ template requires std::is_trivially_copyable_v - DriverResult ReadSPI(SpiAddress addr, Output& output) { + Common::Input::DriverResult ReadSPI(SpiAddress addr, Output& output) { std::array buffer; output = {}; const auto result = ReadRawSPI(addr, buffer); - if (result != DriverResult::Success) { + if (result != Common::Input::DriverResult::Success) { return result; } std::memcpy(&output, buffer.data(), sizeof(Output)); - return DriverResult::Success; + return Common::Input::DriverResult::Success; } /** * Enables MCU chip on the joycon * @param enable if true the chip will be enabled */ - DriverResult EnableMCU(bool enable); + Common::Input::DriverResult EnableMCU(bool enable); /** * Configures the MCU to the corresponding mode * @param MCUConfig configuration */ - DriverResult ConfigureMCU(const MCUConfig& config); + Common::Input::DriverResult ConfigureMCU(const MCUConfig& config); /** * Waits until there's MCU data available. On timeout returns error * @param report mode of the expected reply * @returns a buffer containing the response */ - DriverResult GetMCUDataResponse(ReportMode report_mode_, MCUCommandResponse& output); + Common::Input::DriverResult GetMCUDataResponse(ReportMode report_mode_, + MCUCommandResponse& output); /** * Sends data to the MCU chip and waits for it's reply @@ -156,15 +158,15 @@ public: * @param buffer data to be send * @returns output buffer containing the response */ - DriverResult SendMCUData(ReportMode report_mode, MCUSubCommand sc, std::span buffer, - MCUCommandResponse& output); + Common::Input::DriverResult SendMCUData(ReportMode report_mode, MCUSubCommand sc, + std::span buffer, MCUCommandResponse& output); /** * Wait's until the MCU chip is on the specified mode * @param report mode of the expected reply * @param MCUMode configuration */ - DriverResult WaitSetMCUMode(ReportMode report_mode, MCUMode mode); + Common::Input::DriverResult WaitSetMCUMode(ReportMode report_mode, MCUMode mode); /** * Calculates the checksum from the MCU data diff --git a/src/input_common/helpers/joycon_protocol/generic_functions.cpp b/src/input_common/helpers/joycon_protocol/generic_functions.cpp index 548a4b9e3..e9a056448 100644 --- a/src/input_common/helpers/joycon_protocol/generic_functions.cpp +++ b/src/input_common/helpers/joycon_protocol/generic_functions.cpp @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include "common/input.h" #include "common/logging/log.h" #include "input_common/helpers/joycon_protocol/generic_functions.h" @@ -9,73 +10,74 @@ namespace InputCommon::Joycon { GenericProtocol::GenericProtocol(std::shared_ptr handle) : JoyconCommonProtocol(std::move(handle)) {} -DriverResult GenericProtocol::EnablePassiveMode() { +Common::Input::DriverResult GenericProtocol::EnablePassiveMode() { ScopedSetBlocking sb(this); return SetReportMode(ReportMode::SIMPLE_HID_MODE); } -DriverResult GenericProtocol::EnableActiveMode() { +Common::Input::DriverResult GenericProtocol::EnableActiveMode() { ScopedSetBlocking sb(this); return SetReportMode(ReportMode::STANDARD_FULL_60HZ); } -DriverResult GenericProtocol::SetLowPowerMode(bool enable) { +Common::Input::DriverResult GenericProtocol::SetLowPowerMode(bool enable) { ScopedSetBlocking sb(this); const std::array buffer{static_cast(enable ? 1 : 0)}; return SendSubCommand(SubCommand::LOW_POWER_MODE, buffer); } -DriverResult GenericProtocol::TriggersElapsed() { +Common::Input::DriverResult GenericProtocol::TriggersElapsed() { ScopedSetBlocking sb(this); return SendSubCommand(SubCommand::TRIGGERS_ELAPSED, {}); } -DriverResult GenericProtocol::GetDeviceInfo(DeviceInfo& device_info) { +Common::Input::DriverResult GenericProtocol::GetDeviceInfo(DeviceInfo& device_info) { ScopedSetBlocking sb(this); SubCommandResponse output{}; const auto result = SendSubCommand(SubCommand::REQ_DEV_INFO, {}, output); device_info = {}; - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { device_info = output.device_info; } return result; } -DriverResult GenericProtocol::GetControllerType(ControllerType& controller_type) { +Common::Input::DriverResult GenericProtocol::GetControllerType(ControllerType& controller_type) { return GetDeviceType(controller_type); } -DriverResult GenericProtocol::EnableImu(bool enable) { +Common::Input::DriverResult GenericProtocol::EnableImu(bool enable) { ScopedSetBlocking sb(this); const std::array buffer{static_cast(enable ? 1 : 0)}; return SendSubCommand(SubCommand::ENABLE_IMU, buffer); } -DriverResult GenericProtocol::SetImuConfig(GyroSensitivity gsen, GyroPerformance gfrec, - AccelerometerSensitivity asen, - AccelerometerPerformance afrec) { +Common::Input::DriverResult GenericProtocol::SetImuConfig(GyroSensitivity gsen, + GyroPerformance gfrec, + AccelerometerSensitivity asen, + AccelerometerPerformance afrec) { ScopedSetBlocking sb(this); const std::array buffer{static_cast(gsen), static_cast(asen), static_cast(gfrec), static_cast(afrec)}; return SendSubCommand(SubCommand::SET_IMU_SENSITIVITY, buffer); } -DriverResult GenericProtocol::GetBattery(u32& battery_level) { +Common::Input::DriverResult GenericProtocol::GetBattery(u32& battery_level) { // This function is meant to request the high resolution battery status battery_level = 0; - return DriverResult::NotSupported; + return Common::Input::DriverResult::NotSupported; } -DriverResult GenericProtocol::GetColor(Color& color) { +Common::Input::DriverResult GenericProtocol::GetColor(Color& color) { ScopedSetBlocking sb(this); std::array buffer{}; const auto result = ReadRawSPI(SpiAddress::COLOR_DATA, buffer); color = {}; - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { color.body = static_cast((buffer[0] << 16) | (buffer[1] << 8) | buffer[2]); color.buttons = static_cast((buffer[3] << 16) | (buffer[4] << 8) | buffer[5]); color.left_grip = static_cast((buffer[6] << 16) | (buffer[7] << 8) | buffer[8]); @@ -85,26 +87,26 @@ DriverResult GenericProtocol::GetColor(Color& color) { return result; } -DriverResult GenericProtocol::GetSerialNumber(SerialNumber& serial_number) { +Common::Input::DriverResult GenericProtocol::GetSerialNumber(SerialNumber& serial_number) { ScopedSetBlocking sb(this); std::array buffer{}; const auto result = ReadRawSPI(SpiAddress::SERIAL_NUMBER, buffer); serial_number = {}; - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { memcpy(serial_number.data(), buffer.data() + 1, sizeof(SerialNumber)); } return result; } -DriverResult GenericProtocol::GetTemperature(u32& temperature) { +Common::Input::DriverResult GenericProtocol::GetTemperature(u32& temperature) { // Not all devices have temperature sensor temperature = 25; - return DriverResult::NotSupported; + return Common::Input::DriverResult::NotSupported; } -DriverResult GenericProtocol::GetVersionNumber(FirmwareVersion& version) { +Common::Input::DriverResult GenericProtocol::GetVersionNumber(FirmwareVersion& version) { DeviceInfo device_info{}; const auto result = GetDeviceInfo(device_info); @@ -113,23 +115,23 @@ DriverResult GenericProtocol::GetVersionNumber(FirmwareVersion& version) { return result; } -DriverResult GenericProtocol::SetHomeLight() { +Common::Input::DriverResult GenericProtocol::SetHomeLight() { ScopedSetBlocking sb(this); static constexpr std::array buffer{0x0f, 0xf0, 0x00}; return SendSubCommand(SubCommand::SET_HOME_LIGHT, buffer); } -DriverResult GenericProtocol::SetLedBusy() { - return DriverResult::NotSupported; +Common::Input::DriverResult GenericProtocol::SetLedBusy() { + return Common::Input::DriverResult::NotSupported; } -DriverResult GenericProtocol::SetLedPattern(u8 leds) { +Common::Input::DriverResult GenericProtocol::SetLedPattern(u8 leds) { ScopedSetBlocking sb(this); const std::array buffer{leds}; return SendSubCommand(SubCommand::SET_PLAYER_LIGHTS, buffer); } -DriverResult GenericProtocol::SetLedBlinkPattern(u8 leds) { +Common::Input::DriverResult GenericProtocol::SetLedBlinkPattern(u8 leds) { return SetLedPattern(static_cast(leds << 4)); } diff --git a/src/input_common/helpers/joycon_protocol/generic_functions.h b/src/input_common/helpers/joycon_protocol/generic_functions.h index 424831e81..90fcd17f6 100644 --- a/src/input_common/helpers/joycon_protocol/generic_functions.h +++ b/src/input_common/helpers/joycon_protocol/generic_functions.h @@ -11,6 +11,10 @@ #include "input_common/helpers/joycon_protocol/common_protocol.h" #include "input_common/helpers/joycon_protocol/joycon_types.h" +namespace Common::Input { +enum class DriverResult; +} + namespace InputCommon::Joycon { /// Joycon driver functions that easily implemented @@ -20,34 +24,34 @@ public: /// Enables passive mode. This mode only sends button data on change. Sticks will return digital /// data instead of analog. Motion will be disabled - DriverResult EnablePassiveMode(); + Common::Input::DriverResult EnablePassiveMode(); /// Enables active mode. This mode will return the current status every 5-15ms - DriverResult EnableActiveMode(); + Common::Input::DriverResult EnableActiveMode(); /// Enables or disables the low power mode - DriverResult SetLowPowerMode(bool enable); + Common::Input::DriverResult SetLowPowerMode(bool enable); /// Unknown function used by the switch - DriverResult TriggersElapsed(); + Common::Input::DriverResult TriggersElapsed(); /** * Sends a request to obtain the joycon firmware and mac from handle * @returns controller device info */ - DriverResult GetDeviceInfo(DeviceInfo& controller_type); + Common::Input::DriverResult GetDeviceInfo(DeviceInfo& controller_type); /** * Sends a request to obtain the joycon type from handle * @returns controller type of the joycon */ - DriverResult GetControllerType(ControllerType& controller_type); + Common::Input::DriverResult GetControllerType(ControllerType& controller_type); /** * Enables motion input * @param enable if true motion data will be enabled */ - DriverResult EnableImu(bool enable); + Common::Input::DriverResult EnableImu(bool enable); /** * Configures the motion sensor with the specified parameters @@ -56,59 +60,60 @@ public: * @param asen accelerometer sensitivity in G force * @param afrec accelerometer frequency in hertz */ - DriverResult SetImuConfig(GyroSensitivity gsen, GyroPerformance gfrec, - AccelerometerSensitivity asen, AccelerometerPerformance afrec); + Common::Input::DriverResult SetImuConfig(GyroSensitivity gsen, GyroPerformance gfrec, + AccelerometerSensitivity asen, + AccelerometerPerformance afrec); /** * Request battery level from the device * @returns battery level */ - DriverResult GetBattery(u32& battery_level); + Common::Input::DriverResult GetBattery(u32& battery_level); /** * Request joycon colors from the device * @returns colors of the body and buttons */ - DriverResult GetColor(Color& color); + Common::Input::DriverResult GetColor(Color& color); /** * Request joycon serial number from the device * @returns 16 byte serial number */ - DriverResult GetSerialNumber(SerialNumber& serial_number); + Common::Input::DriverResult GetSerialNumber(SerialNumber& serial_number); /** * Request joycon serial number from the device * @returns 16 byte serial number */ - DriverResult GetTemperature(u32& temperature); + Common::Input::DriverResult GetTemperature(u32& temperature); /** * Request joycon serial number from the device * @returns 16 byte serial number */ - DriverResult GetVersionNumber(FirmwareVersion& version); + Common::Input::DriverResult GetVersionNumber(FirmwareVersion& version); /** * Sets home led behaviour */ - DriverResult SetHomeLight(); + Common::Input::DriverResult SetHomeLight(); /** * Sets home led into a slow breathing state */ - DriverResult SetLedBusy(); + Common::Input::DriverResult SetLedBusy(); /** * Sets the 4 player leds on the joycon on a solid state * @params bit flag containing the led state */ - DriverResult SetLedPattern(u8 leds); + Common::Input::DriverResult SetLedPattern(u8 leds); /** * Sets the 4 player leds on the joycon on a blinking state * @returns bit flag containing the led state */ - DriverResult SetLedBlinkPattern(u8 leds); + Common::Input::DriverResult SetLedBlinkPattern(u8 leds); }; } // namespace InputCommon::Joycon diff --git a/src/input_common/helpers/joycon_protocol/irs.cpp b/src/input_common/helpers/joycon_protocol/irs.cpp index 731fd5981..68b0589e3 100644 --- a/src/input_common/helpers/joycon_protocol/irs.cpp +++ b/src/input_common/helpers/joycon_protocol/irs.cpp @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include +#include "common/input.h" #include "common/logging/log.h" #include "input_common/helpers/joycon_protocol/irs.h" @@ -10,21 +10,21 @@ namespace InputCommon::Joycon { IrsProtocol::IrsProtocol(std::shared_ptr handle) : JoyconCommonProtocol(std::move(handle)) {} -DriverResult IrsProtocol::EnableIrs() { +Common::Input::DriverResult IrsProtocol::EnableIrs() { LOG_INFO(Input, "Enable IRS"); ScopedSetBlocking sb(this); - DriverResult result{DriverResult::Success}; + Common::Input::DriverResult result{Common::Input::DriverResult::Success}; - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { result = SetReportMode(ReportMode::NFC_IR_MODE_60HZ); } - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { result = EnableMCU(true); } - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::Standby); } - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { const MCUConfig config{ .command = MCUCommand::ConfigureMCU, .sub_command = MCUSubCommand::SetMCUMode, @@ -34,16 +34,16 @@ DriverResult IrsProtocol::EnableIrs() { result = ConfigureMCU(config); } - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::IR); } - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { result = ConfigureIrs(); } - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { result = WriteRegistersStep1(); } - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { result = WriteRegistersStep2(); } @@ -52,12 +52,12 @@ DriverResult IrsProtocol::EnableIrs() { return result; } -DriverResult IrsProtocol::DisableIrs() { +Common::Input::DriverResult IrsProtocol::DisableIrs() { LOG_DEBUG(Input, "Disable IRS"); ScopedSetBlocking sb(this); - DriverResult result{DriverResult::Success}; + Common::Input::DriverResult result{Common::Input::DriverResult::Success}; - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { result = EnableMCU(false); } @@ -66,7 +66,7 @@ DriverResult IrsProtocol::DisableIrs() { return result; } -DriverResult IrsProtocol::SetIrsConfig(IrsMode mode, IrsResolution format) { +Common::Input::DriverResult IrsProtocol::SetIrsConfig(IrsMode mode, IrsResolution format) { irs_mode = mode; switch (format) { case IrsResolution::Size320x240: @@ -103,10 +103,10 @@ DriverResult IrsProtocol::SetIrsConfig(IrsMode mode, IrsResolution format) { return EnableIrs(); } - return DriverResult::Success; + return Common::Input::DriverResult::Success; } -DriverResult IrsProtocol::RequestImage(std::span buffer) { +Common::Input::DriverResult IrsProtocol::RequestImage(std::span buffer) { const u8 next_packet_fragment = static_cast((packet_fragment + 1) % (static_cast(fragments) + 1)); @@ -129,7 +129,7 @@ DriverResult IrsProtocol::RequestImage(std::span buffer) { return RequestFrame(packet_fragment); } -DriverResult IrsProtocol::ConfigureIrs() { +Common::Input::DriverResult IrsProtocol::ConfigureIrs() { LOG_DEBUG(Input, "Configure IRS"); constexpr std::size_t max_tries = 28; SubCommandResponse output{}; @@ -152,20 +152,20 @@ DriverResult IrsProtocol::ConfigureIrs() { do { const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, request_data, output); - if (result != DriverResult::Success) { + if (result != Common::Input::DriverResult::Success) { return result; } if (tries++ >= max_tries) { - return DriverResult::WrongReply; + return Common::Input::DriverResult::WrongReply; } } while (output.command_data[0] != 0x0b); - return DriverResult::Success; + return Common::Input::DriverResult::Success; } -DriverResult IrsProtocol::WriteRegistersStep1() { +Common::Input::DriverResult IrsProtocol::WriteRegistersStep1() { LOG_DEBUG(Input, "WriteRegistersStep1"); - DriverResult result{DriverResult::Success}; + Common::Input::DriverResult result{Common::Input::DriverResult::Success}; constexpr std::size_t max_tries = 28; SubCommandResponse output{}; std::size_t tries = 0; @@ -197,7 +197,7 @@ DriverResult IrsProtocol::WriteRegistersStep1() { mcu_request[36] = CalculateMCU_CRC8(mcu_request.data(), 36); mcu_request[37] = 0xFF; - if (result != DriverResult::Success) { + if (result != Common::Input::DriverResult::Success) { return result; } @@ -205,26 +205,26 @@ DriverResult IrsProtocol::WriteRegistersStep1() { result = SendSubCommand(SubCommand::SET_MCU_CONFIG, request_data, output); // First time we need to set the report mode - if (result == DriverResult::Success && tries == 0) { + if (result == Common::Input::DriverResult::Success && tries == 0) { result = SendMCUCommand(SubCommand::SET_REPORT_MODE, mcu_request); } - if (result == DriverResult::Success && tries == 0) { + if (result == Common::Input::DriverResult::Success && tries == 0) { GetSubCommandResponse(SubCommand::SET_MCU_CONFIG, output); } - if (result != DriverResult::Success) { + if (result != Common::Input::DriverResult::Success) { return result; } if (tries++ >= max_tries) { - return DriverResult::WrongReply; + return Common::Input::DriverResult::WrongReply; } } while (!(output.command_data[0] == 0x13 && output.command_data[2] == 0x07) && output.command_data[0] != 0x23); - return DriverResult::Success; + return Common::Input::DriverResult::Success; } -DriverResult IrsProtocol::WriteRegistersStep2() { +Common::Input::DriverResult IrsProtocol::WriteRegistersStep2() { LOG_DEBUG(Input, "WriteRegistersStep2"); constexpr std::size_t max_tries = 28; SubCommandResponse output{}; @@ -255,18 +255,18 @@ DriverResult IrsProtocol::WriteRegistersStep2() { do { const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, request_data, output); - if (result != DriverResult::Success) { + if (result != Common::Input::DriverResult::Success) { return result; } if (tries++ >= max_tries) { - return DriverResult::WrongReply; + return Common::Input::DriverResult::WrongReply; } } while (output.command_data[0] != 0x13 && output.command_data[0] != 0x23); - return DriverResult::Success; + return Common::Input::DriverResult::Success; } -DriverResult IrsProtocol::RequestFrame(u8 frame) { +Common::Input::DriverResult IrsProtocol::RequestFrame(u8 frame) { std::array mcu_request{}; mcu_request[3] = frame; mcu_request[36] = CalculateMCU_CRC8(mcu_request.data(), 36); @@ -274,7 +274,7 @@ DriverResult IrsProtocol::RequestFrame(u8 frame) { return SendMCUCommand(SubCommand::SET_REPORT_MODE, mcu_request); } -DriverResult IrsProtocol::ResendFrame(u8 frame) { +Common::Input::DriverResult IrsProtocol::ResendFrame(u8 frame) { std::array mcu_request{}; mcu_request[1] = 0x1; mcu_request[2] = frame; diff --git a/src/input_common/helpers/joycon_protocol/irs.h b/src/input_common/helpers/joycon_protocol/irs.h index 76dfa02ea..714cbb6b2 100644 --- a/src/input_common/helpers/joycon_protocol/irs.h +++ b/src/input_common/helpers/joycon_protocol/irs.h @@ -13,19 +13,23 @@ #include "input_common/helpers/joycon_protocol/common_protocol.h" #include "input_common/helpers/joycon_protocol/joycon_types.h" +namespace Common::Input { +enum class DriverResult; +} + namespace InputCommon::Joycon { class IrsProtocol final : private JoyconCommonProtocol { public: explicit IrsProtocol(std::shared_ptr handle); - DriverResult EnableIrs(); + Common::Input::DriverResult EnableIrs(); - DriverResult DisableIrs(); + Common::Input::DriverResult DisableIrs(); - DriverResult SetIrsConfig(IrsMode mode, IrsResolution format); + Common::Input::DriverResult SetIrsConfig(IrsMode mode, IrsResolution format); - DriverResult RequestImage(std::span buffer); + Common::Input::DriverResult RequestImage(std::span buffer); std::vector GetImage() const; @@ -34,13 +38,13 @@ public: bool IsEnabled() const; private: - DriverResult ConfigureIrs(); + Common::Input::DriverResult ConfigureIrs(); - DriverResult WriteRegistersStep1(); - DriverResult WriteRegistersStep2(); + Common::Input::DriverResult WriteRegistersStep1(); + Common::Input::DriverResult WriteRegistersStep2(); - DriverResult RequestFrame(u8 frame); - DriverResult ResendFrame(u8 frame); + Common::Input::DriverResult RequestFrame(u8 frame); + Common::Input::DriverResult ResendFrame(u8 frame); IrsMode irs_mode{IrsMode::ImageTransfer}; IrsResolution resolution{IrsResolution::Size40x30}; diff --git a/src/input_common/helpers/joycon_protocol/joycon_types.h b/src/input_common/helpers/joycon_protocol/joycon_types.h index e0e431156..77a43c67a 100644 --- a/src/input_common/helpers/joycon_protocol/joycon_types.h +++ b/src/input_common/helpers/joycon_protocol/joycon_types.h @@ -402,23 +402,6 @@ enum class ExternalDeviceId : u16 { Starlink = 0x2800, }; -enum class DriverResult { - Success, - WrongReply, - Timeout, - InvalidParameters, - UnsupportedControllerType, - HandleInUse, - ErrorReadingData, - ErrorWritingData, - NoDeviceDetected, - InvalidHandle, - NotSupported, - Disabled, - Delayed, - Unknown, -}; - struct MotionSensorCalibration { s16 offset; s16 scale; diff --git a/src/input_common/helpers/joycon_protocol/nfc.cpp b/src/input_common/helpers/joycon_protocol/nfc.cpp index 261f46255..09953394b 100644 --- a/src/input_common/helpers/joycon_protocol/nfc.cpp +++ b/src/input_common/helpers/joycon_protocol/nfc.cpp @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include +#include "common/input.h" #include "common/logging/log.h" #include "input_common/helpers/joycon_protocol/nfc.h" @@ -10,21 +10,21 @@ namespace InputCommon::Joycon { NfcProtocol::NfcProtocol(std::shared_ptr handle) : JoyconCommonProtocol(std::move(handle)) {} -DriverResult NfcProtocol::EnableNfc() { +Common::Input::DriverResult NfcProtocol::EnableNfc() { LOG_INFO(Input, "Enable NFC"); ScopedSetBlocking sb(this); - DriverResult result{DriverResult::Success}; + Common::Input::DriverResult result{Common::Input::DriverResult::Success}; - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { result = SetReportMode(ReportMode::NFC_IR_MODE_60HZ); } - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { result = EnableMCU(true); } - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::Standby); } - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { const MCUConfig config{ .command = MCUCommand::ConfigureMCU, .sub_command = MCUSubCommand::SetMCUMode, @@ -34,32 +34,32 @@ DriverResult NfcProtocol::EnableNfc() { result = ConfigureMCU(config); } - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::NFC); } - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { result = WaitUntilNfcIs(NFCStatus::Ready); } - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { MCUCommandResponse output{}; result = SendStopPollingRequest(output); } - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { result = WaitUntilNfcIs(NFCStatus::Ready); } - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { is_enabled = true; } return result; } -DriverResult NfcProtocol::DisableNfc() { +Common::Input::DriverResult NfcProtocol::DisableNfc() { LOG_DEBUG(Input, "Disable NFC"); ScopedSetBlocking sb(this); - DriverResult result{DriverResult::Success}; + Common::Input::DriverResult result{Common::Input::DriverResult::Success}; - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { result = EnableMCU(false); } @@ -69,60 +69,60 @@ DriverResult NfcProtocol::DisableNfc() { return result; } -DriverResult NfcProtocol::StartNFCPollingMode() { +Common::Input::DriverResult NfcProtocol::StartNFCPollingMode() { LOG_DEBUG(Input, "Start NFC polling Mode"); ScopedSetBlocking sb(this); - DriverResult result{DriverResult::Success}; + Common::Input::DriverResult result{Common::Input::DriverResult::Success}; - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { MCUCommandResponse output{}; result = SendStartPollingRequest(output); } - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { result = WaitUntilNfcIs(NFCStatus::Polling); } - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { is_polling = true; } return result; } -DriverResult NfcProtocol::StopNFCPollingMode() { +Common::Input::DriverResult NfcProtocol::StopNFCPollingMode() { LOG_DEBUG(Input, "Stop NFC polling Mode"); ScopedSetBlocking sb(this); - DriverResult result{DriverResult::Success}; + Common::Input::DriverResult result{Common::Input::DriverResult::Success}; - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { MCUCommandResponse output{}; result = SendStopPollingRequest(output); } - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { result = WaitUntilNfcIs(NFCStatus::WriteReady); } - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { is_polling = false; } return result; } -DriverResult NfcProtocol::GetTagInfo(Joycon::TagInfo& tag_info) { +Common::Input::DriverResult NfcProtocol::GetTagInfo(Joycon::TagInfo& tag_info) { if (update_counter++ < AMIIBO_UPDATE_DELAY) { - return DriverResult::Delayed; + return Common::Input::DriverResult::Delayed; } update_counter = 0; LOG_DEBUG(Input, "Scan for amiibos"); ScopedSetBlocking sb(this); - DriverResult result{DriverResult::Success}; + Common::Input::DriverResult result{Common::Input::DriverResult::Success}; TagFoundData tag_data{}; - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { result = IsTagInRange(tag_data); } - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { tag_info = { .uuid_length = tag_data.uuid_size, .protocol = 1, @@ -147,59 +147,59 @@ DriverResult NfcProtocol::GetTagInfo(Joycon::TagInfo& tag_info) { return result; } -DriverResult NfcProtocol::ReadAmiibo(std::vector& data) { +Common::Input::DriverResult NfcProtocol::ReadAmiibo(std::vector& data) { LOG_DEBUG(Input, "Scan for amiibos"); ScopedSetBlocking sb(this); - DriverResult result{DriverResult::Success}; + Common::Input::DriverResult result{Common::Input::DriverResult::Success}; TagFoundData tag_data{}; - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { result = IsTagInRange(tag_data, 7); } - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { result = GetAmiiboData(data); } return result; } -DriverResult NfcProtocol::WriteAmiibo(std::span data) { +Common::Input::DriverResult NfcProtocol::WriteAmiibo(std::span data) { LOG_DEBUG(Input, "Write amiibo"); ScopedSetBlocking sb(this); - DriverResult result{DriverResult::Success}; + Common::Input::DriverResult result{Common::Input::DriverResult::Success}; TagUUID tag_uuid = GetTagUUID(data); TagFoundData tag_data{}; - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { result = IsTagInRange(tag_data, 7); } - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { if (tag_data.uuid != tag_uuid) { - result = DriverResult::InvalidParameters; + result = Common::Input::DriverResult::InvalidParameters; } } - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { MCUCommandResponse output{}; result = SendStopPollingRequest(output); } - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { result = WaitUntilNfcIs(NFCStatus::Ready); } - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { MCUCommandResponse output{}; result = SendStartPollingRequest(output, true); } - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { result = WaitUntilNfcIs(NFCStatus::WriteReady); } - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { result = WriteAmiiboData(tag_uuid, data); } - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { result = WaitUntilNfcIs(NFCStatus::WriteDone); } - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { MCUCommandResponse output{}; result = SendStopPollingRequest(output); } @@ -207,64 +207,65 @@ DriverResult NfcProtocol::WriteAmiibo(std::span data) { return result; } -DriverResult NfcProtocol::ReadMifare(std::span read_request, - std::span out_data) { +Common::Input::DriverResult NfcProtocol::ReadMifare(std::span read_request, + std::span out_data) { LOG_DEBUG(Input, "Read mifare"); ScopedSetBlocking sb(this); - DriverResult result{DriverResult::Success}; + Common::Input::DriverResult result{Common::Input::DriverResult::Success}; TagFoundData tag_data{}; MifareUUID tag_uuid{}; - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { result = IsTagInRange(tag_data, 7); } - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { memcpy(tag_uuid.data(), tag_data.uuid.data(), sizeof(MifareUUID)); result = GetMifareData(tag_uuid, read_request, out_data); } - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { MCUCommandResponse output{}; result = SendStopPollingRequest(output); } - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { result = WaitUntilNfcIs(NFCStatus::Ready); } - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { MCUCommandResponse output{}; result = SendStartPollingRequest(output, true); } - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { result = WaitUntilNfcIs(NFCStatus::WriteReady); } return result; } -DriverResult NfcProtocol::WriteMifare(std::span write_request) { +Common::Input::DriverResult NfcProtocol::WriteMifare( + std::span write_request) { LOG_DEBUG(Input, "Write mifare"); ScopedSetBlocking sb(this); - DriverResult result{DriverResult::Success}; + Common::Input::DriverResult result{Common::Input::DriverResult::Success}; TagFoundData tag_data{}; MifareUUID tag_uuid{}; - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { result = IsTagInRange(tag_data, 7); } - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { memcpy(tag_uuid.data(), tag_data.uuid.data(), sizeof(MifareUUID)); result = WriteMifareData(tag_uuid, write_request); } - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { MCUCommandResponse output{}; result = SendStopPollingRequest(output); } - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { result = WaitUntilNfcIs(NFCStatus::Ready); } - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { MCUCommandResponse output{}; result = SendStartPollingRequest(output, true); } - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { result = WaitUntilNfcIs(NFCStatus::WriteReady); } return result; @@ -277,17 +278,17 @@ bool NfcProtocol::HasAmiibo() { update_counter = 0; ScopedSetBlocking sb(this); - DriverResult result{DriverResult::Success}; + Common::Input::DriverResult result{Common::Input::DriverResult::Success}; TagFoundData tag_data{}; - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { result = IsTagInRange(tag_data, 7); } - return result == DriverResult::Success; + return result == Common::Input::DriverResult::Success; } -DriverResult NfcProtocol::WaitUntilNfcIs(NFCStatus status) { +Common::Input::DriverResult NfcProtocol::WaitUntilNfcIs(NFCStatus status) { constexpr std::size_t timeout_limit = 10; MCUCommandResponse output{}; std::size_t tries = 0; @@ -295,30 +296,31 @@ DriverResult NfcProtocol::WaitUntilNfcIs(NFCStatus status) { do { auto result = SendNextPackageRequest(output, {}); - if (result != DriverResult::Success) { + if (result != Common::Input::DriverResult::Success) { return result; } if (tries++ > timeout_limit) { - return DriverResult::Timeout; + return Common::Input::DriverResult::Timeout; } } while (output.mcu_report != MCUReport::NFCState || (output.mcu_data[1] << 8) + output.mcu_data[0] != 0x0500 || output.mcu_data[5] != 0x31 || output.mcu_data[6] != static_cast(status)); - return DriverResult::Success; + return Common::Input::DriverResult::Success; } -DriverResult NfcProtocol::IsTagInRange(TagFoundData& data, std::size_t timeout_limit) { +Common::Input::DriverResult NfcProtocol::IsTagInRange(TagFoundData& data, + std::size_t timeout_limit) { MCUCommandResponse output{}; std::size_t tries = 0; do { const auto result = SendNextPackageRequest(output, {}); - if (result != DriverResult::Success) { + if (result != Common::Input::DriverResult::Success) { return result; } if (tries++ > timeout_limit) { - return DriverResult::Timeout; + return Common::Input::DriverResult::Timeout; } } while (output.mcu_report != MCUReport::NFCState || (output.mcu_data[1] << 8) + output.mcu_data[0] != 0x0500 || @@ -328,10 +330,10 @@ DriverResult NfcProtocol::IsTagInRange(TagFoundData& data, std::size_t timeout_l data.uuid_size = std::min(output.mcu_data[14], static_cast(sizeof(TagUUID))); memcpy(data.uuid.data(), output.mcu_data.data() + 15, data.uuid.size()); - return DriverResult::Success; + return Common::Input::DriverResult::Success; } -DriverResult NfcProtocol::GetAmiiboData(std::vector& ntag_data) { +Common::Input::DriverResult NfcProtocol::GetAmiiboData(std::vector& ntag_data) { constexpr std::size_t timeout_limit = 60; MCUCommandResponse output{}; std::size_t tries = 0; @@ -340,7 +342,7 @@ DriverResult NfcProtocol::GetAmiiboData(std::vector& ntag_data) { std::size_t ntag_buffer_pos = 0; auto result = SendReadAmiiboRequest(output, NFCPages::Block135); - if (result != DriverResult::Success) { + if (result != Common::Input::DriverResult::Success) { return result; } @@ -349,14 +351,14 @@ DriverResult NfcProtocol::GetAmiiboData(std::vector& ntag_data) { result = SendNextPackageRequest(output, package_index); const auto nfc_status = static_cast(output.mcu_data[6]); - if (result != DriverResult::Success) { + if (result != Common::Input::DriverResult::Success) { return result; } if ((output.mcu_report == MCUReport::NFCReadData || output.mcu_report == MCUReport::NFCState) && nfc_status == NFCStatus::TagLost) { - return DriverResult::ErrorReadingData; + return Common::Input::DriverResult::ErrorReadingData; } if (output.mcu_report == MCUReport::NFCReadData && output.mcu_data[1] == 0x07) { @@ -375,14 +377,15 @@ DriverResult NfcProtocol::GetAmiiboData(std::vector& ntag_data) { if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::LastPackage) { LOG_INFO(Input, "Finished reading amiibo"); - return DriverResult::Success; + return Common::Input::DriverResult::Success; } } - return DriverResult::Timeout; + return Common::Input::DriverResult::Timeout; } -DriverResult NfcProtocol::WriteAmiiboData(const TagUUID& tag_uuid, std::span data) { +Common::Input::DriverResult NfcProtocol::WriteAmiiboData(const TagUUID& tag_uuid, + std::span data) { constexpr std::size_t timeout_limit = 60; const auto nfc_data = MakeAmiiboWritePackage(tag_uuid, data); const std::vector nfc_buffer_data = SerializeWritePackage(nfc_data); @@ -397,7 +400,7 @@ DriverResult NfcProtocol::WriteAmiiboData(const TagUUID& tag_uuid, std::span(output.mcu_data[6]); - if (result != DriverResult::Success) { + if (result != Common::Input::DriverResult::Success) { return result; } if ((output.mcu_report == MCUReport::NFCReadData || output.mcu_report == MCUReport::NFCState) && nfc_status == NFCStatus::TagLost) { - return DriverResult::ErrorReadingData; + return Common::Input::DriverResult::ErrorReadingData; } if (output.mcu_report == MCUReport::NFCReadData && output.mcu_data[1] == 0x07) { @@ -442,7 +445,7 @@ DriverResult NfcProtocol::WriteAmiiboData(const TagUUID& tag_uuid, std::span read_request, - std::span out_data) { +Common::Input::DriverResult NfcProtocol::GetMifareData( + const MifareUUID& tag_uuid, std::span read_request, + std::span out_data) { constexpr std::size_t timeout_limit = 60; const auto nfc_data = MakeMifareReadPackage(tag_uuid, read_request); const std::vector nfc_buffer_data = SerializeMifareReadPackage(nfc_data); std::span buffer(nfc_buffer_data); - DriverResult result = DriverResult::Success; + Common::Input::DriverResult result = Common::Input::DriverResult::Success; MCUCommandResponse output{}; u8 block_id = 1; u8 package_index = 0; @@ -486,7 +489,7 @@ DriverResult NfcProtocol::GetMifareData(const MifareUUID& tag_uuid, const auto nfc_status = static_cast(output.mcu_data[6]); if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) { - return DriverResult::ErrorReadingData; + return Common::Input::DriverResult::ErrorReadingData; } // Increase position when data is confirmed by the joycon @@ -498,7 +501,7 @@ DriverResult NfcProtocol::GetMifareData(const MifareUUID& tag_uuid, } } - if (result != DriverResult::Success) { + if (result != Common::Input::DriverResult::Success) { return result; } @@ -507,12 +510,12 @@ DriverResult NfcProtocol::GetMifareData(const MifareUUID& tag_uuid, result = SendNextPackageRequest(output, package_index); const auto nfc_status = static_cast(output.mcu_data[6]); - if (result != DriverResult::Success) { + if (result != Common::Input::DriverResult::Success) { return result; } if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) { - return DriverResult::ErrorReadingData; + return Common::Input::DriverResult::ErrorReadingData; } if (output.mcu_report == MCUReport::NFCState && output.mcu_data[1] == 0x10) { @@ -538,13 +541,13 @@ DriverResult NfcProtocol::GetMifareData(const MifareUUID& tag_uuid, return result; } -DriverResult NfcProtocol::WriteMifareData(const MifareUUID& tag_uuid, - std::span write_request) { +Common::Input::DriverResult NfcProtocol::WriteMifareData( + const MifareUUID& tag_uuid, std::span write_request) { constexpr std::size_t timeout_limit = 60; const auto nfc_data = MakeMifareWritePackage(tag_uuid, write_request); const std::vector nfc_buffer_data = SerializeMifareWritePackage(nfc_data); std::span buffer(nfc_buffer_data); - DriverResult result = DriverResult::Success; + Common::Input::DriverResult result = Common::Input::DriverResult::Success; MCUCommandResponse output{}; u8 block_id = 1; u8 package_index = 0; @@ -566,7 +569,7 @@ DriverResult NfcProtocol::WriteMifareData(const MifareUUID& tag_uuid, const auto nfc_status = static_cast(output.mcu_data[6]); if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) { - return DriverResult::ErrorReadingData; + return Common::Input::DriverResult::ErrorReadingData; } // Increase position when data is confirmed by the joycon @@ -578,7 +581,7 @@ DriverResult NfcProtocol::WriteMifareData(const MifareUUID& tag_uuid, } } - if (result != DriverResult::Success) { + if (result != Common::Input::DriverResult::Success) { return result; } @@ -587,12 +590,12 @@ DriverResult NfcProtocol::WriteMifareData(const MifareUUID& tag_uuid, result = SendNextPackageRequest(output, package_index); const auto nfc_status = static_cast(output.mcu_data[6]); - if (result != DriverResult::Success) { + if (result != Common::Input::DriverResult::Success) { return result; } if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) { - return DriverResult::ErrorReadingData; + return Common::Input::DriverResult::ErrorReadingData; } if (output.mcu_report == MCUReport::NFCState && output.mcu_data[1] == 0x10) { @@ -609,8 +612,8 @@ DriverResult NfcProtocol::WriteMifareData(const MifareUUID& tag_uuid, return result; } -DriverResult NfcProtocol::SendStartPollingRequest(MCUCommandResponse& output, - bool is_second_attempt) { +Common::Input::DriverResult NfcProtocol::SendStartPollingRequest(MCUCommandResponse& output, + bool is_second_attempt) { NFCRequestState request{ .command_argument = NFCCommand::StartPolling, .block_id = {}, @@ -635,7 +638,7 @@ DriverResult NfcProtocol::SendStartPollingRequest(MCUCommandResponse& output, output); } -DriverResult NfcProtocol::SendStopPollingRequest(MCUCommandResponse& output) { +Common::Input::DriverResult NfcProtocol::SendStopPollingRequest(MCUCommandResponse& output) { NFCRequestState request{ .command_argument = NFCCommand::StopPolling, .block_id = {}, @@ -653,7 +656,8 @@ DriverResult NfcProtocol::SendStopPollingRequest(MCUCommandResponse& output) { output); } -DriverResult NfcProtocol::SendNextPackageRequest(MCUCommandResponse& output, u8 packet_id) { +Common::Input::DriverResult NfcProtocol::SendNextPackageRequest(MCUCommandResponse& output, + u8 packet_id) { NFCRequestState request{ .command_argument = NFCCommand::StartWaitingRecieve, .block_id = {}, @@ -671,7 +675,8 @@ DriverResult NfcProtocol::SendNextPackageRequest(MCUCommandResponse& output, u8 output); } -DriverResult NfcProtocol::SendReadAmiiboRequest(MCUCommandResponse& output, NFCPages ntag_pages) { +Common::Input::DriverResult NfcProtocol::SendReadAmiiboRequest(MCUCommandResponse& output, + NFCPages ntag_pages) { NFCRequestState request{ .command_argument = NFCCommand::ReadNtag, .block_id = {}, @@ -696,8 +701,8 @@ DriverResult NfcProtocol::SendReadAmiiboRequest(MCUCommandResponse& output, NFCP output); } -DriverResult NfcProtocol::SendWriteAmiiboRequest(MCUCommandResponse& output, - const TagUUID& tag_uuid) { +Common::Input::DriverResult NfcProtocol::SendWriteAmiiboRequest(MCUCommandResponse& output, + const TagUUID& tag_uuid) { NFCRequestState request{ .command_argument = NFCCommand::ReadNtag, .block_id = {}, @@ -722,9 +727,10 @@ DriverResult NfcProtocol::SendWriteAmiiboRequest(MCUCommandResponse& output, output); } -DriverResult NfcProtocol::SendWriteDataAmiiboRequest(MCUCommandResponse& output, u8 block_id, - bool is_last_packet, - std::span data) { +Common::Input::DriverResult NfcProtocol::SendWriteDataAmiiboRequest(MCUCommandResponse& output, + u8 block_id, + bool is_last_packet, + std::span data) { const auto data_size = std::min(data.size(), sizeof(NFCRequestState::raw_data)); NFCRequestState request{ .command_argument = NFCCommand::WriteNtag, @@ -745,8 +751,9 @@ DriverResult NfcProtocol::SendWriteDataAmiiboRequest(MCUCommandResponse& output, output); } -DriverResult NfcProtocol::SendReadDataMifareRequest(MCUCommandResponse& output, u8 block_id, - bool is_last_packet, std::span data) { +Common::Input::DriverResult NfcProtocol::SendReadDataMifareRequest(MCUCommandResponse& output, + u8 block_id, bool is_last_packet, + std::span data) { const auto data_size = std::min(data.size(), sizeof(NFCRequestState::raw_data)); NFCRequestState request{ .command_argument = NFCCommand::Mifare, diff --git a/src/input_common/helpers/joycon_protocol/nfc.h b/src/input_common/helpers/joycon_protocol/nfc.h index 0be95e40e..22db95170 100644 --- a/src/input_common/helpers/joycon_protocol/nfc.h +++ b/src/input_common/helpers/joycon_protocol/nfc.h @@ -13,30 +13,34 @@ #include "input_common/helpers/joycon_protocol/common_protocol.h" #include "input_common/helpers/joycon_protocol/joycon_types.h" +namespace Common::Input { +enum class DriverResult; +} + namespace InputCommon::Joycon { class NfcProtocol final : private JoyconCommonProtocol { public: explicit NfcProtocol(std::shared_ptr handle); - DriverResult EnableNfc(); + Common::Input::DriverResult EnableNfc(); - DriverResult DisableNfc(); + Common::Input::DriverResult DisableNfc(); - DriverResult StartNFCPollingMode(); + Common::Input::DriverResult StartNFCPollingMode(); - DriverResult StopNFCPollingMode(); + Common::Input::DriverResult StopNFCPollingMode(); - DriverResult GetTagInfo(Joycon::TagInfo& tag_info); + Common::Input::DriverResult GetTagInfo(Joycon::TagInfo& tag_info); - DriverResult ReadAmiibo(std::vector& data); + Common::Input::DriverResult ReadAmiibo(std::vector& data); - DriverResult WriteAmiibo(std::span data); + Common::Input::DriverResult WriteAmiibo(std::span data); - DriverResult ReadMifare(std::span read_request, - std::span out_data); + Common::Input::DriverResult ReadMifare(std::span read_request, + std::span out_data); - DriverResult WriteMifare(std::span write_request); + Common::Input::DriverResult WriteMifare(std::span write_request); bool HasAmiibo(); @@ -54,37 +58,41 @@ private: TagUUID uuid; }; - DriverResult WaitUntilNfcIs(NFCStatus status); + Common::Input::DriverResult WaitUntilNfcIs(NFCStatus status); - DriverResult IsTagInRange(TagFoundData& data, std::size_t timeout_limit = 1); + Common::Input::DriverResult IsTagInRange(TagFoundData& data, std::size_t timeout_limit = 1); - DriverResult GetAmiiboData(std::vector& data); + Common::Input::DriverResult GetAmiiboData(std::vector& data); - DriverResult WriteAmiiboData(const TagUUID& tag_uuid, std::span data); + Common::Input::DriverResult WriteAmiiboData(const TagUUID& tag_uuid, std::span data); - DriverResult GetMifareData(const MifareUUID& tag_uuid, - std::span read_request, - std::span out_data); + Common::Input::DriverResult GetMifareData(const MifareUUID& tag_uuid, + std::span read_request, + std::span out_data); - DriverResult WriteMifareData(const MifareUUID& tag_uuid, - std::span write_request); + Common::Input::DriverResult WriteMifareData(const MifareUUID& tag_uuid, + std::span write_request); - DriverResult SendStartPollingRequest(MCUCommandResponse& output, - bool is_second_attempt = false); + Common::Input::DriverResult SendStartPollingRequest(MCUCommandResponse& output, + bool is_second_attempt = false); - DriverResult SendStopPollingRequest(MCUCommandResponse& output); + Common::Input::DriverResult SendStopPollingRequest(MCUCommandResponse& output); - DriverResult SendNextPackageRequest(MCUCommandResponse& output, u8 packet_id); + Common::Input::DriverResult SendNextPackageRequest(MCUCommandResponse& output, u8 packet_id); - DriverResult SendReadAmiiboRequest(MCUCommandResponse& output, NFCPages ntag_pages); + Common::Input::DriverResult SendReadAmiiboRequest(MCUCommandResponse& output, + NFCPages ntag_pages); - DriverResult SendWriteAmiiboRequest(MCUCommandResponse& output, const TagUUID& tag_uuid); + Common::Input::DriverResult SendWriteAmiiboRequest(MCUCommandResponse& output, + const TagUUID& tag_uuid); - DriverResult SendWriteDataAmiiboRequest(MCUCommandResponse& output, u8 block_id, - bool is_last_packet, std::span data); + Common::Input::DriverResult SendWriteDataAmiiboRequest(MCUCommandResponse& output, u8 block_id, + bool is_last_packet, + std::span data); - DriverResult SendReadDataMifareRequest(MCUCommandResponse& output, u8 block_id, - bool is_last_packet, std::span data); + Common::Input::DriverResult SendReadDataMifareRequest(MCUCommandResponse& output, u8 block_id, + bool is_last_packet, + std::span data); std::vector SerializeWritePackage(const NFCWritePackage& package) const; diff --git a/src/input_common/helpers/joycon_protocol/ringcon.cpp b/src/input_common/helpers/joycon_protocol/ringcon.cpp index 190cef812..f31ff6b34 100644 --- a/src/input_common/helpers/joycon_protocol/ringcon.cpp +++ b/src/input_common/helpers/joycon_protocol/ringcon.cpp @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include "common/input.h" #include "common/logging/log.h" #include "input_common/helpers/joycon_protocol/ringcon.h" @@ -9,18 +10,18 @@ namespace InputCommon::Joycon { RingConProtocol::RingConProtocol(std::shared_ptr handle) : JoyconCommonProtocol(std::move(handle)) {} -DriverResult RingConProtocol::EnableRingCon() { +Common::Input::DriverResult RingConProtocol::EnableRingCon() { LOG_DEBUG(Input, "Enable Ringcon"); ScopedSetBlocking sb(this); - DriverResult result{DriverResult::Success}; + Common::Input::DriverResult result{Common::Input::DriverResult::Success}; - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { result = SetReportMode(ReportMode::STANDARD_FULL_60HZ); } - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { result = EnableMCU(true); } - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { const MCUConfig config{ .command = MCUCommand::ConfigureMCU, .sub_command = MCUSubCommand::SetDeviceMode, @@ -33,12 +34,12 @@ DriverResult RingConProtocol::EnableRingCon() { return result; } -DriverResult RingConProtocol::DisableRingCon() { +Common::Input::DriverResult RingConProtocol::DisableRingCon() { LOG_DEBUG(Input, "Disable RingCon"); ScopedSetBlocking sb(this); - DriverResult result{DriverResult::Success}; + Common::Input::DriverResult result{Common::Input::DriverResult::Success}; - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { result = EnableMCU(false); } @@ -47,27 +48,27 @@ DriverResult RingConProtocol::DisableRingCon() { return result; } -DriverResult RingConProtocol::StartRingconPolling() { +Common::Input::DriverResult RingConProtocol::StartRingconPolling() { LOG_DEBUG(Input, "Enable Ringcon"); ScopedSetBlocking sb(this); - DriverResult result{DriverResult::Success}; + Common::Input::DriverResult result{Common::Input::DriverResult::Success}; bool is_connected = false; - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { result = IsRingConnected(is_connected); } - if (result == DriverResult::Success && is_connected) { + if (result == Common::Input::DriverResult::Success && is_connected) { LOG_INFO(Input, "Ringcon detected"); result = ConfigureRing(); } - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { is_enabled = true; } return result; } -DriverResult RingConProtocol::IsRingConnected(bool& is_connected) { +Common::Input::DriverResult RingConProtocol::IsRingConnected(bool& is_connected) { LOG_DEBUG(Input, "IsRingConnected"); constexpr std::size_t max_tries = 28; SubCommandResponse output{}; @@ -77,20 +78,20 @@ DriverResult RingConProtocol::IsRingConnected(bool& is_connected) { do { const auto result = SendSubCommand(SubCommand::GET_EXTERNAL_DEVICE_INFO, {}, output); - if (result != DriverResult::Success) { + if (result != Common::Input::DriverResult::Success) { return result; } if (tries++ >= max_tries) { - return DriverResult::NoDeviceDetected; + return Common::Input::DriverResult::NoDeviceDetected; } } while (output.external_device_id != ExternalDeviceId::RingController); is_connected = true; - return DriverResult::Success; + return Common::Input::DriverResult::Success; } -DriverResult RingConProtocol::ConfigureRing() { +Common::Input::DriverResult RingConProtocol::ConfigureRing() { LOG_DEBUG(Input, "ConfigureRing"); static constexpr std::array ring_config{ @@ -98,9 +99,10 @@ DriverResult RingConProtocol::ConfigureRing() { 0x00, 0x00, 0x00, 0x0A, 0x64, 0x0B, 0xE6, 0xA9, 0x22, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0xA8, 0xE1, 0x34, 0x36}; - const DriverResult result = SendSubCommand(SubCommand::SET_EXTERNAL_FORMAT_CONFIG, ring_config); + const Common::Input::DriverResult result = + SendSubCommand(SubCommand::SET_EXTERNAL_FORMAT_CONFIG, ring_config); - if (result != DriverResult::Success) { + if (result != Common::Input::DriverResult::Success) { return result; } diff --git a/src/input_common/helpers/joycon_protocol/ringcon.h b/src/input_common/helpers/joycon_protocol/ringcon.h index 6e858f3fc..9f0888de3 100644 --- a/src/input_common/helpers/joycon_protocol/ringcon.h +++ b/src/input_common/helpers/joycon_protocol/ringcon.h @@ -13,24 +13,28 @@ #include "input_common/helpers/joycon_protocol/common_protocol.h" #include "input_common/helpers/joycon_protocol/joycon_types.h" +namespace Common::Input { +enum class DriverResult; +} + namespace InputCommon::Joycon { class RingConProtocol final : private JoyconCommonProtocol { public: explicit RingConProtocol(std::shared_ptr handle); - DriverResult EnableRingCon(); + Common::Input::DriverResult EnableRingCon(); - DriverResult DisableRingCon(); + Common::Input::DriverResult DisableRingCon(); - DriverResult StartRingconPolling(); + Common::Input::DriverResult StartRingconPolling(); bool IsEnabled() const; private: - DriverResult IsRingConnected(bool& is_connected); + Common::Input::DriverResult IsRingConnected(bool& is_connected); - DriverResult ConfigureRing(); + Common::Input::DriverResult ConfigureRing(); bool is_enabled{}; }; diff --git a/src/input_common/helpers/joycon_protocol/rumble.cpp b/src/input_common/helpers/joycon_protocol/rumble.cpp index 63b60c946..7647f505e 100644 --- a/src/input_common/helpers/joycon_protocol/rumble.cpp +++ b/src/input_common/helpers/joycon_protocol/rumble.cpp @@ -4,6 +4,7 @@ #include #include +#include "common/input.h" #include "common/logging/log.h" #include "input_common/helpers/joycon_protocol/rumble.h" @@ -12,14 +13,14 @@ namespace InputCommon::Joycon { RumbleProtocol::RumbleProtocol(std::shared_ptr handle) : JoyconCommonProtocol(std::move(handle)) {} -DriverResult RumbleProtocol::EnableRumble(bool is_enabled) { +Common::Input::DriverResult RumbleProtocol::EnableRumble(bool is_enabled) { LOG_DEBUG(Input, "Enable Rumble"); ScopedSetBlocking sb(this); const std::array buffer{static_cast(is_enabled ? 1 : 0)}; return SendSubCommand(SubCommand::ENABLE_VIBRATION, buffer); } -DriverResult RumbleProtocol::SendVibration(const VibrationValue& vibration) { +Common::Input::DriverResult RumbleProtocol::SendVibration(const VibrationValue& vibration) { std::array buffer{}; if (vibration.high_amplitude <= 0.0f && vibration.low_amplitude <= 0.0f) { diff --git a/src/input_common/helpers/joycon_protocol/rumble.h b/src/input_common/helpers/joycon_protocol/rumble.h index 6c12b7925..5e50e531a 100644 --- a/src/input_common/helpers/joycon_protocol/rumble.h +++ b/src/input_common/helpers/joycon_protocol/rumble.h @@ -13,15 +13,19 @@ #include "input_common/helpers/joycon_protocol/common_protocol.h" #include "input_common/helpers/joycon_protocol/joycon_types.h" +namespace Common::Input { +enum class DriverResult; +} + namespace InputCommon::Joycon { class RumbleProtocol final : private JoyconCommonProtocol { public: explicit RumbleProtocol(std::shared_ptr handle); - DriverResult EnableRumble(bool is_enabled); + Common::Input::DriverResult EnableRumble(bool is_enabled); - DriverResult SendVibration(const VibrationValue& vibration); + Common::Input::DriverResult SendVibration(const VibrationValue& vibration); private: u16 EncodeHighFrequency(f32 frequency) const; diff --git a/src/yuzu/configuration/configure_ringcon.cpp b/src/yuzu/configuration/configure_ringcon.cpp index 71afbc423..f83705544 100644 --- a/src/yuzu/configuration/configure_ringcon.cpp +++ b/src/yuzu/configuration/configure_ringcon.cpp @@ -305,6 +305,9 @@ void ConfigureRingController::EnableRingController() { QMessageBox::warning(this, dialog_title, tr("The current mapped device doesn't have a ring attached")); break; + case Common::Input::DriverResult::InvalidHandle: + QMessageBox::warning(this, dialog_title, tr("The current mapped device is not connected")); + break; default: QMessageBox::warning(this, dialog_title, tr("Unexpected driver result %1").arg(static_cast(result))); -- cgit v1.2.3 From b76b698c173a58d19b7e7425768b6402ef68023e Mon Sep 17 00:00:00 2001 From: Charles Lombardo Date: Wed, 28 Jun 2023 16:15:18 -0400 Subject: android: Android 14 support Specifies the permissions needed for the changes to foreground services in Android 14. --- src/android/app/build.gradle.kts | 4 ++-- src/android/app/src/main/AndroidManifest.xml | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/android/app/build.gradle.kts b/src/android/app/build.gradle.kts index bab4f4d0f..9a47e2bd8 100644 --- a/src/android/app/build.gradle.kts +++ b/src/android/app/build.gradle.kts @@ -26,7 +26,7 @@ val autoVersion = (((System.currentTimeMillis() / 1000) - 1451606400) / 10).toIn android { namespace = "org.yuzu.yuzu_emu" - compileSdkVersion = "android-33" + compileSdkVersion = "android-34" ndkVersion = "25.2.9519653" buildFeatures { @@ -51,7 +51,7 @@ android { // TODO If this is ever modified, change application_id in strings.xml applicationId = "org.yuzu.yuzu_emu" minSdk = 30 - targetSdk = 33 + targetSdk = 34 versionName = getGitVersion() // If you want to use autoVersion for the versionCode, create a property in local.properties diff --git a/src/android/app/src/main/AndroidManifest.xml b/src/android/app/src/main/AndroidManifest.xml index e31ad69e2..51d949d65 100644 --- a/src/android/app/src/main/AndroidManifest.xml +++ b/src/android/app/src/main/AndroidManifest.xml @@ -13,6 +13,7 @@ SPDX-License-Identifier: GPL-3.0-or-later + @@ -69,7 +70,9 @@ SPDX-License-Identifier: GPL-3.0-or-later android:resource="@xml/nfc_tech_filter" /> - + + + Date: Wed, 28 Jun 2023 20:10:27 -0300 Subject: Blacklist EDS3 blending from new AMD drivers --- src/video_core/vulkan_common/vulkan_device.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src') diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 70436cf1c..421e71e5a 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -528,6 +528,14 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR } sets_per_pool = 64; + if (extensions.extended_dynamic_state3 && is_amd_driver && + properties.properties.driverVersion >= VK_MAKE_API_VERSION(0, 2, 0, 270)) { + LOG_WARNING(Render_Vulkan, + "AMD drivers after 23.5.2 have broken extendedDynamicState3ColorBlendEquation"); + features.extended_dynamic_state3.extendedDynamicState3ColorBlendEnable = false; + features.extended_dynamic_state3.extendedDynamicState3ColorBlendEquation = false; + dynamic_state3_blending = false; + } if (is_amd_driver) { // AMD drivers need a higher amount of Sets per Pool in certain circumstances like in XC2. sets_per_pool = 96; -- cgit v1.2.3 From ac755476cdaa8bace9c86183125d34dbe4c8cee9 Mon Sep 17 00:00:00 2001 From: german77 Date: Wed, 28 Jun 2023 08:38:45 -0600 Subject: input_common: Allow timeouts to happen while scanning for a ring --- src/input_common/helpers/joycon_protocol/common_protocol.cpp | 2 +- src/input_common/helpers/joycon_protocol/ringcon.cpp | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/input_common/helpers/joycon_protocol/common_protocol.cpp b/src/input_common/helpers/joycon_protocol/common_protocol.cpp index e10d15c18..a6eecf980 100644 --- a/src/input_common/helpers/joycon_protocol/common_protocol.cpp +++ b/src/input_common/helpers/joycon_protocol/common_protocol.cpp @@ -75,7 +75,7 @@ Common::Input::DriverResult JoyconCommonProtocol::SendRawData(std::span Date: Thu, 29 Jun 2023 11:58:45 +0200 Subject: Texture cache: Fix YFC regression due to code testing --- src/video_core/texture_cache/texture_cache.h | 9 --------- 1 file changed, 9 deletions(-) (limited to 'src') diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index d3f03a995..485f6b6f3 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -598,14 +598,6 @@ void TextureCache

::UnmapGPUMemory(size_t as_id, GPUVAddr gpu_addr, size_t siz [&](ImageId id, Image&) { deleted_images.push_back(id); }); for (const ImageId id : deleted_images) { Image& image = slot_images[id]; - if (True(image.flags & ImageFlagBits::CpuModified)) { - return; - } - image.flags |= ImageFlagBits::CpuModified; - if (True(image.flags & ImageFlagBits::Tracked)) { - UntrackImage(image, id); - } - /* if (True(image.flags & ImageFlagBits::Remapped)) { continue; } @@ -613,7 +605,6 @@ void TextureCache

::UnmapGPUMemory(size_t as_id, GPUVAddr gpu_addr, size_t siz if (True(image.flags & ImageFlagBits::Tracked)) { UntrackImage(image, id); } - */ } } -- cgit v1.2.3 From 13506e7782d2f8e5704d0369819bdae37c9b31af Mon Sep 17 00:00:00 2001 From: Abandoned Cart Date: Thu, 29 Jun 2023 07:19:44 -0400 Subject: android: Suppress a known incompatibility Android Gradle plugin 8.0.2 is designed for API 33, but a newer plugin hasn't been released yet. The warning message is rather extravagant, but also suggests adding this property if you are aware of the risks. --- src/android/gradle.properties | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/android/gradle.properties b/src/android/gradle.properties index e2f278f33..4fca1b576 100644 --- a/src/android/gradle.properties +++ b/src/android/gradle.properties @@ -15,3 +15,6 @@ android.useAndroidX=true kotlin.code.style=official kotlin.parallel.tasks.in.project=true android.defaults.buildfeatures.buildconfig=true + +# Android Gradle plugin 8.0.2 +android.suppressUnsupportedCompileSdk=34 -- cgit v1.2.3 From 596a6132b974dd73935854d8f51842424e058be8 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Thu, 29 Jun 2023 17:23:29 +0200 Subject: AccelerateDMA: Don't accelerate 3D texture DMA operations --- src/video_core/texture_cache/texture_cache.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index d3f03a995..0330415b7 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -879,6 +879,10 @@ ImageId TextureCache

::DmaImageId(const Tegra::DMA::ImageOperand& operand, boo return NULL_IMAGE_ID; } auto& image = slot_images[image_id]; + if (image.info.type == ImageType::e3D) { + // Don't accelerate 3D images. + return NULL_IMAGE_ID; + } if (!is_upload && !image.info.dma_downloaded) { // Force a full sync. image.info.dma_downloaded = true; -- cgit v1.2.3