summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/android/gradle.properties3
-rw-r--r--src/audio_core/sink/sink_stream.cpp34
-rw-r--r--src/audio_core/sink/sink_stream.h3
-rw-r--r--src/common/input.h2
-rw-r--r--src/common/ring_buffer.h2
-rw-r--r--src/common/scratch_buffer.h46
-rw-r--r--src/common/settings.h10
-rw-r--r--src/common/telemetry.cpp1
-rw-r--r--src/common/x64/cpu_detect.cpp1
-rw-r--r--src/common/x64/cpu_detect.h1
-rw-r--r--src/common/x64/cpu_wait.cpp52
-rw-r--r--src/core/core.cpp32
-rw-r--r--src/core/core.h11
-rw-r--r--src/core/file_sys/fsmitm_romfsbuild.cpp38
-rw-r--r--src/core/gpu_dirty_memory_manager.h122
-rw-r--r--src/core/hle/service/audio/audin_u.cpp16
-rw-r--r--src/core/hle/service/audio/audout_u.cpp20
-rw-r--r--src/core/hle/service/audio/audren_u.cpp23
-rw-r--r--src/core/hle/service/audio/hwopus.cpp9
-rw-r--r--src/core/hle/service/nvdrv/nvdrv_interface.cpp25
-rw-r--r--src/core/hle/service/nvdrv/nvdrv_interface.h5
-rw-r--r--src/core/hle/service/nvnflinger/parcel.h24
-rw-r--r--src/core/memory.cpp40
-rw-r--r--src/core/memory.h6
-rw-r--r--src/input_common/drivers/joycon.cpp35
-rw-r--r--src/input_common/drivers/joycon.h3
-rw-r--r--src/input_common/drivers/mouse.cpp86
-rw-r--r--src/input_common/drivers/mouse.h2
-rw-r--r--src/input_common/helpers/joycon_driver.cpp129
-rw-r--r--src/input_common/helpers/joycon_driver.h48
-rw-r--r--src/input_common/helpers/joycon_protocol/calibration.cpp53
-rw-r--r--src/input_common/helpers/joycon_protocol/calibration.h15
-rw-r--r--src/input_common/helpers/joycon_protocol/common_protocol.cpp104
-rw-r--r--src/input_common/helpers/joycon_protocol/common_protocol.h44
-rw-r--r--src/input_common/helpers/joycon_protocol/generic_functions.cpp52
-rw-r--r--src/input_common/helpers/joycon_protocol/generic_functions.h41
-rw-r--r--src/input_common/helpers/joycon_protocol/irs.cpp70
-rw-r--r--src/input_common/helpers/joycon_protocol/irs.h22
-rw-r--r--src/input_common/helpers/joycon_protocol/joycon_types.h17
-rw-r--r--src/input_common/helpers/joycon_protocol/nfc.cpp231
-rw-r--r--src/input_common/helpers/joycon_protocol/nfc.h66
-rw-r--r--src/input_common/helpers/joycon_protocol/ringcon.cpp45
-rw-r--r--src/input_common/helpers/joycon_protocol/ringcon.h14
-rw-r--r--src/input_common/helpers/joycon_protocol/rumble.cpp5
-rw-r--r--src/input_common/helpers/joycon_protocol/rumble.h8
-rw-r--r--src/video_core/buffer_cache/buffer_cache.h39
-rw-r--r--src/video_core/buffer_cache/buffer_cache_base.h5
-rw-r--r--src/video_core/engines/maxwell_dma.cpp7
-rw-r--r--src/video_core/fence_manager.h2
-rw-r--r--src/video_core/gpu.cpp12
-rw-r--r--src/video_core/gpu.h4
-rw-r--r--src/video_core/gpu_thread.cpp6
-rw-r--r--src/video_core/host1x/codecs/codec.cpp2
-rw-r--r--src/video_core/host1x/codecs/h264.cpp14
-rw-r--r--src/video_core/host1x/codecs/h264.h12
-rw-r--r--src/video_core/host1x/codecs/vp8.cpp2
-rw-r--r--src/video_core/host1x/codecs/vp8.h7
-rw-r--r--src/video_core/host1x/codecs/vp9.cpp1
-rw-r--r--src/video_core/host1x/codecs/vp9.h8
-rw-r--r--src/video_core/host1x/codecs/vp9_types.h1
-rw-r--r--src/video_core/rasterizer_interface.h4
-rw-r--r--src/video_core/renderer_null/null_rasterizer.cpp5
-rw-r--r--src/video_core/renderer_null/null_rasterizer.h3
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp35
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h3
-rw-r--r--src/video_core/renderer_vulkan/vk_buffer_cache.cpp3
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp34
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.h3
-rw-r--r--src/video_core/shader_cache.cpp2
-rw-r--r--src/video_core/shader_cache.h2
-rw-r--r--src/video_core/texture_cache/texture_cache.h25
-rw-r--r--src/video_core/vulkan_common/vulkan_device.cpp8
-rw-r--r--src/video_core/vulkan_common/vulkan_instance.cpp6
-rw-r--r--src/video_core/vulkan_common/vulkan_surface.cpp17
-rw-r--r--src/video_core/vulkan_common/vulkan_wrapper.h2
-rw-r--r--src/yuzu/configuration/config.cpp6
-rw-r--r--src/yuzu/configuration/configure_input_player.ui15
-rw-r--r--src/yuzu/configuration/configure_mouse_panning.cpp49
-rw-r--r--src/yuzu/configuration/configure_mouse_panning.ui36
-rw-r--r--src/yuzu/configuration/configure_ringcon.cpp3
-rw-r--r--src/yuzu/qt_common.cpp9
-rw-r--r--src/yuzu/vk_device_info.cpp5
82 files changed, 1192 insertions, 821 deletions
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
15kotlin.code.style=official 15kotlin.code.style=official
16kotlin.parallel.tasks.in.project=true 16kotlin.parallel.tasks.in.project=true
17android.defaults.buildfeatures.buildconfig=true 17android.defaults.buildfeatures.buildconfig=true
18
19# Android Gradle plugin 8.0.2
20android.suppressUnsupportedCompileSdk=34
diff --git a/src/audio_core/sink/sink_stream.cpp b/src/audio_core/sink/sink_stream.cpp
index 404dcd0e9..6081352a2 100644
--- a/src/audio_core/sink/sink_stream.cpp
+++ b/src/audio_core/sink/sink_stream.cpp
@@ -12,6 +12,7 @@
12#include "audio_core/sink/sink_stream.h" 12#include "audio_core/sink/sink_stream.h"
13#include "common/common_types.h" 13#include "common/common_types.h"
14#include "common/fixed_point.h" 14#include "common/fixed_point.h"
15#include "common/scope_exit.h"
15#include "common/settings.h" 16#include "common/settings.h"
16#include "core/core.h" 17#include "core/core.h"
17#include "core/core_timing.h" 18#include "core/core_timing.h"
@@ -19,9 +20,12 @@
19namespace AudioCore::Sink { 20namespace AudioCore::Sink {
20 21
21void SinkStream::AppendBuffer(SinkBuffer& buffer, std::span<s16> samples) { 22void SinkStream::AppendBuffer(SinkBuffer& buffer, std::span<s16> samples) {
22 if (type == StreamType::In) { 23 SCOPE_EXIT({
23 queue.enqueue(buffer); 24 queue.enqueue(buffer);
24 queued_buffers++; 25 ++queued_buffers;
26 });
27
28 if (type == StreamType::In) {
25 return; 29 return;
26 } 30 }
27 31
@@ -66,16 +70,17 @@ void SinkStream::AppendBuffer(SinkBuffer& buffer, std::span<s16> samples) {
66 static_cast<s16>(std::clamp(right_sample, min, max)); 70 static_cast<s16>(std::clamp(right_sample, min, max));
67 } 71 }
68 72
69 samples = samples.subspan(0, samples.size() / system_channels * device_channels); 73 samples_buffer.Push(samples.subspan(0, samples.size() / system_channels * device_channels));
74 return;
75 }
70 76
71 } else if (system_channels == 2 && device_channels == 6) { 77 if (system_channels == 2 && device_channels == 6) {
72 // We need moar samples! Not all games will provide 6 channel audio. 78 // We need moar samples! Not all games will provide 6 channel audio.
73 // TODO: Implement some upmixing here. Currently just passthrough, with other 79 // TODO: Implement some upmixing here. Currently just passthrough, with other
74 // channels left as silence. 80 // channels left as silence.
75 auto new_size = samples.size() / system_channels * device_channels; 81 std::vector<s16> new_samples(samples.size() / system_channels * device_channels);
76 tmp_samples.resize_destructive(new_size);
77 82
78 for (u32 read_index = 0, write_index = 0; read_index < new_size; 83 for (u32 read_index = 0, write_index = 0; read_index < samples.size();
79 read_index += system_channels, write_index += device_channels) { 84 read_index += system_channels, write_index += device_channels) {
80 const auto left_sample{static_cast<s16>(std::clamp( 85 const auto left_sample{static_cast<s16>(std::clamp(
81 static_cast<s32>( 86 static_cast<s32>(
@@ -83,7 +88,7 @@ void SinkStream::AppendBuffer(SinkBuffer& buffer, std::span<s16> samples) {
83 volume), 88 volume),
84 min, max))}; 89 min, max))};
85 90
86 tmp_samples[write_index + static_cast<u32>(Channels::FrontLeft)] = left_sample; 91 new_samples[write_index + static_cast<u32>(Channels::FrontLeft)] = left_sample;
87 92
88 const auto right_sample{static_cast<s16>(std::clamp( 93 const auto right_sample{static_cast<s16>(std::clamp(
89 static_cast<s32>( 94 static_cast<s32>(
@@ -91,20 +96,21 @@ void SinkStream::AppendBuffer(SinkBuffer& buffer, std::span<s16> samples) {
91 volume), 96 volume),
92 min, max))}; 97 min, max))};
93 98
94 tmp_samples[write_index + static_cast<u32>(Channels::FrontRight)] = right_sample; 99 new_samples[write_index + static_cast<u32>(Channels::FrontRight)] = right_sample;
95 } 100 }
96 samples = std::span<s16>(tmp_samples);
97 101
98 } else if (volume != 1.0f) { 102 samples_buffer.Push(new_samples);
99 for (u32 i = 0; i < samples.size(); i++) { 103 return;
104 }
105
106 if (volume != 1.0f) {
107 for (u32 i = 0; i < samples.size(); ++i) {
100 samples[i] = static_cast<s16>( 108 samples[i] = static_cast<s16>(
101 std::clamp(static_cast<s32>(static_cast<f32>(samples[i]) * volume), min, max)); 109 std::clamp(static_cast<s32>(static_cast<f32>(samples[i]) * volume), min, max));
102 } 110 }
103 } 111 }
104 112
105 samples_buffer.Push(samples); 113 samples_buffer.Push(samples);
106 queue.enqueue(buffer);
107 queued_buffers++;
108} 114}
109 115
110std::vector<s16> SinkStream::ReleaseBuffer(u64 num_samples) { 116std::vector<s16> SinkStream::ReleaseBuffer(u64 num_samples) {
diff --git a/src/audio_core/sink/sink_stream.h b/src/audio_core/sink/sink_stream.h
index 98d72ace1..6a4996ca3 100644
--- a/src/audio_core/sink/sink_stream.h
+++ b/src/audio_core/sink/sink_stream.h
@@ -16,7 +16,6 @@
16#include "common/polyfill_thread.h" 16#include "common/polyfill_thread.h"
17#include "common/reader_writer_queue.h" 17#include "common/reader_writer_queue.h"
18#include "common/ring_buffer.h" 18#include "common/ring_buffer.h"
19#include "common/scratch_buffer.h"
20#include "common/thread.h" 19#include "common/thread.h"
21 20
22namespace Core { 21namespace Core {
@@ -256,8 +255,6 @@ private:
256 /// Signalled when ring buffer entries are consumed 255 /// Signalled when ring buffer entries are consumed
257 std::condition_variable_any release_cv; 256 std::condition_variable_any release_cv;
258 std::mutex release_mutex; 257 std::mutex release_mutex;
259 /// Temporary buffer for appending samples when upmixing
260 Common::ScratchBuffer<s16> tmp_samples{};
261}; 258};
262 259
263using SinkStreamPtr = std::unique_ptr<SinkStream>; 260using SinkStreamPtr = std::unique_ptr<SinkStream>;
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 {
75 ErrorWritingData, 75 ErrorWritingData,
76 NoDeviceDetected, 76 NoDeviceDetected,
77 InvalidHandle, 77 InvalidHandle,
78 InvalidParameters,
78 NotSupported, 79 NotSupported,
79 Disabled, 80 Disabled,
81 Delayed,
80 Unknown, 82 Unknown,
81}; 83};
82 84
diff --git a/src/common/ring_buffer.h b/src/common/ring_buffer.h
index 416680d44..5c961b202 100644
--- a/src/common/ring_buffer.h
+++ b/src/common/ring_buffer.h
@@ -54,7 +54,7 @@ public:
54 return push_count; 54 return push_count;
55 } 55 }
56 56
57 std::size_t Push(const std::span<T> input) { 57 std::size_t Push(std::span<const T> input) {
58 return Push(input.data(), input.size()); 58 return Push(input.data(), input.size());
59 } 59 }
60 60
diff --git a/src/common/scratch_buffer.h b/src/common/scratch_buffer.h
index 6fe907953..d5961b020 100644
--- a/src/common/scratch_buffer.h
+++ b/src/common/scratch_buffer.h
@@ -5,7 +5,6 @@
5 5
6#include <iterator> 6#include <iterator>
7 7
8#include "common/concepts.h"
9#include "common/make_unique_for_overwrite.h" 8#include "common/make_unique_for_overwrite.h"
10 9
11namespace Common { 10namespace Common {
@@ -19,15 +18,22 @@ namespace Common {
19template <typename T> 18template <typename T>
20class ScratchBuffer { 19class ScratchBuffer {
21public: 20public:
22 using iterator = T*;
23 using const_iterator = const T*;
24 using value_type = T;
25 using element_type = T; 21 using element_type = T;
26 using iterator_category = std::contiguous_iterator_tag; 22 using value_type = T;
23 using size_type = size_t;
24 using difference_type = std::ptrdiff_t;
25 using pointer = T*;
26 using const_pointer = const T*;
27 using reference = T&;
28 using const_reference = const T&;
29 using iterator = pointer;
30 using const_iterator = const_pointer;
31 using iterator_category = std::random_access_iterator_tag;
32 using iterator_concept = std::contiguous_iterator_tag;
27 33
28 ScratchBuffer() = default; 34 ScratchBuffer() = default;
29 35
30 explicit ScratchBuffer(size_t initial_capacity) 36 explicit ScratchBuffer(size_type initial_capacity)
31 : last_requested_size{initial_capacity}, buffer_capacity{initial_capacity}, 37 : last_requested_size{initial_capacity}, buffer_capacity{initial_capacity},
32 buffer{Common::make_unique_for_overwrite<T[]>(initial_capacity)} {} 38 buffer{Common::make_unique_for_overwrite<T[]>(initial_capacity)} {}
33 39
@@ -39,7 +45,7 @@ public:
39 45
40 /// This will only grow the buffer's capacity if size is greater than the current capacity. 46 /// This will only grow the buffer's capacity if size is greater than the current capacity.
41 /// The previously held data will remain intact. 47 /// The previously held data will remain intact.
42 void resize(size_t size) { 48 void resize(size_type size) {
43 if (size > buffer_capacity) { 49 if (size > buffer_capacity) {
44 auto new_buffer = Common::make_unique_for_overwrite<T[]>(size); 50 auto new_buffer = Common::make_unique_for_overwrite<T[]>(size);
45 std::move(buffer.get(), buffer.get() + buffer_capacity, new_buffer.get()); 51 std::move(buffer.get(), buffer.get() + buffer_capacity, new_buffer.get());
@@ -51,7 +57,7 @@ public:
51 57
52 /// This will only grow the buffer's capacity if size is greater than the current capacity. 58 /// This will only grow the buffer's capacity if size is greater than the current capacity.
53 /// The previously held data will be destroyed if a reallocation occurs. 59 /// The previously held data will be destroyed if a reallocation occurs.
54 void resize_destructive(size_t size) { 60 void resize_destructive(size_type size) {
55 if (size > buffer_capacity) { 61 if (size > buffer_capacity) {
56 buffer_capacity = size; 62 buffer_capacity = size;
57 buffer = Common::make_unique_for_overwrite<T[]>(buffer_capacity); 63 buffer = Common::make_unique_for_overwrite<T[]>(buffer_capacity);
@@ -59,43 +65,43 @@ public:
59 last_requested_size = size; 65 last_requested_size = size;
60 } 66 }
61 67
62 [[nodiscard]] T* data() noexcept { 68 [[nodiscard]] pointer data() noexcept {
63 return buffer.get(); 69 return buffer.get();
64 } 70 }
65 71
66 [[nodiscard]] const T* data() const noexcept { 72 [[nodiscard]] const_pointer data() const noexcept {
67 return buffer.get(); 73 return buffer.get();
68 } 74 }
69 75
70 [[nodiscard]] T* begin() noexcept { 76 [[nodiscard]] iterator begin() noexcept {
71 return data(); 77 return data();
72 } 78 }
73 79
74 [[nodiscard]] const T* begin() const noexcept { 80 [[nodiscard]] const_iterator begin() const noexcept {
75 return data(); 81 return data();
76 } 82 }
77 83
78 [[nodiscard]] T* end() noexcept { 84 [[nodiscard]] iterator end() noexcept {
79 return data() + last_requested_size; 85 return data() + last_requested_size;
80 } 86 }
81 87
82 [[nodiscard]] const T* end() const noexcept { 88 [[nodiscard]] const_iterator end() const noexcept {
83 return data() + last_requested_size; 89 return data() + last_requested_size;
84 } 90 }
85 91
86 [[nodiscard]] T& operator[](size_t i) { 92 [[nodiscard]] reference operator[](size_type i) {
87 return buffer[i]; 93 return buffer[i];
88 } 94 }
89 95
90 [[nodiscard]] const T& operator[](size_t i) const { 96 [[nodiscard]] const_reference operator[](size_type i) const {
91 return buffer[i]; 97 return buffer[i];
92 } 98 }
93 99
94 [[nodiscard]] size_t size() const noexcept { 100 [[nodiscard]] size_type size() const noexcept {
95 return last_requested_size; 101 return last_requested_size;
96 } 102 }
97 103
98 [[nodiscard]] size_t capacity() const noexcept { 104 [[nodiscard]] size_type capacity() const noexcept {
99 return buffer_capacity; 105 return buffer_capacity;
100 } 106 }
101 107
@@ -106,8 +112,8 @@ public:
106 } 112 }
107 113
108private: 114private:
109 size_t last_requested_size{}; 115 size_type last_requested_size{};
110 size_t buffer_capacity{}; 116 size_type buffer_capacity{};
111 std::unique_ptr<T[]> buffer{}; 117 std::unique_ptr<T[]> buffer{};
112}; 118};
113 119
diff --git a/src/common/settings.h b/src/common/settings.h
index ae5ed93d8..59e96e74f 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -527,12 +527,10 @@ struct Values {
527 Setting<bool> mouse_panning{false, "mouse_panning"}; 527 Setting<bool> mouse_panning{false, "mouse_panning"};
528 Setting<u8, true> mouse_panning_x_sensitivity{50, 1, 100, "mouse_panning_x_sensitivity"}; 528 Setting<u8, true> mouse_panning_x_sensitivity{50, 1, 100, "mouse_panning_x_sensitivity"};
529 Setting<u8, true> mouse_panning_y_sensitivity{50, 1, 100, "mouse_panning_y_sensitivity"}; 529 Setting<u8, true> mouse_panning_y_sensitivity{50, 1, 100, "mouse_panning_y_sensitivity"};
530 Setting<u8, true> mouse_panning_deadzone_x_counterweight{ 530 Setting<u8, true> mouse_panning_deadzone_counterweight{20, 0, 100,
531 0, 0, 100, "mouse_panning_deadzone_x_counterweight"}; 531 "mouse_panning_deadzone_counterweight"};
532 Setting<u8, true> mouse_panning_deadzone_y_counterweight{ 532 Setting<u8, true> mouse_panning_decay_strength{18, 0, 100, "mouse_panning_decay_strength"};
533 0, 0, 100, "mouse_panning_deadzone_y_counterweight"}; 533 Setting<u8, true> mouse_panning_min_decay{6, 0, 100, "mouse_panning_min_decay"};
534 Setting<u8, true> mouse_panning_decay_strength{22, 0, 100, "mouse_panning_decay_strength"};
535 Setting<u8, true> mouse_panning_min_decay{5, 0, 100, "mouse_panning_min_decay"};
536 534
537 Setting<bool> mouse_enabled{false, "mouse_enabled"}; 535 Setting<bool> mouse_enabled{false, "mouse_enabled"};
538 Setting<bool> emulate_analog_keyboard{false, "emulate_analog_keyboard"}; 536 Setting<bool> emulate_analog_keyboard{false, "emulate_analog_keyboard"};
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) {
93 add_field("CPU_Extension_x64_GFNI", caps.gfni); 93 add_field("CPU_Extension_x64_GFNI", caps.gfni);
94 add_field("CPU_Extension_x64_INVARIANT_TSC", caps.invariant_tsc); 94 add_field("CPU_Extension_x64_INVARIANT_TSC", caps.invariant_tsc);
95 add_field("CPU_Extension_x64_LZCNT", caps.lzcnt); 95 add_field("CPU_Extension_x64_LZCNT", caps.lzcnt);
96 add_field("CPU_Extension_x64_MONITORX", caps.monitorx);
96 add_field("CPU_Extension_x64_MOVBE", caps.movbe); 97 add_field("CPU_Extension_x64_MOVBE", caps.movbe);
97 add_field("CPU_Extension_x64_PCLMULQDQ", caps.pclmulqdq); 98 add_field("CPU_Extension_x64_PCLMULQDQ", caps.pclmulqdq);
98 add_field("CPU_Extension_x64_POPCNT", caps.popcnt); 99 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() {
168 __cpuid(cpu_id, 0x80000001); 168 __cpuid(cpu_id, 0x80000001);
169 caps.lzcnt = Common::Bit<5>(cpu_id[2]); 169 caps.lzcnt = Common::Bit<5>(cpu_id[2]);
170 caps.fma4 = Common::Bit<16>(cpu_id[2]); 170 caps.fma4 = Common::Bit<16>(cpu_id[2]);
171 caps.monitorx = Common::Bit<29>(cpu_id[2]);
171 } 172 }
172 173
173 if (max_ex_fn >= 0x80000007) { 174 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 {
63 bool gfni : 1; 63 bool gfni : 1;
64 bool invariant_tsc : 1; 64 bool invariant_tsc : 1;
65 bool lzcnt : 1; 65 bool lzcnt : 1;
66 bool monitorx : 1;
66 bool movbe : 1; 67 bool movbe : 1;
67 bool pclmulqdq : 1; 68 bool pclmulqdq : 1;
68 bool popcnt : 1; 69 bool popcnt : 1;
diff --git a/src/common/x64/cpu_wait.cpp b/src/common/x64/cpu_wait.cpp
index c53dd4945..41d385f59 100644
--- a/src/common/x64/cpu_wait.cpp
+++ b/src/common/x64/cpu_wait.cpp
@@ -13,36 +13,60 @@
13 13
14namespace Common::X64 { 14namespace Common::X64 {
15 15
16namespace {
17
18// 100,000 cycles is a reasonable amount of time to wait to save on CPU resources.
19// For reference:
20// At 1 GHz, 100K cycles is 100us
21// At 2 GHz, 100K cycles is 50us
22// At 4 GHz, 100K cycles is 25us
23constexpr auto PauseCycles = 100'000U;
24
25} // Anonymous namespace
26
16#ifdef _MSC_VER 27#ifdef _MSC_VER
17__forceinline static void TPAUSE() { 28__forceinline static void TPAUSE() {
18 // 100,000 cycles is a reasonable amount of time to wait to save on CPU resources. 29 static constexpr auto RequestC02State = 0U;
19 // For reference: 30 _tpause(RequestC02State, FencedRDTSC() + PauseCycles);
20 // At 1 GHz, 100K cycles is 100us 31}
21 // At 2 GHz, 100K cycles is 50us 32
22 // At 4 GHz, 100K cycles is 25us 33__forceinline static void MWAITX() {
23 static constexpr auto PauseCycles = 100'000; 34 static constexpr auto EnableWaitTimeFlag = 1U << 1;
24 _tpause(0, FencedRDTSC() + PauseCycles); 35 static constexpr auto RequestC1State = 0U;
36
37 // monitor_var should be aligned to a cache line.
38 alignas(64) u64 monitor_var{};
39 _mm_monitorx(&monitor_var, 0, 0);
40 _mm_mwaitx(EnableWaitTimeFlag, RequestC1State, PauseCycles);
25} 41}
26#else 42#else
27static void TPAUSE() { 43static void TPAUSE() {
28 // 100,000 cycles is a reasonable amount of time to wait to save on CPU resources. 44 static constexpr auto RequestC02State = 0U;
29 // For reference:
30 // At 1 GHz, 100K cycles is 100us
31 // At 2 GHz, 100K cycles is 50us
32 // At 4 GHz, 100K cycles is 25us
33 static constexpr auto PauseCycles = 100'000;
34 const auto tsc = FencedRDTSC() + PauseCycles; 45 const auto tsc = FencedRDTSC() + PauseCycles;
35 const auto eax = static_cast<u32>(tsc & 0xFFFFFFFF); 46 const auto eax = static_cast<u32>(tsc & 0xFFFFFFFF);
36 const auto edx = static_cast<u32>(tsc >> 32); 47 const auto edx = static_cast<u32>(tsc >> 32);
37 asm volatile("tpause %0" : : "r"(0), "d"(edx), "a"(eax)); 48 asm volatile("tpause %0" : : "r"(RequestC02State), "d"(edx), "a"(eax));
49}
50
51static void MWAITX() {
52 static constexpr auto EnableWaitTimeFlag = 1U << 1;
53 static constexpr auto RequestC1State = 0U;
54
55 // monitor_var should be aligned to a cache line.
56 alignas(64) u64 monitor_var{};
57 asm volatile("monitorx" : : "a"(&monitor_var), "c"(0), "d"(0));
58 asm volatile("mwaitx" : : "a"(RequestC1State), "b"(PauseCycles), "c"(EnableWaitTimeFlag));
38} 59}
39#endif 60#endif
40 61
41void MicroSleep() { 62void MicroSleep() {
42 static const bool has_waitpkg = GetCPUCaps().waitpkg; 63 static const bool has_waitpkg = GetCPUCaps().waitpkg;
64 static const bool has_monitorx = GetCPUCaps().monitorx;
43 65
44 if (has_waitpkg) { 66 if (has_waitpkg) {
45 TPAUSE(); 67 TPAUSE();
68 } else if (has_monitorx) {
69 MWAITX();
46 } else { 70 } else {
47 std::this_thread::yield(); 71 std::this_thread::yield();
48 } 72 }
diff --git a/src/core/core.cpp b/src/core/core.cpp
index b74fd0a58..9e3eb3795 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -27,6 +27,7 @@
27#include "core/file_sys/savedata_factory.h" 27#include "core/file_sys/savedata_factory.h"
28#include "core/file_sys/vfs_concat.h" 28#include "core/file_sys/vfs_concat.h"
29#include "core/file_sys/vfs_real.h" 29#include "core/file_sys/vfs_real.h"
30#include "core/gpu_dirty_memory_manager.h"
30#include "core/hid/hid_core.h" 31#include "core/hid/hid_core.h"
31#include "core/hle/kernel/k_memory_manager.h" 32#include "core/hle/kernel/k_memory_manager.h"
32#include "core/hle/kernel/k_process.h" 33#include "core/hle/kernel/k_process.h"
@@ -130,7 +131,10 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
130struct System::Impl { 131struct System::Impl {
131 explicit Impl(System& system) 132 explicit Impl(System& system)
132 : kernel{system}, fs_controller{system}, memory{system}, hid_core{}, room_network{}, 133 : kernel{system}, fs_controller{system}, memory{system}, hid_core{}, room_network{},
133 cpu_manager{system}, reporter{system}, applet_manager{system}, time_manager{system} {} 134 cpu_manager{system}, reporter{system}, applet_manager{system}, time_manager{system},
135 gpu_dirty_memory_write_manager{} {
136 memory.SetGPUDirtyManagers(gpu_dirty_memory_write_manager);
137 }
134 138
135 void Initialize(System& system) { 139 void Initialize(System& system) {
136 device_memory = std::make_unique<Core::DeviceMemory>(); 140 device_memory = std::make_unique<Core::DeviceMemory>();
@@ -234,6 +238,8 @@ struct System::Impl {
234 // Setting changes may require a full system reinitialization (e.g., disabling multicore). 238 // Setting changes may require a full system reinitialization (e.g., disabling multicore).
235 ReinitializeIfNecessary(system); 239 ReinitializeIfNecessary(system);
236 240
241 memory.SetGPUDirtyManagers(gpu_dirty_memory_write_manager);
242
237 kernel.Initialize(); 243 kernel.Initialize();
238 cpu_manager.Initialize(); 244 cpu_manager.Initialize();
239 245
@@ -540,6 +546,9 @@ struct System::Impl {
540 546
541 std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{}; 547 std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{};
542 std::array<MicroProfileToken, Core::Hardware::NUM_CPU_CORES> microprofile_cpu{}; 548 std::array<MicroProfileToken, Core::Hardware::NUM_CPU_CORES> microprofile_cpu{};
549
550 std::array<Core::GPUDirtyMemoryManager, Core::Hardware::NUM_CPU_CORES>
551 gpu_dirty_memory_write_manager{};
543}; 552};
544 553
545System::System() : impl{std::make_unique<Impl>(*this)} {} 554System::System() : impl{std::make_unique<Impl>(*this)} {}
@@ -629,10 +638,31 @@ void System::PrepareReschedule(const u32 core_index) {
629 impl->kernel.PrepareReschedule(core_index); 638 impl->kernel.PrepareReschedule(core_index);
630} 639}
631 640
641Core::GPUDirtyMemoryManager& System::CurrentGPUDirtyMemoryManager() {
642 const std::size_t core = impl->kernel.GetCurrentHostThreadID();
643 return impl->gpu_dirty_memory_write_manager[core < Core::Hardware::NUM_CPU_CORES
644 ? core
645 : Core::Hardware::NUM_CPU_CORES - 1];
646}
647
648/// Provides a constant reference to the current gou dirty memory manager.
649const Core::GPUDirtyMemoryManager& System::CurrentGPUDirtyMemoryManager() const {
650 const std::size_t core = impl->kernel.GetCurrentHostThreadID();
651 return impl->gpu_dirty_memory_write_manager[core < Core::Hardware::NUM_CPU_CORES
652 ? core
653 : Core::Hardware::NUM_CPU_CORES - 1];
654}
655
632size_t System::GetCurrentHostThreadID() const { 656size_t System::GetCurrentHostThreadID() const {
633 return impl->kernel.GetCurrentHostThreadID(); 657 return impl->kernel.GetCurrentHostThreadID();
634} 658}
635 659
660void System::GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback) {
661 for (auto& manager : impl->gpu_dirty_memory_write_manager) {
662 manager.Gather(callback);
663 }
664}
665
636PerfStatsResults System::GetAndResetPerfStats() { 666PerfStatsResults System::GetAndResetPerfStats() {
637 return impl->GetAndResetPerfStats(); 667 return impl->GetAndResetPerfStats();
638} 668}
diff --git a/src/core/core.h b/src/core/core.h
index 93afc9303..14b2f7785 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -108,9 +108,10 @@ class CpuManager;
108class Debugger; 108class Debugger;
109class DeviceMemory; 109class DeviceMemory;
110class ExclusiveMonitor; 110class ExclusiveMonitor;
111class SpeedLimiter; 111class GPUDirtyMemoryManager;
112class PerfStats; 112class PerfStats;
113class Reporter; 113class Reporter;
114class SpeedLimiter;
114class TelemetrySession; 115class TelemetrySession;
115 116
116struct PerfStatsResults; 117struct PerfStatsResults;
@@ -225,6 +226,14 @@ public:
225 /// Prepare the core emulation for a reschedule 226 /// Prepare the core emulation for a reschedule
226 void PrepareReschedule(u32 core_index); 227 void PrepareReschedule(u32 core_index);
227 228
229 /// Provides a reference to the gou dirty memory manager.
230 [[nodiscard]] Core::GPUDirtyMemoryManager& CurrentGPUDirtyMemoryManager();
231
232 /// Provides a constant reference to the current gou dirty memory manager.
233 [[nodiscard]] const Core::GPUDirtyMemoryManager& CurrentGPUDirtyMemoryManager() const;
234
235 void GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback);
236
228 [[nodiscard]] size_t GetCurrentHostThreadID() const; 237 [[nodiscard]] size_t GetCurrentHostThreadID() const;
229 238
230 /// Gets and resets core performance statistics 239 /// Gets and resets core performance statistics
diff --git a/src/core/file_sys/fsmitm_romfsbuild.cpp b/src/core/file_sys/fsmitm_romfsbuild.cpp
index 1ff83c08c..e39c7b62b 100644
--- a/src/core/file_sys/fsmitm_romfsbuild.cpp
+++ b/src/core/file_sys/fsmitm_romfsbuild.cpp
@@ -105,19 +105,11 @@ static u64 romfs_get_hash_table_count(u64 num_entries) {
105 return count; 105 return count;
106} 106}
107 107
108void RomFSBuildContext::VisitDirectory(VirtualDir root_romfs, VirtualDir ext_dir, 108void RomFSBuildContext::VisitDirectory(VirtualDir romfs_dir, VirtualDir ext_dir,
109 std::shared_ptr<RomFSBuildDirectoryContext> parent) { 109 std::shared_ptr<RomFSBuildDirectoryContext> parent) {
110 std::vector<std::shared_ptr<RomFSBuildDirectoryContext>> child_dirs; 110 std::vector<std::shared_ptr<RomFSBuildDirectoryContext>> child_dirs;
111 111
112 VirtualDir dir; 112 const auto entries = romfs_dir->GetEntries();
113
114 if (parent->path_len == 0) {
115 dir = root_romfs;
116 } else {
117 dir = root_romfs->GetDirectoryRelative(parent->path);
118 }
119
120 const auto entries = dir->GetEntries();
121 113
122 for (const auto& kv : entries) { 114 for (const auto& kv : entries) {
123 if (kv.second == VfsEntryType::Directory) { 115 if (kv.second == VfsEntryType::Directory) {
@@ -127,7 +119,7 @@ void RomFSBuildContext::VisitDirectory(VirtualDir root_romfs, VirtualDir ext_dir
127 child->path_len = child->cur_path_ofs + static_cast<u32>(kv.first.size()); 119 child->path_len = child->cur_path_ofs + static_cast<u32>(kv.first.size());
128 child->path = parent->path + "/" + kv.first; 120 child->path = parent->path + "/" + kv.first;
129 121
130 if (ext_dir != nullptr && ext_dir->GetFileRelative(child->path + ".stub") != nullptr) { 122 if (ext_dir != nullptr && ext_dir->GetFile(kv.first + ".stub") != nullptr) {
131 continue; 123 continue;
132 } 124 }
133 125
@@ -144,17 +136,17 @@ void RomFSBuildContext::VisitDirectory(VirtualDir root_romfs, VirtualDir ext_dir
144 child->path_len = child->cur_path_ofs + static_cast<u32>(kv.first.size()); 136 child->path_len = child->cur_path_ofs + static_cast<u32>(kv.first.size());
145 child->path = parent->path + "/" + kv.first; 137 child->path = parent->path + "/" + kv.first;
146 138
147 if (ext_dir != nullptr && ext_dir->GetFileRelative(child->path + ".stub") != nullptr) { 139 if (ext_dir != nullptr && ext_dir->GetFile(kv.first + ".stub") != nullptr) {
148 continue; 140 continue;
149 } 141 }
150 142
151 // Sanity check on path_len 143 // Sanity check on path_len
152 ASSERT(child->path_len < FS_MAX_PATH); 144 ASSERT(child->path_len < FS_MAX_PATH);
153 145
154 child->source = root_romfs->GetFileRelative(child->path); 146 child->source = romfs_dir->GetFile(kv.first);
155 147
156 if (ext_dir != nullptr) { 148 if (ext_dir != nullptr) {
157 if (const auto ips = ext_dir->GetFileRelative(child->path + ".ips")) { 149 if (const auto ips = ext_dir->GetFile(kv.first + ".ips")) {
158 if (auto patched = PatchIPS(child->source, ips)) { 150 if (auto patched = PatchIPS(child->source, ips)) {
159 child->source = std::move(patched); 151 child->source = std::move(patched);
160 } 152 }
@@ -168,23 +160,27 @@ void RomFSBuildContext::VisitDirectory(VirtualDir root_romfs, VirtualDir ext_dir
168 } 160 }
169 161
170 for (auto& child : child_dirs) { 162 for (auto& child : child_dirs) {
171 this->VisitDirectory(root_romfs, ext_dir, child); 163 auto subdir_name = std::string_view(child->path).substr(child->cur_path_ofs);
164 auto child_romfs_dir = romfs_dir->GetSubdirectory(subdir_name);
165 auto child_ext_dir = ext_dir != nullptr ? ext_dir->GetSubdirectory(subdir_name) : nullptr;
166 this->VisitDirectory(child_romfs_dir, child_ext_dir, child);
172 } 167 }
173} 168}
174 169
175bool RomFSBuildContext::AddDirectory(std::shared_ptr<RomFSBuildDirectoryContext> parent_dir_ctx, 170bool RomFSBuildContext::AddDirectory(std::shared_ptr<RomFSBuildDirectoryContext> parent_dir_ctx,
176 std::shared_ptr<RomFSBuildDirectoryContext> dir_ctx) { 171 std::shared_ptr<RomFSBuildDirectoryContext> dir_ctx) {
177 // Check whether it's already in the known directories. 172 // Check whether it's already in the known directories.
178 const auto existing = directories.find(dir_ctx->path); 173 const auto [it, is_new] = directories.emplace(dir_ctx->path, nullptr);
179 if (existing != directories.end()) 174 if (!is_new) {
180 return false; 175 return false;
176 }
181 177
182 // Add a new directory. 178 // Add a new directory.
183 num_dirs++; 179 num_dirs++;
184 dir_table_size += 180 dir_table_size +=
185 sizeof(RomFSDirectoryEntry) + Common::AlignUp(dir_ctx->path_len - dir_ctx->cur_path_ofs, 4); 181 sizeof(RomFSDirectoryEntry) + Common::AlignUp(dir_ctx->path_len - dir_ctx->cur_path_ofs, 4);
186 dir_ctx->parent = parent_dir_ctx; 182 dir_ctx->parent = parent_dir_ctx;
187 directories.emplace(dir_ctx->path, dir_ctx); 183 it->second = dir_ctx;
188 184
189 return true; 185 return true;
190} 186}
@@ -192,8 +188,8 @@ bool RomFSBuildContext::AddDirectory(std::shared_ptr<RomFSBuildDirectoryContext>
192bool RomFSBuildContext::AddFile(std::shared_ptr<RomFSBuildDirectoryContext> parent_dir_ctx, 188bool RomFSBuildContext::AddFile(std::shared_ptr<RomFSBuildDirectoryContext> parent_dir_ctx,
193 std::shared_ptr<RomFSBuildFileContext> file_ctx) { 189 std::shared_ptr<RomFSBuildFileContext> file_ctx) {
194 // Check whether it's already in the known files. 190 // Check whether it's already in the known files.
195 const auto existing = files.find(file_ctx->path); 191 const auto [it, is_new] = files.emplace(file_ctx->path, nullptr);
196 if (existing != files.end()) { 192 if (!is_new) {
197 return false; 193 return false;
198 } 194 }
199 195
@@ -202,7 +198,7 @@ bool RomFSBuildContext::AddFile(std::shared_ptr<RomFSBuildDirectoryContext> pare
202 file_table_size += 198 file_table_size +=
203 sizeof(RomFSFileEntry) + Common::AlignUp(file_ctx->path_len - file_ctx->cur_path_ofs, 4); 199 sizeof(RomFSFileEntry) + Common::AlignUp(file_ctx->path_len - file_ctx->cur_path_ofs, 4);
204 file_ctx->parent = parent_dir_ctx; 200 file_ctx->parent = parent_dir_ctx;
205 files.emplace(file_ctx->path, file_ctx); 201 it->second = file_ctx;
206 202
207 return true; 203 return true;
208} 204}
diff --git a/src/core/gpu_dirty_memory_manager.h b/src/core/gpu_dirty_memory_manager.h
new file mode 100644
index 000000000..9687531e8
--- /dev/null
+++ b/src/core/gpu_dirty_memory_manager.h
@@ -0,0 +1,122 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include <atomic>
7#include <bit>
8#include <functional>
9#include <mutex>
10#include <utility>
11#include <vector>
12
13#include "core/memory.h"
14
15namespace Core {
16
17class GPUDirtyMemoryManager {
18public:
19 GPUDirtyMemoryManager() : current{default_transform} {
20 back_buffer.reserve(256);
21 front_buffer.reserve(256);
22 }
23
24 ~GPUDirtyMemoryManager() = default;
25
26 void Collect(VAddr address, size_t size) {
27 TransformAddress t = BuildTransform(address, size);
28 TransformAddress tmp, original;
29 do {
30 tmp = current.load(std::memory_order_acquire);
31 original = tmp;
32 if (tmp.address != t.address) {
33 if (IsValid(tmp.address)) {
34 std::scoped_lock lk(guard);
35 back_buffer.emplace_back(tmp);
36 current.exchange(t, std::memory_order_relaxed);
37 return;
38 }
39 tmp.address = t.address;
40 tmp.mask = 0;
41 }
42 if ((tmp.mask | t.mask) == tmp.mask) {
43 return;
44 }
45 tmp.mask |= t.mask;
46 } while (!current.compare_exchange_weak(original, tmp, std::memory_order_release,
47 std::memory_order_relaxed));
48 }
49
50 void Gather(std::function<void(VAddr, size_t)>& callback) {
51 {
52 std::scoped_lock lk(guard);
53 TransformAddress t = current.exchange(default_transform, std::memory_order_relaxed);
54 front_buffer.swap(back_buffer);
55 if (IsValid(t.address)) {
56 front_buffer.emplace_back(t);
57 }
58 }
59 for (auto& transform : front_buffer) {
60 size_t offset = 0;
61 u64 mask = transform.mask;
62 while (mask != 0) {
63 const size_t empty_bits = std::countr_zero(mask);
64 offset += empty_bits << align_bits;
65 mask = mask >> empty_bits;
66
67 const size_t continuous_bits = std::countr_one(mask);
68 callback((static_cast<VAddr>(transform.address) << page_bits) + offset,
69 continuous_bits << align_bits);
70 mask = continuous_bits < align_size ? (mask >> continuous_bits) : 0;
71 offset += continuous_bits << align_bits;
72 }
73 }
74 front_buffer.clear();
75 }
76
77private:
78 struct alignas(8) TransformAddress {
79 u32 address;
80 u32 mask;
81 };
82
83 constexpr static size_t page_bits = Memory::YUZU_PAGEBITS - 1;
84 constexpr static size_t page_size = 1ULL << page_bits;
85 constexpr static size_t page_mask = page_size - 1;
86
87 constexpr static size_t align_bits = 6U;
88 constexpr static size_t align_size = 1U << align_bits;
89 constexpr static size_t align_mask = align_size - 1;
90 constexpr static TransformAddress default_transform = {.address = ~0U, .mask = 0U};
91
92 bool IsValid(VAddr address) {
93 return address < (1ULL << 39);
94 }
95
96 template <typename T>
97 T CreateMask(size_t top_bit, size_t minor_bit) {
98 T mask = ~T(0);
99 mask <<= (sizeof(T) * 8 - top_bit);
100 mask >>= (sizeof(T) * 8 - top_bit);
101 mask >>= minor_bit;
102 mask <<= minor_bit;
103 return mask;
104 }
105
106 TransformAddress BuildTransform(VAddr address, size_t size) {
107 const size_t minor_address = address & page_mask;
108 const size_t minor_bit = minor_address >> align_bits;
109 const size_t top_bit = (minor_address + size + align_mask) >> align_bits;
110 TransformAddress result{};
111 result.address = static_cast<u32>(address >> page_bits);
112 result.mask = CreateMask<u32>(top_bit, minor_bit);
113 return result;
114 }
115
116 std::atomic<TransformAddress> current{};
117 std::mutex guard;
118 std::vector<TransformAddress> back_buffer;
119 std::vector<TransformAddress> front_buffer;
120};
121
122} // namespace Core
diff --git a/src/core/hle/service/audio/audin_u.cpp b/src/core/hle/service/audio/audin_u.cpp
index c8d574993..526a39130 100644
--- a/src/core/hle/service/audio/audin_u.cpp
+++ b/src/core/hle/service/audio/audin_u.cpp
@@ -5,7 +5,7 @@
5#include "audio_core/renderer/audio_device.h" 5#include "audio_core/renderer/audio_device.h"
6#include "common/common_funcs.h" 6#include "common/common_funcs.h"
7#include "common/logging/log.h" 7#include "common/logging/log.h"
8#include "common/settings.h" 8#include "common/scratch_buffer.h"
9#include "common/string_util.h" 9#include "common/string_util.h"
10#include "core/core.h" 10#include "core/core.h"
11#include "core/hle/kernel/k_event.h" 11#include "core/hle/kernel/k_event.h"
@@ -124,12 +124,15 @@ private:
124 124
125 void GetReleasedAudioInBuffer(HLERequestContext& ctx) { 125 void GetReleasedAudioInBuffer(HLERequestContext& ctx) {
126 const auto write_buffer_size = ctx.GetWriteBufferNumElements<u64>(); 126 const auto write_buffer_size = ctx.GetWriteBufferNumElements<u64>();
127 tmp_buffer.resize_destructive(write_buffer_size); 127 released_buffer.resize_destructive(write_buffer_size);
128 tmp_buffer[0] = 0; 128 released_buffer[0] = 0;
129 129
130 const auto count = impl->GetReleasedBuffers(tmp_buffer); 130 const auto count = impl->GetReleasedBuffers(released_buffer);
131 131
132 ctx.WriteBuffer(tmp_buffer); 132 LOG_TRACE(Service_Audio, "called. Session {} released {} buffers",
133 impl->GetSystem().GetSessionId(), count);
134
135 ctx.WriteBuffer(released_buffer);
133 136
134 IPC::ResponseBuilder rb{ctx, 3}; 137 IPC::ResponseBuilder rb{ctx, 3};
135 rb.Push(ResultSuccess); 138 rb.Push(ResultSuccess);
@@ -155,7 +158,6 @@ private:
155 LOG_DEBUG(Service_Audio, "called. Buffer count={}", buffer_count); 158 LOG_DEBUG(Service_Audio, "called. Buffer count={}", buffer_count);
156 159
157 IPC::ResponseBuilder rb{ctx, 3}; 160 IPC::ResponseBuilder rb{ctx, 3};
158
159 rb.Push(ResultSuccess); 161 rb.Push(ResultSuccess);
160 rb.Push(buffer_count); 162 rb.Push(buffer_count);
161 } 163 }
@@ -195,7 +197,7 @@ private:
195 KernelHelpers::ServiceContext service_context; 197 KernelHelpers::ServiceContext service_context;
196 Kernel::KEvent* event; 198 Kernel::KEvent* event;
197 std::shared_ptr<AudioCore::AudioIn::In> impl; 199 std::shared_ptr<AudioCore::AudioIn::In> impl;
198 Common::ScratchBuffer<u64> tmp_buffer; 200 Common::ScratchBuffer<u64> released_buffer;
199}; 201};
200 202
201AudInU::AudInU(Core::System& system_) 203AudInU::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 032c8c11f..23f84a29f 100644
--- a/src/core/hle/service/audio/audout_u.cpp
+++ b/src/core/hle/service/audio/audout_u.cpp
@@ -9,6 +9,7 @@
9#include "audio_core/renderer/audio_device.h" 9#include "audio_core/renderer/audio_device.h"
10#include "common/common_funcs.h" 10#include "common/common_funcs.h"
11#include "common/logging/log.h" 11#include "common/logging/log.h"
12#include "common/scratch_buffer.h"
12#include "common/string_util.h" 13#include "common/string_util.h"
13#include "common/swap.h" 14#include "common/swap.h"
14#include "core/core.h" 15#include "core/core.h"
@@ -102,8 +103,8 @@ private:
102 AudioOutBuffer buffer{}; 103 AudioOutBuffer buffer{};
103 std::memcpy(&buffer, in_buffer.data(), sizeof(AudioOutBuffer)); 104 std::memcpy(&buffer, in_buffer.data(), sizeof(AudioOutBuffer));
104 105
105 [[maybe_unused]] auto sessionid{impl->GetSystem().GetSessionId()}; 106 LOG_TRACE(Service_Audio, "called. Session {} Appending buffer {:08X}",
106 LOG_TRACE(Service_Audio, "called. Session {} Appending buffer {:08X}", sessionid, tag); 107 impl->GetSystem().GetSessionId(), tag);
107 108
108 auto result = impl->AppendBuffer(buffer, tag); 109 auto result = impl->AppendBuffer(buffer, tag);
109 110
@@ -123,12 +124,15 @@ private:
123 124
124 void GetReleasedAudioOutBuffers(HLERequestContext& ctx) { 125 void GetReleasedAudioOutBuffers(HLERequestContext& ctx) {
125 const auto write_buffer_size = ctx.GetWriteBufferNumElements<u64>(); 126 const auto write_buffer_size = ctx.GetWriteBufferNumElements<u64>();
126 tmp_buffer.resize_destructive(write_buffer_size); 127 released_buffer.resize_destructive(write_buffer_size);
127 tmp_buffer[0] = 0; 128 released_buffer[0] = 0;
128 129
129 const auto count = impl->GetReleasedBuffers(tmp_buffer); 130 const auto count = impl->GetReleasedBuffers(released_buffer);
130 131
131 ctx.WriteBuffer(tmp_buffer); 132 ctx.WriteBuffer(released_buffer);
133
134 LOG_TRACE(Service_Audio, "called. Session {} released {} buffers",
135 impl->GetSystem().GetSessionId(), count);
132 136
133 IPC::ResponseBuilder rb{ctx, 3}; 137 IPC::ResponseBuilder rb{ctx, 3};
134 rb.Push(ResultSuccess); 138 rb.Push(ResultSuccess);
@@ -154,7 +158,6 @@ private:
154 LOG_DEBUG(Service_Audio, "called. Buffer count={}", buffer_count); 158 LOG_DEBUG(Service_Audio, "called. Buffer count={}", buffer_count);
155 159
156 IPC::ResponseBuilder rb{ctx, 3}; 160 IPC::ResponseBuilder rb{ctx, 3};
157
158 rb.Push(ResultSuccess); 161 rb.Push(ResultSuccess);
159 rb.Push(buffer_count); 162 rb.Push(buffer_count);
160 } 163 }
@@ -165,7 +168,6 @@ private:
165 LOG_DEBUG(Service_Audio, "called. Played samples={}", samples_played); 168 LOG_DEBUG(Service_Audio, "called. Played samples={}", samples_played);
166 169
167 IPC::ResponseBuilder rb{ctx, 4}; 170 IPC::ResponseBuilder rb{ctx, 4};
168
169 rb.Push(ResultSuccess); 171 rb.Push(ResultSuccess);
170 rb.Push(samples_played); 172 rb.Push(samples_played);
171 } 173 }
@@ -205,7 +207,7 @@ private:
205 KernelHelpers::ServiceContext service_context; 207 KernelHelpers::ServiceContext service_context;
206 Kernel::KEvent* event; 208 Kernel::KEvent* event;
207 std::shared_ptr<AudioCore::AudioOut::Out> impl; 209 std::shared_ptr<AudioCore::AudioOut::Out> impl;
208 Common::ScratchBuffer<u64> tmp_buffer; 210 Common::ScratchBuffer<u64> released_buffer;
209}; 211};
210 212
211AudOutU::AudOutU(Core::System& system_) 213AudOutU::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 12845c23a..003870176 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -15,6 +15,7 @@
15#include "common/common_funcs.h" 15#include "common/common_funcs.h"
16#include "common/logging/log.h" 16#include "common/logging/log.h"
17#include "common/polyfill_ranges.h" 17#include "common/polyfill_ranges.h"
18#include "common/scratch_buffer.h"
18#include "common/string_util.h" 19#include "common/string_util.h"
19#include "core/core.h" 20#include "core/core.h"
20#include "core/hle/kernel/k_event.h" 21#include "core/hle/kernel/k_event.h"
@@ -119,23 +120,23 @@ private:
119 auto is_buffer_b{ctx.BufferDescriptorB()[0].Size() != 0}; 120 auto is_buffer_b{ctx.BufferDescriptorB()[0].Size() != 0};
120 if (is_buffer_b) { 121 if (is_buffer_b) {
121 const auto buffersB{ctx.BufferDescriptorB()}; 122 const auto buffersB{ctx.BufferDescriptorB()};
122 tmp_output.resize_destructive(buffersB[0].Size()); 123 output_buffer.resize_destructive(buffersB[0].Size());
123 tmp_performance.resize_destructive(buffersB[1].Size()); 124 performance_buffer.resize_destructive(buffersB[1].Size());
124 } else { 125 } else {
125 const auto buffersC{ctx.BufferDescriptorC()}; 126 const auto buffersC{ctx.BufferDescriptorC()};
126 tmp_output.resize_destructive(buffersC[0].Size()); 127 output_buffer.resize_destructive(buffersC[0].Size());
127 tmp_performance.resize_destructive(buffersC[1].Size()); 128 performance_buffer.resize_destructive(buffersC[1].Size());
128 } 129 }
129 130
130 auto result = impl->RequestUpdate(input, tmp_performance, tmp_output); 131 auto result = impl->RequestUpdate(input, performance_buffer, output_buffer);
131 132
132 if (result.IsSuccess()) { 133 if (result.IsSuccess()) {
133 if (is_buffer_b) { 134 if (is_buffer_b) {
134 ctx.WriteBufferB(tmp_output.data(), tmp_output.size(), 0); 135 ctx.WriteBufferB(output_buffer.data(), output_buffer.size(), 0);
135 ctx.WriteBufferB(tmp_performance.data(), tmp_performance.size(), 1); 136 ctx.WriteBufferB(performance_buffer.data(), performance_buffer.size(), 1);
136 } else { 137 } else {
137 ctx.WriteBufferC(tmp_output.data(), tmp_output.size(), 0); 138 ctx.WriteBufferC(output_buffer.data(), output_buffer.size(), 0);
138 ctx.WriteBufferC(tmp_performance.data(), tmp_performance.size(), 1); 139 ctx.WriteBufferC(performance_buffer.data(), performance_buffer.size(), 1);
139 } 140 }
140 } else { 141 } else {
141 LOG_ERROR(Service_Audio, "RequestUpdate failed error 0x{:02X}!", result.description); 142 LOG_ERROR(Service_Audio, "RequestUpdate failed error 0x{:02X}!", result.description);
@@ -233,8 +234,8 @@ private:
233 Kernel::KEvent* rendered_event; 234 Kernel::KEvent* rendered_event;
234 Manager& manager; 235 Manager& manager;
235 std::unique_ptr<Renderer> impl; 236 std::unique_ptr<Renderer> impl;
236 Common::ScratchBuffer<u8> tmp_output; 237 Common::ScratchBuffer<u8> output_buffer;
237 Common::ScratchBuffer<u8> tmp_performance; 238 Common::ScratchBuffer<u8> performance_buffer;
238}; 239};
239 240
240class IAudioDevice final : public ServiceFramework<IAudioDevice> { 241class IAudioDevice final : public ServiceFramework<IAudioDevice> {
diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp
index c835f6cb7..fa77007f3 100644
--- a/src/core/hle/service/audio/hwopus.cpp
+++ b/src/core/hle/service/audio/hwopus.cpp
@@ -11,6 +11,7 @@
11 11
12#include "common/assert.h" 12#include "common/assert.h"
13#include "common/logging/log.h" 13#include "common/logging/log.h"
14#include "common/scratch_buffer.h"
14#include "core/hle/service/audio/hwopus.h" 15#include "core/hle/service/audio/hwopus.h"
15#include "core/hle/service/ipc_helpers.h" 16#include "core/hle/service/ipc_helpers.h"
16 17
@@ -68,13 +69,13 @@ private:
68 ExtraBehavior extra_behavior) { 69 ExtraBehavior extra_behavior) {
69 u32 consumed = 0; 70 u32 consumed = 0;
70 u32 sample_count = 0; 71 u32 sample_count = 0;
71 tmp_samples.resize_destructive(ctx.GetWriteBufferNumElements<opus_int16>()); 72 samples.resize_destructive(ctx.GetWriteBufferNumElements<opus_int16>());
72 73
73 if (extra_behavior == ExtraBehavior::ResetContext) { 74 if (extra_behavior == ExtraBehavior::ResetContext) {
74 ResetDecoderContext(); 75 ResetDecoderContext();
75 } 76 }
76 77
77 if (!DecodeOpusData(consumed, sample_count, ctx.ReadBuffer(), tmp_samples, performance)) { 78 if (!DecodeOpusData(consumed, sample_count, ctx.ReadBuffer(), samples, performance)) {
78 LOG_ERROR(Audio, "Failed to decode opus data"); 79 LOG_ERROR(Audio, "Failed to decode opus data");
79 IPC::ResponseBuilder rb{ctx, 2}; 80 IPC::ResponseBuilder rb{ctx, 2};
80 // TODO(ogniK): Use correct error code 81 // TODO(ogniK): Use correct error code
@@ -90,7 +91,7 @@ private:
90 if (performance) { 91 if (performance) {
91 rb.Push<u64>(*performance); 92 rb.Push<u64>(*performance);
92 } 93 }
93 ctx.WriteBuffer(tmp_samples); 94 ctx.WriteBuffer(samples);
94 } 95 }
95 96
96 bool DecodeOpusData(u32& consumed, u32& sample_count, std::span<const u8> input, 97 bool DecodeOpusData(u32& consumed, u32& sample_count, std::span<const u8> input,
@@ -154,7 +155,7 @@ private:
154 OpusDecoderPtr decoder; 155 OpusDecoderPtr decoder;
155 u32 sample_rate; 156 u32 sample_rate;
156 u32 channel_count; 157 u32 channel_count;
157 Common::ScratchBuffer<opus_int16> tmp_samples; 158 Common::ScratchBuffer<opus_int16> samples;
158}; 159};
159 160
160class IHardwareOpusDecoderManager final : public ServiceFramework<IHardwareOpusDecoderManager> { 161class IHardwareOpusDecoderManager final : public ServiceFramework<IHardwareOpusDecoderManager> {
diff --git a/src/core/hle/service/nvdrv/nvdrv_interface.cpp b/src/core/hle/service/nvdrv/nvdrv_interface.cpp
index 348207e25..c8a880e84 100644
--- a/src/core/hle/service/nvdrv/nvdrv_interface.cpp
+++ b/src/core/hle/service/nvdrv/nvdrv_interface.cpp
@@ -2,7 +2,6 @@
2// SPDX-FileCopyrightText: 2021 Skyline Team and Contributors 2// SPDX-FileCopyrightText: 2021 Skyline Team and Contributors
3// SPDX-License-Identifier: GPL-3.0-or-later 3// SPDX-License-Identifier: GPL-3.0-or-later
4 4
5#include <cinttypes>
6#include "common/logging/log.h" 5#include "common/logging/log.h"
7#include "core/core.h" 6#include "core/core.h"
8#include "core/hle/kernel/k_event.h" 7#include "core/hle/kernel/k_event.h"
@@ -63,12 +62,12 @@ void NVDRV::Ioctl1(HLERequestContext& ctx) {
63 } 62 }
64 63
65 // Check device 64 // Check device
66 tmp_output.resize_destructive(ctx.GetWriteBufferSize(0)); 65 output_buffer.resize_destructive(ctx.GetWriteBufferSize(0));
67 const auto input_buffer = ctx.ReadBuffer(0); 66 const auto input_buffer = ctx.ReadBuffer(0);
68 67
69 const auto nv_result = nvdrv->Ioctl1(fd, command, input_buffer, tmp_output); 68 const auto nv_result = nvdrv->Ioctl1(fd, command, input_buffer, output_buffer);
70 if (command.is_out != 0) { 69 if (command.is_out != 0) {
71 ctx.WriteBuffer(tmp_output); 70 ctx.WriteBuffer(output_buffer);
72 } 71 }
73 72
74 IPC::ResponseBuilder rb{ctx, 3}; 73 IPC::ResponseBuilder rb{ctx, 3};
@@ -90,12 +89,12 @@ void NVDRV::Ioctl2(HLERequestContext& ctx) {
90 89
91 const auto input_buffer = ctx.ReadBuffer(0); 90 const auto input_buffer = ctx.ReadBuffer(0);
92 const auto input_inlined_buffer = ctx.ReadBuffer(1); 91 const auto input_inlined_buffer = ctx.ReadBuffer(1);
93 tmp_output.resize_destructive(ctx.GetWriteBufferSize(0)); 92 output_buffer.resize_destructive(ctx.GetWriteBufferSize(0));
94 93
95 const auto nv_result = 94 const auto nv_result =
96 nvdrv->Ioctl2(fd, command, input_buffer, input_inlined_buffer, tmp_output); 95 nvdrv->Ioctl2(fd, command, input_buffer, input_inlined_buffer, output_buffer);
97 if (command.is_out != 0) { 96 if (command.is_out != 0) {
98 ctx.WriteBuffer(tmp_output); 97 ctx.WriteBuffer(output_buffer);
99 } 98 }
100 99
101 IPC::ResponseBuilder rb{ctx, 3}; 100 IPC::ResponseBuilder rb{ctx, 3};
@@ -116,12 +115,14 @@ void NVDRV::Ioctl3(HLERequestContext& ctx) {
116 } 115 }
117 116
118 const auto input_buffer = ctx.ReadBuffer(0); 117 const auto input_buffer = ctx.ReadBuffer(0);
119 tmp_output.resize_destructive(ctx.GetWriteBufferSize(0)); 118 output_buffer.resize_destructive(ctx.GetWriteBufferSize(0));
120 tmp_output_inline.resize_destructive(ctx.GetWriteBufferSize(1)); 119 inline_output_buffer.resize_destructive(ctx.GetWriteBufferSize(1));
121 const auto nv_result = nvdrv->Ioctl3(fd, command, input_buffer, tmp_output, tmp_output_inline); 120
121 const auto nv_result =
122 nvdrv->Ioctl3(fd, command, input_buffer, output_buffer, inline_output_buffer);
122 if (command.is_out != 0) { 123 if (command.is_out != 0) {
123 ctx.WriteBuffer(tmp_output, 0); 124 ctx.WriteBuffer(output_buffer, 0);
124 ctx.WriteBuffer(tmp_output_inline, 1); 125 ctx.WriteBuffer(inline_output_buffer, 1);
125 } 126 }
126 127
127 IPC::ResponseBuilder rb{ctx, 3}; 128 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 4b593ff90..6e98115dc 100644
--- a/src/core/hle/service/nvdrv/nvdrv_interface.h
+++ b/src/core/hle/service/nvdrv/nvdrv_interface.h
@@ -4,6 +4,7 @@
4#pragma once 4#pragma once
5 5
6#include <memory> 6#include <memory>
7
7#include "common/scratch_buffer.h" 8#include "common/scratch_buffer.h"
8#include "core/hle/service/nvdrv/nvdrv.h" 9#include "core/hle/service/nvdrv/nvdrv.h"
9#include "core/hle/service/service.h" 10#include "core/hle/service/service.h"
@@ -34,8 +35,8 @@ private:
34 35
35 u64 pid{}; 36 u64 pid{};
36 bool is_initialized{}; 37 bool is_initialized{};
37 Common::ScratchBuffer<u8> tmp_output; 38 Common::ScratchBuffer<u8> output_buffer;
38 Common::ScratchBuffer<u8> tmp_output_inline; 39 Common::ScratchBuffer<u8> inline_output_buffer;
39}; 40};
40 41
41} // namespace Service::Nvidia 42} // namespace Service::Nvidia
diff --git a/src/core/hle/service/nvnflinger/parcel.h b/src/core/hle/service/nvnflinger/parcel.h
index 23ba315a0..e2c9bbd50 100644
--- a/src/core/hle/service/nvnflinger/parcel.h
+++ b/src/core/hle/service/nvnflinger/parcel.h
@@ -6,6 +6,7 @@
6#include <memory> 6#include <memory>
7#include <span> 7#include <span>
8#include <vector> 8#include <vector>
9
9#include <boost/container/small_vector.hpp> 10#include <boost/container/small_vector.hpp>
10 11
11#include "common/alignment.h" 12#include "common/alignment.h"
@@ -148,9 +149,9 @@ public:
148 this->WriteImpl(0U, m_object_buffer); 149 this->WriteImpl(0U, m_object_buffer);
149 } 150 }
150 151
151 std::vector<u8> Serialize() const { 152 std::span<u8> Serialize() {
152 std::vector<u8> output_buffer(sizeof(ParcelHeader) + m_data_buffer.size() + 153 m_output_buffer.resize(sizeof(ParcelHeader) + m_data_buffer.size() +
153 m_object_buffer.size()); 154 m_object_buffer.size());
154 155
155 ParcelHeader header{}; 156 ParcelHeader header{};
156 header.data_size = static_cast<u32>(m_data_buffer.size()); 157 header.data_size = static_cast<u32>(m_data_buffer.size());
@@ -158,17 +159,17 @@ public:
158 header.objects_size = static_cast<u32>(m_object_buffer.size()); 159 header.objects_size = static_cast<u32>(m_object_buffer.size());
159 header.objects_offset = header.data_offset + header.data_size; 160 header.objects_offset = header.data_offset + header.data_size;
160 161
161 std::memcpy(output_buffer.data(), &header, sizeof(header)); 162 std::memcpy(m_output_buffer.data(), &header, sizeof(ParcelHeader));
162 std::ranges::copy(m_data_buffer, output_buffer.data() + header.data_offset); 163 std::ranges::copy(m_data_buffer, m_output_buffer.data() + header.data_offset);
163 std::ranges::copy(m_object_buffer, output_buffer.data() + header.objects_offset); 164 std::ranges::copy(m_object_buffer, m_output_buffer.data() + header.objects_offset);
164 165
165 return output_buffer; 166 return m_output_buffer;
166 } 167 }
167 168
168private: 169private:
169 template <typename T> 170 template <typename T, size_t BufferSize>
170 requires(std::is_trivially_copyable_v<T>) 171 requires(std::is_trivially_copyable_v<T>)
171 void WriteImpl(const T& val, boost::container::small_vector<u8, 0x200>& buffer) { 172 void WriteImpl(const T& val, boost::container::small_vector<u8, BufferSize>& buffer) {
172 const size_t aligned_size = Common::AlignUp(sizeof(T), 4); 173 const size_t aligned_size = Common::AlignUp(sizeof(T), 4);
173 const size_t old_size = buffer.size(); 174 const size_t old_size = buffer.size();
174 buffer.resize(old_size + aligned_size); 175 buffer.resize(old_size + aligned_size);
@@ -177,8 +178,9 @@ private:
177 } 178 }
178 179
179private: 180private:
180 boost::container::small_vector<u8, 0x200> m_data_buffer; 181 boost::container::small_vector<u8, 0x1B0> m_data_buffer;
181 boost::container::small_vector<u8, 0x200> m_object_buffer; 182 boost::container::small_vector<u8, 0x40> m_object_buffer;
183 boost::container::small_vector<u8, 0x200> m_output_buffer;
182}; 184};
183 185
184} // namespace Service::android 186} // namespace Service::android
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 514ba0d66..257406f09 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -3,6 +3,7 @@
3 3
4#include <algorithm> 4#include <algorithm>
5#include <cstring> 5#include <cstring>
6#include <span>
6 7
7#include "common/assert.h" 8#include "common/assert.h"
8#include "common/atomic_ops.h" 9#include "common/atomic_ops.h"
@@ -13,6 +14,7 @@
13#include "common/swap.h" 14#include "common/swap.h"
14#include "core/core.h" 15#include "core/core.h"
15#include "core/device_memory.h" 16#include "core/device_memory.h"
17#include "core/gpu_dirty_memory_manager.h"
16#include "core/hardware_properties.h" 18#include "core/hardware_properties.h"
17#include "core/hle/kernel/k_page_table.h" 19#include "core/hle/kernel/k_page_table.h"
18#include "core/hle/kernel/k_process.h" 20#include "core/hle/kernel/k_process.h"
@@ -678,7 +680,7 @@ struct Memory::Impl {
678 LOG_ERROR(HW_Memory, "Unmapped Write{} @ 0x{:016X} = 0x{:016X}", sizeof(T) * 8, 680 LOG_ERROR(HW_Memory, "Unmapped Write{} @ 0x{:016X} = 0x{:016X}", sizeof(T) * 8,
679 GetInteger(vaddr), static_cast<u64>(data)); 681 GetInteger(vaddr), static_cast<u64>(data));
680 }, 682 },
681 [&]() { system.GPU().InvalidateRegion(GetInteger(vaddr), sizeof(T)); }); 683 [&]() { HandleRasterizerWrite(GetInteger(vaddr), sizeof(T)); });
682 if (ptr) { 684 if (ptr) {
683 std::memcpy(ptr, &data, sizeof(T)); 685 std::memcpy(ptr, &data, sizeof(T));
684 } 686 }
@@ -692,7 +694,7 @@ struct Memory::Impl {
692 LOG_ERROR(HW_Memory, "Unmapped WriteExclusive{} @ 0x{:016X} = 0x{:016X}", 694 LOG_ERROR(HW_Memory, "Unmapped WriteExclusive{} @ 0x{:016X} = 0x{:016X}",
693 sizeof(T) * 8, GetInteger(vaddr), static_cast<u64>(data)); 695 sizeof(T) * 8, GetInteger(vaddr), static_cast<u64>(data));
694 }, 696 },
695 [&]() { system.GPU().InvalidateRegion(GetInteger(vaddr), sizeof(T)); }); 697 [&]() { HandleRasterizerWrite(GetInteger(vaddr), sizeof(T)); });
696 if (ptr) { 698 if (ptr) {
697 const auto volatile_pointer = reinterpret_cast<volatile T*>(ptr); 699 const auto volatile_pointer = reinterpret_cast<volatile T*>(ptr);
698 return Common::AtomicCompareAndSwap(volatile_pointer, data, expected); 700 return Common::AtomicCompareAndSwap(volatile_pointer, data, expected);
@@ -707,7 +709,7 @@ struct Memory::Impl {
707 LOG_ERROR(HW_Memory, "Unmapped WriteExclusive128 @ 0x{:016X} = 0x{:016X}{:016X}", 709 LOG_ERROR(HW_Memory, "Unmapped WriteExclusive128 @ 0x{:016X} = 0x{:016X}{:016X}",
708 GetInteger(vaddr), static_cast<u64>(data[1]), static_cast<u64>(data[0])); 710 GetInteger(vaddr), static_cast<u64>(data[1]), static_cast<u64>(data[0]));
709 }, 711 },
710 [&]() { system.GPU().InvalidateRegion(GetInteger(vaddr), sizeof(u128)); }); 712 [&]() { HandleRasterizerWrite(GetInteger(vaddr), sizeof(u128)); });
711 if (ptr) { 713 if (ptr) {
712 const auto volatile_pointer = reinterpret_cast<volatile u64*>(ptr); 714 const auto volatile_pointer = reinterpret_cast<volatile u64*>(ptr);
713 return Common::AtomicCompareAndSwap(volatile_pointer, data, expected); 715 return Common::AtomicCompareAndSwap(volatile_pointer, data, expected);
@@ -717,7 +719,7 @@ struct Memory::Impl {
717 719
718 void HandleRasterizerDownload(VAddr address, size_t size) { 720 void HandleRasterizerDownload(VAddr address, size_t size) {
719 const size_t core = system.GetCurrentHostThreadID(); 721 const size_t core = system.GetCurrentHostThreadID();
720 auto& current_area = rasterizer_areas[core]; 722 auto& current_area = rasterizer_read_areas[core];
721 const VAddr end_address = address + size; 723 const VAddr end_address = address + size;
722 if (current_area.start_address <= address && end_address <= current_area.end_address) 724 if (current_area.start_address <= address && end_address <= current_area.end_address)
723 [[likely]] { 725 [[likely]] {
@@ -726,9 +728,31 @@ struct Memory::Impl {
726 current_area = system.GPU().OnCPURead(address, size); 728 current_area = system.GPU().OnCPURead(address, size);
727 } 729 }
728 730
729 Common::PageTable* current_page_table = nullptr; 731 void HandleRasterizerWrite(VAddr address, size_t size) {
730 std::array<VideoCore::RasterizerDownloadArea, Core::Hardware::NUM_CPU_CORES> rasterizer_areas{}; 732 const size_t core = system.GetCurrentHostThreadID();
733 auto& current_area = rasterizer_write_areas[core];
734 VAddr subaddress = address >> YUZU_PAGEBITS;
735 bool do_collection = current_area.last_address == subaddress;
736 if (!do_collection) [[unlikely]] {
737 do_collection = system.GPU().OnCPUWrite(address, size);
738 if (!do_collection) {
739 return;
740 }
741 current_area.last_address = subaddress;
742 }
743 gpu_dirty_managers[core].Collect(address, size);
744 }
745
746 struct GPUDirtyState {
747 VAddr last_address;
748 };
749
731 Core::System& system; 750 Core::System& system;
751 Common::PageTable* current_page_table = nullptr;
752 std::array<VideoCore::RasterizerDownloadArea, Core::Hardware::NUM_CPU_CORES>
753 rasterizer_read_areas{};
754 std::array<GPUDirtyState, Core::Hardware::NUM_CPU_CORES> rasterizer_write_areas{};
755 std::span<Core::GPUDirtyMemoryManager> gpu_dirty_managers;
732}; 756};
733 757
734Memory::Memory(Core::System& system_) : system{system_} { 758Memory::Memory(Core::System& system_) : system{system_} {
@@ -876,6 +900,10 @@ void Memory::ZeroBlock(Common::ProcessAddress dest_addr, const std::size_t size)
876 impl->ZeroBlock(*system.ApplicationProcess(), dest_addr, size); 900 impl->ZeroBlock(*system.ApplicationProcess(), dest_addr, size);
877} 901}
878 902
903void Memory::SetGPUDirtyManagers(std::span<Core::GPUDirtyMemoryManager> managers) {
904 impl->gpu_dirty_managers = managers;
905}
906
879Result Memory::InvalidateDataCache(Common::ProcessAddress dest_addr, const std::size_t size) { 907Result Memory::InvalidateDataCache(Common::ProcessAddress dest_addr, const std::size_t size) {
880 return impl->InvalidateDataCache(*system.ApplicationProcess(), dest_addr, size); 908 return impl->InvalidateDataCache(*system.ApplicationProcess(), dest_addr, size);
881} 909}
diff --git a/src/core/memory.h b/src/core/memory.h
index 72a0be813..ea01824f8 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -5,6 +5,7 @@
5 5
6#include <cstddef> 6#include <cstddef>
7#include <memory> 7#include <memory>
8#include <span>
8#include <string> 9#include <string>
9#include "common/typed_address.h" 10#include "common/typed_address.h"
10#include "core/hle/result.h" 11#include "core/hle/result.h"
@@ -15,7 +16,8 @@ struct PageTable;
15 16
16namespace Core { 17namespace Core {
17class System; 18class System;
18} 19class GPUDirtyMemoryManager;
20} // namespace Core
19 21
20namespace Kernel { 22namespace Kernel {
21class PhysicalMemory; 23class PhysicalMemory;
@@ -458,6 +460,8 @@ public:
458 */ 460 */
459 void MarkRegionDebug(Common::ProcessAddress vaddr, u64 size, bool debug); 461 void MarkRegionDebug(Common::ProcessAddress vaddr, u64 size, bool debug);
460 462
463 void SetGPUDirtyManagers(std::span<Core::GPUDirtyMemoryManager> managers);
464
461private: 465private:
462 Core::System& system; 466 Core::System& system;
463 467
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 {
102 Joycon::SerialNumber serial_number{}; 102 Joycon::SerialNumber serial_number{};
103 103
104 const auto result = Joycon::JoyconDriver::GetDeviceType(device_info, type); 104 const auto result = Joycon::JoyconDriver::GetDeviceType(device_info, type);
105 if (result != Joycon::DriverResult::Success) { 105 if (result != Common::Input::DriverResult::Success) {
106 return false; 106 return false;
107 } 107 }
108 108
109 const auto result2 = Joycon::JoyconDriver::GetSerialNumber(device_info, serial_number); 109 const auto result2 = Joycon::JoyconDriver::GetSerialNumber(device_info, serial_number);
110 if (result2 != Joycon::DriverResult::Success) { 110 if (result2 != Common::Input::DriverResult::Success) {
111 return false; 111 return false;
112 } 112 }
113 113
@@ -171,10 +171,10 @@ void Joycons::RegisterNewDevice(SDL_hid_device_info* device_info) {
171 LOG_WARNING(Input, "No free handles available"); 171 LOG_WARNING(Input, "No free handles available");
172 return; 172 return;
173 } 173 }
174 if (result == Joycon::DriverResult::Success) { 174 if (result == Common::Input::DriverResult::Success) {
175 result = handle->RequestDeviceAccess(device_info); 175 result = handle->RequestDeviceAccess(device_info);
176 } 176 }
177 if (result == Joycon::DriverResult::Success) { 177 if (result == Common::Input::DriverResult::Success) {
178 LOG_WARNING(Input, "Initialize device"); 178 LOG_WARNING(Input, "Initialize device");
179 179
180 const std::size_t port = handle->GetDevicePort(); 180 const std::size_t port = handle->GetDevicePort();
@@ -273,8 +273,7 @@ Common::Input::DriverResult Joycons::SetLeds(const PadIdentifier& identifier,
273 led_config += led_status.led_3 ? 4 : 0; 273 led_config += led_status.led_3 ? 4 : 0;
274 led_config += led_status.led_4 ? 8 : 0; 274 led_config += led_status.led_4 ? 8 : 0;
275 275
276 return static_cast<Common::Input::DriverResult>( 276 return handle->SetLedConfig(static_cast<u8>(led_config));
277 handle->SetLedConfig(static_cast<u8>(led_config)));
278} 277}
279 278
280Common::Input::DriverResult Joycons::SetCameraFormat(const PadIdentifier& identifier, 279Common::Input::DriverResult Joycons::SetCameraFormat(const PadIdentifier& identifier,
@@ -283,8 +282,8 @@ Common::Input::DriverResult Joycons::SetCameraFormat(const PadIdentifier& identi
283 if (handle == nullptr) { 282 if (handle == nullptr) {
284 return Common::Input::DriverResult::InvalidHandle; 283 return Common::Input::DriverResult::InvalidHandle;
285 } 284 }
286 return static_cast<Common::Input::DriverResult>(handle->SetIrsConfig( 285 return handle->SetIrsConfig(Joycon::IrsMode::ImageTransfer,
287 Joycon::IrsMode::ImageTransfer, static_cast<Joycon::IrsResolution>(camera_format))); 286 static_cast<Joycon::IrsResolution>(camera_format));
288}; 287};
289 288
290Common::Input::NfcState Joycons::SupportsNfc(const PadIdentifier& identifier_) const { 289Common::Input::NfcState Joycons::SupportsNfc(const PadIdentifier& identifier_) const {
@@ -351,7 +350,7 @@ Common::Input::NfcState Joycons::ReadMifareData(const PadIdentifier& identifier,
351 350
352 std::vector<Joycon::MifareReadData> read_data(read_request.size()); 351 std::vector<Joycon::MifareReadData> read_data(read_request.size());
353 const auto result = handle->ReadMifareData(read_request, read_data); 352 const auto result = handle->ReadMifareData(read_request, read_data);
354 if (result == Joycon::DriverResult::Success) { 353 if (result == Common::Input::DriverResult::Success) {
355 for (std::size_t i = 0; i < read_request.size(); i++) { 354 for (std::size_t i = 0; i < read_request.size(); i++) {
356 data.data[i] = { 355 data.data[i] = {
357 .command = static_cast<u8>(command), 356 .command = static_cast<u8>(command),
@@ -402,15 +401,15 @@ Common::Input::DriverResult Joycons::SetPollingMode(const PadIdentifier& identif
402 401
403 switch (polling_mode) { 402 switch (polling_mode) {
404 case Common::Input::PollingMode::Active: 403 case Common::Input::PollingMode::Active:
405 return static_cast<Common::Input::DriverResult>(handle->SetActiveMode()); 404 return handle->SetActiveMode();
406 case Common::Input::PollingMode::Passive: 405 case Common::Input::PollingMode::Passive:
407 return static_cast<Common::Input::DriverResult>(handle->SetPassiveMode()); 406 return handle->SetPassiveMode();
408 case Common::Input::PollingMode::IR: 407 case Common::Input::PollingMode::IR:
409 return static_cast<Common::Input::DriverResult>(handle->SetIrMode()); 408 return handle->SetIrMode();
410 case Common::Input::PollingMode::NFC: 409 case Common::Input::PollingMode::NFC:
411 return static_cast<Common::Input::DriverResult>(handle->SetNfcMode()); 410 return handle->SetNfcMode();
412 case Common::Input::PollingMode::Ring: 411 case Common::Input::PollingMode::Ring:
413 return static_cast<Common::Input::DriverResult>(handle->SetRingConMode()); 412 return handle->SetRingConMode();
414 default: 413 default:
415 return Common::Input::DriverResult::NotSupported; 414 return Common::Input::DriverResult::NotSupported;
416 } 415 }
@@ -828,13 +827,13 @@ std::string Joycons::JoyconName(Joycon::ControllerType type) const {
828 } 827 }
829} 828}
830 829
831Common::Input::NfcState Joycons::TranslateDriverResult(Joycon::DriverResult result) const { 830Common::Input::NfcState Joycons::TranslateDriverResult(Common::Input::DriverResult result) const {
832 switch (result) { 831 switch (result) {
833 case Joycon::DriverResult::Success: 832 case Common::Input::DriverResult::Success:
834 return Common::Input::NfcState::Success; 833 return Common::Input::NfcState::Success;
835 case Joycon::DriverResult::Disabled: 834 case Common::Input::DriverResult::Disabled:
836 return Common::Input::NfcState::WrongDeviceState; 835 return Common::Input::NfcState::WrongDeviceState;
837 case Joycon::DriverResult::NotSupported: 836 case Common::Input::DriverResult::NotSupported:
838 return Common::Input::NfcState::NotSupported; 837 return Common::Input::NfcState::NotSupported;
839 default: 838 default:
840 return Common::Input::NfcState::Unknown; 839 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;
17struct MotionData; 17struct MotionData;
18struct TagInfo; 18struct TagInfo;
19enum class ControllerType : u8; 19enum class ControllerType : u8;
20enum class DriverResult;
21enum class IrsResolution; 20enum class IrsResolution;
22class JoyconDriver; 21class JoyconDriver;
23} // namespace InputCommon::Joycon 22} // namespace InputCommon::Joycon
@@ -112,7 +111,7 @@ private:
112 /// Returns the name of the device in text format 111 /// Returns the name of the device in text format
113 std::string JoyconName(Joycon::ControllerType type) const; 112 std::string JoyconName(Joycon::ControllerType type) const;
114 113
115 Common::Input::NfcState TranslateDriverResult(Joycon::DriverResult result) const; 114 Common::Input::NfcState TranslateDriverResult(Common::Input::DriverResult result) const;
116 115
117 std::jthread scan_thread; 116 std::jthread scan_thread;
118 117
diff --git a/src/input_common/drivers/mouse.cpp b/src/input_common/drivers/mouse.cpp
index f07cf8a0e..dac29c78f 100644
--- a/src/input_common/drivers/mouse.cpp
+++ b/src/input_common/drivers/mouse.cpp
@@ -12,9 +12,13 @@
12 12
13namespace InputCommon { 13namespace InputCommon {
14constexpr int update_time = 10; 14constexpr int update_time = 10;
15constexpr float default_stick_sensitivity = 0.0044f; 15constexpr float default_panning_sensitivity = 0.0010f;
16constexpr float default_motion_sensitivity = 0.0003f; 16constexpr float default_stick_sensitivity = 0.0006f;
17constexpr float default_deadzone_counterweight = 0.01f;
18constexpr float default_motion_panning_sensitivity = 2.5f;
19constexpr float default_motion_sensitivity = 0.416f;
17constexpr float maximum_rotation_speed = 2.0f; 20constexpr float maximum_rotation_speed = 2.0f;
21constexpr float maximum_stick_range = 1.5f;
18constexpr int mouse_axis_x = 0; 22constexpr int mouse_axis_x = 0;
19constexpr int mouse_axis_y = 1; 23constexpr int mouse_axis_y = 1;
20constexpr int wheel_axis_x = 2; 24constexpr int wheel_axis_x = 2;
@@ -81,7 +85,7 @@ void Mouse::UpdateThread(std::stop_token stop_token) {
81} 85}
82 86
83void Mouse::UpdateStickInput() { 87void Mouse::UpdateStickInput() {
84 if (!Settings::values.mouse_panning) { 88 if (!IsMousePanningEnabled()) {
85 return; 89 return;
86 } 90 }
87 91
@@ -89,26 +93,13 @@ void Mouse::UpdateStickInput() {
89 93
90 // Prevent input from exceeding the max range (1.0f) too much, 94 // Prevent input from exceeding the max range (1.0f) too much,
91 // but allow some room to make it easier to sustain 95 // but allow some room to make it easier to sustain
92 if (length > 1.2f) { 96 if (length > maximum_stick_range) {
93 last_mouse_change /= length; 97 last_mouse_change /= length;
94 last_mouse_change *= 1.2f; 98 last_mouse_change *= maximum_stick_range;
95 } 99 }
96 100
97 auto mouse_change = last_mouse_change; 101 SetAxis(identifier, mouse_axis_x, last_mouse_change.x);
98 102 SetAxis(identifier, mouse_axis_y, -last_mouse_change.y);
99 // Bind the mouse change to [0 <= deadzone_counterweight <= 1,1]
100 if (length < 1.0f) {
101 const float deadzone_h_counterweight =
102 Settings::values.mouse_panning_deadzone_x_counterweight.GetValue();
103 const float deadzone_v_counterweight =
104 Settings::values.mouse_panning_deadzone_y_counterweight.GetValue();
105 mouse_change /= length;
106 mouse_change.x *= length + (1 - length) * deadzone_h_counterweight * 0.01f;
107 mouse_change.y *= length + (1 - length) * deadzone_v_counterweight * 0.01f;
108 }
109
110 SetAxis(identifier, mouse_axis_x, mouse_change.x);
111 SetAxis(identifier, mouse_axis_y, -mouse_change.y);
112 103
113 // Decay input over time 104 // Decay input over time
114 const float clamped_length = std::min(1.0f, length); 105 const float clamped_length = std::min(1.0f, length);
@@ -120,14 +111,13 @@ void Mouse::UpdateStickInput() {
120} 111}
121 112
122void Mouse::UpdateMotionInput() { 113void Mouse::UpdateMotionInput() {
123 // This may need its own sensitivity instead of using the average 114 const float sensitivity =
124 const float sensitivity = (Settings::values.mouse_panning_x_sensitivity.GetValue() + 115 IsMousePanningEnabled() ? default_motion_panning_sensitivity : default_motion_sensitivity;
125 Settings::values.mouse_panning_y_sensitivity.GetValue()) /
126 2.0f * default_motion_sensitivity;
127 116
128 const float rotation_velocity = std::sqrt(last_motion_change.x * last_motion_change.x + 117 const float rotation_velocity = std::sqrt(last_motion_change.x * last_motion_change.x +
129 last_motion_change.y * last_motion_change.y); 118 last_motion_change.y * last_motion_change.y);
130 119
120 // Clamp rotation speed
131 if (rotation_velocity > maximum_rotation_speed / sensitivity) { 121 if (rotation_velocity > maximum_rotation_speed / sensitivity) {
132 const float multiplier = maximum_rotation_speed / rotation_velocity / sensitivity; 122 const float multiplier = maximum_rotation_speed / rotation_velocity / sensitivity;
133 last_motion_change.x = last_motion_change.x * multiplier; 123 last_motion_change.x = last_motion_change.x * multiplier;
@@ -144,7 +134,7 @@ void Mouse::UpdateMotionInput() {
144 .delta_timestamp = update_time * 1000, 134 .delta_timestamp = update_time * 1000,
145 }; 135 };
146 136
147 if (Settings::values.mouse_panning) { 137 if (IsMousePanningEnabled()) {
148 last_motion_change.x = 0; 138 last_motion_change.x = 0;
149 last_motion_change.y = 0; 139 last_motion_change.y = 0;
150 } 140 }
@@ -154,33 +144,42 @@ void Mouse::UpdateMotionInput() {
154} 144}
155 145
156void Mouse::Move(int x, int y, int center_x, int center_y) { 146void Mouse::Move(int x, int y, int center_x, int center_y) {
157 if (Settings::values.mouse_panning) { 147 if (IsMousePanningEnabled()) {
158 const auto mouse_change = 148 const auto mouse_change =
159 (Common::MakeVec(x, y) - Common::MakeVec(center_x, center_y)).Cast<float>(); 149 (Common::MakeVec(x, y) - Common::MakeVec(center_x, center_y)).Cast<float>();
160 const float x_sensitivity = 150 const float x_sensitivity =
161 Settings::values.mouse_panning_x_sensitivity.GetValue() * default_stick_sensitivity; 151 Settings::values.mouse_panning_x_sensitivity.GetValue() * default_panning_sensitivity;
162 const float y_sensitivity = 152 const float y_sensitivity =
163 Settings::values.mouse_panning_y_sensitivity.GetValue() * default_stick_sensitivity; 153 Settings::values.mouse_panning_y_sensitivity.GetValue() * default_panning_sensitivity;
154 const float deadzone_counterweight =
155 Settings::values.mouse_panning_deadzone_counterweight.GetValue() *
156 default_deadzone_counterweight;
157
158 last_motion_change += {-mouse_change.y * x_sensitivity, -mouse_change.x * y_sensitivity, 0};
159 last_mouse_change.x += mouse_change.x * x_sensitivity;
160 last_mouse_change.y += mouse_change.y * y_sensitivity;
164 161
165 last_motion_change += {-mouse_change.y, -mouse_change.x, 0}; 162 // Bind the mouse change to [0 <= deadzone_counterweight <= 1.0]
166 last_mouse_change.x += mouse_change.x * x_sensitivity * 0.09f; 163 if (last_mouse_change.Length() < deadzone_counterweight) {
167 last_mouse_change.y += mouse_change.y * y_sensitivity * 0.09f; 164 last_mouse_change /= last_mouse_change.Length();
165 last_mouse_change *= deadzone_counterweight;
166 }
168 167
169 return; 168 return;
170 } 169 }
171 170
172 if (button_pressed) { 171 if (button_pressed) {
173 const auto mouse_move = Common::MakeVec<int>(x, y) - mouse_origin; 172 const auto mouse_move = Common::MakeVec<int>(x, y) - mouse_origin;
174 const float x_sensitivity = Settings::values.mouse_panning_x_sensitivity.GetValue(); 173 const float x_sensitivity =
175 const float y_sensitivity = Settings::values.mouse_panning_y_sensitivity.GetValue(); 174 Settings::values.mouse_panning_x_sensitivity.GetValue() * default_stick_sensitivity;
176 SetAxis(identifier, mouse_axis_x, 175 const float y_sensitivity =
177 static_cast<float>(mouse_move.x) * x_sensitivity * 0.0012f); 176 Settings::values.mouse_panning_y_sensitivity.GetValue() * default_stick_sensitivity;
178 SetAxis(identifier, mouse_axis_y, 177 SetAxis(identifier, mouse_axis_x, static_cast<float>(mouse_move.x) * x_sensitivity);
179 static_cast<float>(-mouse_move.y) * y_sensitivity * 0.0012f); 178 SetAxis(identifier, mouse_axis_y, static_cast<float>(-mouse_move.y) * y_sensitivity);
180 179
181 last_motion_change = { 180 last_motion_change = {
182 static_cast<float>(-mouse_move.y) / 50.0f, 181 static_cast<float>(-mouse_move.y) * x_sensitivity,
183 static_cast<float>(-mouse_move.x) / 50.0f, 182 static_cast<float>(-mouse_move.x) * y_sensitivity,
184 last_motion_change.z, 183 last_motion_change.z,
185 }; 184 };
186 } 185 }
@@ -220,7 +219,7 @@ void Mouse::ReleaseButton(MouseButton button) {
220 SetButton(real_mouse_identifier, static_cast<int>(button), false); 219 SetButton(real_mouse_identifier, static_cast<int>(button), false);
221 SetButton(touch_identifier, static_cast<int>(button), false); 220 SetButton(touch_identifier, static_cast<int>(button), false);
222 221
223 if (!Settings::values.mouse_panning) { 222 if (!IsMousePanningEnabled()) {
224 SetAxis(identifier, mouse_axis_x, 0); 223 SetAxis(identifier, mouse_axis_x, 0);
225 SetAxis(identifier, mouse_axis_y, 0); 224 SetAxis(identifier, mouse_axis_y, 0);
226 } 225 }
@@ -234,7 +233,7 @@ void Mouse::ReleaseButton(MouseButton button) {
234void Mouse::MouseWheelChange(int x, int y) { 233void Mouse::MouseWheelChange(int x, int y) {
235 wheel_position.x += x; 234 wheel_position.x += x;
236 wheel_position.y += y; 235 wheel_position.y += y;
237 last_motion_change.z += static_cast<f32>(y) / 100.0f; 236 last_motion_change.z += static_cast<f32>(y);
238 SetAxis(identifier, wheel_axis_x, static_cast<f32>(wheel_position.x)); 237 SetAxis(identifier, wheel_axis_x, static_cast<f32>(wheel_position.x));
239 SetAxis(identifier, wheel_axis_y, static_cast<f32>(wheel_position.y)); 238 SetAxis(identifier, wheel_axis_y, static_cast<f32>(wheel_position.y));
240} 239}
@@ -244,6 +243,11 @@ void Mouse::ReleaseAllButtons() {
244 button_pressed = false; 243 button_pressed = false;
245} 244}
246 245
246bool Mouse::IsMousePanningEnabled() {
247 // Disable mouse panning when a real mouse is connected
248 return Settings::values.mouse_panning && !Settings::values.mouse_enabled;
249}
250
247std::vector<Common::ParamPackage> Mouse::GetInputDevices() const { 251std::vector<Common::ParamPackage> Mouse::GetInputDevices() const {
248 std::vector<Common::ParamPackage> devices; 252 std::vector<Common::ParamPackage> devices;
249 devices.emplace_back(Common::ParamPackage{ 253 devices.emplace_back(Common::ParamPackage{
diff --git a/src/input_common/drivers/mouse.h b/src/input_common/drivers/mouse.h
index 0e8edcce1..2b93a40b9 100644
--- a/src/input_common/drivers/mouse.h
+++ b/src/input_common/drivers/mouse.h
@@ -99,6 +99,8 @@ private:
99 void UpdateStickInput(); 99 void UpdateStickInput();
100 void UpdateMotionInput(); 100 void UpdateMotionInput();
101 101
102 bool IsMousePanningEnabled();
103
102 Common::Input::ButtonNames GetUIButtonName(const Common::ParamPackage& params) const; 104 Common::Input::ButtonNames GetUIButtonName(const Common::ParamPackage& params) const;
103 105
104 Common::Vec2<int> mouse_origin; 106 Common::Vec2<int> mouse_origin;
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 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "common/input.h"
4#include "common/logging/log.h" 5#include "common/logging/log.h"
5#include "common/scope_exit.h" 6#include "common/scope_exit.h"
6#include "common/swap.h" 7#include "common/swap.h"
@@ -28,13 +29,13 @@ void JoyconDriver::Stop() {
28 input_thread = {}; 29 input_thread = {};
29} 30}
30 31
31DriverResult JoyconDriver::RequestDeviceAccess(SDL_hid_device_info* device_info) { 32Common::Input::DriverResult JoyconDriver::RequestDeviceAccess(SDL_hid_device_info* device_info) {
32 std::scoped_lock lock{mutex}; 33 std::scoped_lock lock{mutex};
33 34
34 handle_device_type = ControllerType::None; 35 handle_device_type = ControllerType::None;
35 GetDeviceType(device_info, handle_device_type); 36 GetDeviceType(device_info, handle_device_type);
36 if (handle_device_type == ControllerType::None) { 37 if (handle_device_type == ControllerType::None) {
37 return DriverResult::UnsupportedControllerType; 38 return Common::Input::DriverResult::UnsupportedControllerType;
38 } 39 }
39 40
40 hidapi_handle->handle = 41 hidapi_handle->handle =
@@ -43,15 +44,15 @@ DriverResult JoyconDriver::RequestDeviceAccess(SDL_hid_device_info* device_info)
43 if (!hidapi_handle->handle) { 44 if (!hidapi_handle->handle) {
44 LOG_ERROR(Input, "Yuzu can't gain access to this device: ID {:04X}:{:04X}.", 45 LOG_ERROR(Input, "Yuzu can't gain access to this device: ID {:04X}:{:04X}.",
45 device_info->vendor_id, device_info->product_id); 46 device_info->vendor_id, device_info->product_id);
46 return DriverResult::HandleInUse; 47 return Common::Input::DriverResult::HandleInUse;
47 } 48 }
48 SDL_hid_set_nonblocking(hidapi_handle->handle, 1); 49 SDL_hid_set_nonblocking(hidapi_handle->handle, 1);
49 return DriverResult::Success; 50 return Common::Input::DriverResult::Success;
50} 51}
51 52
52DriverResult JoyconDriver::InitializeDevice() { 53Common::Input::DriverResult JoyconDriver::InitializeDevice() {
53 if (!hidapi_handle->handle) { 54 if (!hidapi_handle->handle) {
54 return DriverResult::InvalidHandle; 55 return Common::Input::DriverResult::InvalidHandle;
55 } 56 }
56 std::scoped_lock lock{mutex}; 57 std::scoped_lock lock{mutex};
57 disable_input_thread = true; 58 disable_input_thread = true;
@@ -87,7 +88,7 @@ DriverResult JoyconDriver::InitializeDevice() {
87 rumble_protocol = std::make_unique<RumbleProtocol>(hidapi_handle); 88 rumble_protocol = std::make_unique<RumbleProtocol>(hidapi_handle);
88 89
89 // Get fixed joycon info 90 // Get fixed joycon info
90 if (generic_protocol->GetVersionNumber(version) != DriverResult::Success) { 91 if (generic_protocol->GetVersionNumber(version) != Common::Input::DriverResult::Success) {
91 // If this command fails the device doesn't accept configuration commands 92 // If this command fails the device doesn't accept configuration commands
92 input_only_device = true; 93 input_only_device = true;
93 } 94 }
@@ -129,7 +130,7 @@ DriverResult JoyconDriver::InitializeDevice() {
129 } 130 }
130 131
131 disable_input_thread = false; 132 disable_input_thread = false;
132 return DriverResult::Success; 133 return Common::Input::DriverResult::Success;
133} 134}
134 135
135void JoyconDriver::InputThread(std::stop_token stop_token) { 136void JoyconDriver::InputThread(std::stop_token stop_token) {
@@ -229,7 +230,7 @@ void JoyconDriver::OnNewData(std::span<u8> buffer) {
229 if (!amiibo_detected) { 230 if (!amiibo_detected) {
230 Joycon::TagInfo tag_info; 231 Joycon::TagInfo tag_info;
231 const auto result = nfc_protocol->GetTagInfo(tag_info); 232 const auto result = nfc_protocol->GetTagInfo(tag_info);
232 if (result == DriverResult::Success) { 233 if (result == Common::Input::DriverResult::Success) {
233 joycon_poller->UpdateAmiibo(tag_info); 234 joycon_poller->UpdateAmiibo(tag_info);
234 amiibo_detected = true; 235 amiibo_detected = true;
235 } 236 }
@@ -255,7 +256,7 @@ void JoyconDriver::OnNewData(std::span<u8> buffer) {
255 } 256 }
256} 257}
257 258
258DriverResult JoyconDriver::SetPollingMode() { 259Common::Input::DriverResult JoyconDriver::SetPollingMode() {
259 SCOPE_EXIT({ disable_input_thread = false; }); 260 SCOPE_EXIT({ disable_input_thread = false; });
260 disable_input_thread = true; 261 disable_input_thread = true;
261 262
@@ -270,7 +271,7 @@ DriverResult JoyconDriver::SetPollingMode() {
270 } 271 }
271 272
272 if (input_only_device) { 273 if (input_only_device) {
273 return DriverResult::NotSupported; 274 return Common::Input::DriverResult::NotSupported;
274 } 275 }
275 276
276 if (irs_protocol->IsEnabled()) { 277 if (irs_protocol->IsEnabled()) {
@@ -289,7 +290,7 @@ DriverResult JoyconDriver::SetPollingMode() {
289 290
290 if (irs_enabled && supported_features.irs) { 291 if (irs_enabled && supported_features.irs) {
291 auto result = irs_protocol->EnableIrs(); 292 auto result = irs_protocol->EnableIrs();
292 if (result == DriverResult::Success) { 293 if (result == Common::Input::DriverResult::Success) {
293 return result; 294 return result;
294 } 295 }
295 irs_protocol->DisableIrs(); 296 irs_protocol->DisableIrs();
@@ -299,7 +300,7 @@ DriverResult JoyconDriver::SetPollingMode() {
299 300
300 if (nfc_enabled && supported_features.nfc) { 301 if (nfc_enabled && supported_features.nfc) {
301 auto result = nfc_protocol->EnableNfc(); 302 auto result = nfc_protocol->EnableNfc();
302 if (result == DriverResult::Success) { 303 if (result == Common::Input::DriverResult::Success) {
303 return result; 304 return result;
304 } 305 }
305 nfc_protocol->DisableNfc(); 306 nfc_protocol->DisableNfc();
@@ -309,10 +310,10 @@ DriverResult JoyconDriver::SetPollingMode() {
309 310
310 if (hidbus_enabled && supported_features.hidbus) { 311 if (hidbus_enabled && supported_features.hidbus) {
311 auto result = ring_protocol->EnableRingCon(); 312 auto result = ring_protocol->EnableRingCon();
312 if (result == DriverResult::Success) { 313 if (result == Common::Input::DriverResult::Success) {
313 result = ring_protocol->StartRingconPolling(); 314 result = ring_protocol->StartRingconPolling();
314 } 315 }
315 if (result == DriverResult::Success) { 316 if (result == Common::Input::DriverResult::Success) {
316 ring_connected = true; 317 ring_connected = true;
317 return result; 318 return result;
318 } 319 }
@@ -324,7 +325,7 @@ DriverResult JoyconDriver::SetPollingMode() {
324 325
325 if (passive_enabled && supported_features.passive) { 326 if (passive_enabled && supported_features.passive) {
326 const auto result = generic_protocol->EnablePassiveMode(); 327 const auto result = generic_protocol->EnablePassiveMode();
327 if (result == DriverResult::Success) { 328 if (result == Common::Input::DriverResult::Success) {
328 return result; 329 return result;
329 } 330 }
330 LOG_ERROR(Input, "Error enabling passive mode"); 331 LOG_ERROR(Input, "Error enabling passive mode");
@@ -332,7 +333,7 @@ DriverResult JoyconDriver::SetPollingMode() {
332 333
333 // Default Mode 334 // Default Mode
334 const auto result = generic_protocol->EnableActiveMode(); 335 const auto result = generic_protocol->EnableActiveMode();
335 if (result != DriverResult::Success) { 336 if (result != Common::Input::DriverResult::Success) {
336 LOG_ERROR(Input, "Error enabling active mode"); 337 LOG_ERROR(Input, "Error enabling active mode");
337 } 338 }
338 // Switch calls this function after enabling active mode 339 // Switch calls this function after enabling active mode
@@ -396,26 +397,26 @@ bool JoyconDriver::IsPayloadCorrect(int status, std::span<const u8> buffer) {
396 return true; 397 return true;
397} 398}
398 399
399DriverResult JoyconDriver::SetVibration(const VibrationValue& vibration) { 400Common::Input::DriverResult JoyconDriver::SetVibration(const VibrationValue& vibration) {
400 std::scoped_lock lock{mutex}; 401 std::scoped_lock lock{mutex};
401 if (disable_input_thread) { 402 if (disable_input_thread) {
402 return DriverResult::HandleInUse; 403 return Common::Input::DriverResult::HandleInUse;
403 } 404 }
404 return rumble_protocol->SendVibration(vibration); 405 return rumble_protocol->SendVibration(vibration);
405} 406}
406 407
407DriverResult JoyconDriver::SetLedConfig(u8 led_pattern) { 408Common::Input::DriverResult JoyconDriver::SetLedConfig(u8 led_pattern) {
408 std::scoped_lock lock{mutex}; 409 std::scoped_lock lock{mutex};
409 if (disable_input_thread) { 410 if (disable_input_thread) {
410 return DriverResult::HandleInUse; 411 return Common::Input::DriverResult::HandleInUse;
411 } 412 }
412 return generic_protocol->SetLedPattern(led_pattern); 413 return generic_protocol->SetLedPattern(led_pattern);
413} 414}
414 415
415DriverResult JoyconDriver::SetIrsConfig(IrsMode mode_, IrsResolution format_) { 416Common::Input::DriverResult JoyconDriver::SetIrsConfig(IrsMode mode_, IrsResolution format_) {
416 std::scoped_lock lock{mutex}; 417 std::scoped_lock lock{mutex};
417 if (disable_input_thread) { 418 if (disable_input_thread) {
418 return DriverResult::HandleInUse; 419 return Common::Input::DriverResult::HandleInUse;
419 } 420 }
420 disable_input_thread = true; 421 disable_input_thread = true;
421 const auto result = irs_protocol->SetIrsConfig(mode_, format_); 422 const auto result = irs_protocol->SetIrsConfig(mode_, format_);
@@ -423,7 +424,7 @@ DriverResult JoyconDriver::SetIrsConfig(IrsMode mode_, IrsResolution format_) {
423 return result; 424 return result;
424} 425}
425 426
426DriverResult JoyconDriver::SetPassiveMode() { 427Common::Input::DriverResult JoyconDriver::SetPassiveMode() {
427 std::scoped_lock lock{mutex}; 428 std::scoped_lock lock{mutex};
428 motion_enabled = false; 429 motion_enabled = false;
429 hidbus_enabled = false; 430 hidbus_enabled = false;
@@ -433,7 +434,7 @@ DriverResult JoyconDriver::SetPassiveMode() {
433 return SetPollingMode(); 434 return SetPollingMode();
434} 435}
435 436
436DriverResult JoyconDriver::SetActiveMode() { 437Common::Input::DriverResult JoyconDriver::SetActiveMode() {
437 if (is_ring_disabled_by_irs) { 438 if (is_ring_disabled_by_irs) {
438 is_ring_disabled_by_irs = false; 439 is_ring_disabled_by_irs = false;
439 SetActiveMode(); 440 SetActiveMode();
@@ -449,11 +450,11 @@ DriverResult JoyconDriver::SetActiveMode() {
449 return SetPollingMode(); 450 return SetPollingMode();
450} 451}
451 452
452DriverResult JoyconDriver::SetIrMode() { 453Common::Input::DriverResult JoyconDriver::SetIrMode() {
453 std::scoped_lock lock{mutex}; 454 std::scoped_lock lock{mutex};
454 455
455 if (!supported_features.irs) { 456 if (!supported_features.irs) {
456 return DriverResult::NotSupported; 457 return Common::Input::DriverResult::NotSupported;
457 } 458 }
458 459
459 if (ring_connected) { 460 if (ring_connected) {
@@ -468,11 +469,11 @@ DriverResult JoyconDriver::SetIrMode() {
468 return SetPollingMode(); 469 return SetPollingMode();
469} 470}
470 471
471DriverResult JoyconDriver::SetNfcMode() { 472Common::Input::DriverResult JoyconDriver::SetNfcMode() {
472 std::scoped_lock lock{mutex}; 473 std::scoped_lock lock{mutex};
473 474
474 if (!supported_features.nfc) { 475 if (!supported_features.nfc) {
475 return DriverResult::NotSupported; 476 return Common::Input::DriverResult::NotSupported;
476 } 477 }
477 478
478 motion_enabled = true; 479 motion_enabled = true;
@@ -483,11 +484,11 @@ DriverResult JoyconDriver::SetNfcMode() {
483 return SetPollingMode(); 484 return SetPollingMode();
484} 485}
485 486
486DriverResult JoyconDriver::SetRingConMode() { 487Common::Input::DriverResult JoyconDriver::SetRingConMode() {
487 std::scoped_lock lock{mutex}; 488 std::scoped_lock lock{mutex};
488 489
489 if (!supported_features.hidbus) { 490 if (!supported_features.hidbus) {
490 return DriverResult::NotSupported; 491 return Common::Input::DriverResult::NotSupported;
491 } 492 }
492 493
493 motion_enabled = true; 494 motion_enabled = true;
@@ -499,20 +500,20 @@ DriverResult JoyconDriver::SetRingConMode() {
499 const auto result = SetPollingMode(); 500 const auto result = SetPollingMode();
500 501
501 if (!ring_connected) { 502 if (!ring_connected) {
502 return DriverResult::NoDeviceDetected; 503 return Common::Input::DriverResult::NoDeviceDetected;
503 } 504 }
504 505
505 return result; 506 return result;
506} 507}
507 508
508DriverResult JoyconDriver::StartNfcPolling() { 509Common::Input::DriverResult JoyconDriver::StartNfcPolling() {
509 std::scoped_lock lock{mutex}; 510 std::scoped_lock lock{mutex};
510 511
511 if (!supported_features.nfc) { 512 if (!supported_features.nfc) {
512 return DriverResult::NotSupported; 513 return Common::Input::DriverResult::NotSupported;
513 } 514 }
514 if (!nfc_protocol->IsEnabled()) { 515 if (!nfc_protocol->IsEnabled()) {
515 return DriverResult::Disabled; 516 return Common::Input::DriverResult::Disabled;
516 } 517 }
517 518
518 disable_input_thread = true; 519 disable_input_thread = true;
@@ -522,14 +523,14 @@ DriverResult JoyconDriver::StartNfcPolling() {
522 return result; 523 return result;
523} 524}
524 525
525DriverResult JoyconDriver::StopNfcPolling() { 526Common::Input::DriverResult JoyconDriver::StopNfcPolling() {
526 std::scoped_lock lock{mutex}; 527 std::scoped_lock lock{mutex};
527 528
528 if (!supported_features.nfc) { 529 if (!supported_features.nfc) {
529 return DriverResult::NotSupported; 530 return Common::Input::DriverResult::NotSupported;
530 } 531 }
531 if (!nfc_protocol->IsEnabled()) { 532 if (!nfc_protocol->IsEnabled()) {
532 return DriverResult::Disabled; 533 return Common::Input::DriverResult::Disabled;
533 } 534 }
534 535
535 disable_input_thread = true; 536 disable_input_thread = true;
@@ -544,17 +545,17 @@ DriverResult JoyconDriver::StopNfcPolling() {
544 return result; 545 return result;
545} 546}
546 547
547DriverResult JoyconDriver::ReadAmiiboData(std::vector<u8>& out_data) { 548Common::Input::DriverResult JoyconDriver::ReadAmiiboData(std::vector<u8>& out_data) {
548 std::scoped_lock lock{mutex}; 549 std::scoped_lock lock{mutex};
549 550
550 if (!supported_features.nfc) { 551 if (!supported_features.nfc) {
551 return DriverResult::NotSupported; 552 return Common::Input::DriverResult::NotSupported;
552 } 553 }
553 if (!nfc_protocol->IsEnabled()) { 554 if (!nfc_protocol->IsEnabled()) {
554 return DriverResult::Disabled; 555 return Common::Input::DriverResult::Disabled;
555 } 556 }
556 if (!amiibo_detected) { 557 if (!amiibo_detected) {
557 return DriverResult::ErrorWritingData; 558 return Common::Input::DriverResult::ErrorWritingData;
558 } 559 }
559 560
560 out_data.resize(0x21C); 561 out_data.resize(0x21C);
@@ -565,17 +566,17 @@ DriverResult JoyconDriver::ReadAmiiboData(std::vector<u8>& out_data) {
565 return result; 566 return result;
566} 567}
567 568
568DriverResult JoyconDriver::WriteNfcData(std::span<const u8> data) { 569Common::Input::DriverResult JoyconDriver::WriteNfcData(std::span<const u8> data) {
569 std::scoped_lock lock{mutex}; 570 std::scoped_lock lock{mutex};
570 571
571 if (!supported_features.nfc) { 572 if (!supported_features.nfc) {
572 return DriverResult::NotSupported; 573 return Common::Input::DriverResult::NotSupported;
573 } 574 }
574 if (!nfc_protocol->IsEnabled()) { 575 if (!nfc_protocol->IsEnabled()) {
575 return DriverResult::Disabled; 576 return Common::Input::DriverResult::Disabled;
576 } 577 }
577 if (!amiibo_detected) { 578 if (!amiibo_detected) {
578 return DriverResult::ErrorWritingData; 579 return Common::Input::DriverResult::ErrorWritingData;
579 } 580 }
580 581
581 disable_input_thread = true; 582 disable_input_thread = true;
@@ -585,18 +586,18 @@ DriverResult JoyconDriver::WriteNfcData(std::span<const u8> data) {
585 return result; 586 return result;
586} 587}
587 588
588DriverResult JoyconDriver::ReadMifareData(std::span<const MifareReadChunk> data, 589Common::Input::DriverResult JoyconDriver::ReadMifareData(std::span<const MifareReadChunk> data,
589 std::span<MifareReadData> out_data) { 590 std::span<MifareReadData> out_data) {
590 std::scoped_lock lock{mutex}; 591 std::scoped_lock lock{mutex};
591 592
592 if (!supported_features.nfc) { 593 if (!supported_features.nfc) {
593 return DriverResult::NotSupported; 594 return Common::Input::DriverResult::NotSupported;
594 } 595 }
595 if (!nfc_protocol->IsEnabled()) { 596 if (!nfc_protocol->IsEnabled()) {
596 return DriverResult::Disabled; 597 return Common::Input::DriverResult::Disabled;
597 } 598 }
598 if (!amiibo_detected) { 599 if (!amiibo_detected) {
599 return DriverResult::ErrorWritingData; 600 return Common::Input::DriverResult::ErrorWritingData;
600 } 601 }
601 602
602 disable_input_thread = true; 603 disable_input_thread = true;
@@ -606,17 +607,17 @@ DriverResult JoyconDriver::ReadMifareData(std::span<const MifareReadChunk> data,
606 return result; 607 return result;
607} 608}
608 609
609DriverResult JoyconDriver::WriteMifareData(std::span<const MifareWriteChunk> data) { 610Common::Input::DriverResult JoyconDriver::WriteMifareData(std::span<const MifareWriteChunk> data) {
610 std::scoped_lock lock{mutex}; 611 std::scoped_lock lock{mutex};
611 612
612 if (!supported_features.nfc) { 613 if (!supported_features.nfc) {
613 return DriverResult::NotSupported; 614 return Common::Input::DriverResult::NotSupported;
614 } 615 }
615 if (!nfc_protocol->IsEnabled()) { 616 if (!nfc_protocol->IsEnabled()) {
616 return DriverResult::Disabled; 617 return Common::Input::DriverResult::Disabled;
617 } 618 }
618 if (!amiibo_detected) { 619 if (!amiibo_detected) {
619 return DriverResult::ErrorWritingData; 620 return Common::Input::DriverResult::ErrorWritingData;
620 } 621 }
621 622
622 disable_input_thread = true; 623 disable_input_thread = true;
@@ -675,8 +676,8 @@ void JoyconDriver::SetCallbacks(const JoyconCallbacks& callbacks) {
675 joycon_poller->SetCallbacks(callbacks); 676 joycon_poller->SetCallbacks(callbacks);
676} 677}
677 678
678DriverResult JoyconDriver::GetDeviceType(SDL_hid_device_info* device_info, 679Common::Input::DriverResult JoyconDriver::GetDeviceType(SDL_hid_device_info* device_info,
679 ControllerType& controller_type) { 680 ControllerType& controller_type) {
680 static constexpr std::array<std::pair<u32, ControllerType>, 6> supported_devices{ 681 static constexpr std::array<std::pair<u32, ControllerType>, 6> supported_devices{
681 std::pair<u32, ControllerType>{0x2006, ControllerType::Left}, 682 std::pair<u32, ControllerType>{0x2006, ControllerType::Left},
682 {0x2007, ControllerType::Right}, 683 {0x2007, ControllerType::Right},
@@ -686,25 +687,25 @@ DriverResult JoyconDriver::GetDeviceType(SDL_hid_device_info* device_info,
686 687
687 controller_type = ControllerType::None; 688 controller_type = ControllerType::None;
688 if (device_info->vendor_id != nintendo_vendor_id) { 689 if (device_info->vendor_id != nintendo_vendor_id) {
689 return DriverResult::UnsupportedControllerType; 690 return Common::Input::DriverResult::UnsupportedControllerType;
690 } 691 }
691 692
692 for (const auto& [product_id, type] : supported_devices) { 693 for (const auto& [product_id, type] : supported_devices) {
693 if (device_info->product_id == static_cast<u16>(product_id)) { 694 if (device_info->product_id == static_cast<u16>(product_id)) {
694 controller_type = type; 695 controller_type = type;
695 return Joycon::DriverResult::Success; 696 return Common::Input::DriverResult::Success;
696 } 697 }
697 } 698 }
698 return Joycon::DriverResult::UnsupportedControllerType; 699 return Common::Input::DriverResult::UnsupportedControllerType;
699} 700}
700 701
701DriverResult JoyconDriver::GetSerialNumber(SDL_hid_device_info* device_info, 702Common::Input::DriverResult JoyconDriver::GetSerialNumber(SDL_hid_device_info* device_info,
702 SerialNumber& serial_number) { 703 SerialNumber& serial_number) {
703 if (device_info->serial_number == nullptr) { 704 if (device_info->serial_number == nullptr) {
704 return DriverResult::Unknown; 705 return Common::Input::DriverResult::Unknown;
705 } 706 }
706 std::memcpy(&serial_number, device_info->serial_number, 15); 707 std::memcpy(&serial_number, device_info->serial_number, 15);
707 return Joycon::DriverResult::Success; 708 return Common::Input::DriverResult::Success;
708} 709}
709 710
710} // namespace InputCommon::Joycon 711} // 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 @@
11 11
12#include "input_common/helpers/joycon_protocol/joycon_types.h" 12#include "input_common/helpers/joycon_protocol/joycon_types.h"
13 13
14namespace Common::Input {
15enum class DriverResult;
16}
17
14namespace InputCommon::Joycon { 18namespace InputCommon::Joycon {
15class CalibrationProtocol; 19class CalibrationProtocol;
16class GenericProtocol; 20class GenericProtocol;
@@ -26,8 +30,8 @@ public:
26 30
27 ~JoyconDriver(); 31 ~JoyconDriver();
28 32
29 DriverResult RequestDeviceAccess(SDL_hid_device_info* device_info); 33 Common::Input::DriverResult RequestDeviceAccess(SDL_hid_device_info* device_info);
30 DriverResult InitializeDevice(); 34 Common::Input::DriverResult InitializeDevice();
31 void Stop(); 35 void Stop();
32 36
33 bool IsConnected() const; 37 bool IsConnected() const;
@@ -41,31 +45,31 @@ public:
41 SerialNumber GetSerialNumber() const; 45 SerialNumber GetSerialNumber() const;
42 SerialNumber GetHandleSerialNumber() const; 46 SerialNumber GetHandleSerialNumber() const;
43 47
44 DriverResult SetVibration(const VibrationValue& vibration); 48 Common::Input::DriverResult SetVibration(const VibrationValue& vibration);
45 DriverResult SetLedConfig(u8 led_pattern); 49 Common::Input::DriverResult SetLedConfig(u8 led_pattern);
46 DriverResult SetIrsConfig(IrsMode mode_, IrsResolution format_); 50 Common::Input::DriverResult SetIrsConfig(IrsMode mode_, IrsResolution format_);
47 DriverResult SetPassiveMode(); 51 Common::Input::DriverResult SetPassiveMode();
48 DriverResult SetActiveMode(); 52 Common::Input::DriverResult SetActiveMode();
49 DriverResult SetIrMode(); 53 Common::Input::DriverResult SetIrMode();
50 DriverResult SetNfcMode(); 54 Common::Input::DriverResult SetNfcMode();
51 DriverResult SetRingConMode(); 55 Common::Input::DriverResult SetRingConMode();
52 DriverResult StartNfcPolling(); 56 Common::Input::DriverResult StartNfcPolling();
53 DriverResult StopNfcPolling(); 57 Common::Input::DriverResult StopNfcPolling();
54 DriverResult ReadAmiiboData(std::vector<u8>& out_data); 58 Common::Input::DriverResult ReadAmiiboData(std::vector<u8>& out_data);
55 DriverResult WriteNfcData(std::span<const u8> data); 59 Common::Input::DriverResult WriteNfcData(std::span<const u8> data);
56 DriverResult ReadMifareData(std::span<const MifareReadChunk> request, 60 Common::Input::DriverResult ReadMifareData(std::span<const MifareReadChunk> request,
57 std::span<MifareReadData> out_data); 61 std::span<MifareReadData> out_data);
58 DriverResult WriteMifareData(std::span<const MifareWriteChunk> request); 62 Common::Input::DriverResult WriteMifareData(std::span<const MifareWriteChunk> request);
59 63
60 void SetCallbacks(const JoyconCallbacks& callbacks); 64 void SetCallbacks(const JoyconCallbacks& callbacks);
61 65
62 // Returns device type from hidapi handle 66 // Returns device type from hidapi handle
63 static DriverResult GetDeviceType(SDL_hid_device_info* device_info, 67 static Common::Input::DriverResult GetDeviceType(SDL_hid_device_info* device_info,
64 ControllerType& controller_type); 68 ControllerType& controller_type);
65 69
66 // Returns serial number from hidapi handle 70 // Returns serial number from hidapi handle
67 static DriverResult GetSerialNumber(SDL_hid_device_info* device_info, 71 static Common::Input::DriverResult GetSerialNumber(SDL_hid_device_info* device_info,
68 SerialNumber& serial_number); 72 SerialNumber& serial_number);
69 73
70private: 74private:
71 struct SupportedFeatures { 75 struct SupportedFeatures {
@@ -84,7 +88,7 @@ private:
84 void OnNewData(std::span<u8> buffer); 88 void OnNewData(std::span<u8> buffer);
85 89
86 /// Updates device configuration to enable or disable features 90 /// Updates device configuration to enable or disable features
87 DriverResult SetPollingMode(); 91 Common::Input::DriverResult SetPollingMode();
88 92
89 /// Returns true if input thread is valid and doesn't need to be stopped 93 /// Returns true if input thread is valid and doesn't need to be stopped
90 bool IsInputThreadValid() const; 94 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 @@
3 3
4#include <cstring> 4#include <cstring>
5 5
6#include "common/input.h"
6#include "input_common/helpers/joycon_protocol/calibration.h" 7#include "input_common/helpers/joycon_protocol/calibration.h"
7#include "input_common/helpers/joycon_protocol/joycon_types.h" 8#include "input_common/helpers/joycon_protocol/joycon_types.h"
8 9
@@ -11,28 +12,29 @@ namespace InputCommon::Joycon {
11CalibrationProtocol::CalibrationProtocol(std::shared_ptr<JoyconHandle> handle) 12CalibrationProtocol::CalibrationProtocol(std::shared_ptr<JoyconHandle> handle)
12 : JoyconCommonProtocol(std::move(handle)) {} 13 : JoyconCommonProtocol(std::move(handle)) {}
13 14
14DriverResult CalibrationProtocol::GetLeftJoyStickCalibration(JoyStickCalibration& calibration) { 15Common::Input::DriverResult CalibrationProtocol::GetLeftJoyStickCalibration(
16 JoyStickCalibration& calibration) {
15 ScopedSetBlocking sb(this); 17 ScopedSetBlocking sb(this);
16 DriverResult result{DriverResult::Success}; 18 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
17 JoystickLeftSpiCalibration spi_calibration{}; 19 JoystickLeftSpiCalibration spi_calibration{};
18 bool has_user_calibration = false; 20 bool has_user_calibration = false;
19 calibration = {}; 21 calibration = {};
20 22
21 if (result == DriverResult::Success) { 23 if (result == Common::Input::DriverResult::Success) {
22 result = HasUserCalibration(SpiAddress::USER_LEFT_MAGIC, has_user_calibration); 24 result = HasUserCalibration(SpiAddress::USER_LEFT_MAGIC, has_user_calibration);
23 } 25 }
24 26
25 // Read User defined calibration 27 // Read User defined calibration
26 if (result == DriverResult::Success && has_user_calibration) { 28 if (result == Common::Input::DriverResult::Success && has_user_calibration) {
27 result = ReadSPI(SpiAddress::USER_LEFT_DATA, spi_calibration); 29 result = ReadSPI(SpiAddress::USER_LEFT_DATA, spi_calibration);
28 } 30 }
29 31
30 // Read Factory calibration 32 // Read Factory calibration
31 if (result == DriverResult::Success && !has_user_calibration) { 33 if (result == Common::Input::DriverResult::Success && !has_user_calibration) {
32 result = ReadSPI(SpiAddress::FACT_LEFT_DATA, spi_calibration); 34 result = ReadSPI(SpiAddress::FACT_LEFT_DATA, spi_calibration);
33 } 35 }
34 36
35 if (result == DriverResult::Success) { 37 if (result == Common::Input::DriverResult::Success) {
36 calibration.x.center = GetXAxisCalibrationValue(spi_calibration.center); 38 calibration.x.center = GetXAxisCalibrationValue(spi_calibration.center);
37 calibration.y.center = GetYAxisCalibrationValue(spi_calibration.center); 39 calibration.y.center = GetYAxisCalibrationValue(spi_calibration.center);
38 calibration.x.min = GetXAxisCalibrationValue(spi_calibration.min); 40 calibration.x.min = GetXAxisCalibrationValue(spi_calibration.min);
@@ -47,28 +49,29 @@ DriverResult CalibrationProtocol::GetLeftJoyStickCalibration(JoyStickCalibration
47 return result; 49 return result;
48} 50}
49 51
50DriverResult CalibrationProtocol::GetRightJoyStickCalibration(JoyStickCalibration& calibration) { 52Common::Input::DriverResult CalibrationProtocol::GetRightJoyStickCalibration(
53 JoyStickCalibration& calibration) {
51 ScopedSetBlocking sb(this); 54 ScopedSetBlocking sb(this);
52 DriverResult result{DriverResult::Success}; 55 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
53 JoystickRightSpiCalibration spi_calibration{}; 56 JoystickRightSpiCalibration spi_calibration{};
54 bool has_user_calibration = false; 57 bool has_user_calibration = false;
55 calibration = {}; 58 calibration = {};
56 59
57 if (result == DriverResult::Success) { 60 if (result == Common::Input::DriverResult::Success) {
58 result = HasUserCalibration(SpiAddress::USER_RIGHT_MAGIC, has_user_calibration); 61 result = HasUserCalibration(SpiAddress::USER_RIGHT_MAGIC, has_user_calibration);
59 } 62 }
60 63
61 // Read User defined calibration 64 // Read User defined calibration
62 if (result == DriverResult::Success && has_user_calibration) { 65 if (result == Common::Input::DriverResult::Success && has_user_calibration) {
63 result = ReadSPI(SpiAddress::USER_RIGHT_DATA, spi_calibration); 66 result = ReadSPI(SpiAddress::USER_RIGHT_DATA, spi_calibration);
64 } 67 }
65 68
66 // Read Factory calibration 69 // Read Factory calibration
67 if (result == DriverResult::Success && !has_user_calibration) { 70 if (result == Common::Input::DriverResult::Success && !has_user_calibration) {
68 result = ReadSPI(SpiAddress::FACT_RIGHT_DATA, spi_calibration); 71 result = ReadSPI(SpiAddress::FACT_RIGHT_DATA, spi_calibration);
69 } 72 }
70 73
71 if (result == DriverResult::Success) { 74 if (result == Common::Input::DriverResult::Success) {
72 calibration.x.center = GetXAxisCalibrationValue(spi_calibration.center); 75 calibration.x.center = GetXAxisCalibrationValue(spi_calibration.center);
73 calibration.y.center = GetYAxisCalibrationValue(spi_calibration.center); 76 calibration.y.center = GetYAxisCalibrationValue(spi_calibration.center);
74 calibration.x.min = GetXAxisCalibrationValue(spi_calibration.min); 77 calibration.x.min = GetXAxisCalibrationValue(spi_calibration.min);
@@ -83,28 +86,28 @@ DriverResult CalibrationProtocol::GetRightJoyStickCalibration(JoyStickCalibratio
83 return result; 86 return result;
84} 87}
85 88
86DriverResult CalibrationProtocol::GetImuCalibration(MotionCalibration& calibration) { 89Common::Input::DriverResult CalibrationProtocol::GetImuCalibration(MotionCalibration& calibration) {
87 ScopedSetBlocking sb(this); 90 ScopedSetBlocking sb(this);
88 DriverResult result{DriverResult::Success}; 91 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
89 ImuSpiCalibration spi_calibration{}; 92 ImuSpiCalibration spi_calibration{};
90 bool has_user_calibration = false; 93 bool has_user_calibration = false;
91 calibration = {}; 94 calibration = {};
92 95
93 if (result == DriverResult::Success) { 96 if (result == Common::Input::DriverResult::Success) {
94 result = HasUserCalibration(SpiAddress::USER_IMU_MAGIC, has_user_calibration); 97 result = HasUserCalibration(SpiAddress::USER_IMU_MAGIC, has_user_calibration);
95 } 98 }
96 99
97 // Read User defined calibration 100 // Read User defined calibration
98 if (result == DriverResult::Success && has_user_calibration) { 101 if (result == Common::Input::DriverResult::Success && has_user_calibration) {
99 result = ReadSPI(SpiAddress::USER_IMU_DATA, spi_calibration); 102 result = ReadSPI(SpiAddress::USER_IMU_DATA, spi_calibration);
100 } 103 }
101 104
102 // Read Factory calibration 105 // Read Factory calibration
103 if (result == DriverResult::Success && !has_user_calibration) { 106 if (result == Common::Input::DriverResult::Success && !has_user_calibration) {
104 result = ReadSPI(SpiAddress::FACT_IMU_DATA, spi_calibration); 107 result = ReadSPI(SpiAddress::FACT_IMU_DATA, spi_calibration);
105 } 108 }
106 109
107 if (result == DriverResult::Success) { 110 if (result == Common::Input::DriverResult::Success) {
108 calibration.accelerometer[0].offset = spi_calibration.accelerometer_offset[0]; 111 calibration.accelerometer[0].offset = spi_calibration.accelerometer_offset[0];
109 calibration.accelerometer[1].offset = spi_calibration.accelerometer_offset[1]; 112 calibration.accelerometer[1].offset = spi_calibration.accelerometer_offset[1];
110 calibration.accelerometer[2].offset = spi_calibration.accelerometer_offset[2]; 113 calibration.accelerometer[2].offset = spi_calibration.accelerometer_offset[2];
@@ -127,8 +130,8 @@ DriverResult CalibrationProtocol::GetImuCalibration(MotionCalibration& calibrati
127 return result; 130 return result;
128} 131}
129 132
130DriverResult CalibrationProtocol::GetRingCalibration(RingCalibration& calibration, 133Common::Input::DriverResult CalibrationProtocol::GetRingCalibration(RingCalibration& calibration,
131 s16 current_value) { 134 s16 current_value) {
132 constexpr s16 DefaultRingRange{800}; 135 constexpr s16 DefaultRingRange{800};
133 136
134 // TODO: Get default calibration form ring itself 137 // TODO: Get default calibration form ring itself
@@ -144,15 +147,15 @@ DriverResult CalibrationProtocol::GetRingCalibration(RingCalibration& calibratio
144 .max_value = ring_data_max, 147 .max_value = ring_data_max,
145 .min_value = ring_data_min, 148 .min_value = ring_data_min,
146 }; 149 };
147 return DriverResult::Success; 150 return Common::Input::DriverResult::Success;
148} 151}
149 152
150DriverResult CalibrationProtocol::HasUserCalibration(SpiAddress address, 153Common::Input::DriverResult CalibrationProtocol::HasUserCalibration(SpiAddress address,
151 bool& has_user_calibration) { 154 bool& has_user_calibration) {
152 MagicSpiCalibration spi_magic{}; 155 MagicSpiCalibration spi_magic{};
153 const DriverResult result{ReadSPI(address, spi_magic)}; 156 const Common::Input::DriverResult result{ReadSPI(address, spi_magic)};
154 has_user_calibration = false; 157 has_user_calibration = false;
155 if (result == DriverResult::Success) { 158 if (result == Common::Input::DriverResult::Success) {
156 has_user_calibration = spi_magic.first == CalibrationMagic::USR_MAGIC_0 && 159 has_user_calibration = spi_magic.first == CalibrationMagic::USR_MAGIC_0 &&
157 spi_magic.second == CalibrationMagic::USR_MAGIC_1; 160 spi_magic.second == CalibrationMagic::USR_MAGIC_1;
158 } 161 }
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 @@
12 12
13#include "input_common/helpers/joycon_protocol/common_protocol.h" 13#include "input_common/helpers/joycon_protocol/common_protocol.h"
14 14
15namespace InputCommon::Joycon { 15namespace Common::Input {
16enum class DriverResult; 16enum class DriverResult;
17}
18
19namespace InputCommon::Joycon {
17struct JoyStickCalibration; 20struct JoyStickCalibration;
18struct IMUCalibration; 21struct IMUCalibration;
19struct JoyconHandle; 22struct JoyconHandle;
@@ -31,30 +34,30 @@ public:
31 * @param is_factory_calibration if true factory values will be returned 34 * @param is_factory_calibration if true factory values will be returned
32 * @returns JoyStickCalibration of the left joystick 35 * @returns JoyStickCalibration of the left joystick
33 */ 36 */
34 DriverResult GetLeftJoyStickCalibration(JoyStickCalibration& calibration); 37 Common::Input::DriverResult GetLeftJoyStickCalibration(JoyStickCalibration& calibration);
35 38
36 /** 39 /**
37 * Sends a request to obtain the right stick calibration from memory 40 * Sends a request to obtain the right stick calibration from memory
38 * @param is_factory_calibration if true factory values will be returned 41 * @param is_factory_calibration if true factory values will be returned
39 * @returns JoyStickCalibration of the right joystick 42 * @returns JoyStickCalibration of the right joystick
40 */ 43 */
41 DriverResult GetRightJoyStickCalibration(JoyStickCalibration& calibration); 44 Common::Input::DriverResult GetRightJoyStickCalibration(JoyStickCalibration& calibration);
42 45
43 /** 46 /**
44 * Sends a request to obtain the motion calibration from memory 47 * Sends a request to obtain the motion calibration from memory
45 * @returns ImuCalibration of the motion sensor 48 * @returns ImuCalibration of the motion sensor
46 */ 49 */
47 DriverResult GetImuCalibration(MotionCalibration& calibration); 50 Common::Input::DriverResult GetImuCalibration(MotionCalibration& calibration);
48 51
49 /** 52 /**
50 * Calculates on run time the proper calibration of the ring controller 53 * Calculates on run time the proper calibration of the ring controller
51 * @returns RingCalibration of the ring sensor 54 * @returns RingCalibration of the ring sensor
52 */ 55 */
53 DriverResult GetRingCalibration(RingCalibration& calibration, s16 current_value); 56 Common::Input::DriverResult GetRingCalibration(RingCalibration& calibration, s16 current_value);
54 57
55private: 58private:
56 /// Returns true if the specified address corresponds to the magic value of user calibration 59 /// Returns true if the specified address corresponds to the magic value of user calibration
57 DriverResult HasUserCalibration(SpiAddress address, bool& has_user_calibration); 60 Common::Input::DriverResult HasUserCalibration(SpiAddress address, bool& has_user_calibration);
58 61
59 /// Converts a raw calibration block to an u16 value containing the x axis value 62 /// Converts a raw calibration block to an u16 value containing the x axis value
60 u16 GetXAxisCalibrationValue(std::span<u8> block) const; 63 u16 GetXAxisCalibrationValue(std::span<u8> 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..a6eecf980 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 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "common/input.h"
4#include "common/logging/log.h" 5#include "common/logging/log.h"
5#include "input_common/helpers/joycon_protocol/common_protocol.h" 6#include "input_common/helpers/joycon_protocol/common_protocol.h"
6 7
@@ -21,10 +22,10 @@ void JoyconCommonProtocol::SetNonBlocking() {
21 SDL_hid_set_nonblocking(hidapi_handle->handle, 1); 22 SDL_hid_set_nonblocking(hidapi_handle->handle, 1);
22} 23}
23 24
24DriverResult JoyconCommonProtocol::GetDeviceType(ControllerType& controller_type) { 25Common::Input::DriverResult JoyconCommonProtocol::GetDeviceType(ControllerType& controller_type) {
25 const auto result = ReadSPI(SpiAddress::DEVICE_TYPE, controller_type); 26 const auto result = ReadSPI(SpiAddress::DEVICE_TYPE, controller_type);
26 27
27 if (result == DriverResult::Success) { 28 if (result == Common::Input::DriverResult::Success) {
28 // Fallback to 3rd party pro controllers 29 // Fallback to 3rd party pro controllers
29 if (controller_type == ControllerType::None) { 30 if (controller_type == ControllerType::None) {
30 controller_type = ControllerType::Pro; 31 controller_type = ControllerType::Pro;
@@ -34,12 +35,13 @@ DriverResult JoyconCommonProtocol::GetDeviceType(ControllerType& controller_type
34 return result; 35 return result;
35} 36}
36 37
37DriverResult JoyconCommonProtocol::CheckDeviceAccess(SDL_hid_device_info* device_info) { 38Common::Input::DriverResult JoyconCommonProtocol::CheckDeviceAccess(
39 SDL_hid_device_info* device_info) {
38 ControllerType controller_type{ControllerType::None}; 40 ControllerType controller_type{ControllerType::None};
39 const auto result = GetDeviceType(controller_type); 41 const auto result = GetDeviceType(controller_type);
40 42
41 if (result != DriverResult::Success || controller_type == ControllerType::None) { 43 if (result != Common::Input::DriverResult::Success || controller_type == ControllerType::None) {
42 return DriverResult::UnsupportedControllerType; 44 return Common::Input::DriverResult::UnsupportedControllerType;
43 } 45 }
44 46
45 hidapi_handle->handle = 47 hidapi_handle->handle =
@@ -48,32 +50,32 @@ DriverResult JoyconCommonProtocol::CheckDeviceAccess(SDL_hid_device_info* device
48 if (!hidapi_handle->handle) { 50 if (!hidapi_handle->handle) {
49 LOG_ERROR(Input, "Yuzu can't gain access to this device: ID {:04X}:{:04X}.", 51 LOG_ERROR(Input, "Yuzu can't gain access to this device: ID {:04X}:{:04X}.",
50 device_info->vendor_id, device_info->product_id); 52 device_info->vendor_id, device_info->product_id);
51 return DriverResult::HandleInUse; 53 return Common::Input::DriverResult::HandleInUse;
52 } 54 }
53 55
54 SetNonBlocking(); 56 SetNonBlocking();
55 return DriverResult::Success; 57 return Common::Input::DriverResult::Success;
56} 58}
57 59
58DriverResult JoyconCommonProtocol::SetReportMode(ReportMode report_mode) { 60Common::Input::DriverResult JoyconCommonProtocol::SetReportMode(ReportMode report_mode) {
59 const std::array<u8, 1> buffer{static_cast<u8>(report_mode)}; 61 const std::array<u8, 1> buffer{static_cast<u8>(report_mode)};
60 return SendSubCommand(SubCommand::SET_REPORT_MODE, buffer); 62 return SendSubCommand(SubCommand::SET_REPORT_MODE, buffer);
61} 63}
62 64
63DriverResult JoyconCommonProtocol::SendRawData(std::span<const u8> buffer) { 65Common::Input::DriverResult JoyconCommonProtocol::SendRawData(std::span<const u8> buffer) {
64 const auto result = SDL_hid_write(hidapi_handle->handle, buffer.data(), buffer.size()); 66 const auto result = SDL_hid_write(hidapi_handle->handle, buffer.data(), buffer.size());
65 67
66 if (result == -1) { 68 if (result == -1) {
67 return DriverResult::ErrorWritingData; 69 return Common::Input::DriverResult::ErrorWritingData;
68 } 70 }
69 71
70 return DriverResult::Success; 72 return Common::Input::DriverResult::Success;
71} 73}
72 74
73DriverResult JoyconCommonProtocol::GetSubCommandResponse(SubCommand sc, 75Common::Input::DriverResult JoyconCommonProtocol::GetSubCommandResponse(
74 SubCommandResponse& output) { 76 SubCommand sc, SubCommandResponse& output) {
75 constexpr int timeout_mili = 66; 77 constexpr int timeout_mili = 66;
76 constexpr int MaxTries = 3; 78 constexpr int MaxTries = 10;
77 int tries = 0; 79 int tries = 0;
78 80
79 do { 81 do {
@@ -84,16 +86,17 @@ DriverResult JoyconCommonProtocol::GetSubCommandResponse(SubCommand sc,
84 LOG_ERROR(Input, "No response from joycon"); 86 LOG_ERROR(Input, "No response from joycon");
85 } 87 }
86 if (tries++ > MaxTries) { 88 if (tries++ > MaxTries) {
87 return DriverResult::Timeout; 89 return Common::Input::DriverResult::Timeout;
88 } 90 }
89 } while (output.input_report.report_mode != ReportMode::SUBCMD_REPLY && 91 } while (output.input_report.report_mode != ReportMode::SUBCMD_REPLY &&
90 output.sub_command != sc); 92 output.sub_command != sc);
91 93
92 return DriverResult::Success; 94 return Common::Input::DriverResult::Success;
93} 95}
94 96
95DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const u8> buffer, 97Common::Input::DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc,
96 SubCommandResponse& output) { 98 std::span<const u8> buffer,
99 SubCommandResponse& output) {
97 SubCommandPacket packet{ 100 SubCommandPacket packet{
98 .output_report = OutputReport::RUMBLE_AND_SUBCMD, 101 .output_report = OutputReport::RUMBLE_AND_SUBCMD,
99 .packet_counter = GetCounter(), 102 .packet_counter = GetCounter(),
@@ -102,26 +105,28 @@ DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const
102 }; 105 };
103 106
104 if (buffer.size() > packet.command_data.size()) { 107 if (buffer.size() > packet.command_data.size()) {
105 return DriverResult::InvalidParameters; 108 return Common::Input::DriverResult::InvalidParameters;
106 } 109 }
107 110
108 memcpy(packet.command_data.data(), buffer.data(), buffer.size()); 111 memcpy(packet.command_data.data(), buffer.data(), buffer.size());
109 112
110 auto result = SendData(packet); 113 auto result = SendData(packet);
111 114
112 if (result != DriverResult::Success) { 115 if (result != Common::Input::DriverResult::Success) {
113 return result; 116 return result;
114 } 117 }
115 118
116 return GetSubCommandResponse(sc, output); 119 return GetSubCommandResponse(sc, output);
117} 120}
118 121
119DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const u8> buffer) { 122Common::Input::DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc,
123 std::span<const u8> buffer) {
120 SubCommandResponse output{}; 124 SubCommandResponse output{};
121 return SendSubCommand(sc, buffer, output); 125 return SendSubCommand(sc, buffer, output);
122} 126}
123 127
124DriverResult JoyconCommonProtocol::SendMCUCommand(SubCommand sc, std::span<const u8> buffer) { 128Common::Input::DriverResult JoyconCommonProtocol::SendMCUCommand(SubCommand sc,
129 std::span<const u8> buffer) {
125 SubCommandPacket packet{ 130 SubCommandPacket packet{
126 .output_report = OutputReport::MCU_DATA, 131 .output_report = OutputReport::MCU_DATA,
127 .packet_counter = GetCounter(), 132 .packet_counter = GetCounter(),
@@ -130,7 +135,7 @@ DriverResult JoyconCommonProtocol::SendMCUCommand(SubCommand sc, std::span<const
130 }; 135 };
131 136
132 if (buffer.size() > packet.command_data.size()) { 137 if (buffer.size() > packet.command_data.size()) {
133 return DriverResult::InvalidParameters; 138 return Common::Input::DriverResult::InvalidParameters;
134 } 139 }
135 140
136 memcpy(packet.command_data.data(), buffer.data(), buffer.size()); 141 memcpy(packet.command_data.data(), buffer.data(), buffer.size());
@@ -138,7 +143,7 @@ DriverResult JoyconCommonProtocol::SendMCUCommand(SubCommand sc, std::span<const
138 return SendData(packet); 143 return SendData(packet);
139} 144}
140 145
141DriverResult JoyconCommonProtocol::SendVibrationReport(std::span<const u8> buffer) { 146Common::Input::DriverResult JoyconCommonProtocol::SendVibrationReport(std::span<const u8> buffer) {
142 VibrationPacket packet{ 147 VibrationPacket packet{
143 .output_report = OutputReport::RUMBLE_ONLY, 148 .output_report = OutputReport::RUMBLE_ONLY,
144 .packet_counter = GetCounter(), 149 .packet_counter = GetCounter(),
@@ -146,7 +151,7 @@ DriverResult JoyconCommonProtocol::SendVibrationReport(std::span<const u8> buffe
146 }; 151 };
147 152
148 if (buffer.size() > packet.vibration_data.size()) { 153 if (buffer.size() > packet.vibration_data.size()) {
149 return DriverResult::InvalidParameters; 154 return Common::Input::DriverResult::InvalidParameters;
150 } 155 }
151 156
152 memcpy(packet.vibration_data.data(), buffer.data(), buffer.size()); 157 memcpy(packet.vibration_data.data(), buffer.data(), buffer.size());
@@ -154,7 +159,8 @@ DriverResult JoyconCommonProtocol::SendVibrationReport(std::span<const u8> buffe
154 return SendData(packet); 159 return SendData(packet);
155} 160}
156 161
157DriverResult JoyconCommonProtocol::ReadRawSPI(SpiAddress addr, std::span<u8> output) { 162Common::Input::DriverResult JoyconCommonProtocol::ReadRawSPI(SpiAddress addr,
163 std::span<u8> output) {
158 constexpr std::size_t HeaderSize = 5; 164 constexpr std::size_t HeaderSize = 5;
159 constexpr std::size_t MaxTries = 5; 165 constexpr std::size_t MaxTries = 5;
160 std::size_t tries = 0; 166 std::size_t tries = 0;
@@ -168,36 +174,36 @@ DriverResult JoyconCommonProtocol::ReadRawSPI(SpiAddress addr, std::span<u8> out
168 memcpy(buffer.data(), &packet_data, sizeof(ReadSpiPacket)); 174 memcpy(buffer.data(), &packet_data, sizeof(ReadSpiPacket));
169 do { 175 do {
170 const auto result = SendSubCommand(SubCommand::SPI_FLASH_READ, buffer, response); 176 const auto result = SendSubCommand(SubCommand::SPI_FLASH_READ, buffer, response);
171 if (result != DriverResult::Success) { 177 if (result != Common::Input::DriverResult::Success) {
172 return result; 178 return result;
173 } 179 }
174 180
175 if (tries++ > MaxTries) { 181 if (tries++ > MaxTries) {
176 return DriverResult::Timeout; 182 return Common::Input::DriverResult::Timeout;
177 } 183 }
178 } while (response.spi_address != addr); 184 } while (response.spi_address != addr);
179 185
180 if (response.command_data.size() < packet_data.size + HeaderSize) { 186 if (response.command_data.size() < packet_data.size + HeaderSize) {
181 return DriverResult::WrongReply; 187 return Common::Input::DriverResult::WrongReply;
182 } 188 }
183 189
184 // Remove header from output 190 // Remove header from output
185 memcpy(output.data(), response.command_data.data() + HeaderSize, packet_data.size); 191 memcpy(output.data(), response.command_data.data() + HeaderSize, packet_data.size);
186 return DriverResult::Success; 192 return Common::Input::DriverResult::Success;
187} 193}
188 194
189DriverResult JoyconCommonProtocol::EnableMCU(bool enable) { 195Common::Input::DriverResult JoyconCommonProtocol::EnableMCU(bool enable) {
190 const std::array<u8, 1> mcu_state{static_cast<u8>(enable ? 1 : 0)}; 196 const std::array<u8, 1> mcu_state{static_cast<u8>(enable ? 1 : 0)};
191 const auto result = SendSubCommand(SubCommand::SET_MCU_STATE, mcu_state); 197 const auto result = SendSubCommand(SubCommand::SET_MCU_STATE, mcu_state);
192 198
193 if (result != DriverResult::Success) { 199 if (result != Common::Input::DriverResult::Success) {
194 LOG_ERROR(Input, "Failed with error {}", result); 200 LOG_ERROR(Input, "Failed with error {}", result);
195 } 201 }
196 202
197 return result; 203 return result;
198} 204}
199 205
200DriverResult JoyconCommonProtocol::ConfigureMCU(const MCUConfig& config) { 206Common::Input::DriverResult JoyconCommonProtocol::ConfigureMCU(const MCUConfig& config) {
201 LOG_DEBUG(Input, "ConfigureMCU"); 207 LOG_DEBUG(Input, "ConfigureMCU");
202 std::array<u8, sizeof(MCUConfig)> config_buffer; 208 std::array<u8, sizeof(MCUConfig)> config_buffer;
203 memcpy(config_buffer.data(), &config, sizeof(MCUConfig)); 209 memcpy(config_buffer.data(), &config, sizeof(MCUConfig));
@@ -205,15 +211,15 @@ DriverResult JoyconCommonProtocol::ConfigureMCU(const MCUConfig& config) {
205 211
206 const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, config_buffer); 212 const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, config_buffer);
207 213
208 if (result != DriverResult::Success) { 214 if (result != Common::Input::DriverResult::Success) {
209 LOG_ERROR(Input, "Failed with error {}", result); 215 LOG_ERROR(Input, "Failed with error {}", result);
210 } 216 }
211 217
212 return result; 218 return result;
213} 219}
214 220
215DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode, 221Common::Input::DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode,
216 MCUCommandResponse& output) { 222 MCUCommandResponse& output) {
217 constexpr int TimeoutMili = 200; 223 constexpr int TimeoutMili = 200;
218 constexpr int MaxTries = 9; 224 constexpr int MaxTries = 9;
219 int tries = 0; 225 int tries = 0;
@@ -226,17 +232,18 @@ DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode,
226 LOG_ERROR(Input, "No response from joycon attempt {}", tries); 232 LOG_ERROR(Input, "No response from joycon attempt {}", tries);
227 } 233 }
228 if (tries++ > MaxTries) { 234 if (tries++ > MaxTries) {
229 return DriverResult::Timeout; 235 return Common::Input::DriverResult::Timeout;
230 } 236 }
231 } while (output.input_report.report_mode != report_mode || 237 } while (output.input_report.report_mode != report_mode ||
232 output.mcu_report == MCUReport::EmptyAwaitingCmd); 238 output.mcu_report == MCUReport::EmptyAwaitingCmd);
233 239
234 return DriverResult::Success; 240 return Common::Input::DriverResult::Success;
235} 241}
236 242
237DriverResult JoyconCommonProtocol::SendMCUData(ReportMode report_mode, MCUSubCommand sc, 243Common::Input::DriverResult JoyconCommonProtocol::SendMCUData(ReportMode report_mode,
238 std::span<const u8> buffer, 244 MCUSubCommand sc,
239 MCUCommandResponse& output) { 245 std::span<const u8> buffer,
246 MCUCommandResponse& output) {
240 SubCommandPacket packet{ 247 SubCommandPacket packet{
241 .output_report = OutputReport::MCU_DATA, 248 .output_report = OutputReport::MCU_DATA,
242 .packet_counter = GetCounter(), 249 .packet_counter = GetCounter(),
@@ -245,23 +252,24 @@ DriverResult JoyconCommonProtocol::SendMCUData(ReportMode report_mode, MCUSubCom
245 }; 252 };
246 253
247 if (buffer.size() > packet.command_data.size()) { 254 if (buffer.size() > packet.command_data.size()) {
248 return DriverResult::InvalidParameters; 255 return Common::Input::DriverResult::InvalidParameters;
249 } 256 }
250 257
251 memcpy(packet.command_data.data(), buffer.data(), buffer.size()); 258 memcpy(packet.command_data.data(), buffer.data(), buffer.size());
252 259
253 auto result = SendData(packet); 260 auto result = SendData(packet);
254 261
255 if (result != DriverResult::Success) { 262 if (result != Common::Input::DriverResult::Success) {
256 return result; 263 return result;
257 } 264 }
258 265
259 result = GetMCUDataResponse(report_mode, output); 266 result = GetMCUDataResponse(report_mode, output);
260 267
261 return DriverResult::Success; 268 return Common::Input::DriverResult::Success;
262} 269}
263 270
264DriverResult JoyconCommonProtocol::WaitSetMCUMode(ReportMode report_mode, MCUMode mode) { 271Common::Input::DriverResult JoyconCommonProtocol::WaitSetMCUMode(ReportMode report_mode,
272 MCUMode mode) {
265 MCUCommandResponse output{}; 273 MCUCommandResponse output{};
266 constexpr std::size_t MaxTries{16}; 274 constexpr std::size_t MaxTries{16};
267 std::size_t tries{}; 275 std::size_t tries{};
@@ -269,17 +277,17 @@ DriverResult JoyconCommonProtocol::WaitSetMCUMode(ReportMode report_mode, MCUMod
269 do { 277 do {
270 const auto result = SendMCUData(report_mode, MCUSubCommand::SetDeviceMode, {}, output); 278 const auto result = SendMCUData(report_mode, MCUSubCommand::SetDeviceMode, {}, output);
271 279
272 if (result != DriverResult::Success) { 280 if (result != Common::Input::DriverResult::Success) {
273 return result; 281 return result;
274 } 282 }
275 283
276 if (tries++ > MaxTries) { 284 if (tries++ > MaxTries) {
277 return DriverResult::WrongReply; 285 return Common::Input::DriverResult::WrongReply;
278 } 286 }
279 } while (output.mcu_report != MCUReport::StateReport || 287 } while (output.mcu_report != MCUReport::StateReport ||
280 output.mcu_data[6] != static_cast<u8>(mode)); 288 output.mcu_data[6] != static_cast<u8>(mode));
281 289
282 return DriverResult::Success; 290 return Common::Input::DriverResult::Success;
283} 291}
284 292
285// crc-8-ccitt / polynomial 0x07 look up table 293// 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:
38 * Sends a request to obtain the joycon type from device 38 * Sends a request to obtain the joycon type from device
39 * @returns controller type of the joycon 39 * @returns controller type of the joycon
40 */ 40 */
41 DriverResult GetDeviceType(ControllerType& controller_type); 41 Common::Input::DriverResult GetDeviceType(ControllerType& controller_type);
42 42
43 /** 43 /**
44 * Verifies and sets the joycon_handle if device is valid 44 * Verifies and sets the joycon_handle if device is valid
45 * @param device info from the driver 45 * @param device info from the driver
46 * @returns success if the device is valid 46 * @returns success if the device is valid
47 */ 47 */
48 DriverResult CheckDeviceAccess(SDL_hid_device_info* device); 48 Common::Input::DriverResult CheckDeviceAccess(SDL_hid_device_info* device);
49 49
50 /** 50 /**
51 * Sends a request to set the polling mode of the joycon 51 * Sends a request to set the polling mode of the joycon
52 * @param report_mode polling mode to be set 52 * @param report_mode polling mode to be set
53 */ 53 */
54 DriverResult SetReportMode(Joycon::ReportMode report_mode); 54 Common::Input::DriverResult SetReportMode(Joycon::ReportMode report_mode);
55 55
56 /** 56 /**
57 * Sends data to the joycon device 57 * Sends data to the joycon device
58 * @param buffer data to be send 58 * @param buffer data to be send
59 */ 59 */
60 DriverResult SendRawData(std::span<const u8> buffer); 60 Common::Input::DriverResult SendRawData(std::span<const u8> buffer);
61 61
62 template <typename Output> 62 template <typename Output>
63 requires std::is_trivially_copyable_v<Output> 63 requires std::is_trivially_copyable_v<Output>
64 DriverResult SendData(const Output& output) { 64 Common::Input::DriverResult SendData(const Output& output) {
65 std::array<u8, sizeof(Output)> buffer; 65 std::array<u8, sizeof(Output)> buffer;
66 std::memcpy(buffer.data(), &output, sizeof(Output)); 66 std::memcpy(buffer.data(), &output, sizeof(Output));
67 return SendRawData(buffer); 67 return SendRawData(buffer);
@@ -72,7 +72,8 @@ public:
72 * @param sub_command type of data to be returned 72 * @param sub_command type of data to be returned
73 * @returns a buffer containing the response 73 * @returns a buffer containing the response
74 */ 74 */
75 DriverResult GetSubCommandResponse(SubCommand sub_command, SubCommandResponse& output); 75 Common::Input::DriverResult GetSubCommandResponse(SubCommand sub_command,
76 SubCommandResponse& output);
76 77
77 /** 78 /**
78 * Sends a sub command to the device and waits for it's reply 79 * Sends a sub command to the device and waits for it's reply
@@ -80,35 +81,35 @@ public:
80 * @param buffer data to be send 81 * @param buffer data to be send
81 * @returns output buffer containing the response 82 * @returns output buffer containing the response
82 */ 83 */
83 DriverResult SendSubCommand(SubCommand sc, std::span<const u8> buffer, 84 Common::Input::DriverResult SendSubCommand(SubCommand sc, std::span<const u8> buffer,
84 SubCommandResponse& output); 85 SubCommandResponse& output);
85 86
86 /** 87 /**
87 * Sends a sub command to the device and waits for it's reply and ignores the output 88 * Sends a sub command to the device and waits for it's reply and ignores the output
88 * @param sc sub command to be send 89 * @param sc sub command to be send
89 * @param buffer data to be send 90 * @param buffer data to be send
90 */ 91 */
91 DriverResult SendSubCommand(SubCommand sc, std::span<const u8> buffer); 92 Common::Input::DriverResult SendSubCommand(SubCommand sc, std::span<const u8> buffer);
92 93
93 /** 94 /**
94 * Sends a mcu command to the device 95 * Sends a mcu command to the device
95 * @param sc sub command to be send 96 * @param sc sub command to be send
96 * @param buffer data to be send 97 * @param buffer data to be send
97 */ 98 */
98 DriverResult SendMCUCommand(SubCommand sc, std::span<const u8> buffer); 99 Common::Input::DriverResult SendMCUCommand(SubCommand sc, std::span<const u8> buffer);
99 100
100 /** 101 /**
101 * Sends vibration data to the joycon 102 * Sends vibration data to the joycon
102 * @param buffer data to be send 103 * @param buffer data to be send
103 */ 104 */
104 DriverResult SendVibrationReport(std::span<const u8> buffer); 105 Common::Input::DriverResult SendVibrationReport(std::span<const u8> buffer);
105 106
106 /** 107 /**
107 * Reads the SPI memory stored on the joycon 108 * Reads the SPI memory stored on the joycon
108 * @param Initial address location 109 * @param Initial address location
109 * @returns output buffer containing the response 110 * @returns output buffer containing the response
110 */ 111 */
111 DriverResult ReadRawSPI(SpiAddress addr, std::span<u8> output); 112 Common::Input::DriverResult ReadRawSPI(SpiAddress addr, std::span<u8> output);
112 113
113 /** 114 /**
114 * Reads the SPI memory stored on the joycon 115 * Reads the SPI memory stored on the joycon
@@ -117,37 +118,38 @@ public:
117 */ 118 */
118 template <typename Output> 119 template <typename Output>
119 requires std::is_trivially_copyable_v<Output> 120 requires std::is_trivially_copyable_v<Output>
120 DriverResult ReadSPI(SpiAddress addr, Output& output) { 121 Common::Input::DriverResult ReadSPI(SpiAddress addr, Output& output) {
121 std::array<u8, sizeof(Output)> buffer; 122 std::array<u8, sizeof(Output)> buffer;
122 output = {}; 123 output = {};
123 124
124 const auto result = ReadRawSPI(addr, buffer); 125 const auto result = ReadRawSPI(addr, buffer);
125 if (result != DriverResult::Success) { 126 if (result != Common::Input::DriverResult::Success) {
126 return result; 127 return result;
127 } 128 }
128 129
129 std::memcpy(&output, buffer.data(), sizeof(Output)); 130 std::memcpy(&output, buffer.data(), sizeof(Output));
130 return DriverResult::Success; 131 return Common::Input::DriverResult::Success;
131 } 132 }
132 133
133 /** 134 /**
134 * Enables MCU chip on the joycon 135 * Enables MCU chip on the joycon
135 * @param enable if true the chip will be enabled 136 * @param enable if true the chip will be enabled
136 */ 137 */
137 DriverResult EnableMCU(bool enable); 138 Common::Input::DriverResult EnableMCU(bool enable);
138 139
139 /** 140 /**
140 * Configures the MCU to the corresponding mode 141 * Configures the MCU to the corresponding mode
141 * @param MCUConfig configuration 142 * @param MCUConfig configuration
142 */ 143 */
143 DriverResult ConfigureMCU(const MCUConfig& config); 144 Common::Input::DriverResult ConfigureMCU(const MCUConfig& config);
144 145
145 /** 146 /**
146 * Waits until there's MCU data available. On timeout returns error 147 * Waits until there's MCU data available. On timeout returns error
147 * @param report mode of the expected reply 148 * @param report mode of the expected reply
148 * @returns a buffer containing the response 149 * @returns a buffer containing the response
149 */ 150 */
150 DriverResult GetMCUDataResponse(ReportMode report_mode_, MCUCommandResponse& output); 151 Common::Input::DriverResult GetMCUDataResponse(ReportMode report_mode_,
152 MCUCommandResponse& output);
151 153
152 /** 154 /**
153 * Sends data to the MCU chip and waits for it's reply 155 * Sends data to the MCU chip and waits for it's reply
@@ -156,15 +158,15 @@ public:
156 * @param buffer data to be send 158 * @param buffer data to be send
157 * @returns output buffer containing the response 159 * @returns output buffer containing the response
158 */ 160 */
159 DriverResult SendMCUData(ReportMode report_mode, MCUSubCommand sc, std::span<const u8> buffer, 161 Common::Input::DriverResult SendMCUData(ReportMode report_mode, MCUSubCommand sc,
160 MCUCommandResponse& output); 162 std::span<const u8> buffer, MCUCommandResponse& output);
161 163
162 /** 164 /**
163 * Wait's until the MCU chip is on the specified mode 165 * Wait's until the MCU chip is on the specified mode
164 * @param report mode of the expected reply 166 * @param report mode of the expected reply
165 * @param MCUMode configuration 167 * @param MCUMode configuration
166 */ 168 */
167 DriverResult WaitSetMCUMode(ReportMode report_mode, MCUMode mode); 169 Common::Input::DriverResult WaitSetMCUMode(ReportMode report_mode, MCUMode mode);
168 170
169 /** 171 /**
170 * Calculates the checksum from the MCU data 172 * 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 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "common/input.h"
4#include "common/logging/log.h" 5#include "common/logging/log.h"
5#include "input_common/helpers/joycon_protocol/generic_functions.h" 6#include "input_common/helpers/joycon_protocol/generic_functions.h"
6 7
@@ -9,73 +10,74 @@ namespace InputCommon::Joycon {
9GenericProtocol::GenericProtocol(std::shared_ptr<JoyconHandle> handle) 10GenericProtocol::GenericProtocol(std::shared_ptr<JoyconHandle> handle)
10 : JoyconCommonProtocol(std::move(handle)) {} 11 : JoyconCommonProtocol(std::move(handle)) {}
11 12
12DriverResult GenericProtocol::EnablePassiveMode() { 13Common::Input::DriverResult GenericProtocol::EnablePassiveMode() {
13 ScopedSetBlocking sb(this); 14 ScopedSetBlocking sb(this);
14 return SetReportMode(ReportMode::SIMPLE_HID_MODE); 15 return SetReportMode(ReportMode::SIMPLE_HID_MODE);
15} 16}
16 17
17DriverResult GenericProtocol::EnableActiveMode() { 18Common::Input::DriverResult GenericProtocol::EnableActiveMode() {
18 ScopedSetBlocking sb(this); 19 ScopedSetBlocking sb(this);
19 return SetReportMode(ReportMode::STANDARD_FULL_60HZ); 20 return SetReportMode(ReportMode::STANDARD_FULL_60HZ);
20} 21}
21 22
22DriverResult GenericProtocol::SetLowPowerMode(bool enable) { 23Common::Input::DriverResult GenericProtocol::SetLowPowerMode(bool enable) {
23 ScopedSetBlocking sb(this); 24 ScopedSetBlocking sb(this);
24 const std::array<u8, 1> buffer{static_cast<u8>(enable ? 1 : 0)}; 25 const std::array<u8, 1> buffer{static_cast<u8>(enable ? 1 : 0)};
25 return SendSubCommand(SubCommand::LOW_POWER_MODE, buffer); 26 return SendSubCommand(SubCommand::LOW_POWER_MODE, buffer);
26} 27}
27 28
28DriverResult GenericProtocol::TriggersElapsed() { 29Common::Input::DriverResult GenericProtocol::TriggersElapsed() {
29 ScopedSetBlocking sb(this); 30 ScopedSetBlocking sb(this);
30 return SendSubCommand(SubCommand::TRIGGERS_ELAPSED, {}); 31 return SendSubCommand(SubCommand::TRIGGERS_ELAPSED, {});
31} 32}
32 33
33DriverResult GenericProtocol::GetDeviceInfo(DeviceInfo& device_info) { 34Common::Input::DriverResult GenericProtocol::GetDeviceInfo(DeviceInfo& device_info) {
34 ScopedSetBlocking sb(this); 35 ScopedSetBlocking sb(this);
35 SubCommandResponse output{}; 36 SubCommandResponse output{};
36 37
37 const auto result = SendSubCommand(SubCommand::REQ_DEV_INFO, {}, output); 38 const auto result = SendSubCommand(SubCommand::REQ_DEV_INFO, {}, output);
38 39
39 device_info = {}; 40 device_info = {};
40 if (result == DriverResult::Success) { 41 if (result == Common::Input::DriverResult::Success) {
41 device_info = output.device_info; 42 device_info = output.device_info;
42 } 43 }
43 44
44 return result; 45 return result;
45} 46}
46 47
47DriverResult GenericProtocol::GetControllerType(ControllerType& controller_type) { 48Common::Input::DriverResult GenericProtocol::GetControllerType(ControllerType& controller_type) {
48 return GetDeviceType(controller_type); 49 return GetDeviceType(controller_type);
49} 50}
50 51
51DriverResult GenericProtocol::EnableImu(bool enable) { 52Common::Input::DriverResult GenericProtocol::EnableImu(bool enable) {
52 ScopedSetBlocking sb(this); 53 ScopedSetBlocking sb(this);
53 const std::array<u8, 1> buffer{static_cast<u8>(enable ? 1 : 0)}; 54 const std::array<u8, 1> buffer{static_cast<u8>(enable ? 1 : 0)};
54 return SendSubCommand(SubCommand::ENABLE_IMU, buffer); 55 return SendSubCommand(SubCommand::ENABLE_IMU, buffer);
55} 56}
56 57
57DriverResult GenericProtocol::SetImuConfig(GyroSensitivity gsen, GyroPerformance gfrec, 58Common::Input::DriverResult GenericProtocol::SetImuConfig(GyroSensitivity gsen,
58 AccelerometerSensitivity asen, 59 GyroPerformance gfrec,
59 AccelerometerPerformance afrec) { 60 AccelerometerSensitivity asen,
61 AccelerometerPerformance afrec) {
60 ScopedSetBlocking sb(this); 62 ScopedSetBlocking sb(this);
61 const std::array<u8, 4> buffer{static_cast<u8>(gsen), static_cast<u8>(asen), 63 const std::array<u8, 4> buffer{static_cast<u8>(gsen), static_cast<u8>(asen),
62 static_cast<u8>(gfrec), static_cast<u8>(afrec)}; 64 static_cast<u8>(gfrec), static_cast<u8>(afrec)};
63 return SendSubCommand(SubCommand::SET_IMU_SENSITIVITY, buffer); 65 return SendSubCommand(SubCommand::SET_IMU_SENSITIVITY, buffer);
64} 66}
65 67
66DriverResult GenericProtocol::GetBattery(u32& battery_level) { 68Common::Input::DriverResult GenericProtocol::GetBattery(u32& battery_level) {
67 // This function is meant to request the high resolution battery status 69 // This function is meant to request the high resolution battery status
68 battery_level = 0; 70 battery_level = 0;
69 return DriverResult::NotSupported; 71 return Common::Input::DriverResult::NotSupported;
70} 72}
71 73
72DriverResult GenericProtocol::GetColor(Color& color) { 74Common::Input::DriverResult GenericProtocol::GetColor(Color& color) {
73 ScopedSetBlocking sb(this); 75 ScopedSetBlocking sb(this);
74 std::array<u8, 12> buffer{}; 76 std::array<u8, 12> buffer{};
75 const auto result = ReadRawSPI(SpiAddress::COLOR_DATA, buffer); 77 const auto result = ReadRawSPI(SpiAddress::COLOR_DATA, buffer);
76 78
77 color = {}; 79 color = {};
78 if (result == DriverResult::Success) { 80 if (result == Common::Input::DriverResult::Success) {
79 color.body = static_cast<u32>((buffer[0] << 16) | (buffer[1] << 8) | buffer[2]); 81 color.body = static_cast<u32>((buffer[0] << 16) | (buffer[1] << 8) | buffer[2]);
80 color.buttons = static_cast<u32>((buffer[3] << 16) | (buffer[4] << 8) | buffer[5]); 82 color.buttons = static_cast<u32>((buffer[3] << 16) | (buffer[4] << 8) | buffer[5]);
81 color.left_grip = static_cast<u32>((buffer[6] << 16) | (buffer[7] << 8) | buffer[8]); 83 color.left_grip = static_cast<u32>((buffer[6] << 16) | (buffer[7] << 8) | buffer[8]);
@@ -85,26 +87,26 @@ DriverResult GenericProtocol::GetColor(Color& color) {
85 return result; 87 return result;
86} 88}
87 89
88DriverResult GenericProtocol::GetSerialNumber(SerialNumber& serial_number) { 90Common::Input::DriverResult GenericProtocol::GetSerialNumber(SerialNumber& serial_number) {
89 ScopedSetBlocking sb(this); 91 ScopedSetBlocking sb(this);
90 std::array<u8, 16> buffer{}; 92 std::array<u8, 16> buffer{};
91 const auto result = ReadRawSPI(SpiAddress::SERIAL_NUMBER, buffer); 93 const auto result = ReadRawSPI(SpiAddress::SERIAL_NUMBER, buffer);
92 94
93 serial_number = {}; 95 serial_number = {};
94 if (result == DriverResult::Success) { 96 if (result == Common::Input::DriverResult::Success) {
95 memcpy(serial_number.data(), buffer.data() + 1, sizeof(SerialNumber)); 97 memcpy(serial_number.data(), buffer.data() + 1, sizeof(SerialNumber));
96 } 98 }
97 99
98 return result; 100 return result;
99} 101}
100 102
101DriverResult GenericProtocol::GetTemperature(u32& temperature) { 103Common::Input::DriverResult GenericProtocol::GetTemperature(u32& temperature) {
102 // Not all devices have temperature sensor 104 // Not all devices have temperature sensor
103 temperature = 25; 105 temperature = 25;
104 return DriverResult::NotSupported; 106 return Common::Input::DriverResult::NotSupported;
105} 107}
106 108
107DriverResult GenericProtocol::GetVersionNumber(FirmwareVersion& version) { 109Common::Input::DriverResult GenericProtocol::GetVersionNumber(FirmwareVersion& version) {
108 DeviceInfo device_info{}; 110 DeviceInfo device_info{};
109 111
110 const auto result = GetDeviceInfo(device_info); 112 const auto result = GetDeviceInfo(device_info);
@@ -113,23 +115,23 @@ DriverResult GenericProtocol::GetVersionNumber(FirmwareVersion& version) {
113 return result; 115 return result;
114} 116}
115 117
116DriverResult GenericProtocol::SetHomeLight() { 118Common::Input::DriverResult GenericProtocol::SetHomeLight() {
117 ScopedSetBlocking sb(this); 119 ScopedSetBlocking sb(this);
118 static constexpr std::array<u8, 3> buffer{0x0f, 0xf0, 0x00}; 120 static constexpr std::array<u8, 3> buffer{0x0f, 0xf0, 0x00};
119 return SendSubCommand(SubCommand::SET_HOME_LIGHT, buffer); 121 return SendSubCommand(SubCommand::SET_HOME_LIGHT, buffer);
120} 122}
121 123
122DriverResult GenericProtocol::SetLedBusy() { 124Common::Input::DriverResult GenericProtocol::SetLedBusy() {
123 return DriverResult::NotSupported; 125 return Common::Input::DriverResult::NotSupported;
124} 126}
125 127
126DriverResult GenericProtocol::SetLedPattern(u8 leds) { 128Common::Input::DriverResult GenericProtocol::SetLedPattern(u8 leds) {
127 ScopedSetBlocking sb(this); 129 ScopedSetBlocking sb(this);
128 const std::array<u8, 1> buffer{leds}; 130 const std::array<u8, 1> buffer{leds};
129 return SendSubCommand(SubCommand::SET_PLAYER_LIGHTS, buffer); 131 return SendSubCommand(SubCommand::SET_PLAYER_LIGHTS, buffer);
130} 132}
131 133
132DriverResult GenericProtocol::SetLedBlinkPattern(u8 leds) { 134Common::Input::DriverResult GenericProtocol::SetLedBlinkPattern(u8 leds) {
133 return SetLedPattern(static_cast<u8>(leds << 4)); 135 return SetLedPattern(static_cast<u8>(leds << 4));
134} 136}
135 137
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 @@
11#include "input_common/helpers/joycon_protocol/common_protocol.h" 11#include "input_common/helpers/joycon_protocol/common_protocol.h"
12#include "input_common/helpers/joycon_protocol/joycon_types.h" 12#include "input_common/helpers/joycon_protocol/joycon_types.h"
13 13
14namespace Common::Input {
15enum class DriverResult;
16}
17
14namespace InputCommon::Joycon { 18namespace InputCommon::Joycon {
15 19
16/// Joycon driver functions that easily implemented 20/// Joycon driver functions that easily implemented
@@ -20,34 +24,34 @@ public:
20 24
21 /// Enables passive mode. This mode only sends button data on change. Sticks will return digital 25 /// Enables passive mode. This mode only sends button data on change. Sticks will return digital
22 /// data instead of analog. Motion will be disabled 26 /// data instead of analog. Motion will be disabled
23 DriverResult EnablePassiveMode(); 27 Common::Input::DriverResult EnablePassiveMode();
24 28
25 /// Enables active mode. This mode will return the current status every 5-15ms 29 /// Enables active mode. This mode will return the current status every 5-15ms
26 DriverResult EnableActiveMode(); 30 Common::Input::DriverResult EnableActiveMode();
27 31
28 /// Enables or disables the low power mode 32 /// Enables or disables the low power mode
29 DriverResult SetLowPowerMode(bool enable); 33 Common::Input::DriverResult SetLowPowerMode(bool enable);
30 34
31 /// Unknown function used by the switch 35 /// Unknown function used by the switch
32 DriverResult TriggersElapsed(); 36 Common::Input::DriverResult TriggersElapsed();
33 37
34 /** 38 /**
35 * Sends a request to obtain the joycon firmware and mac from handle 39 * Sends a request to obtain the joycon firmware and mac from handle
36 * @returns controller device info 40 * @returns controller device info
37 */ 41 */
38 DriverResult GetDeviceInfo(DeviceInfo& controller_type); 42 Common::Input::DriverResult GetDeviceInfo(DeviceInfo& controller_type);
39 43
40 /** 44 /**
41 * Sends a request to obtain the joycon type from handle 45 * Sends a request to obtain the joycon type from handle
42 * @returns controller type of the joycon 46 * @returns controller type of the joycon
43 */ 47 */
44 DriverResult GetControllerType(ControllerType& controller_type); 48 Common::Input::DriverResult GetControllerType(ControllerType& controller_type);
45 49
46 /** 50 /**
47 * Enables motion input 51 * Enables motion input
48 * @param enable if true motion data will be enabled 52 * @param enable if true motion data will be enabled
49 */ 53 */
50 DriverResult EnableImu(bool enable); 54 Common::Input::DriverResult EnableImu(bool enable);
51 55
52 /** 56 /**
53 * Configures the motion sensor with the specified parameters 57 * Configures the motion sensor with the specified parameters
@@ -56,59 +60,60 @@ public:
56 * @param asen accelerometer sensitivity in G force 60 * @param asen accelerometer sensitivity in G force
57 * @param afrec accelerometer frequency in hertz 61 * @param afrec accelerometer frequency in hertz
58 */ 62 */
59 DriverResult SetImuConfig(GyroSensitivity gsen, GyroPerformance gfrec, 63 Common::Input::DriverResult SetImuConfig(GyroSensitivity gsen, GyroPerformance gfrec,
60 AccelerometerSensitivity asen, AccelerometerPerformance afrec); 64 AccelerometerSensitivity asen,
65 AccelerometerPerformance afrec);
61 66
62 /** 67 /**
63 * Request battery level from the device 68 * Request battery level from the device
64 * @returns battery level 69 * @returns battery level
65 */ 70 */
66 DriverResult GetBattery(u32& battery_level); 71 Common::Input::DriverResult GetBattery(u32& battery_level);
67 72
68 /** 73 /**
69 * Request joycon colors from the device 74 * Request joycon colors from the device
70 * @returns colors of the body and buttons 75 * @returns colors of the body and buttons
71 */ 76 */
72 DriverResult GetColor(Color& color); 77 Common::Input::DriverResult GetColor(Color& color);
73 78
74 /** 79 /**
75 * Request joycon serial number from the device 80 * Request joycon serial number from the device
76 * @returns 16 byte serial number 81 * @returns 16 byte serial number
77 */ 82 */
78 DriverResult GetSerialNumber(SerialNumber& serial_number); 83 Common::Input::DriverResult GetSerialNumber(SerialNumber& serial_number);
79 84
80 /** 85 /**
81 * Request joycon serial number from the device 86 * Request joycon serial number from the device
82 * @returns 16 byte serial number 87 * @returns 16 byte serial number
83 */ 88 */
84 DriverResult GetTemperature(u32& temperature); 89 Common::Input::DriverResult GetTemperature(u32& temperature);
85 90
86 /** 91 /**
87 * Request joycon serial number from the device 92 * Request joycon serial number from the device
88 * @returns 16 byte serial number 93 * @returns 16 byte serial number
89 */ 94 */
90 DriverResult GetVersionNumber(FirmwareVersion& version); 95 Common::Input::DriverResult GetVersionNumber(FirmwareVersion& version);
91 96
92 /** 97 /**
93 * Sets home led behaviour 98 * Sets home led behaviour
94 */ 99 */
95 DriverResult SetHomeLight(); 100 Common::Input::DriverResult SetHomeLight();
96 101
97 /** 102 /**
98 * Sets home led into a slow breathing state 103 * Sets home led into a slow breathing state
99 */ 104 */
100 DriverResult SetLedBusy(); 105 Common::Input::DriverResult SetLedBusy();
101 106
102 /** 107 /**
103 * Sets the 4 player leds on the joycon on a solid state 108 * Sets the 4 player leds on the joycon on a solid state
104 * @params bit flag containing the led state 109 * @params bit flag containing the led state
105 */ 110 */
106 DriverResult SetLedPattern(u8 leds); 111 Common::Input::DriverResult SetLedPattern(u8 leds);
107 112
108 /** 113 /**
109 * Sets the 4 player leds on the joycon on a blinking state 114 * Sets the 4 player leds on the joycon on a blinking state
110 * @returns bit flag containing the led state 115 * @returns bit flag containing the led state
111 */ 116 */
112 DriverResult SetLedBlinkPattern(u8 leds); 117 Common::Input::DriverResult SetLedBlinkPattern(u8 leds);
113}; 118};
114} // namespace InputCommon::Joycon 119} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include <thread> 4#include "common/input.h"
5#include "common/logging/log.h" 5#include "common/logging/log.h"
6#include "input_common/helpers/joycon_protocol/irs.h" 6#include "input_common/helpers/joycon_protocol/irs.h"
7 7
@@ -10,21 +10,21 @@ namespace InputCommon::Joycon {
10IrsProtocol::IrsProtocol(std::shared_ptr<JoyconHandle> handle) 10IrsProtocol::IrsProtocol(std::shared_ptr<JoyconHandle> handle)
11 : JoyconCommonProtocol(std::move(handle)) {} 11 : JoyconCommonProtocol(std::move(handle)) {}
12 12
13DriverResult IrsProtocol::EnableIrs() { 13Common::Input::DriverResult IrsProtocol::EnableIrs() {
14 LOG_INFO(Input, "Enable IRS"); 14 LOG_INFO(Input, "Enable IRS");
15 ScopedSetBlocking sb(this); 15 ScopedSetBlocking sb(this);
16 DriverResult result{DriverResult::Success}; 16 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
17 17
18 if (result == DriverResult::Success) { 18 if (result == Common::Input::DriverResult::Success) {
19 result = SetReportMode(ReportMode::NFC_IR_MODE_60HZ); 19 result = SetReportMode(ReportMode::NFC_IR_MODE_60HZ);
20 } 20 }
21 if (result == DriverResult::Success) { 21 if (result == Common::Input::DriverResult::Success) {
22 result = EnableMCU(true); 22 result = EnableMCU(true);
23 } 23 }
24 if (result == DriverResult::Success) { 24 if (result == Common::Input::DriverResult::Success) {
25 result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::Standby); 25 result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::Standby);
26 } 26 }
27 if (result == DriverResult::Success) { 27 if (result == Common::Input::DriverResult::Success) {
28 const MCUConfig config{ 28 const MCUConfig config{
29 .command = MCUCommand::ConfigureMCU, 29 .command = MCUCommand::ConfigureMCU,
30 .sub_command = MCUSubCommand::SetMCUMode, 30 .sub_command = MCUSubCommand::SetMCUMode,
@@ -34,16 +34,16 @@ DriverResult IrsProtocol::EnableIrs() {
34 34
35 result = ConfigureMCU(config); 35 result = ConfigureMCU(config);
36 } 36 }
37 if (result == DriverResult::Success) { 37 if (result == Common::Input::DriverResult::Success) {
38 result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::IR); 38 result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::IR);
39 } 39 }
40 if (result == DriverResult::Success) { 40 if (result == Common::Input::DriverResult::Success) {
41 result = ConfigureIrs(); 41 result = ConfigureIrs();
42 } 42 }
43 if (result == DriverResult::Success) { 43 if (result == Common::Input::DriverResult::Success) {
44 result = WriteRegistersStep1(); 44 result = WriteRegistersStep1();
45 } 45 }
46 if (result == DriverResult::Success) { 46 if (result == Common::Input::DriverResult::Success) {
47 result = WriteRegistersStep2(); 47 result = WriteRegistersStep2();
48 } 48 }
49 49
@@ -52,12 +52,12 @@ DriverResult IrsProtocol::EnableIrs() {
52 return result; 52 return result;
53} 53}
54 54
55DriverResult IrsProtocol::DisableIrs() { 55Common::Input::DriverResult IrsProtocol::DisableIrs() {
56 LOG_DEBUG(Input, "Disable IRS"); 56 LOG_DEBUG(Input, "Disable IRS");
57 ScopedSetBlocking sb(this); 57 ScopedSetBlocking sb(this);
58 DriverResult result{DriverResult::Success}; 58 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
59 59
60 if (result == DriverResult::Success) { 60 if (result == Common::Input::DriverResult::Success) {
61 result = EnableMCU(false); 61 result = EnableMCU(false);
62 } 62 }
63 63
@@ -66,7 +66,7 @@ DriverResult IrsProtocol::DisableIrs() {
66 return result; 66 return result;
67} 67}
68 68
69DriverResult IrsProtocol::SetIrsConfig(IrsMode mode, IrsResolution format) { 69Common::Input::DriverResult IrsProtocol::SetIrsConfig(IrsMode mode, IrsResolution format) {
70 irs_mode = mode; 70 irs_mode = mode;
71 switch (format) { 71 switch (format) {
72 case IrsResolution::Size320x240: 72 case IrsResolution::Size320x240:
@@ -103,10 +103,10 @@ DriverResult IrsProtocol::SetIrsConfig(IrsMode mode, IrsResolution format) {
103 return EnableIrs(); 103 return EnableIrs();
104 } 104 }
105 105
106 return DriverResult::Success; 106 return Common::Input::DriverResult::Success;
107} 107}
108 108
109DriverResult IrsProtocol::RequestImage(std::span<u8> buffer) { 109Common::Input::DriverResult IrsProtocol::RequestImage(std::span<u8> buffer) {
110 const u8 next_packet_fragment = 110 const u8 next_packet_fragment =
111 static_cast<u8>((packet_fragment + 1) % (static_cast<u8>(fragments) + 1)); 111 static_cast<u8>((packet_fragment + 1) % (static_cast<u8>(fragments) + 1));
112 112
@@ -129,7 +129,7 @@ DriverResult IrsProtocol::RequestImage(std::span<u8> buffer) {
129 return RequestFrame(packet_fragment); 129 return RequestFrame(packet_fragment);
130} 130}
131 131
132DriverResult IrsProtocol::ConfigureIrs() { 132Common::Input::DriverResult IrsProtocol::ConfigureIrs() {
133 LOG_DEBUG(Input, "Configure IRS"); 133 LOG_DEBUG(Input, "Configure IRS");
134 constexpr std::size_t max_tries = 28; 134 constexpr std::size_t max_tries = 28;
135 SubCommandResponse output{}; 135 SubCommandResponse output{};
@@ -152,20 +152,20 @@ DriverResult IrsProtocol::ConfigureIrs() {
152 do { 152 do {
153 const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, request_data, output); 153 const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, request_data, output);
154 154
155 if (result != DriverResult::Success) { 155 if (result != Common::Input::DriverResult::Success) {
156 return result; 156 return result;
157 } 157 }
158 if (tries++ >= max_tries) { 158 if (tries++ >= max_tries) {
159 return DriverResult::WrongReply; 159 return Common::Input::DriverResult::WrongReply;
160 } 160 }
161 } while (output.command_data[0] != 0x0b); 161 } while (output.command_data[0] != 0x0b);
162 162
163 return DriverResult::Success; 163 return Common::Input::DriverResult::Success;
164} 164}
165 165
166DriverResult IrsProtocol::WriteRegistersStep1() { 166Common::Input::DriverResult IrsProtocol::WriteRegistersStep1() {
167 LOG_DEBUG(Input, "WriteRegistersStep1"); 167 LOG_DEBUG(Input, "WriteRegistersStep1");
168 DriverResult result{DriverResult::Success}; 168 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
169 constexpr std::size_t max_tries = 28; 169 constexpr std::size_t max_tries = 28;
170 SubCommandResponse output{}; 170 SubCommandResponse output{};
171 std::size_t tries = 0; 171 std::size_t tries = 0;
@@ -197,7 +197,7 @@ DriverResult IrsProtocol::WriteRegistersStep1() {
197 mcu_request[36] = CalculateMCU_CRC8(mcu_request.data(), 36); 197 mcu_request[36] = CalculateMCU_CRC8(mcu_request.data(), 36);
198 mcu_request[37] = 0xFF; 198 mcu_request[37] = 0xFF;
199 199
200 if (result != DriverResult::Success) { 200 if (result != Common::Input::DriverResult::Success) {
201 return result; 201 return result;
202 } 202 }
203 203
@@ -205,26 +205,26 @@ DriverResult IrsProtocol::WriteRegistersStep1() {
205 result = SendSubCommand(SubCommand::SET_MCU_CONFIG, request_data, output); 205 result = SendSubCommand(SubCommand::SET_MCU_CONFIG, request_data, output);
206 206
207 // First time we need to set the report mode 207 // First time we need to set the report mode
208 if (result == DriverResult::Success && tries == 0) { 208 if (result == Common::Input::DriverResult::Success && tries == 0) {
209 result = SendMCUCommand(SubCommand::SET_REPORT_MODE, mcu_request); 209 result = SendMCUCommand(SubCommand::SET_REPORT_MODE, mcu_request);
210 } 210 }
211 if (result == DriverResult::Success && tries == 0) { 211 if (result == Common::Input::DriverResult::Success && tries == 0) {
212 GetSubCommandResponse(SubCommand::SET_MCU_CONFIG, output); 212 GetSubCommandResponse(SubCommand::SET_MCU_CONFIG, output);
213 } 213 }
214 214
215 if (result != DriverResult::Success) { 215 if (result != Common::Input::DriverResult::Success) {
216 return result; 216 return result;
217 } 217 }
218 if (tries++ >= max_tries) { 218 if (tries++ >= max_tries) {
219 return DriverResult::WrongReply; 219 return Common::Input::DriverResult::WrongReply;
220 } 220 }
221 } while (!(output.command_data[0] == 0x13 && output.command_data[2] == 0x07) && 221 } while (!(output.command_data[0] == 0x13 && output.command_data[2] == 0x07) &&
222 output.command_data[0] != 0x23); 222 output.command_data[0] != 0x23);
223 223
224 return DriverResult::Success; 224 return Common::Input::DriverResult::Success;
225} 225}
226 226
227DriverResult IrsProtocol::WriteRegistersStep2() { 227Common::Input::DriverResult IrsProtocol::WriteRegistersStep2() {
228 LOG_DEBUG(Input, "WriteRegistersStep2"); 228 LOG_DEBUG(Input, "WriteRegistersStep2");
229 constexpr std::size_t max_tries = 28; 229 constexpr std::size_t max_tries = 28;
230 SubCommandResponse output{}; 230 SubCommandResponse output{};
@@ -255,18 +255,18 @@ DriverResult IrsProtocol::WriteRegistersStep2() {
255 do { 255 do {
256 const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, request_data, output); 256 const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, request_data, output);
257 257
258 if (result != DriverResult::Success) { 258 if (result != Common::Input::DriverResult::Success) {
259 return result; 259 return result;
260 } 260 }
261 if (tries++ >= max_tries) { 261 if (tries++ >= max_tries) {
262 return DriverResult::WrongReply; 262 return Common::Input::DriverResult::WrongReply;
263 } 263 }
264 } while (output.command_data[0] != 0x13 && output.command_data[0] != 0x23); 264 } while (output.command_data[0] != 0x13 && output.command_data[0] != 0x23);
265 265
266 return DriverResult::Success; 266 return Common::Input::DriverResult::Success;
267} 267}
268 268
269DriverResult IrsProtocol::RequestFrame(u8 frame) { 269Common::Input::DriverResult IrsProtocol::RequestFrame(u8 frame) {
270 std::array<u8, 38> mcu_request{}; 270 std::array<u8, 38> mcu_request{};
271 mcu_request[3] = frame; 271 mcu_request[3] = frame;
272 mcu_request[36] = CalculateMCU_CRC8(mcu_request.data(), 36); 272 mcu_request[36] = CalculateMCU_CRC8(mcu_request.data(), 36);
@@ -274,7 +274,7 @@ DriverResult IrsProtocol::RequestFrame(u8 frame) {
274 return SendMCUCommand(SubCommand::SET_REPORT_MODE, mcu_request); 274 return SendMCUCommand(SubCommand::SET_REPORT_MODE, mcu_request);
275} 275}
276 276
277DriverResult IrsProtocol::ResendFrame(u8 frame) { 277Common::Input::DriverResult IrsProtocol::ResendFrame(u8 frame) {
278 std::array<u8, 38> mcu_request{}; 278 std::array<u8, 38> mcu_request{};
279 mcu_request[1] = 0x1; 279 mcu_request[1] = 0x1;
280 mcu_request[2] = frame; 280 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 @@
13#include "input_common/helpers/joycon_protocol/common_protocol.h" 13#include "input_common/helpers/joycon_protocol/common_protocol.h"
14#include "input_common/helpers/joycon_protocol/joycon_types.h" 14#include "input_common/helpers/joycon_protocol/joycon_types.h"
15 15
16namespace Common::Input {
17enum class DriverResult;
18}
19
16namespace InputCommon::Joycon { 20namespace InputCommon::Joycon {
17 21
18class IrsProtocol final : private JoyconCommonProtocol { 22class IrsProtocol final : private JoyconCommonProtocol {
19public: 23public:
20 explicit IrsProtocol(std::shared_ptr<JoyconHandle> handle); 24 explicit IrsProtocol(std::shared_ptr<JoyconHandle> handle);
21 25
22 DriverResult EnableIrs(); 26 Common::Input::DriverResult EnableIrs();
23 27
24 DriverResult DisableIrs(); 28 Common::Input::DriverResult DisableIrs();
25 29
26 DriverResult SetIrsConfig(IrsMode mode, IrsResolution format); 30 Common::Input::DriverResult SetIrsConfig(IrsMode mode, IrsResolution format);
27 31
28 DriverResult RequestImage(std::span<u8> buffer); 32 Common::Input::DriverResult RequestImage(std::span<u8> buffer);
29 33
30 std::vector<u8> GetImage() const; 34 std::vector<u8> GetImage() const;
31 35
@@ -34,13 +38,13 @@ public:
34 bool IsEnabled() const; 38 bool IsEnabled() const;
35 39
36private: 40private:
37 DriverResult ConfigureIrs(); 41 Common::Input::DriverResult ConfigureIrs();
38 42
39 DriverResult WriteRegistersStep1(); 43 Common::Input::DriverResult WriteRegistersStep1();
40 DriverResult WriteRegistersStep2(); 44 Common::Input::DriverResult WriteRegistersStep2();
41 45
42 DriverResult RequestFrame(u8 frame); 46 Common::Input::DriverResult RequestFrame(u8 frame);
43 DriverResult ResendFrame(u8 frame); 47 Common::Input::DriverResult ResendFrame(u8 frame);
44 48
45 IrsMode irs_mode{IrsMode::ImageTransfer}; 49 IrsMode irs_mode{IrsMode::ImageTransfer};
46 IrsResolution resolution{IrsResolution::Size40x30}; 50 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 {
402 Starlink = 0x2800, 402 Starlink = 0x2800,
403}; 403};
404 404
405enum class DriverResult {
406 Success,
407 WrongReply,
408 Timeout,
409 InvalidParameters,
410 UnsupportedControllerType,
411 HandleInUse,
412 ErrorReadingData,
413 ErrorWritingData,
414 NoDeviceDetected,
415 InvalidHandle,
416 NotSupported,
417 Disabled,
418 Delayed,
419 Unknown,
420};
421
422struct MotionSensorCalibration { 405struct MotionSensorCalibration {
423 s16 offset; 406 s16 offset;
424 s16 scale; 407 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 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include <thread> 4#include "common/input.h"
5#include "common/logging/log.h" 5#include "common/logging/log.h"
6#include "input_common/helpers/joycon_protocol/nfc.h" 6#include "input_common/helpers/joycon_protocol/nfc.h"
7 7
@@ -10,21 +10,21 @@ namespace InputCommon::Joycon {
10NfcProtocol::NfcProtocol(std::shared_ptr<JoyconHandle> handle) 10NfcProtocol::NfcProtocol(std::shared_ptr<JoyconHandle> handle)
11 : JoyconCommonProtocol(std::move(handle)) {} 11 : JoyconCommonProtocol(std::move(handle)) {}
12 12
13DriverResult NfcProtocol::EnableNfc() { 13Common::Input::DriverResult NfcProtocol::EnableNfc() {
14 LOG_INFO(Input, "Enable NFC"); 14 LOG_INFO(Input, "Enable NFC");
15 ScopedSetBlocking sb(this); 15 ScopedSetBlocking sb(this);
16 DriverResult result{DriverResult::Success}; 16 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
17 17
18 if (result == DriverResult::Success) { 18 if (result == Common::Input::DriverResult::Success) {
19 result = SetReportMode(ReportMode::NFC_IR_MODE_60HZ); 19 result = SetReportMode(ReportMode::NFC_IR_MODE_60HZ);
20 } 20 }
21 if (result == DriverResult::Success) { 21 if (result == Common::Input::DriverResult::Success) {
22 result = EnableMCU(true); 22 result = EnableMCU(true);
23 } 23 }
24 if (result == DriverResult::Success) { 24 if (result == Common::Input::DriverResult::Success) {
25 result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::Standby); 25 result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::Standby);
26 } 26 }
27 if (result == DriverResult::Success) { 27 if (result == Common::Input::DriverResult::Success) {
28 const MCUConfig config{ 28 const MCUConfig config{
29 .command = MCUCommand::ConfigureMCU, 29 .command = MCUCommand::ConfigureMCU,
30 .sub_command = MCUSubCommand::SetMCUMode, 30 .sub_command = MCUSubCommand::SetMCUMode,
@@ -34,32 +34,32 @@ DriverResult NfcProtocol::EnableNfc() {
34 34
35 result = ConfigureMCU(config); 35 result = ConfigureMCU(config);
36 } 36 }
37 if (result == DriverResult::Success) { 37 if (result == Common::Input::DriverResult::Success) {
38 result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::NFC); 38 result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::NFC);
39 } 39 }
40 if (result == DriverResult::Success) { 40 if (result == Common::Input::DriverResult::Success) {
41 result = WaitUntilNfcIs(NFCStatus::Ready); 41 result = WaitUntilNfcIs(NFCStatus::Ready);
42 } 42 }
43 if (result == DriverResult::Success) { 43 if (result == Common::Input::DriverResult::Success) {
44 MCUCommandResponse output{}; 44 MCUCommandResponse output{};
45 result = SendStopPollingRequest(output); 45 result = SendStopPollingRequest(output);
46 } 46 }
47 if (result == DriverResult::Success) { 47 if (result == Common::Input::DriverResult::Success) {
48 result = WaitUntilNfcIs(NFCStatus::Ready); 48 result = WaitUntilNfcIs(NFCStatus::Ready);
49 } 49 }
50 if (result == DriverResult::Success) { 50 if (result == Common::Input::DriverResult::Success) {
51 is_enabled = true; 51 is_enabled = true;
52 } 52 }
53 53
54 return result; 54 return result;
55} 55}
56 56
57DriverResult NfcProtocol::DisableNfc() { 57Common::Input::DriverResult NfcProtocol::DisableNfc() {
58 LOG_DEBUG(Input, "Disable NFC"); 58 LOG_DEBUG(Input, "Disable NFC");
59 ScopedSetBlocking sb(this); 59 ScopedSetBlocking sb(this);
60 DriverResult result{DriverResult::Success}; 60 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
61 61
62 if (result == DriverResult::Success) { 62 if (result == Common::Input::DriverResult::Success) {
63 result = EnableMCU(false); 63 result = EnableMCU(false);
64 } 64 }
65 65
@@ -69,60 +69,60 @@ DriverResult NfcProtocol::DisableNfc() {
69 return result; 69 return result;
70} 70}
71 71
72DriverResult NfcProtocol::StartNFCPollingMode() { 72Common::Input::DriverResult NfcProtocol::StartNFCPollingMode() {
73 LOG_DEBUG(Input, "Start NFC polling Mode"); 73 LOG_DEBUG(Input, "Start NFC polling Mode");
74 ScopedSetBlocking sb(this); 74 ScopedSetBlocking sb(this);
75 DriverResult result{DriverResult::Success}; 75 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
76 76
77 if (result == DriverResult::Success) { 77 if (result == Common::Input::DriverResult::Success) {
78 MCUCommandResponse output{}; 78 MCUCommandResponse output{};
79 result = SendStartPollingRequest(output); 79 result = SendStartPollingRequest(output);
80 } 80 }
81 if (result == DriverResult::Success) { 81 if (result == Common::Input::DriverResult::Success) {
82 result = WaitUntilNfcIs(NFCStatus::Polling); 82 result = WaitUntilNfcIs(NFCStatus::Polling);
83 } 83 }
84 if (result == DriverResult::Success) { 84 if (result == Common::Input::DriverResult::Success) {
85 is_polling = true; 85 is_polling = true;
86 } 86 }
87 87
88 return result; 88 return result;
89} 89}
90 90
91DriverResult NfcProtocol::StopNFCPollingMode() { 91Common::Input::DriverResult NfcProtocol::StopNFCPollingMode() {
92 LOG_DEBUG(Input, "Stop NFC polling Mode"); 92 LOG_DEBUG(Input, "Stop NFC polling Mode");
93 ScopedSetBlocking sb(this); 93 ScopedSetBlocking sb(this);
94 DriverResult result{DriverResult::Success}; 94 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
95 95
96 if (result == DriverResult::Success) { 96 if (result == Common::Input::DriverResult::Success) {
97 MCUCommandResponse output{}; 97 MCUCommandResponse output{};
98 result = SendStopPollingRequest(output); 98 result = SendStopPollingRequest(output);
99 } 99 }
100 if (result == DriverResult::Success) { 100 if (result == Common::Input::DriverResult::Success) {
101 result = WaitUntilNfcIs(NFCStatus::WriteReady); 101 result = WaitUntilNfcIs(NFCStatus::WriteReady);
102 } 102 }
103 if (result == DriverResult::Success) { 103 if (result == Common::Input::DriverResult::Success) {
104 is_polling = false; 104 is_polling = false;
105 } 105 }
106 106
107 return result; 107 return result;
108} 108}
109 109
110DriverResult NfcProtocol::GetTagInfo(Joycon::TagInfo& tag_info) { 110Common::Input::DriverResult NfcProtocol::GetTagInfo(Joycon::TagInfo& tag_info) {
111 if (update_counter++ < AMIIBO_UPDATE_DELAY) { 111 if (update_counter++ < AMIIBO_UPDATE_DELAY) {
112 return DriverResult::Delayed; 112 return Common::Input::DriverResult::Delayed;
113 } 113 }
114 update_counter = 0; 114 update_counter = 0;
115 115
116 LOG_DEBUG(Input, "Scan for amiibos"); 116 LOG_DEBUG(Input, "Scan for amiibos");
117 ScopedSetBlocking sb(this); 117 ScopedSetBlocking sb(this);
118 DriverResult result{DriverResult::Success}; 118 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
119 TagFoundData tag_data{}; 119 TagFoundData tag_data{};
120 120
121 if (result == DriverResult::Success) { 121 if (result == Common::Input::DriverResult::Success) {
122 result = IsTagInRange(tag_data); 122 result = IsTagInRange(tag_data);
123 } 123 }
124 124
125 if (result == DriverResult::Success) { 125 if (result == Common::Input::DriverResult::Success) {
126 tag_info = { 126 tag_info = {
127 .uuid_length = tag_data.uuid_size, 127 .uuid_length = tag_data.uuid_size,
128 .protocol = 1, 128 .protocol = 1,
@@ -147,59 +147,59 @@ DriverResult NfcProtocol::GetTagInfo(Joycon::TagInfo& tag_info) {
147 return result; 147 return result;
148} 148}
149 149
150DriverResult NfcProtocol::ReadAmiibo(std::vector<u8>& data) { 150Common::Input::DriverResult NfcProtocol::ReadAmiibo(std::vector<u8>& data) {
151 LOG_DEBUG(Input, "Scan for amiibos"); 151 LOG_DEBUG(Input, "Scan for amiibos");
152 ScopedSetBlocking sb(this); 152 ScopedSetBlocking sb(this);
153 DriverResult result{DriverResult::Success}; 153 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
154 TagFoundData tag_data{}; 154 TagFoundData tag_data{};
155 155
156 if (result == DriverResult::Success) { 156 if (result == Common::Input::DriverResult::Success) {
157 result = IsTagInRange(tag_data, 7); 157 result = IsTagInRange(tag_data, 7);
158 } 158 }
159 159
160 if (result == DriverResult::Success) { 160 if (result == Common::Input::DriverResult::Success) {
161 result = GetAmiiboData(data); 161 result = GetAmiiboData(data);
162 } 162 }
163 163
164 return result; 164 return result;
165} 165}
166 166
167DriverResult NfcProtocol::WriteAmiibo(std::span<const u8> data) { 167Common::Input::DriverResult NfcProtocol::WriteAmiibo(std::span<const u8> data) {
168 LOG_DEBUG(Input, "Write amiibo"); 168 LOG_DEBUG(Input, "Write amiibo");
169 ScopedSetBlocking sb(this); 169 ScopedSetBlocking sb(this);
170 DriverResult result{DriverResult::Success}; 170 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
171 TagUUID tag_uuid = GetTagUUID(data); 171 TagUUID tag_uuid = GetTagUUID(data);
172 TagFoundData tag_data{}; 172 TagFoundData tag_data{};
173 173
174 if (result == DriverResult::Success) { 174 if (result == Common::Input::DriverResult::Success) {
175 result = IsTagInRange(tag_data, 7); 175 result = IsTagInRange(tag_data, 7);
176 } 176 }
177 if (result == DriverResult::Success) { 177 if (result == Common::Input::DriverResult::Success) {
178 if (tag_data.uuid != tag_uuid) { 178 if (tag_data.uuid != tag_uuid) {
179 result = DriverResult::InvalidParameters; 179 result = Common::Input::DriverResult::InvalidParameters;
180 } 180 }
181 } 181 }
182 if (result == DriverResult::Success) { 182 if (result == Common::Input::DriverResult::Success) {
183 MCUCommandResponse output{}; 183 MCUCommandResponse output{};
184 result = SendStopPollingRequest(output); 184 result = SendStopPollingRequest(output);
185 } 185 }
186 if (result == DriverResult::Success) { 186 if (result == Common::Input::DriverResult::Success) {
187 result = WaitUntilNfcIs(NFCStatus::Ready); 187 result = WaitUntilNfcIs(NFCStatus::Ready);
188 } 188 }
189 if (result == DriverResult::Success) { 189 if (result == Common::Input::DriverResult::Success) {
190 MCUCommandResponse output{}; 190 MCUCommandResponse output{};
191 result = SendStartPollingRequest(output, true); 191 result = SendStartPollingRequest(output, true);
192 } 192 }
193 if (result == DriverResult::Success) { 193 if (result == Common::Input::DriverResult::Success) {
194 result = WaitUntilNfcIs(NFCStatus::WriteReady); 194 result = WaitUntilNfcIs(NFCStatus::WriteReady);
195 } 195 }
196 if (result == DriverResult::Success) { 196 if (result == Common::Input::DriverResult::Success) {
197 result = WriteAmiiboData(tag_uuid, data); 197 result = WriteAmiiboData(tag_uuid, data);
198 } 198 }
199 if (result == DriverResult::Success) { 199 if (result == Common::Input::DriverResult::Success) {
200 result = WaitUntilNfcIs(NFCStatus::WriteDone); 200 result = WaitUntilNfcIs(NFCStatus::WriteDone);
201 } 201 }
202 if (result == DriverResult::Success) { 202 if (result == Common::Input::DriverResult::Success) {
203 MCUCommandResponse output{}; 203 MCUCommandResponse output{};
204 result = SendStopPollingRequest(output); 204 result = SendStopPollingRequest(output);
205 } 205 }
@@ -207,64 +207,65 @@ DriverResult NfcProtocol::WriteAmiibo(std::span<const u8> data) {
207 return result; 207 return result;
208} 208}
209 209
210DriverResult NfcProtocol::ReadMifare(std::span<const MifareReadChunk> read_request, 210Common::Input::DriverResult NfcProtocol::ReadMifare(std::span<const MifareReadChunk> read_request,
211 std::span<MifareReadData> out_data) { 211 std::span<MifareReadData> out_data) {
212 LOG_DEBUG(Input, "Read mifare"); 212 LOG_DEBUG(Input, "Read mifare");
213 ScopedSetBlocking sb(this); 213 ScopedSetBlocking sb(this);
214 DriverResult result{DriverResult::Success}; 214 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
215 TagFoundData tag_data{}; 215 TagFoundData tag_data{};
216 MifareUUID tag_uuid{}; 216 MifareUUID tag_uuid{};
217 217
218 if (result == DriverResult::Success) { 218 if (result == Common::Input::DriverResult::Success) {
219 result = IsTagInRange(tag_data, 7); 219 result = IsTagInRange(tag_data, 7);
220 } 220 }
221 if (result == DriverResult::Success) { 221 if (result == Common::Input::DriverResult::Success) {
222 memcpy(tag_uuid.data(), tag_data.uuid.data(), sizeof(MifareUUID)); 222 memcpy(tag_uuid.data(), tag_data.uuid.data(), sizeof(MifareUUID));
223 result = GetMifareData(tag_uuid, read_request, out_data); 223 result = GetMifareData(tag_uuid, read_request, out_data);
224 } 224 }
225 if (result == DriverResult::Success) { 225 if (result == Common::Input::DriverResult::Success) {
226 MCUCommandResponse output{}; 226 MCUCommandResponse output{};
227 result = SendStopPollingRequest(output); 227 result = SendStopPollingRequest(output);
228 } 228 }
229 if (result == DriverResult::Success) { 229 if (result == Common::Input::DriverResult::Success) {
230 result = WaitUntilNfcIs(NFCStatus::Ready); 230 result = WaitUntilNfcIs(NFCStatus::Ready);
231 } 231 }
232 if (result == DriverResult::Success) { 232 if (result == Common::Input::DriverResult::Success) {
233 MCUCommandResponse output{}; 233 MCUCommandResponse output{};
234 result = SendStartPollingRequest(output, true); 234 result = SendStartPollingRequest(output, true);
235 } 235 }
236 if (result == DriverResult::Success) { 236 if (result == Common::Input::DriverResult::Success) {
237 result = WaitUntilNfcIs(NFCStatus::WriteReady); 237 result = WaitUntilNfcIs(NFCStatus::WriteReady);
238 } 238 }
239 return result; 239 return result;
240} 240}
241 241
242DriverResult NfcProtocol::WriteMifare(std::span<const MifareWriteChunk> write_request) { 242Common::Input::DriverResult NfcProtocol::WriteMifare(
243 std::span<const MifareWriteChunk> write_request) {
243 LOG_DEBUG(Input, "Write mifare"); 244 LOG_DEBUG(Input, "Write mifare");
244 ScopedSetBlocking sb(this); 245 ScopedSetBlocking sb(this);
245 DriverResult result{DriverResult::Success}; 246 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
246 TagFoundData tag_data{}; 247 TagFoundData tag_data{};
247 MifareUUID tag_uuid{}; 248 MifareUUID tag_uuid{};
248 249
249 if (result == DriverResult::Success) { 250 if (result == Common::Input::DriverResult::Success) {
250 result = IsTagInRange(tag_data, 7); 251 result = IsTagInRange(tag_data, 7);
251 } 252 }
252 if (result == DriverResult::Success) { 253 if (result == Common::Input::DriverResult::Success) {
253 memcpy(tag_uuid.data(), tag_data.uuid.data(), sizeof(MifareUUID)); 254 memcpy(tag_uuid.data(), tag_data.uuid.data(), sizeof(MifareUUID));
254 result = WriteMifareData(tag_uuid, write_request); 255 result = WriteMifareData(tag_uuid, write_request);
255 } 256 }
256 if (result == DriverResult::Success) { 257 if (result == Common::Input::DriverResult::Success) {
257 MCUCommandResponse output{}; 258 MCUCommandResponse output{};
258 result = SendStopPollingRequest(output); 259 result = SendStopPollingRequest(output);
259 } 260 }
260 if (result == DriverResult::Success) { 261 if (result == Common::Input::DriverResult::Success) {
261 result = WaitUntilNfcIs(NFCStatus::Ready); 262 result = WaitUntilNfcIs(NFCStatus::Ready);
262 } 263 }
263 if (result == DriverResult::Success) { 264 if (result == Common::Input::DriverResult::Success) {
264 MCUCommandResponse output{}; 265 MCUCommandResponse output{};
265 result = SendStartPollingRequest(output, true); 266 result = SendStartPollingRequest(output, true);
266 } 267 }
267 if (result == DriverResult::Success) { 268 if (result == Common::Input::DriverResult::Success) {
268 result = WaitUntilNfcIs(NFCStatus::WriteReady); 269 result = WaitUntilNfcIs(NFCStatus::WriteReady);
269 } 270 }
270 return result; 271 return result;
@@ -277,17 +278,17 @@ bool NfcProtocol::HasAmiibo() {
277 update_counter = 0; 278 update_counter = 0;
278 279
279 ScopedSetBlocking sb(this); 280 ScopedSetBlocking sb(this);
280 DriverResult result{DriverResult::Success}; 281 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
281 TagFoundData tag_data{}; 282 TagFoundData tag_data{};
282 283
283 if (result == DriverResult::Success) { 284 if (result == Common::Input::DriverResult::Success) {
284 result = IsTagInRange(tag_data, 7); 285 result = IsTagInRange(tag_data, 7);
285 } 286 }
286 287
287 return result == DriverResult::Success; 288 return result == Common::Input::DriverResult::Success;
288} 289}
289 290
290DriverResult NfcProtocol::WaitUntilNfcIs(NFCStatus status) { 291Common::Input::DriverResult NfcProtocol::WaitUntilNfcIs(NFCStatus status) {
291 constexpr std::size_t timeout_limit = 10; 292 constexpr std::size_t timeout_limit = 10;
292 MCUCommandResponse output{}; 293 MCUCommandResponse output{};
293 std::size_t tries = 0; 294 std::size_t tries = 0;
@@ -295,30 +296,31 @@ DriverResult NfcProtocol::WaitUntilNfcIs(NFCStatus status) {
295 do { 296 do {
296 auto result = SendNextPackageRequest(output, {}); 297 auto result = SendNextPackageRequest(output, {});
297 298
298 if (result != DriverResult::Success) { 299 if (result != Common::Input::DriverResult::Success) {
299 return result; 300 return result;
300 } 301 }
301 if (tries++ > timeout_limit) { 302 if (tries++ > timeout_limit) {
302 return DriverResult::Timeout; 303 return Common::Input::DriverResult::Timeout;
303 } 304 }
304 } while (output.mcu_report != MCUReport::NFCState || 305 } while (output.mcu_report != MCUReport::NFCState ||
305 (output.mcu_data[1] << 8) + output.mcu_data[0] != 0x0500 || 306 (output.mcu_data[1] << 8) + output.mcu_data[0] != 0x0500 ||
306 output.mcu_data[5] != 0x31 || output.mcu_data[6] != static_cast<u8>(status)); 307 output.mcu_data[5] != 0x31 || output.mcu_data[6] != static_cast<u8>(status));
307 308
308 return DriverResult::Success; 309 return Common::Input::DriverResult::Success;
309} 310}
310 311
311DriverResult NfcProtocol::IsTagInRange(TagFoundData& data, std::size_t timeout_limit) { 312Common::Input::DriverResult NfcProtocol::IsTagInRange(TagFoundData& data,
313 std::size_t timeout_limit) {
312 MCUCommandResponse output{}; 314 MCUCommandResponse output{};
313 std::size_t tries = 0; 315 std::size_t tries = 0;
314 316
315 do { 317 do {
316 const auto result = SendNextPackageRequest(output, {}); 318 const auto result = SendNextPackageRequest(output, {});
317 if (result != DriverResult::Success) { 319 if (result != Common::Input::DriverResult::Success) {
318 return result; 320 return result;
319 } 321 }
320 if (tries++ > timeout_limit) { 322 if (tries++ > timeout_limit) {
321 return DriverResult::Timeout; 323 return Common::Input::DriverResult::Timeout;
322 } 324 }
323 } while (output.mcu_report != MCUReport::NFCState || 325 } while (output.mcu_report != MCUReport::NFCState ||
324 (output.mcu_data[1] << 8) + output.mcu_data[0] != 0x0500 || 326 (output.mcu_data[1] << 8) + output.mcu_data[0] != 0x0500 ||
@@ -328,10 +330,10 @@ DriverResult NfcProtocol::IsTagInRange(TagFoundData& data, std::size_t timeout_l
328 data.uuid_size = std::min(output.mcu_data[14], static_cast<u8>(sizeof(TagUUID))); 330 data.uuid_size = std::min(output.mcu_data[14], static_cast<u8>(sizeof(TagUUID)));
329 memcpy(data.uuid.data(), output.mcu_data.data() + 15, data.uuid.size()); 331 memcpy(data.uuid.data(), output.mcu_data.data() + 15, data.uuid.size());
330 332
331 return DriverResult::Success; 333 return Common::Input::DriverResult::Success;
332} 334}
333 335
334DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) { 336Common::Input::DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) {
335 constexpr std::size_t timeout_limit = 60; 337 constexpr std::size_t timeout_limit = 60;
336 MCUCommandResponse output{}; 338 MCUCommandResponse output{};
337 std::size_t tries = 0; 339 std::size_t tries = 0;
@@ -340,7 +342,7 @@ DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) {
340 std::size_t ntag_buffer_pos = 0; 342 std::size_t ntag_buffer_pos = 0;
341 auto result = SendReadAmiiboRequest(output, NFCPages::Block135); 343 auto result = SendReadAmiiboRequest(output, NFCPages::Block135);
342 344
343 if (result != DriverResult::Success) { 345 if (result != Common::Input::DriverResult::Success) {
344 return result; 346 return result;
345 } 347 }
346 348
@@ -349,14 +351,14 @@ DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) {
349 result = SendNextPackageRequest(output, package_index); 351 result = SendNextPackageRequest(output, package_index);
350 const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]); 352 const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]);
351 353
352 if (result != DriverResult::Success) { 354 if (result != Common::Input::DriverResult::Success) {
353 return result; 355 return result;
354 } 356 }
355 357
356 if ((output.mcu_report == MCUReport::NFCReadData || 358 if ((output.mcu_report == MCUReport::NFCReadData ||
357 output.mcu_report == MCUReport::NFCState) && 359 output.mcu_report == MCUReport::NFCState) &&
358 nfc_status == NFCStatus::TagLost) { 360 nfc_status == NFCStatus::TagLost) {
359 return DriverResult::ErrorReadingData; 361 return Common::Input::DriverResult::ErrorReadingData;
360 } 362 }
361 363
362 if (output.mcu_report == MCUReport::NFCReadData && output.mcu_data[1] == 0x07) { 364 if (output.mcu_report == MCUReport::NFCReadData && output.mcu_data[1] == 0x07) {
@@ -375,14 +377,15 @@ DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) {
375 377
376 if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::LastPackage) { 378 if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::LastPackage) {
377 LOG_INFO(Input, "Finished reading amiibo"); 379 LOG_INFO(Input, "Finished reading amiibo");
378 return DriverResult::Success; 380 return Common::Input::DriverResult::Success;
379 } 381 }
380 } 382 }
381 383
382 return DriverResult::Timeout; 384 return Common::Input::DriverResult::Timeout;
383} 385}
384 386
385DriverResult NfcProtocol::WriteAmiiboData(const TagUUID& tag_uuid, std::span<const u8> data) { 387Common::Input::DriverResult NfcProtocol::WriteAmiiboData(const TagUUID& tag_uuid,
388 std::span<const u8> data) {
386 constexpr std::size_t timeout_limit = 60; 389 constexpr std::size_t timeout_limit = 60;
387 const auto nfc_data = MakeAmiiboWritePackage(tag_uuid, data); 390 const auto nfc_data = MakeAmiiboWritePackage(tag_uuid, data);
388 const std::vector<u8> nfc_buffer_data = SerializeWritePackage(nfc_data); 391 const std::vector<u8> nfc_buffer_data = SerializeWritePackage(nfc_data);
@@ -397,7 +400,7 @@ DriverResult NfcProtocol::WriteAmiiboData(const TagUUID& tag_uuid, std::span<con
397 400
398 auto result = SendWriteAmiiboRequest(output, tag_uuid); 401 auto result = SendWriteAmiiboRequest(output, tag_uuid);
399 402
400 if (result != DriverResult::Success) { 403 if (result != Common::Input::DriverResult::Success) {
401 return result; 404 return result;
402 } 405 }
403 406
@@ -406,14 +409,14 @@ DriverResult NfcProtocol::WriteAmiiboData(const TagUUID& tag_uuid, std::span<con
406 result = SendNextPackageRequest(output, package_index); 409 result = SendNextPackageRequest(output, package_index);
407 const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]); 410 const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]);
408 411
409 if (result != DriverResult::Success) { 412 if (result != Common::Input::DriverResult::Success) {
410 return result; 413 return result;
411 } 414 }
412 415
413 if ((output.mcu_report == MCUReport::NFCReadData || 416 if ((output.mcu_report == MCUReport::NFCReadData ||
414 output.mcu_report == MCUReport::NFCState) && 417 output.mcu_report == MCUReport::NFCState) &&
415 nfc_status == NFCStatus::TagLost) { 418 nfc_status == NFCStatus::TagLost) {
416 return DriverResult::ErrorReadingData; 419 return Common::Input::DriverResult::ErrorReadingData;
417 } 420 }
418 421
419 if (output.mcu_report == MCUReport::NFCReadData && output.mcu_data[1] == 0x07) { 422 if (output.mcu_report == MCUReport::NFCReadData && output.mcu_data[1] == 0x07) {
@@ -442,7 +445,7 @@ DriverResult NfcProtocol::WriteAmiiboData(const TagUUID& tag_uuid, std::span<con
442 if ((output.mcu_report == MCUReport::NFCReadData || 445 if ((output.mcu_report == MCUReport::NFCReadData ||
443 output.mcu_report == MCUReport::NFCState) && 446 output.mcu_report == MCUReport::NFCState) &&
444 nfc_status == NFCStatus::TagLost) { 447 nfc_status == NFCStatus::TagLost) {
445 return DriverResult::ErrorReadingData; 448 return Common::Input::DriverResult::ErrorReadingData;
446 } 449 }
447 450
448 // Increase position when data is confirmed by the joycon 451 // Increase position when data is confirmed by the joycon
@@ -457,14 +460,14 @@ DriverResult NfcProtocol::WriteAmiiboData(const TagUUID& tag_uuid, std::span<con
457 return result; 460 return result;
458} 461}
459 462
460DriverResult NfcProtocol::GetMifareData(const MifareUUID& tag_uuid, 463Common::Input::DriverResult NfcProtocol::GetMifareData(
461 std::span<const MifareReadChunk> read_request, 464 const MifareUUID& tag_uuid, std::span<const MifareReadChunk> read_request,
462 std::span<MifareReadData> out_data) { 465 std::span<MifareReadData> out_data) {
463 constexpr std::size_t timeout_limit = 60; 466 constexpr std::size_t timeout_limit = 60;
464 const auto nfc_data = MakeMifareReadPackage(tag_uuid, read_request); 467 const auto nfc_data = MakeMifareReadPackage(tag_uuid, read_request);
465 const std::vector<u8> nfc_buffer_data = SerializeMifareReadPackage(nfc_data); 468 const std::vector<u8> nfc_buffer_data = SerializeMifareReadPackage(nfc_data);
466 std::span<const u8> buffer(nfc_buffer_data); 469 std::span<const u8> buffer(nfc_buffer_data);
467 DriverResult result = DriverResult::Success; 470 Common::Input::DriverResult result = Common::Input::DriverResult::Success;
468 MCUCommandResponse output{}; 471 MCUCommandResponse output{};
469 u8 block_id = 1; 472 u8 block_id = 1;
470 u8 package_index = 0; 473 u8 package_index = 0;
@@ -486,7 +489,7 @@ DriverResult NfcProtocol::GetMifareData(const MifareUUID& tag_uuid,
486 const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]); 489 const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]);
487 490
488 if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) { 491 if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) {
489 return DriverResult::ErrorReadingData; 492 return Common::Input::DriverResult::ErrorReadingData;
490 } 493 }
491 494
492 // Increase position when data is confirmed by the joycon 495 // Increase position when data is confirmed by the joycon
@@ -498,7 +501,7 @@ DriverResult NfcProtocol::GetMifareData(const MifareUUID& tag_uuid,
498 } 501 }
499 } 502 }
500 503
501 if (result != DriverResult::Success) { 504 if (result != Common::Input::DriverResult::Success) {
502 return result; 505 return result;
503 } 506 }
504 507
@@ -507,12 +510,12 @@ DriverResult NfcProtocol::GetMifareData(const MifareUUID& tag_uuid,
507 result = SendNextPackageRequest(output, package_index); 510 result = SendNextPackageRequest(output, package_index);
508 const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]); 511 const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]);
509 512
510 if (result != DriverResult::Success) { 513 if (result != Common::Input::DriverResult::Success) {
511 return result; 514 return result;
512 } 515 }
513 516
514 if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) { 517 if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) {
515 return DriverResult::ErrorReadingData; 518 return Common::Input::DriverResult::ErrorReadingData;
516 } 519 }
517 520
518 if (output.mcu_report == MCUReport::NFCState && output.mcu_data[1] == 0x10) { 521 if (output.mcu_report == MCUReport::NFCState && output.mcu_data[1] == 0x10) {
@@ -538,13 +541,13 @@ DriverResult NfcProtocol::GetMifareData(const MifareUUID& tag_uuid,
538 return result; 541 return result;
539} 542}
540 543
541DriverResult NfcProtocol::WriteMifareData(const MifareUUID& tag_uuid, 544Common::Input::DriverResult NfcProtocol::WriteMifareData(
542 std::span<const MifareWriteChunk> write_request) { 545 const MifareUUID& tag_uuid, std::span<const MifareWriteChunk> write_request) {
543 constexpr std::size_t timeout_limit = 60; 546 constexpr std::size_t timeout_limit = 60;
544 const auto nfc_data = MakeMifareWritePackage(tag_uuid, write_request); 547 const auto nfc_data = MakeMifareWritePackage(tag_uuid, write_request);
545 const std::vector<u8> nfc_buffer_data = SerializeMifareWritePackage(nfc_data); 548 const std::vector<u8> nfc_buffer_data = SerializeMifareWritePackage(nfc_data);
546 std::span<const u8> buffer(nfc_buffer_data); 549 std::span<const u8> buffer(nfc_buffer_data);
547 DriverResult result = DriverResult::Success; 550 Common::Input::DriverResult result = Common::Input::DriverResult::Success;
548 MCUCommandResponse output{}; 551 MCUCommandResponse output{};
549 u8 block_id = 1; 552 u8 block_id = 1;
550 u8 package_index = 0; 553 u8 package_index = 0;
@@ -566,7 +569,7 @@ DriverResult NfcProtocol::WriteMifareData(const MifareUUID& tag_uuid,
566 const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]); 569 const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]);
567 570
568 if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) { 571 if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) {
569 return DriverResult::ErrorReadingData; 572 return Common::Input::DriverResult::ErrorReadingData;
570 } 573 }
571 574
572 // Increase position when data is confirmed by the joycon 575 // Increase position when data is confirmed by the joycon
@@ -578,7 +581,7 @@ DriverResult NfcProtocol::WriteMifareData(const MifareUUID& tag_uuid,
578 } 581 }
579 } 582 }
580 583
581 if (result != DriverResult::Success) { 584 if (result != Common::Input::DriverResult::Success) {
582 return result; 585 return result;
583 } 586 }
584 587
@@ -587,12 +590,12 @@ DriverResult NfcProtocol::WriteMifareData(const MifareUUID& tag_uuid,
587 result = SendNextPackageRequest(output, package_index); 590 result = SendNextPackageRequest(output, package_index);
588 const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]); 591 const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]);
589 592
590 if (result != DriverResult::Success) { 593 if (result != Common::Input::DriverResult::Success) {
591 return result; 594 return result;
592 } 595 }
593 596
594 if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) { 597 if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) {
595 return DriverResult::ErrorReadingData; 598 return Common::Input::DriverResult::ErrorReadingData;
596 } 599 }
597 600
598 if (output.mcu_report == MCUReport::NFCState && output.mcu_data[1] == 0x10) { 601 if (output.mcu_report == MCUReport::NFCState && output.mcu_data[1] == 0x10) {
@@ -609,8 +612,8 @@ DriverResult NfcProtocol::WriteMifareData(const MifareUUID& tag_uuid,
609 return result; 612 return result;
610} 613}
611 614
612DriverResult NfcProtocol::SendStartPollingRequest(MCUCommandResponse& output, 615Common::Input::DriverResult NfcProtocol::SendStartPollingRequest(MCUCommandResponse& output,
613 bool is_second_attempt) { 616 bool is_second_attempt) {
614 NFCRequestState request{ 617 NFCRequestState request{
615 .command_argument = NFCCommand::StartPolling, 618 .command_argument = NFCCommand::StartPolling,
616 .block_id = {}, 619 .block_id = {},
@@ -635,7 +638,7 @@ DriverResult NfcProtocol::SendStartPollingRequest(MCUCommandResponse& output,
635 output); 638 output);
636} 639}
637 640
638DriverResult NfcProtocol::SendStopPollingRequest(MCUCommandResponse& output) { 641Common::Input::DriverResult NfcProtocol::SendStopPollingRequest(MCUCommandResponse& output) {
639 NFCRequestState request{ 642 NFCRequestState request{
640 .command_argument = NFCCommand::StopPolling, 643 .command_argument = NFCCommand::StopPolling,
641 .block_id = {}, 644 .block_id = {},
@@ -653,7 +656,8 @@ DriverResult NfcProtocol::SendStopPollingRequest(MCUCommandResponse& output) {
653 output); 656 output);
654} 657}
655 658
656DriverResult NfcProtocol::SendNextPackageRequest(MCUCommandResponse& output, u8 packet_id) { 659Common::Input::DriverResult NfcProtocol::SendNextPackageRequest(MCUCommandResponse& output,
660 u8 packet_id) {
657 NFCRequestState request{ 661 NFCRequestState request{
658 .command_argument = NFCCommand::StartWaitingRecieve, 662 .command_argument = NFCCommand::StartWaitingRecieve,
659 .block_id = {}, 663 .block_id = {},
@@ -671,7 +675,8 @@ DriverResult NfcProtocol::SendNextPackageRequest(MCUCommandResponse& output, u8
671 output); 675 output);
672} 676}
673 677
674DriverResult NfcProtocol::SendReadAmiiboRequest(MCUCommandResponse& output, NFCPages ntag_pages) { 678Common::Input::DriverResult NfcProtocol::SendReadAmiiboRequest(MCUCommandResponse& output,
679 NFCPages ntag_pages) {
675 NFCRequestState request{ 680 NFCRequestState request{
676 .command_argument = NFCCommand::ReadNtag, 681 .command_argument = NFCCommand::ReadNtag,
677 .block_id = {}, 682 .block_id = {},
@@ -696,8 +701,8 @@ DriverResult NfcProtocol::SendReadAmiiboRequest(MCUCommandResponse& output, NFCP
696 output); 701 output);
697} 702}
698 703
699DriverResult NfcProtocol::SendWriteAmiiboRequest(MCUCommandResponse& output, 704Common::Input::DriverResult NfcProtocol::SendWriteAmiiboRequest(MCUCommandResponse& output,
700 const TagUUID& tag_uuid) { 705 const TagUUID& tag_uuid) {
701 NFCRequestState request{ 706 NFCRequestState request{
702 .command_argument = NFCCommand::ReadNtag, 707 .command_argument = NFCCommand::ReadNtag,
703 .block_id = {}, 708 .block_id = {},
@@ -722,9 +727,10 @@ DriverResult NfcProtocol::SendWriteAmiiboRequest(MCUCommandResponse& output,
722 output); 727 output);
723} 728}
724 729
725DriverResult NfcProtocol::SendWriteDataAmiiboRequest(MCUCommandResponse& output, u8 block_id, 730Common::Input::DriverResult NfcProtocol::SendWriteDataAmiiboRequest(MCUCommandResponse& output,
726 bool is_last_packet, 731 u8 block_id,
727 std::span<const u8> data) { 732 bool is_last_packet,
733 std::span<const u8> data) {
728 const auto data_size = std::min(data.size(), sizeof(NFCRequestState::raw_data)); 734 const auto data_size = std::min(data.size(), sizeof(NFCRequestState::raw_data));
729 NFCRequestState request{ 735 NFCRequestState request{
730 .command_argument = NFCCommand::WriteNtag, 736 .command_argument = NFCCommand::WriteNtag,
@@ -745,8 +751,9 @@ DriverResult NfcProtocol::SendWriteDataAmiiboRequest(MCUCommandResponse& output,
745 output); 751 output);
746} 752}
747 753
748DriverResult NfcProtocol::SendReadDataMifareRequest(MCUCommandResponse& output, u8 block_id, 754Common::Input::DriverResult NfcProtocol::SendReadDataMifareRequest(MCUCommandResponse& output,
749 bool is_last_packet, std::span<const u8> data) { 755 u8 block_id, bool is_last_packet,
756 std::span<const u8> data) {
750 const auto data_size = std::min(data.size(), sizeof(NFCRequestState::raw_data)); 757 const auto data_size = std::min(data.size(), sizeof(NFCRequestState::raw_data));
751 NFCRequestState request{ 758 NFCRequestState request{
752 .command_argument = NFCCommand::Mifare, 759 .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 @@
13#include "input_common/helpers/joycon_protocol/common_protocol.h" 13#include "input_common/helpers/joycon_protocol/common_protocol.h"
14#include "input_common/helpers/joycon_protocol/joycon_types.h" 14#include "input_common/helpers/joycon_protocol/joycon_types.h"
15 15
16namespace Common::Input {
17enum class DriverResult;
18}
19
16namespace InputCommon::Joycon { 20namespace InputCommon::Joycon {
17 21
18class NfcProtocol final : private JoyconCommonProtocol { 22class NfcProtocol final : private JoyconCommonProtocol {
19public: 23public:
20 explicit NfcProtocol(std::shared_ptr<JoyconHandle> handle); 24 explicit NfcProtocol(std::shared_ptr<JoyconHandle> handle);
21 25
22 DriverResult EnableNfc(); 26 Common::Input::DriverResult EnableNfc();
23 27
24 DriverResult DisableNfc(); 28 Common::Input::DriverResult DisableNfc();
25 29
26 DriverResult StartNFCPollingMode(); 30 Common::Input::DriverResult StartNFCPollingMode();
27 31
28 DriverResult StopNFCPollingMode(); 32 Common::Input::DriverResult StopNFCPollingMode();
29 33
30 DriverResult GetTagInfo(Joycon::TagInfo& tag_info); 34 Common::Input::DriverResult GetTagInfo(Joycon::TagInfo& tag_info);
31 35
32 DriverResult ReadAmiibo(std::vector<u8>& data); 36 Common::Input::DriverResult ReadAmiibo(std::vector<u8>& data);
33 37
34 DriverResult WriteAmiibo(std::span<const u8> data); 38 Common::Input::DriverResult WriteAmiibo(std::span<const u8> data);
35 39
36 DriverResult ReadMifare(std::span<const MifareReadChunk> read_request, 40 Common::Input::DriverResult ReadMifare(std::span<const MifareReadChunk> read_request,
37 std::span<MifareReadData> out_data); 41 std::span<MifareReadData> out_data);
38 42
39 DriverResult WriteMifare(std::span<const MifareWriteChunk> write_request); 43 Common::Input::DriverResult WriteMifare(std::span<const MifareWriteChunk> write_request);
40 44
41 bool HasAmiibo(); 45 bool HasAmiibo();
42 46
@@ -54,37 +58,41 @@ private:
54 TagUUID uuid; 58 TagUUID uuid;
55 }; 59 };
56 60
57 DriverResult WaitUntilNfcIs(NFCStatus status); 61 Common::Input::DriverResult WaitUntilNfcIs(NFCStatus status);
58 62
59 DriverResult IsTagInRange(TagFoundData& data, std::size_t timeout_limit = 1); 63 Common::Input::DriverResult IsTagInRange(TagFoundData& data, std::size_t timeout_limit = 1);
60 64
61 DriverResult GetAmiiboData(std::vector<u8>& data); 65 Common::Input::DriverResult GetAmiiboData(std::vector<u8>& data);
62 66
63 DriverResult WriteAmiiboData(const TagUUID& tag_uuid, std::span<const u8> data); 67 Common::Input::DriverResult WriteAmiiboData(const TagUUID& tag_uuid, std::span<const u8> data);
64 68
65 DriverResult GetMifareData(const MifareUUID& tag_uuid, 69 Common::Input::DriverResult GetMifareData(const MifareUUID& tag_uuid,
66 std::span<const MifareReadChunk> read_request, 70 std::span<const MifareReadChunk> read_request,
67 std::span<MifareReadData> out_data); 71 std::span<MifareReadData> out_data);
68 72
69 DriverResult WriteMifareData(const MifareUUID& tag_uuid, 73 Common::Input::DriverResult WriteMifareData(const MifareUUID& tag_uuid,
70 std::span<const MifareWriteChunk> write_request); 74 std::span<const MifareWriteChunk> write_request);
71 75
72 DriverResult SendStartPollingRequest(MCUCommandResponse& output, 76 Common::Input::DriverResult SendStartPollingRequest(MCUCommandResponse& output,
73 bool is_second_attempt = false); 77 bool is_second_attempt = false);
74 78
75 DriverResult SendStopPollingRequest(MCUCommandResponse& output); 79 Common::Input::DriverResult SendStopPollingRequest(MCUCommandResponse& output);
76 80
77 DriverResult SendNextPackageRequest(MCUCommandResponse& output, u8 packet_id); 81 Common::Input::DriverResult SendNextPackageRequest(MCUCommandResponse& output, u8 packet_id);
78 82
79 DriverResult SendReadAmiiboRequest(MCUCommandResponse& output, NFCPages ntag_pages); 83 Common::Input::DriverResult SendReadAmiiboRequest(MCUCommandResponse& output,
84 NFCPages ntag_pages);
80 85
81 DriverResult SendWriteAmiiboRequest(MCUCommandResponse& output, const TagUUID& tag_uuid); 86 Common::Input::DriverResult SendWriteAmiiboRequest(MCUCommandResponse& output,
87 const TagUUID& tag_uuid);
82 88
83 DriverResult SendWriteDataAmiiboRequest(MCUCommandResponse& output, u8 block_id, 89 Common::Input::DriverResult SendWriteDataAmiiboRequest(MCUCommandResponse& output, u8 block_id,
84 bool is_last_packet, std::span<const u8> data); 90 bool is_last_packet,
91 std::span<const u8> data);
85 92
86 DriverResult SendReadDataMifareRequest(MCUCommandResponse& output, u8 block_id, 93 Common::Input::DriverResult SendReadDataMifareRequest(MCUCommandResponse& output, u8 block_id,
87 bool is_last_packet, std::span<const u8> data); 94 bool is_last_packet,
95 std::span<const u8> data);
88 96
89 std::vector<u8> SerializeWritePackage(const NFCWritePackage& package) const; 97 std::vector<u8> SerializeWritePackage(const NFCWritePackage& package) const;
90 98
diff --git a/src/input_common/helpers/joycon_protocol/ringcon.cpp b/src/input_common/helpers/joycon_protocol/ringcon.cpp
index 190cef812..96414fb67 100644
--- a/src/input_common/helpers/joycon_protocol/ringcon.cpp
+++ b/src/input_common/helpers/joycon_protocol/ringcon.cpp
@@ -1,6 +1,7 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "common/input.h"
4#include "common/logging/log.h" 5#include "common/logging/log.h"
5#include "input_common/helpers/joycon_protocol/ringcon.h" 6#include "input_common/helpers/joycon_protocol/ringcon.h"
6 7
@@ -9,18 +10,18 @@ namespace InputCommon::Joycon {
9RingConProtocol::RingConProtocol(std::shared_ptr<JoyconHandle> handle) 10RingConProtocol::RingConProtocol(std::shared_ptr<JoyconHandle> handle)
10 : JoyconCommonProtocol(std::move(handle)) {} 11 : JoyconCommonProtocol(std::move(handle)) {}
11 12
12DriverResult RingConProtocol::EnableRingCon() { 13Common::Input::DriverResult RingConProtocol::EnableRingCon() {
13 LOG_DEBUG(Input, "Enable Ringcon"); 14 LOG_DEBUG(Input, "Enable Ringcon");
14 ScopedSetBlocking sb(this); 15 ScopedSetBlocking sb(this);
15 DriverResult result{DriverResult::Success}; 16 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
16 17
17 if (result == DriverResult::Success) { 18 if (result == Common::Input::DriverResult::Success) {
18 result = SetReportMode(ReportMode::STANDARD_FULL_60HZ); 19 result = SetReportMode(ReportMode::STANDARD_FULL_60HZ);
19 } 20 }
20 if (result == DriverResult::Success) { 21 if (result == Common::Input::DriverResult::Success) {
21 result = EnableMCU(true); 22 result = EnableMCU(true);
22 } 23 }
23 if (result == DriverResult::Success) { 24 if (result == Common::Input::DriverResult::Success) {
24 const MCUConfig config{ 25 const MCUConfig config{
25 .command = MCUCommand::ConfigureMCU, 26 .command = MCUCommand::ConfigureMCU,
26 .sub_command = MCUSubCommand::SetDeviceMode, 27 .sub_command = MCUSubCommand::SetDeviceMode,
@@ -33,12 +34,12 @@ DriverResult RingConProtocol::EnableRingCon() {
33 return result; 34 return result;
34} 35}
35 36
36DriverResult RingConProtocol::DisableRingCon() { 37Common::Input::DriverResult RingConProtocol::DisableRingCon() {
37 LOG_DEBUG(Input, "Disable RingCon"); 38 LOG_DEBUG(Input, "Disable RingCon");
38 ScopedSetBlocking sb(this); 39 ScopedSetBlocking sb(this);
39 DriverResult result{DriverResult::Success}; 40 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
40 41
41 if (result == DriverResult::Success) { 42 if (result == Common::Input::DriverResult::Success) {
42 result = EnableMCU(false); 43 result = EnableMCU(false);
43 } 44 }
44 45
@@ -47,29 +48,29 @@ DriverResult RingConProtocol::DisableRingCon() {
47 return result; 48 return result;
48} 49}
49 50
50DriverResult RingConProtocol::StartRingconPolling() { 51Common::Input::DriverResult RingConProtocol::StartRingconPolling() {
51 LOG_DEBUG(Input, "Enable Ringcon"); 52 LOG_DEBUG(Input, "Enable Ringcon");
52 ScopedSetBlocking sb(this); 53 ScopedSetBlocking sb(this);
53 DriverResult result{DriverResult::Success}; 54 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
54 bool is_connected = false; 55 bool is_connected = false;
55 56
56 if (result == DriverResult::Success) { 57 if (result == Common::Input::DriverResult::Success) {
57 result = IsRingConnected(is_connected); 58 result = IsRingConnected(is_connected);
58 } 59 }
59 if (result == DriverResult::Success && is_connected) { 60 if (result == Common::Input::DriverResult::Success && is_connected) {
60 LOG_INFO(Input, "Ringcon detected"); 61 LOG_INFO(Input, "Ringcon detected");
61 result = ConfigureRing(); 62 result = ConfigureRing();
62 } 63 }
63 if (result == DriverResult::Success) { 64 if (result == Common::Input::DriverResult::Success) {
64 is_enabled = true; 65 is_enabled = true;
65 } 66 }
66 67
67 return result; 68 return result;
68} 69}
69 70
70DriverResult RingConProtocol::IsRingConnected(bool& is_connected) { 71Common::Input::DriverResult RingConProtocol::IsRingConnected(bool& is_connected) {
71 LOG_DEBUG(Input, "IsRingConnected"); 72 LOG_DEBUG(Input, "IsRingConnected");
72 constexpr std::size_t max_tries = 28; 73 constexpr std::size_t max_tries = 42;
73 SubCommandResponse output{}; 74 SubCommandResponse output{};
74 std::size_t tries = 0; 75 std::size_t tries = 0;
75 is_connected = false; 76 is_connected = false;
@@ -77,20 +78,21 @@ DriverResult RingConProtocol::IsRingConnected(bool& is_connected) {
77 do { 78 do {
78 const auto result = SendSubCommand(SubCommand::GET_EXTERNAL_DEVICE_INFO, {}, output); 79 const auto result = SendSubCommand(SubCommand::GET_EXTERNAL_DEVICE_INFO, {}, output);
79 80
80 if (result != DriverResult::Success) { 81 if (result != Common::Input::DriverResult::Success &&
82 result != Common::Input::DriverResult::Timeout) {
81 return result; 83 return result;
82 } 84 }
83 85
84 if (tries++ >= max_tries) { 86 if (tries++ >= max_tries) {
85 return DriverResult::NoDeviceDetected; 87 return Common::Input::DriverResult::NoDeviceDetected;
86 } 88 }
87 } while (output.external_device_id != ExternalDeviceId::RingController); 89 } while (output.external_device_id != ExternalDeviceId::RingController);
88 90
89 is_connected = true; 91 is_connected = true;
90 return DriverResult::Success; 92 return Common::Input::DriverResult::Success;
91} 93}
92 94
93DriverResult RingConProtocol::ConfigureRing() { 95Common::Input::DriverResult RingConProtocol::ConfigureRing() {
94 LOG_DEBUG(Input, "ConfigureRing"); 96 LOG_DEBUG(Input, "ConfigureRing");
95 97
96 static constexpr std::array<u8, 37> ring_config{ 98 static constexpr std::array<u8, 37> ring_config{
@@ -98,9 +100,10 @@ DriverResult RingConProtocol::ConfigureRing() {
98 0x00, 0x00, 0x00, 0x0A, 0x64, 0x0B, 0xE6, 0xA9, 0x22, 0x00, 0x00, 0x04, 0x00, 100 0x00, 0x00, 0x00, 0x0A, 0x64, 0x0B, 0xE6, 0xA9, 0x22, 0x00, 0x00, 0x04, 0x00,
99 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0xA8, 0xE1, 0x34, 0x36}; 101 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0xA8, 0xE1, 0x34, 0x36};
100 102
101 const DriverResult result = SendSubCommand(SubCommand::SET_EXTERNAL_FORMAT_CONFIG, ring_config); 103 const Common::Input::DriverResult result =
104 SendSubCommand(SubCommand::SET_EXTERNAL_FORMAT_CONFIG, ring_config);
102 105
103 if (result != DriverResult::Success) { 106 if (result != Common::Input::DriverResult::Success) {
104 return result; 107 return result;
105 } 108 }
106 109
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 @@
13#include "input_common/helpers/joycon_protocol/common_protocol.h" 13#include "input_common/helpers/joycon_protocol/common_protocol.h"
14#include "input_common/helpers/joycon_protocol/joycon_types.h" 14#include "input_common/helpers/joycon_protocol/joycon_types.h"
15 15
16namespace Common::Input {
17enum class DriverResult;
18}
19
16namespace InputCommon::Joycon { 20namespace InputCommon::Joycon {
17 21
18class RingConProtocol final : private JoyconCommonProtocol { 22class RingConProtocol final : private JoyconCommonProtocol {
19public: 23public:
20 explicit RingConProtocol(std::shared_ptr<JoyconHandle> handle); 24 explicit RingConProtocol(std::shared_ptr<JoyconHandle> handle);
21 25
22 DriverResult EnableRingCon(); 26 Common::Input::DriverResult EnableRingCon();
23 27
24 DriverResult DisableRingCon(); 28 Common::Input::DriverResult DisableRingCon();
25 29
26 DriverResult StartRingconPolling(); 30 Common::Input::DriverResult StartRingconPolling();
27 31
28 bool IsEnabled() const; 32 bool IsEnabled() const;
29 33
30private: 34private:
31 DriverResult IsRingConnected(bool& is_connected); 35 Common::Input::DriverResult IsRingConnected(bool& is_connected);
32 36
33 DriverResult ConfigureRing(); 37 Common::Input::DriverResult ConfigureRing();
34 38
35 bool is_enabled{}; 39 bool is_enabled{};
36}; 40};
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 @@
4#include <algorithm> 4#include <algorithm>
5#include <cmath> 5#include <cmath>
6 6
7#include "common/input.h"
7#include "common/logging/log.h" 8#include "common/logging/log.h"
8#include "input_common/helpers/joycon_protocol/rumble.h" 9#include "input_common/helpers/joycon_protocol/rumble.h"
9 10
@@ -12,14 +13,14 @@ namespace InputCommon::Joycon {
12RumbleProtocol::RumbleProtocol(std::shared_ptr<JoyconHandle> handle) 13RumbleProtocol::RumbleProtocol(std::shared_ptr<JoyconHandle> handle)
13 : JoyconCommonProtocol(std::move(handle)) {} 14 : JoyconCommonProtocol(std::move(handle)) {}
14 15
15DriverResult RumbleProtocol::EnableRumble(bool is_enabled) { 16Common::Input::DriverResult RumbleProtocol::EnableRumble(bool is_enabled) {
16 LOG_DEBUG(Input, "Enable Rumble"); 17 LOG_DEBUG(Input, "Enable Rumble");
17 ScopedSetBlocking sb(this); 18 ScopedSetBlocking sb(this);
18 const std::array<u8, 1> buffer{static_cast<u8>(is_enabled ? 1 : 0)}; 19 const std::array<u8, 1> buffer{static_cast<u8>(is_enabled ? 1 : 0)};
19 return SendSubCommand(SubCommand::ENABLE_VIBRATION, buffer); 20 return SendSubCommand(SubCommand::ENABLE_VIBRATION, buffer);
20} 21}
21 22
22DriverResult RumbleProtocol::SendVibration(const VibrationValue& vibration) { 23Common::Input::DriverResult RumbleProtocol::SendVibration(const VibrationValue& vibration) {
23 std::array<u8, sizeof(DefaultVibrationBuffer)> buffer{}; 24 std::array<u8, sizeof(DefaultVibrationBuffer)> buffer{};
24 25
25 if (vibration.high_amplitude <= 0.0f && vibration.low_amplitude <= 0.0f) { 26 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 @@
13#include "input_common/helpers/joycon_protocol/common_protocol.h" 13#include "input_common/helpers/joycon_protocol/common_protocol.h"
14#include "input_common/helpers/joycon_protocol/joycon_types.h" 14#include "input_common/helpers/joycon_protocol/joycon_types.h"
15 15
16namespace Common::Input {
17enum class DriverResult;
18}
19
16namespace InputCommon::Joycon { 20namespace InputCommon::Joycon {
17 21
18class RumbleProtocol final : private JoyconCommonProtocol { 22class RumbleProtocol final : private JoyconCommonProtocol {
19public: 23public:
20 explicit RumbleProtocol(std::shared_ptr<JoyconHandle> handle); 24 explicit RumbleProtocol(std::shared_ptr<JoyconHandle> handle);
21 25
22 DriverResult EnableRumble(bool is_enabled); 26 Common::Input::DriverResult EnableRumble(bool is_enabled);
23 27
24 DriverResult SendVibration(const VibrationValue& vibration); 28 Common::Input::DriverResult SendVibration(const VibrationValue& vibration);
25 29
26private: 30private:
27 u16 EncodeHighFrequency(f32 frequency) const; 31 u16 EncodeHighFrequency(f32 frequency) const;
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h
index 58a45ab67..b5ed3380f 100644
--- a/src/video_core/buffer_cache/buffer_cache.h
+++ b/src/video_core/buffer_cache/buffer_cache.h
@@ -115,7 +115,34 @@ void BufferCache<P>::WriteMemory(VAddr cpu_addr, u64 size) {
115 115
116template <class P> 116template <class P>
117void BufferCache<P>::CachedWriteMemory(VAddr cpu_addr, u64 size) { 117void BufferCache<P>::CachedWriteMemory(VAddr cpu_addr, u64 size) {
118 memory_tracker.CachedCpuWrite(cpu_addr, size); 118 const bool is_dirty = IsRegionRegistered(cpu_addr, size);
119 if (!is_dirty) {
120 return;
121 }
122 VAddr aligned_start = Common::AlignDown(cpu_addr, YUZU_PAGESIZE);
123 VAddr aligned_end = Common::AlignUp(cpu_addr + size, YUZU_PAGESIZE);
124 if (!IsRegionGpuModified(aligned_start, aligned_end - aligned_start)) {
125 WriteMemory(cpu_addr, size);
126 return;
127 }
128
129 tmp_buffer.resize_destructive(size);
130 cpu_memory.ReadBlockUnsafe(cpu_addr, tmp_buffer.data(), size);
131
132 InlineMemoryImplementation(cpu_addr, size, tmp_buffer);
133}
134
135template <class P>
136bool BufferCache<P>::OnCPUWrite(VAddr cpu_addr, u64 size) {
137 const bool is_dirty = IsRegionRegistered(cpu_addr, size);
138 if (!is_dirty) {
139 return false;
140 }
141 if (memory_tracker.IsRegionGpuModified(cpu_addr, size)) {
142 return true;
143 }
144 WriteMemory(cpu_addr, size);
145 return false;
119} 146}
120 147
121template <class P> 148template <class P>
@@ -1553,6 +1580,14 @@ bool BufferCache<P>::InlineMemory(VAddr dest_address, size_t copy_size,
1553 return false; 1580 return false;
1554 } 1581 }
1555 1582
1583 InlineMemoryImplementation(dest_address, copy_size, inlined_buffer);
1584
1585 return true;
1586}
1587
1588template <class P>
1589void BufferCache<P>::InlineMemoryImplementation(VAddr dest_address, size_t copy_size,
1590 std::span<const u8> inlined_buffer) {
1556 const IntervalType subtract_interval{dest_address, dest_address + copy_size}; 1591 const IntervalType subtract_interval{dest_address, dest_address + copy_size};
1557 ClearDownload(subtract_interval); 1592 ClearDownload(subtract_interval);
1558 common_ranges.subtract(subtract_interval); 1593 common_ranges.subtract(subtract_interval);
@@ -1574,8 +1609,6 @@ bool BufferCache<P>::InlineMemory(VAddr dest_address, size_t copy_size,
1574 } else { 1609 } else {
1575 buffer.ImmediateUpload(buffer.Offset(dest_address), inlined_buffer.first(copy_size)); 1610 buffer.ImmediateUpload(buffer.Offset(dest_address), inlined_buffer.first(copy_size));
1576 } 1611 }
1577
1578 return true;
1579} 1612}
1580 1613
1581template <class P> 1614template <class P>
diff --git a/src/video_core/buffer_cache/buffer_cache_base.h b/src/video_core/buffer_cache/buffer_cache_base.h
index fe6068cfe..460fc7551 100644
--- a/src/video_core/buffer_cache/buffer_cache_base.h
+++ b/src/video_core/buffer_cache/buffer_cache_base.h
@@ -245,6 +245,8 @@ public:
245 245
246 void CachedWriteMemory(VAddr cpu_addr, u64 size); 246 void CachedWriteMemory(VAddr cpu_addr, u64 size);
247 247
248 bool OnCPUWrite(VAddr cpu_addr, u64 size);
249
248 void DownloadMemory(VAddr cpu_addr, u64 size); 250 void DownloadMemory(VAddr cpu_addr, u64 size);
249 251
250 std::optional<VideoCore::RasterizerDownloadArea> GetFlushArea(VAddr cpu_addr, u64 size); 252 std::optional<VideoCore::RasterizerDownloadArea> GetFlushArea(VAddr cpu_addr, u64 size);
@@ -543,6 +545,9 @@ private:
543 545
544 void ClearDownload(IntervalType subtract_interval); 546 void ClearDownload(IntervalType subtract_interval);
545 547
548 void InlineMemoryImplementation(VAddr dest_address, size_t copy_size,
549 std::span<const u8> inlined_buffer);
550
546 VideoCore::RasterizerInterface& rasterizer; 551 VideoCore::RasterizerInterface& rasterizer;
547 Core::Memory::Memory& cpu_memory; 552 Core::Memory::Memory& cpu_memory;
548 553
diff --git a/src/video_core/engines/maxwell_dma.cpp b/src/video_core/engines/maxwell_dma.cpp
index a290d6ea7..f8598fd98 100644
--- a/src/video_core/engines/maxwell_dma.cpp
+++ b/src/video_core/engines/maxwell_dma.cpp
@@ -174,8 +174,7 @@ void MaxwellDMA::CopyBlockLinearToPitch() {
174 src_operand.address = regs.offset_in; 174 src_operand.address = regs.offset_in;
175 175
176 DMA::BufferOperand dst_operand; 176 DMA::BufferOperand dst_operand;
177 u32 abs_pitch_out = std::abs(static_cast<s32>(regs.pitch_out)); 177 dst_operand.pitch = static_cast<u32>(std::abs(regs.pitch_out));
178 dst_operand.pitch = abs_pitch_out;
179 dst_operand.width = regs.line_length_in; 178 dst_operand.width = regs.line_length_in;
180 dst_operand.height = regs.line_count; 179 dst_operand.height = regs.line_count;
181 dst_operand.address = regs.offset_out; 180 dst_operand.address = regs.offset_out;
@@ -222,7 +221,7 @@ void MaxwellDMA::CopyBlockLinearToPitch() {
222 const size_t src_size = 221 const size_t src_size =
223 CalculateSize(true, bytes_per_pixel, width, height, depth, block_height, block_depth); 222 CalculateSize(true, bytes_per_pixel, width, height, depth, block_height, block_depth);
224 223
225 const size_t dst_size = static_cast<size_t>(abs_pitch_out) * regs.line_count; 224 const size_t dst_size = dst_operand.pitch * regs.line_count;
226 read_buffer.resize_destructive(src_size); 225 read_buffer.resize_destructive(src_size);
227 write_buffer.resize_destructive(dst_size); 226 write_buffer.resize_destructive(dst_size);
228 227
@@ -231,7 +230,7 @@ void MaxwellDMA::CopyBlockLinearToPitch() {
231 230
232 UnswizzleSubrect(write_buffer, read_buffer, bytes_per_pixel, width, height, depth, x_offset, 231 UnswizzleSubrect(write_buffer, read_buffer, bytes_per_pixel, width, height, depth, x_offset,
233 src_params.origin.y, x_elements, regs.line_count, block_height, block_depth, 232 src_params.origin.y, x_elements, regs.line_count, block_height, block_depth,
234 abs_pitch_out); 233 dst_operand.pitch);
235 234
236 memory_manager.WriteBlockCached(regs.offset_out, write_buffer.data(), dst_size); 235 memory_manager.WriteBlockCached(regs.offset_out, write_buffer.data(), dst_size);
237} 236}
diff --git a/src/video_core/fence_manager.h b/src/video_core/fence_manager.h
index 35d699bbf..ab20ff30f 100644
--- a/src/video_core/fence_manager.h
+++ b/src/video_core/fence_manager.h
@@ -69,7 +69,6 @@ public:
69 } 69 }
70 70
71 void SignalFence(std::function<void()>&& func) { 71 void SignalFence(std::function<void()>&& func) {
72 rasterizer.InvalidateGPUCache();
73 bool delay_fence = Settings::IsGPULevelHigh(); 72 bool delay_fence = Settings::IsGPULevelHigh();
74 if constexpr (!can_async_check) { 73 if constexpr (!can_async_check) {
75 TryReleasePendingFences<false>(); 74 TryReleasePendingFences<false>();
@@ -96,6 +95,7 @@ public:
96 guard.unlock(); 95 guard.unlock();
97 cv.notify_all(); 96 cv.notify_all();
98 } 97 }
98 rasterizer.InvalidateGPUCache();
99 } 99 }
100 100
101 void SignalSyncPoint(u32 value) { 101 void SignalSyncPoint(u32 value) {
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index db385076d..c192e33b2 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -95,7 +95,9 @@ struct GPU::Impl {
95 95
96 /// Synchronizes CPU writes with Host GPU memory. 96 /// Synchronizes CPU writes with Host GPU memory.
97 void InvalidateGPUCache() { 97 void InvalidateGPUCache() {
98 rasterizer->InvalidateGPUCache(); 98 std::function<void(VAddr, size_t)> callback_writes(
99 [this](VAddr address, size_t size) { rasterizer->OnCacheInvalidation(address, size); });
100 system.GatherGPUDirtyMemory(callback_writes);
99 } 101 }
100 102
101 /// Signal the ending of command list. 103 /// Signal the ending of command list.
@@ -299,6 +301,10 @@ struct GPU::Impl {
299 gpu_thread.InvalidateRegion(addr, size); 301 gpu_thread.InvalidateRegion(addr, size);
300 } 302 }
301 303
304 bool OnCPUWrite(VAddr addr, u64 size) {
305 return rasterizer->OnCPUWrite(addr, size);
306 }
307
302 /// Notify rasterizer that any caches of the specified region should be flushed and invalidated 308 /// Notify rasterizer that any caches of the specified region should be flushed and invalidated
303 void FlushAndInvalidateRegion(VAddr addr, u64 size) { 309 void FlushAndInvalidateRegion(VAddr addr, u64 size) {
304 gpu_thread.FlushAndInvalidateRegion(addr, size); 310 gpu_thread.FlushAndInvalidateRegion(addr, size);
@@ -561,6 +567,10 @@ void GPU::InvalidateRegion(VAddr addr, u64 size) {
561 impl->InvalidateRegion(addr, size); 567 impl->InvalidateRegion(addr, size);
562} 568}
563 569
570bool GPU::OnCPUWrite(VAddr addr, u64 size) {
571 return impl->OnCPUWrite(addr, size);
572}
573
564void GPU::FlushAndInvalidateRegion(VAddr addr, u64 size) { 574void GPU::FlushAndInvalidateRegion(VAddr addr, u64 size) {
565 impl->FlushAndInvalidateRegion(addr, size); 575 impl->FlushAndInvalidateRegion(addr, size);
566} 576}
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h
index e49c40cf2..ba2838b89 100644
--- a/src/video_core/gpu.h
+++ b/src/video_core/gpu.h
@@ -250,6 +250,10 @@ public:
250 /// Notify rasterizer that any caches of the specified region should be invalidated 250 /// Notify rasterizer that any caches of the specified region should be invalidated
251 void InvalidateRegion(VAddr addr, u64 size); 251 void InvalidateRegion(VAddr addr, u64 size);
252 252
253 /// Notify rasterizer that CPU is trying to write this area. It returns true if the area is
254 /// sensible, false otherwise
255 bool OnCPUWrite(VAddr addr, u64 size);
256
253 /// Notify rasterizer that any caches of the specified region should be flushed and invalidated 257 /// Notify rasterizer that any caches of the specified region should be flushed and invalidated
254 void FlushAndInvalidateRegion(VAddr addr, u64 size); 258 void FlushAndInvalidateRegion(VAddr addr, u64 size);
255 259
diff --git a/src/video_core/gpu_thread.cpp b/src/video_core/gpu_thread.cpp
index 889144f38..2f0f9f593 100644
--- a/src/video_core/gpu_thread.cpp
+++ b/src/video_core/gpu_thread.cpp
@@ -47,7 +47,7 @@ static void RunThread(std::stop_token stop_token, Core::System& system,
47 } else if (const auto* flush = std::get_if<FlushRegionCommand>(&next.data)) { 47 } else if (const auto* flush = std::get_if<FlushRegionCommand>(&next.data)) {
48 rasterizer->FlushRegion(flush->addr, flush->size); 48 rasterizer->FlushRegion(flush->addr, flush->size);
49 } else if (const auto* invalidate = std::get_if<InvalidateRegionCommand>(&next.data)) { 49 } else if (const auto* invalidate = std::get_if<InvalidateRegionCommand>(&next.data)) {
50 rasterizer->OnCPUWrite(invalidate->addr, invalidate->size); 50 rasterizer->OnCacheInvalidation(invalidate->addr, invalidate->size);
51 } else { 51 } else {
52 ASSERT(false); 52 ASSERT(false);
53 } 53 }
@@ -102,12 +102,12 @@ void ThreadManager::TickGPU() {
102} 102}
103 103
104void ThreadManager::InvalidateRegion(VAddr addr, u64 size) { 104void ThreadManager::InvalidateRegion(VAddr addr, u64 size) {
105 rasterizer->OnCPUWrite(addr, size); 105 rasterizer->OnCacheInvalidation(addr, size);
106} 106}
107 107
108void ThreadManager::FlushAndInvalidateRegion(VAddr addr, u64 size) { 108void ThreadManager::FlushAndInvalidateRegion(VAddr addr, u64 size) {
109 // Skip flush on asynch mode, as FlushAndInvalidateRegion is not used for anything too important 109 // Skip flush on asynch mode, as FlushAndInvalidateRegion is not used for anything too important
110 rasterizer->OnCPUWrite(addr, size); 110 rasterizer->OnCacheInvalidation(addr, size);
111} 111}
112 112
113u64 ThreadManager::PushCommand(CommandData&& command_data, bool block) { 113u64 ThreadManager::PushCommand(CommandData&& command_data, bool block) {
diff --git a/src/video_core/host1x/codecs/codec.cpp b/src/video_core/host1x/codecs/codec.cpp
index cd6a3a9b8..da07a556f 100644
--- a/src/video_core/host1x/codecs/codec.cpp
+++ b/src/video_core/host1x/codecs/codec.cpp
@@ -290,7 +290,7 @@ void Codec::Decode() {
290 return vp9_decoder->GetFrameBytes(); 290 return vp9_decoder->GetFrameBytes();
291 default: 291 default:
292 ASSERT(false); 292 ASSERT(false);
293 return std::vector<u8>{}; 293 return std::span<const u8>{};
294 } 294 }
295 }(); 295 }();
296 AVPacketPtr packet{av_packet_alloc(), AVPacketDeleter}; 296 AVPacketPtr packet{av_packet_alloc(), AVPacketDeleter};
diff --git a/src/video_core/host1x/codecs/h264.cpp b/src/video_core/host1x/codecs/h264.cpp
index ce827eb6c..862904e39 100644
--- a/src/video_core/host1x/codecs/h264.cpp
+++ b/src/video_core/host1x/codecs/h264.cpp
@@ -29,15 +29,15 @@ H264::H264(Host1x::Host1x& host1x_) : host1x{host1x_} {}
29 29
30H264::~H264() = default; 30H264::~H264() = default;
31 31
32const std::vector<u8>& H264::ComposeFrame(const Host1x::NvdecCommon::NvdecRegisters& state, 32std::span<const u8> H264::ComposeFrame(const Host1x::NvdecCommon::NvdecRegisters& state,
33 bool is_first_frame) { 33 bool is_first_frame) {
34 H264DecoderContext context; 34 H264DecoderContext context;
35 host1x.MemoryManager().ReadBlock(state.picture_info_offset, &context, 35 host1x.MemoryManager().ReadBlock(state.picture_info_offset, &context,
36 sizeof(H264DecoderContext)); 36 sizeof(H264DecoderContext));
37 37
38 const s64 frame_number = context.h264_parameter_set.frame_number.Value(); 38 const s64 frame_number = context.h264_parameter_set.frame_number.Value();
39 if (!is_first_frame && frame_number != 0) { 39 if (!is_first_frame && frame_number != 0) {
40 frame.resize(context.stream_len); 40 frame.resize_destructive(context.stream_len);
41 host1x.MemoryManager().ReadBlock(state.frame_bitstream_offset, frame.data(), frame.size()); 41 host1x.MemoryManager().ReadBlock(state.frame_bitstream_offset, frame.data(), frame.size());
42 return frame; 42 return frame;
43 } 43 }
@@ -135,14 +135,14 @@ const std::vector<u8>& H264::ComposeFrame(const Host1x::NvdecCommon::NvdecRegist
135 for (s32 index = 0; index < 6; index++) { 135 for (s32 index = 0; index < 6; index++) {
136 writer.WriteBit(true); 136 writer.WriteBit(true);
137 std::span<const u8> matrix{context.weight_scale}; 137 std::span<const u8> matrix{context.weight_scale};
138 writer.WriteScalingList(matrix, index * 16, 16); 138 writer.WriteScalingList(scan, matrix, index * 16, 16);
139 } 139 }
140 140
141 if (context.h264_parameter_set.transform_8x8_mode_flag) { 141 if (context.h264_parameter_set.transform_8x8_mode_flag) {
142 for (s32 index = 0; index < 2; index++) { 142 for (s32 index = 0; index < 2; index++) {
143 writer.WriteBit(true); 143 writer.WriteBit(true);
144 std::span<const u8> matrix{context.weight_scale_8x8}; 144 std::span<const u8> matrix{context.weight_scale_8x8};
145 writer.WriteScalingList(matrix, index * 64, 64); 145 writer.WriteScalingList(scan, matrix, index * 64, 64);
146 } 146 }
147 } 147 }
148 148
@@ -188,8 +188,8 @@ void H264BitWriter::WriteBit(bool state) {
188 WriteBits(state ? 1 : 0, 1); 188 WriteBits(state ? 1 : 0, 1);
189} 189}
190 190
191void H264BitWriter::WriteScalingList(std::span<const u8> list, s32 start, s32 count) { 191void H264BitWriter::WriteScalingList(Common::ScratchBuffer<u8>& scan, std::span<const u8> list,
192 static Common::ScratchBuffer<u8> scan{}; 192 s32 start, s32 count) {
193 scan.resize_destructive(count); 193 scan.resize_destructive(count);
194 if (count == 16) { 194 if (count == 16) {
195 std::memcpy(scan.data(), zig_zag_scan.data(), scan.size()); 195 std::memcpy(scan.data(), zig_zag_scan.data(), scan.size());
diff --git a/src/video_core/host1x/codecs/h264.h b/src/video_core/host1x/codecs/h264.h
index 5cc86454e..d6b556322 100644
--- a/src/video_core/host1x/codecs/h264.h
+++ b/src/video_core/host1x/codecs/h264.h
@@ -5,9 +5,11 @@
5 5
6#include <span> 6#include <span>
7#include <vector> 7#include <vector>
8
8#include "common/bit_field.h" 9#include "common/bit_field.h"
9#include "common/common_funcs.h" 10#include "common/common_funcs.h"
10#include "common/common_types.h" 11#include "common/common_types.h"
12#include "common/scratch_buffer.h"
11#include "video_core/host1x/nvdec_common.h" 13#include "video_core/host1x/nvdec_common.h"
12 14
13namespace Tegra { 15namespace Tegra {
@@ -37,7 +39,8 @@ public:
37 39
38 /// Based on section 7.3.2.1.1.1 and Table 7-4 in the H.264 specification 40 /// Based on section 7.3.2.1.1.1 and Table 7-4 in the H.264 specification
39 /// Writes the scaling matrices of the sream 41 /// Writes the scaling matrices of the sream
40 void WriteScalingList(std::span<const u8> list, s32 start, s32 count); 42 void WriteScalingList(Common::ScratchBuffer<u8>& scan, std::span<const u8> list, s32 start,
43 s32 count);
41 44
42 /// Return the bitstream as a vector. 45 /// Return the bitstream as a vector.
43 [[nodiscard]] std::vector<u8>& GetByteArray(); 46 [[nodiscard]] std::vector<u8>& GetByteArray();
@@ -63,11 +66,12 @@ public:
63 ~H264(); 66 ~H264();
64 67
65 /// Compose the H264 frame for FFmpeg decoding 68 /// Compose the H264 frame for FFmpeg decoding
66 [[nodiscard]] const std::vector<u8>& ComposeFrame( 69 [[nodiscard]] std::span<const u8> ComposeFrame(const Host1x::NvdecCommon::NvdecRegisters& state,
67 const Host1x::NvdecCommon::NvdecRegisters& state, bool is_first_frame = false); 70 bool is_first_frame = false);
68 71
69private: 72private:
70 std::vector<u8> frame; 73 Common::ScratchBuffer<u8> frame;
74 Common::ScratchBuffer<u8> scan;
71 Host1x::Host1x& host1x; 75 Host1x::Host1x& host1x;
72 76
73 struct H264ParameterSet { 77 struct H264ParameterSet {
diff --git a/src/video_core/host1x/codecs/vp8.cpp b/src/video_core/host1x/codecs/vp8.cpp
index 28fb12cb8..ee6392ff9 100644
--- a/src/video_core/host1x/codecs/vp8.cpp
+++ b/src/video_core/host1x/codecs/vp8.cpp
@@ -12,7 +12,7 @@ VP8::VP8(Host1x::Host1x& host1x_) : host1x{host1x_} {}
12 12
13VP8::~VP8() = default; 13VP8::~VP8() = default;
14 14
15const std::vector<u8>& VP8::ComposeFrame(const Host1x::NvdecCommon::NvdecRegisters& state) { 15std::span<const u8> VP8::ComposeFrame(const Host1x::NvdecCommon::NvdecRegisters& state) {
16 VP8PictureInfo info; 16 VP8PictureInfo info;
17 host1x.MemoryManager().ReadBlock(state.picture_info_offset, &info, sizeof(VP8PictureInfo)); 17 host1x.MemoryManager().ReadBlock(state.picture_info_offset, &info, sizeof(VP8PictureInfo));
18 18
diff --git a/src/video_core/host1x/codecs/vp8.h b/src/video_core/host1x/codecs/vp8.h
index 5bf07ecab..7926b73f3 100644
--- a/src/video_core/host1x/codecs/vp8.h
+++ b/src/video_core/host1x/codecs/vp8.h
@@ -4,10 +4,11 @@
4#pragma once 4#pragma once
5 5
6#include <array> 6#include <array>
7#include <vector> 7#include <span>
8 8
9#include "common/common_funcs.h" 9#include "common/common_funcs.h"
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "common/scratch_buffer.h"
11#include "video_core/host1x/nvdec_common.h" 12#include "video_core/host1x/nvdec_common.h"
12 13
13namespace Tegra { 14namespace Tegra {
@@ -24,11 +25,11 @@ public:
24 ~VP8(); 25 ~VP8();
25 26
26 /// Compose the VP8 frame for FFmpeg decoding 27 /// Compose the VP8 frame for FFmpeg decoding
27 [[nodiscard]] const std::vector<u8>& ComposeFrame( 28 [[nodiscard]] std::span<const u8> ComposeFrame(
28 const Host1x::NvdecCommon::NvdecRegisters& state); 29 const Host1x::NvdecCommon::NvdecRegisters& state);
29 30
30private: 31private:
31 std::vector<u8> frame; 32 Common::ScratchBuffer<u8> frame;
32 Host1x::Host1x& host1x; 33 Host1x::Host1x& host1x;
33 34
34 struct VP8PictureInfo { 35 struct VP8PictureInfo {
diff --git a/src/video_core/host1x/codecs/vp9.cpp b/src/video_core/host1x/codecs/vp9.cpp
index cf40c9012..306c3d0e8 100644
--- a/src/video_core/host1x/codecs/vp9.cpp
+++ b/src/video_core/host1x/codecs/vp9.cpp
@@ -3,6 +3,7 @@
3 3
4#include <algorithm> // for std::copy 4#include <algorithm> // for std::copy
5#include <numeric> 5#include <numeric>
6
6#include "common/assert.h" 7#include "common/assert.h"
7#include "video_core/host1x/codecs/vp9.h" 8#include "video_core/host1x/codecs/vp9.h"
8#include "video_core/host1x/host1x.h" 9#include "video_core/host1x/host1x.h"
diff --git a/src/video_core/host1x/codecs/vp9.h b/src/video_core/host1x/codecs/vp9.h
index d4083e8d3..f1ed19508 100644
--- a/src/video_core/host1x/codecs/vp9.h
+++ b/src/video_core/host1x/codecs/vp9.h
@@ -4,9 +4,11 @@
4#pragma once 4#pragma once
5 5
6#include <array> 6#include <array>
7#include <span>
7#include <vector> 8#include <vector>
8 9
9#include "common/common_types.h" 10#include "common/common_types.h"
11#include "common/scratch_buffer.h"
10#include "common/stream.h" 12#include "common/stream.h"
11#include "video_core/host1x/codecs/vp9_types.h" 13#include "video_core/host1x/codecs/vp9_types.h"
12#include "video_core/host1x/nvdec_common.h" 14#include "video_core/host1x/nvdec_common.h"
@@ -128,8 +130,8 @@ public:
128 return !current_frame_info.show_frame; 130 return !current_frame_info.show_frame;
129 } 131 }
130 132
131 /// Returns a const reference to the composed frame data. 133 /// Returns a const span to the composed frame data.
132 [[nodiscard]] const std::vector<u8>& GetFrameBytes() const { 134 [[nodiscard]] std::span<const u8> GetFrameBytes() const {
133 return frame; 135 return frame;
134 } 136 }
135 137
@@ -181,7 +183,7 @@ private:
181 [[nodiscard]] VpxBitStreamWriter ComposeUncompressedHeader(); 183 [[nodiscard]] VpxBitStreamWriter ComposeUncompressedHeader();
182 184
183 Host1x::Host1x& host1x; 185 Host1x::Host1x& host1x;
184 std::vector<u8> frame; 186 Common::ScratchBuffer<u8> frame;
185 187
186 std::array<s8, 4> loop_filter_ref_deltas{}; 188 std::array<s8, 4> loop_filter_ref_deltas{};
187 std::array<s8, 2> loop_filter_mode_deltas{}; 189 std::array<s8, 2> loop_filter_mode_deltas{};
diff --git a/src/video_core/host1x/codecs/vp9_types.h b/src/video_core/host1x/codecs/vp9_types.h
index adad8ed7e..cc9b25690 100644
--- a/src/video_core/host1x/codecs/vp9_types.h
+++ b/src/video_core/host1x/codecs/vp9_types.h
@@ -5,6 +5,7 @@
5 5
6#include <array> 6#include <array>
7#include <vector> 7#include <vector>
8
8#include "common/common_funcs.h" 9#include "common/common_funcs.h"
9#include "common/common_types.h" 10#include "common/common_types.h"
10 11
diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h
index 7566a8c4e..cb8029a4f 100644
--- a/src/video_core/rasterizer_interface.h
+++ b/src/video_core/rasterizer_interface.h
@@ -109,7 +109,9 @@ public:
109 } 109 }
110 110
111 /// Notify rasterizer that any caches of the specified region are desync with guest 111 /// Notify rasterizer that any caches of the specified region are desync with guest
112 virtual void OnCPUWrite(VAddr addr, u64 size) = 0; 112 virtual void OnCacheInvalidation(VAddr addr, u64 size) = 0;
113
114 virtual bool OnCPUWrite(VAddr addr, u64 size) = 0;
113 115
114 /// Sync memory between guest and host. 116 /// Sync memory between guest and host.
115 virtual void InvalidateGPUCache() = 0; 117 virtual void InvalidateGPUCache() = 0;
diff --git a/src/video_core/renderer_null/null_rasterizer.cpp b/src/video_core/renderer_null/null_rasterizer.cpp
index bf2ce4c49..92ecf6682 100644
--- a/src/video_core/renderer_null/null_rasterizer.cpp
+++ b/src/video_core/renderer_null/null_rasterizer.cpp
@@ -47,7 +47,10 @@ bool RasterizerNull::MustFlushRegion(VAddr addr, u64 size, VideoCommon::CacheTyp
47 return false; 47 return false;
48} 48}
49void RasterizerNull::InvalidateRegion(VAddr addr, u64 size, VideoCommon::CacheType) {} 49void RasterizerNull::InvalidateRegion(VAddr addr, u64 size, VideoCommon::CacheType) {}
50void RasterizerNull::OnCPUWrite(VAddr addr, u64 size) {} 50bool RasterizerNull::OnCPUWrite(VAddr addr, u64 size) {
51 return false;
52}
53void RasterizerNull::OnCacheInvalidation(VAddr addr, u64 size) {}
51VideoCore::RasterizerDownloadArea RasterizerNull::GetFlushArea(VAddr addr, u64 size) { 54VideoCore::RasterizerDownloadArea RasterizerNull::GetFlushArea(VAddr addr, u64 size) {
52 VideoCore::RasterizerDownloadArea new_area{ 55 VideoCore::RasterizerDownloadArea new_area{
53 .start_address = Common::AlignDown(addr, Core::Memory::YUZU_PAGESIZE), 56 .start_address = Common::AlignDown(addr, Core::Memory::YUZU_PAGESIZE),
diff --git a/src/video_core/renderer_null/null_rasterizer.h b/src/video_core/renderer_null/null_rasterizer.h
index a8d35d2c1..93b9a6971 100644
--- a/src/video_core/renderer_null/null_rasterizer.h
+++ b/src/video_core/renderer_null/null_rasterizer.h
@@ -53,7 +53,8 @@ public:
53 VideoCommon::CacheType which = VideoCommon::CacheType::All) override; 53 VideoCommon::CacheType which = VideoCommon::CacheType::All) override;
54 void InvalidateRegion(VAddr addr, u64 size, 54 void InvalidateRegion(VAddr addr, u64 size,
55 VideoCommon::CacheType which = VideoCommon::CacheType::All) override; 55 VideoCommon::CacheType which = VideoCommon::CacheType::All) override;
56 void OnCPUWrite(VAddr addr, u64 size) override; 56 void OnCacheInvalidation(VAddr addr, u64 size) override;
57 bool OnCPUWrite(VAddr addr, u64 size) override;
57 VideoCore::RasterizerDownloadArea GetFlushArea(VAddr addr, u64 size) override; 58 VideoCore::RasterizerDownloadArea GetFlushArea(VAddr addr, u64 size) override;
58 void InvalidateGPUCache() override; 59 void InvalidateGPUCache() override;
59 void UnmapMemory(VAddr addr, u64 size) override; 60 void UnmapMemory(VAddr addr, u64 size) override;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index edf527f2d..aadd6967c 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -485,12 +485,33 @@ void RasterizerOpenGL::InvalidateRegion(VAddr addr, u64 size, VideoCommon::Cache
485 } 485 }
486} 486}
487 487
488void RasterizerOpenGL::OnCPUWrite(VAddr addr, u64 size) { 488bool RasterizerOpenGL::OnCPUWrite(VAddr addr, u64 size) {
489 MICROPROFILE_SCOPE(OpenGL_CacheManagement);
490 if (addr == 0 || size == 0) {
491 return false;
492 }
493
494 {
495 std::scoped_lock lock{buffer_cache.mutex};
496 if (buffer_cache.OnCPUWrite(addr, size)) {
497 return true;
498 }
499 }
500
501 {
502 std::scoped_lock lock{texture_cache.mutex};
503 texture_cache.WriteMemory(addr, size);
504 }
505
506 shader_cache.InvalidateRegion(addr, size);
507 return false;
508}
509
510void RasterizerOpenGL::OnCacheInvalidation(VAddr addr, u64 size) {
489 MICROPROFILE_SCOPE(OpenGL_CacheManagement); 511 MICROPROFILE_SCOPE(OpenGL_CacheManagement);
490 if (addr == 0 || size == 0) { 512 if (addr == 0 || size == 0) {
491 return; 513 return;
492 } 514 }
493 shader_cache.OnCPUWrite(addr, size);
494 { 515 {
495 std::scoped_lock lock{texture_cache.mutex}; 516 std::scoped_lock lock{texture_cache.mutex};
496 texture_cache.WriteMemory(addr, size); 517 texture_cache.WriteMemory(addr, size);
@@ -499,15 +520,11 @@ void RasterizerOpenGL::OnCPUWrite(VAddr addr, u64 size) {
499 std::scoped_lock lock{buffer_cache.mutex}; 520 std::scoped_lock lock{buffer_cache.mutex};
500 buffer_cache.CachedWriteMemory(addr, size); 521 buffer_cache.CachedWriteMemory(addr, size);
501 } 522 }
523 shader_cache.InvalidateRegion(addr, size);
502} 524}
503 525
504void RasterizerOpenGL::InvalidateGPUCache() { 526void RasterizerOpenGL::InvalidateGPUCache() {
505 MICROPROFILE_SCOPE(OpenGL_CacheManagement); 527 gpu.InvalidateGPUCache();
506 shader_cache.SyncGuestHost();
507 {
508 std::scoped_lock lock{buffer_cache.mutex};
509 buffer_cache.FlushCachedWrites();
510 }
511} 528}
512 529
513void RasterizerOpenGL::UnmapMemory(VAddr addr, u64 size) { 530void RasterizerOpenGL::UnmapMemory(VAddr addr, u64 size) {
@@ -519,7 +536,7 @@ void RasterizerOpenGL::UnmapMemory(VAddr addr, u64 size) {
519 std::scoped_lock lock{buffer_cache.mutex}; 536 std::scoped_lock lock{buffer_cache.mutex};
520 buffer_cache.WriteMemory(addr, size); 537 buffer_cache.WriteMemory(addr, size);
521 } 538 }
522 shader_cache.OnCPUWrite(addr, size); 539 shader_cache.OnCacheInvalidation(addr, size);
523} 540}
524 541
525void RasterizerOpenGL::ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) { 542void RasterizerOpenGL::ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) {
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index a73ad15c1..8eda2ddba 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -98,7 +98,8 @@ public:
98 VideoCore::RasterizerDownloadArea GetFlushArea(VAddr addr, u64 size) override; 98 VideoCore::RasterizerDownloadArea GetFlushArea(VAddr addr, u64 size) override;
99 void InvalidateRegion(VAddr addr, u64 size, 99 void InvalidateRegion(VAddr addr, u64 size,
100 VideoCommon::CacheType which = VideoCommon::CacheType::All) override; 100 VideoCommon::CacheType which = VideoCommon::CacheType::All) override;
101 void OnCPUWrite(VAddr addr, u64 size) override; 101 void OnCacheInvalidation(VAddr addr, u64 size) override;
102 bool OnCPUWrite(VAddr addr, u64 size) override;
102 void InvalidateGPUCache() override; 103 void InvalidateGPUCache() override;
103 void UnmapMemory(VAddr addr, u64 size) override; 104 void UnmapMemory(VAddr addr, u64 size) override;
104 void ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) override; 105 void ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) override;
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
index b72f95235..51df18ec3 100644
--- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
@@ -591,7 +591,7 @@ void BufferCacheRuntime::ReserveNullBuffer() {
591 .flags = 0, 591 .flags = 0,
592 .size = 4, 592 .size = 4,
593 .usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT | 593 .usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT |
594 VK_BUFFER_USAGE_TRANSFER_DST_BIT, 594 VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT,
595 .sharingMode = VK_SHARING_MODE_EXCLUSIVE, 595 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
596 .queueFamilyIndexCount = 0, 596 .queueFamilyIndexCount = 0,
597 .pQueueFamilyIndices = nullptr, 597 .pQueueFamilyIndices = nullptr,
@@ -599,7 +599,6 @@ void BufferCacheRuntime::ReserveNullBuffer() {
599 if (device.IsExtTransformFeedbackSupported()) { 599 if (device.IsExtTransformFeedbackSupported()) {
600 create_info.usage |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT; 600 create_info.usage |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT;
601 } 601 }
602 create_info.usage |= VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT;
603 null_buffer = memory_allocator.CreateBuffer(create_info, MemoryUsage::DeviceLocal); 602 null_buffer = memory_allocator.CreateBuffer(create_info, MemoryUsage::DeviceLocal);
604 if (device.HasDebuggingToolAttached()) { 603 if (device.HasDebuggingToolAttached()) {
605 null_buffer.SetObjectNameEXT("Null buffer"); 604 null_buffer.SetObjectNameEXT("Null buffer");
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index f7c0d939a..456bb040e 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -566,11 +566,32 @@ void RasterizerVulkan::InnerInvalidation(std::span<const std::pair<VAddr, std::s
566 } 566 }
567} 567}
568 568
569void RasterizerVulkan::OnCPUWrite(VAddr addr, u64 size) { 569bool RasterizerVulkan::OnCPUWrite(VAddr addr, u64 size) {
570 if (addr == 0 || size == 0) {
571 return false;
572 }
573
574 {
575 std::scoped_lock lock{buffer_cache.mutex};
576 if (buffer_cache.OnCPUWrite(addr, size)) {
577 return true;
578 }
579 }
580
581 {
582 std::scoped_lock lock{texture_cache.mutex};
583 texture_cache.WriteMemory(addr, size);
584 }
585
586 pipeline_cache.InvalidateRegion(addr, size);
587 return false;
588}
589
590void RasterizerVulkan::OnCacheInvalidation(VAddr addr, u64 size) {
570 if (addr == 0 || size == 0) { 591 if (addr == 0 || size == 0) {
571 return; 592 return;
572 } 593 }
573 pipeline_cache.OnCPUWrite(addr, size); 594
574 { 595 {
575 std::scoped_lock lock{texture_cache.mutex}; 596 std::scoped_lock lock{texture_cache.mutex};
576 texture_cache.WriteMemory(addr, size); 597 texture_cache.WriteMemory(addr, size);
@@ -579,14 +600,11 @@ void RasterizerVulkan::OnCPUWrite(VAddr addr, u64 size) {
579 std::scoped_lock lock{buffer_cache.mutex}; 600 std::scoped_lock lock{buffer_cache.mutex};
580 buffer_cache.CachedWriteMemory(addr, size); 601 buffer_cache.CachedWriteMemory(addr, size);
581 } 602 }
603 pipeline_cache.InvalidateRegion(addr, size);
582} 604}
583 605
584void RasterizerVulkan::InvalidateGPUCache() { 606void RasterizerVulkan::InvalidateGPUCache() {
585 pipeline_cache.SyncGuestHost(); 607 gpu.InvalidateGPUCache();
586 {
587 std::scoped_lock lock{buffer_cache.mutex};
588 buffer_cache.FlushCachedWrites();
589 }
590} 608}
591 609
592void RasterizerVulkan::UnmapMemory(VAddr addr, u64 size) { 610void RasterizerVulkan::UnmapMemory(VAddr addr, u64 size) {
@@ -598,7 +616,7 @@ void RasterizerVulkan::UnmapMemory(VAddr addr, u64 size) {
598 std::scoped_lock lock{buffer_cache.mutex}; 616 std::scoped_lock lock{buffer_cache.mutex};
599 buffer_cache.WriteMemory(addr, size); 617 buffer_cache.WriteMemory(addr, size);
600 } 618 }
601 pipeline_cache.OnCPUWrite(addr, size); 619 pipeline_cache.OnCacheInvalidation(addr, size);
602} 620}
603 621
604void RasterizerVulkan::ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) { 622void RasterizerVulkan::ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) {
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h
index b39710b3c..73257d964 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.h
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.h
@@ -96,7 +96,8 @@ public:
96 void InvalidateRegion(VAddr addr, u64 size, 96 void InvalidateRegion(VAddr addr, u64 size,
97 VideoCommon::CacheType which = VideoCommon::CacheType::All) override; 97 VideoCommon::CacheType which = VideoCommon::CacheType::All) override;
98 void InnerInvalidation(std::span<const std::pair<VAddr, std::size_t>> sequences) override; 98 void InnerInvalidation(std::span<const std::pair<VAddr, std::size_t>> sequences) override;
99 void OnCPUWrite(VAddr addr, u64 size) override; 99 void OnCacheInvalidation(VAddr addr, u64 size) override;
100 bool OnCPUWrite(VAddr addr, u64 size) override;
100 void InvalidateGPUCache() override; 101 void InvalidateGPUCache() override;
101 void UnmapMemory(VAddr addr, u64 size) override; 102 void UnmapMemory(VAddr addr, u64 size) override;
102 void ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) override; 103 void ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) override;
diff --git a/src/video_core/shader_cache.cpp b/src/video_core/shader_cache.cpp
index 4db948b6d..01701201d 100644
--- a/src/video_core/shader_cache.cpp
+++ b/src/video_core/shader_cache.cpp
@@ -24,7 +24,7 @@ void ShaderCache::InvalidateRegion(VAddr addr, size_t size) {
24 RemovePendingShaders(); 24 RemovePendingShaders();
25} 25}
26 26
27void ShaderCache::OnCPUWrite(VAddr addr, size_t size) { 27void ShaderCache::OnCacheInvalidation(VAddr addr, size_t size) {
28 std::scoped_lock lock{invalidation_mutex}; 28 std::scoped_lock lock{invalidation_mutex};
29 InvalidatePagesInRegion(addr, size); 29 InvalidatePagesInRegion(addr, size);
30} 30}
diff --git a/src/video_core/shader_cache.h b/src/video_core/shader_cache.h
index f3cc4c70b..de8e08002 100644
--- a/src/video_core/shader_cache.h
+++ b/src/video_core/shader_cache.h
@@ -62,7 +62,7 @@ public:
62 /// @brief Unmarks a memory region as cached and marks it for removal 62 /// @brief Unmarks a memory region as cached and marks it for removal
63 /// @param addr Start address of the CPU write operation 63 /// @param addr Start address of the CPU write operation
64 /// @param size Number of bytes of the CPU write operation 64 /// @param size Number of bytes of the CPU write operation
65 void OnCPUWrite(VAddr addr, size_t size); 65 void OnCacheInvalidation(VAddr addr, size_t size);
66 66
67 /// @brief Flushes delayed removal operations 67 /// @brief Flushes delayed removal operations
68 void SyncGuestHost(); 68 void SyncGuestHost();
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index d3f03a995..79f158db4 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<P>::UnmapGPUMemory(size_t as_id, GPUVAddr gpu_addr, size_t siz
598 [&](ImageId id, Image&) { deleted_images.push_back(id); }); 598 [&](ImageId id, Image&) { deleted_images.push_back(id); });
599 for (const ImageId id : deleted_images) { 599 for (const ImageId id : deleted_images) {
600 Image& image = slot_images[id]; 600 Image& image = slot_images[id];
601 if (True(image.flags & ImageFlagBits::CpuModified)) {
602 return;
603 }
604 image.flags |= ImageFlagBits::CpuModified;
605 if (True(image.flags & ImageFlagBits::Tracked)) {
606 UntrackImage(image, id);
607 }
608 /*
609 if (True(image.flags & ImageFlagBits::Remapped)) { 601 if (True(image.flags & ImageFlagBits::Remapped)) {
610 continue; 602 continue;
611 } 603 }
@@ -613,7 +605,6 @@ void TextureCache<P>::UnmapGPUMemory(size_t as_id, GPUVAddr gpu_addr, size_t siz
613 if (True(image.flags & ImageFlagBits::Tracked)) { 605 if (True(image.flags & ImageFlagBits::Tracked)) {
614 UntrackImage(image, id); 606 UntrackImage(image, id);
615 } 607 }
616 */
617 } 608 }
618} 609}
619 610
@@ -874,11 +865,19 @@ void TextureCache<P>::PopAsyncFlushes() {
874template <class P> 865template <class P>
875ImageId TextureCache<P>::DmaImageId(const Tegra::DMA::ImageOperand& operand, bool is_upload) { 866ImageId TextureCache<P>::DmaImageId(const Tegra::DMA::ImageOperand& operand, bool is_upload) {
876 const ImageInfo dst_info(operand); 867 const ImageInfo dst_info(operand);
877 const ImageId image_id = FindDMAImage(dst_info, operand.address); 868 const ImageId dst_id = FindDMAImage(dst_info, operand.address);
878 if (!image_id) { 869 if (!dst_id) {
870 return NULL_IMAGE_ID;
871 }
872 auto& image = slot_images[dst_id];
873 if (False(image.flags & ImageFlagBits::GpuModified)) {
874 // No need to waste time on an image that's synced with guest
875 return NULL_IMAGE_ID;
876 }
877 if (image.info.type == ImageType::e3D) {
878 // Don't accelerate 3D images.
879 return NULL_IMAGE_ID; 879 return NULL_IMAGE_ID;
880 } 880 }
881 auto& image = slot_images[image_id];
882 if (!is_upload && !image.info.dma_downloaded) { 881 if (!is_upload && !image.info.dma_downloaded) {
883 // Force a full sync. 882 // Force a full sync.
884 image.info.dma_downloaded = true; 883 image.info.dma_downloaded = true;
@@ -888,7 +887,7 @@ ImageId TextureCache<P>::DmaImageId(const Tegra::DMA::ImageOperand& operand, boo
888 if (!base) { 887 if (!base) {
889 return NULL_IMAGE_ID; 888 return NULL_IMAGE_ID;
890 } 889 }
891 return image_id; 890 return dst_id;
892} 891}
893 892
894template <class P> 893template <class P>
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
528 } 528 }
529 529
530 sets_per_pool = 64; 530 sets_per_pool = 64;
531 if (extensions.extended_dynamic_state3 && is_amd_driver &&
532 properties.properties.driverVersion >= VK_MAKE_API_VERSION(0, 2, 0, 270)) {
533 LOG_WARNING(Render_Vulkan,
534 "AMD drivers after 23.5.2 have broken extendedDynamicState3ColorBlendEquation");
535 features.extended_dynamic_state3.extendedDynamicState3ColorBlendEnable = false;
536 features.extended_dynamic_state3.extendedDynamicState3ColorBlendEquation = false;
537 dynamic_state3_blending = false;
538 }
531 if (is_amd_driver) { 539 if (is_amd_driver) {
532 // AMD drivers need a higher amount of Sets per Pool in certain circumstances like in XC2. 540 // AMD drivers need a higher amount of Sets per Pool in certain circumstances like in XC2.
533 sets_per_pool = 96; 541 sets_per_pool = 96;
diff --git a/src/video_core/vulkan_common/vulkan_instance.cpp b/src/video_core/vulkan_common/vulkan_instance.cpp
index 7624a9b32..6a294c1da 100644
--- a/src/video_core/vulkan_common/vulkan_instance.cpp
+++ b/src/video_core/vulkan_common/vulkan_instance.cpp
@@ -19,11 +19,9 @@
19#include <windows.h> 19#include <windows.h>
20// ensure include order 20// ensure include order
21#include <vulkan/vulkan_win32.h> 21#include <vulkan/vulkan_win32.h>
22#elif defined(__APPLE__)
23#include <vulkan/vulkan_macos.h>
24#elif defined(__ANDROID__) 22#elif defined(__ANDROID__)
25#include <vulkan/vulkan_android.h> 23#include <vulkan/vulkan_android.h>
26#else 24#elif !defined(__APPLE__)
27#include <X11/Xlib.h> 25#include <X11/Xlib.h>
28#include <vulkan/vulkan_wayland.h> 26#include <vulkan/vulkan_wayland.h>
29#include <vulkan/vulkan_xlib.h> 27#include <vulkan/vulkan_xlib.h>
@@ -68,7 +66,7 @@ namespace {
68 break; 66 break;
69#elif defined(__APPLE__) 67#elif defined(__APPLE__)
70 case Core::Frontend::WindowSystemType::Cocoa: 68 case Core::Frontend::WindowSystemType::Cocoa:
71 extensions.push_back(VK_MVK_MACOS_SURFACE_EXTENSION_NAME); 69 extensions.push_back(VK_EXT_METAL_SURFACE_EXTENSION_NAME);
72 break; 70 break;
73#elif defined(__ANDROID__) 71#elif defined(__ANDROID__)
74 case Core::Frontend::WindowSystemType::Android: 72 case Core::Frontend::WindowSystemType::Android:
diff --git a/src/video_core/vulkan_common/vulkan_surface.cpp b/src/video_core/vulkan_common/vulkan_surface.cpp
index c34599365..cfea4cd7b 100644
--- a/src/video_core/vulkan_common/vulkan_surface.cpp
+++ b/src/video_core/vulkan_common/vulkan_surface.cpp
@@ -11,11 +11,9 @@
11#include <windows.h> 11#include <windows.h>
12// ensure include order 12// ensure include order
13#include <vulkan/vulkan_win32.h> 13#include <vulkan/vulkan_win32.h>
14#elif defined(__APPLE__)
15#include <vulkan/vulkan_macos.h>
16#elif defined(__ANDROID__) 14#elif defined(__ANDROID__)
17#include <vulkan/vulkan_android.h> 15#include <vulkan/vulkan_android.h>
18#else 16#elif !defined(__APPLE__)
19#include <X11/Xlib.h> 17#include <X11/Xlib.h>
20#include <vulkan/vulkan_wayland.h> 18#include <vulkan/vulkan_wayland.h>
21#include <vulkan/vulkan_xlib.h> 19#include <vulkan/vulkan_xlib.h>
@@ -44,12 +42,13 @@ vk::SurfaceKHR CreateSurface(
44 } 42 }
45#elif defined(__APPLE__) 43#elif defined(__APPLE__)
46 if (window_info.type == Core::Frontend::WindowSystemType::Cocoa) { 44 if (window_info.type == Core::Frontend::WindowSystemType::Cocoa) {
47 const VkMacOSSurfaceCreateInfoMVK mvk_ci{VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK, 45 const VkMetalSurfaceCreateInfoEXT macos_ci = {
48 nullptr, 0, window_info.render_surface}; 46 .pLayer = static_cast<const CAMetalLayer*>(window_info.render_surface),
49 const auto vkCreateMacOSSurfaceMVK = reinterpret_cast<PFN_vkCreateMacOSSurfaceMVK>( 47 };
50 dld.vkGetInstanceProcAddr(*instance, "vkCreateMacOSSurfaceMVK")); 48 const auto vkCreateMetalSurfaceEXT = reinterpret_cast<PFN_vkCreateMetalSurfaceEXT>(
51 if (!vkCreateMacOSSurfaceMVK || 49 dld.vkGetInstanceProcAddr(*instance, "vkCreateMetalSurfaceEXT"));
52 vkCreateMacOSSurfaceMVK(*instance, &mvk_ci, nullptr, &unsafe_surface) != VK_SUCCESS) { 50 if (!vkCreateMetalSurfaceEXT ||
51 vkCreateMetalSurfaceEXT(*instance, &macos_ci, nullptr, &unsafe_surface) != VK_SUCCESS) {
53 LOG_ERROR(Render_Vulkan, "Failed to initialize Metal surface"); 52 LOG_ERROR(Render_Vulkan, "Failed to initialize Metal surface");
54 throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED); 53 throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
55 } 54 }
diff --git a/src/video_core/vulkan_common/vulkan_wrapper.h b/src/video_core/vulkan_common/vulkan_wrapper.h
index b5e70fcd4..32bd75ad8 100644
--- a/src/video_core/vulkan_common/vulkan_wrapper.h
+++ b/src/video_core/vulkan_common/vulkan_wrapper.h
@@ -15,6 +15,8 @@
15#define VK_NO_PROTOTYPES 15#define VK_NO_PROTOTYPES
16#ifdef _WIN32 16#ifdef _WIN32
17#define VK_USE_PLATFORM_WIN32_KHR 17#define VK_USE_PLATFORM_WIN32_KHR
18#elif defined(__APPLE__)
19#define VK_USE_PLATFORM_METAL_EXT
18#endif 20#endif
19#include <vulkan/vulkan.h> 21#include <vulkan/vulkan.h>
20 22
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 29467d380..195d3556c 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -503,8 +503,7 @@ void Config::ReadMousePanningValues() {
503 ReadBasicSetting(Settings::values.mouse_panning); 503 ReadBasicSetting(Settings::values.mouse_panning);
504 ReadBasicSetting(Settings::values.mouse_panning_x_sensitivity); 504 ReadBasicSetting(Settings::values.mouse_panning_x_sensitivity);
505 ReadBasicSetting(Settings::values.mouse_panning_y_sensitivity); 505 ReadBasicSetting(Settings::values.mouse_panning_y_sensitivity);
506 ReadBasicSetting(Settings::values.mouse_panning_deadzone_x_counterweight); 506 ReadBasicSetting(Settings::values.mouse_panning_deadzone_counterweight);
507 ReadBasicSetting(Settings::values.mouse_panning_deadzone_y_counterweight);
508 ReadBasicSetting(Settings::values.mouse_panning_decay_strength); 507 ReadBasicSetting(Settings::values.mouse_panning_decay_strength);
509 ReadBasicSetting(Settings::values.mouse_panning_min_decay); 508 ReadBasicSetting(Settings::values.mouse_panning_min_decay);
510} 509}
@@ -1122,8 +1121,7 @@ void Config::SaveMousePanningValues() {
1122 // Don't overwrite values.mouse_panning 1121 // Don't overwrite values.mouse_panning
1123 WriteBasicSetting(Settings::values.mouse_panning_x_sensitivity); 1122 WriteBasicSetting(Settings::values.mouse_panning_x_sensitivity);
1124 WriteBasicSetting(Settings::values.mouse_panning_y_sensitivity); 1123 WriteBasicSetting(Settings::values.mouse_panning_y_sensitivity);
1125 WriteBasicSetting(Settings::values.mouse_panning_deadzone_x_counterweight); 1124 WriteBasicSetting(Settings::values.mouse_panning_deadzone_counterweight);
1126 WriteBasicSetting(Settings::values.mouse_panning_deadzone_y_counterweight);
1127 WriteBasicSetting(Settings::values.mouse_panning_decay_strength); 1125 WriteBasicSetting(Settings::values.mouse_panning_decay_strength);
1128 WriteBasicSetting(Settings::values.mouse_panning_min_decay); 1126 WriteBasicSetting(Settings::values.mouse_panning_min_decay);
1129} 1127}
diff --git a/src/yuzu/configuration/configure_input_player.ui b/src/yuzu/configuration/configure_input_player.ui
index 43f6c7b50..611a79477 100644
--- a/src/yuzu/configuration/configure_input_player.ui
+++ b/src/yuzu/configuration/configure_input_player.ui
@@ -3105,21 +3105,6 @@
3105 </property> 3105 </property>
3106 <item> 3106 <item>
3107 <widget class="QPushButton" name="mousePanningButton"> 3107 <widget class="QPushButton" name="mousePanningButton">
3108 <property name="minimumSize">
3109 <size>
3110 <width>68</width>
3111 <height>0</height>
3112 </size>
3113 </property>
3114 <property name="maximumSize">
3115 <size>
3116 <width>68</width>
3117 <height>16777215</height>
3118 </size>
3119 </property>
3120 <property name="styleSheet">
3121 <string notr="true">min-width: 68px;</string>
3122 </property>
3123 <property name="text"> 3108 <property name="text">
3124 <string>Configure</string> 3109 <string>Configure</string>
3125 </property> 3110 </property>
diff --git a/src/yuzu/configuration/configure_mouse_panning.cpp b/src/yuzu/configuration/configure_mouse_panning.cpp
index f183d2740..e37c546b0 100644
--- a/src/yuzu/configuration/configure_mouse_panning.cpp
+++ b/src/yuzu/configuration/configure_mouse_panning.cpp
@@ -2,6 +2,7 @@
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include <QCloseEvent> 4#include <QCloseEvent>
5#include <QMessageBox>
5 6
6#include "common/settings.h" 7#include "common/settings.h"
7#include "ui_configure_mouse_panning.h" 8#include "ui_configure_mouse_panning.h"
@@ -27,31 +28,34 @@ void ConfigureMousePanning::SetConfiguration(float right_stick_deadzone, float r
27 ui->enable->setChecked(Settings::values.mouse_panning.GetValue()); 28 ui->enable->setChecked(Settings::values.mouse_panning.GetValue());
28 ui->x_sensitivity->setValue(Settings::values.mouse_panning_x_sensitivity.GetValue()); 29 ui->x_sensitivity->setValue(Settings::values.mouse_panning_x_sensitivity.GetValue());
29 ui->y_sensitivity->setValue(Settings::values.mouse_panning_y_sensitivity.GetValue()); 30 ui->y_sensitivity->setValue(Settings::values.mouse_panning_y_sensitivity.GetValue());
30 ui->deadzone_x_counterweight->setValue( 31 ui->deadzone_counterweight->setValue(
31 Settings::values.mouse_panning_deadzone_x_counterweight.GetValue()); 32 Settings::values.mouse_panning_deadzone_counterweight.GetValue());
32 ui->deadzone_y_counterweight->setValue(
33 Settings::values.mouse_panning_deadzone_y_counterweight.GetValue());
34 ui->decay_strength->setValue(Settings::values.mouse_panning_decay_strength.GetValue()); 33 ui->decay_strength->setValue(Settings::values.mouse_panning_decay_strength.GetValue());
35 ui->min_decay->setValue(Settings::values.mouse_panning_min_decay.GetValue()); 34 ui->min_decay->setValue(Settings::values.mouse_panning_min_decay.GetValue());
36 35
37 if (right_stick_deadzone > 0.0f || right_stick_range != 1.0f) { 36 if (right_stick_deadzone > 0.0f || right_stick_range != 1.0f) {
38 ui->warning_label->setText(QString::fromStdString( 37 const QString right_stick_deadzone_str =
39 "Mouse panning works better with a deadzone of 0% and a range of 100%.\n" 38 QString::fromStdString(std::to_string(static_cast<int>(right_stick_deadzone * 100.0f)));
40 "Current values are " + 39 const QString right_stick_range_str =
41 std::to_string(static_cast<int>(right_stick_deadzone * 100.0f)) + "% and " + 40 QString::fromStdString(std::to_string(static_cast<int>(right_stick_range * 100.0f)));
42 std::to_string(static_cast<int>(right_stick_range * 100.0f)) + "% respectively.")); 41
43 } else { 42 ui->warning_label->setText(
44 ui->warning_label->hide(); 43 tr("Mouse panning works better with a deadzone of 0% and a range of 100%.\nCurrent "
44 "values are %1% and %2% respectively.")
45 .arg(right_stick_deadzone_str, right_stick_range_str));
46 }
47
48 if (Settings::values.mouse_enabled) {
49 ui->warning_label->setText(
50 tr("Emulated mouse is enabled. This is incompatible with mouse panning."));
45 } 51 }
46} 52}
47 53
48void ConfigureMousePanning::SetDefaultConfiguration() { 54void ConfigureMousePanning::SetDefaultConfiguration() {
49 ui->x_sensitivity->setValue(Settings::values.mouse_panning_x_sensitivity.GetDefault()); 55 ui->x_sensitivity->setValue(Settings::values.mouse_panning_x_sensitivity.GetDefault());
50 ui->y_sensitivity->setValue(Settings::values.mouse_panning_y_sensitivity.GetDefault()); 56 ui->y_sensitivity->setValue(Settings::values.mouse_panning_y_sensitivity.GetDefault());
51 ui->deadzone_x_counterweight->setValue( 57 ui->deadzone_counterweight->setValue(
52 Settings::values.mouse_panning_deadzone_x_counterweight.GetDefault()); 58 Settings::values.mouse_panning_deadzone_counterweight.GetDefault());
53 ui->deadzone_y_counterweight->setValue(
54 Settings::values.mouse_panning_deadzone_y_counterweight.GetDefault());
55 ui->decay_strength->setValue(Settings::values.mouse_panning_decay_strength.GetDefault()); 59 ui->decay_strength->setValue(Settings::values.mouse_panning_decay_strength.GetDefault());
56 ui->min_decay->setValue(Settings::values.mouse_panning_min_decay.GetDefault()); 60 ui->min_decay->setValue(Settings::values.mouse_panning_min_decay.GetDefault());
57} 61}
@@ -68,12 +72,19 @@ void ConfigureMousePanning::ApplyConfiguration() {
68 Settings::values.mouse_panning = ui->enable->isChecked(); 72 Settings::values.mouse_panning = ui->enable->isChecked();
69 Settings::values.mouse_panning_x_sensitivity = static_cast<float>(ui->x_sensitivity->value()); 73 Settings::values.mouse_panning_x_sensitivity = static_cast<float>(ui->x_sensitivity->value());
70 Settings::values.mouse_panning_y_sensitivity = static_cast<float>(ui->y_sensitivity->value()); 74 Settings::values.mouse_panning_y_sensitivity = static_cast<float>(ui->y_sensitivity->value());
71 Settings::values.mouse_panning_deadzone_x_counterweight = 75 Settings::values.mouse_panning_deadzone_counterweight =
72 static_cast<float>(ui->deadzone_x_counterweight->value()); 76 static_cast<float>(ui->deadzone_counterweight->value());
73 Settings::values.mouse_panning_deadzone_y_counterweight =
74 static_cast<float>(ui->deadzone_y_counterweight->value());
75 Settings::values.mouse_panning_decay_strength = static_cast<float>(ui->decay_strength->value()); 77 Settings::values.mouse_panning_decay_strength = static_cast<float>(ui->decay_strength->value());
76 Settings::values.mouse_panning_min_decay = static_cast<float>(ui->min_decay->value()); 78 Settings::values.mouse_panning_min_decay = static_cast<float>(ui->min_decay->value());
77 79
80 if (Settings::values.mouse_enabled && Settings::values.mouse_panning) {
81 Settings::values.mouse_panning = false;
82 QMessageBox::critical(
83 this, tr("Emulated mouse is enabled"),
84 tr("Real mouse input and mouse panning are incompatible. Please disable the "
85 "emulated mouse in input advanced settings to allow mouse panning."));
86 return;
87 }
88
78 accept(); 89 accept();
79} 90}
diff --git a/src/yuzu/configuration/configure_mouse_panning.ui b/src/yuzu/configuration/configure_mouse_panning.ui
index 75795b727..84fb7ee80 100644
--- a/src/yuzu/configuration/configure_mouse_panning.ui
+++ b/src/yuzu/configuration/configure_mouse_panning.ui
@@ -9,10 +9,10 @@
9 <item> 9 <item>
10 <widget class="QCheckBox" name="enable"> 10 <widget class="QCheckBox" name="enable">
11 <property name="text"> 11 <property name="text">
12 <string>Enable</string> 12 <string>Enable mouse panning</string>
13 </property> 13 </property>
14 <property name="toolTip"> 14 <property name="toolTip">
15 <string>Can be toggled via a hotkey</string> 15 <string>Can be toggled via a hotkey. Default hotkey is Ctrl + F9</string>
16 </property> 16 </property>
17 </widget> 17 </widget>
18 </item> 18 </item>
@@ -89,40 +89,14 @@
89 </property> 89 </property>
90 <layout class="QGridLayout"> 90 <layout class="QGridLayout">
91 <item row="0" column="0"> 91 <item row="0" column="0">
92 <widget class="QLabel" name="deadzone_x_counterweight_label"> 92 <widget class="QLabel" name="deadzone_counterweight_label">
93 <property name="text"> 93 <property name="text">
94 <string>Horizontal</string> 94 <string>Deadzone</string>
95 </property> 95 </property>
96 </widget> 96 </widget>
97 </item> 97 </item>
98 <item row="0" column="1"> 98 <item row="0" column="1">
99 <widget class="QSpinBox" name="deadzone_x_counterweight"> 99 <widget class="QSpinBox" name="deadzone_counterweight">
100 <property name="alignment">
101 <set>Qt::AlignCenter</set>
102 </property>
103 <property name="suffix">
104 <string>%</string>
105 </property>
106 <property name="minimum">
107 <number>0</number>
108 </property>
109 <property name="maximum">
110 <number>100</number>
111 </property>
112 <property name="value">
113 <number>0</number>
114 </property>
115 </widget>
116 </item>
117 <item row="1" column="0">
118 <widget class="QLabel" name="deadzone_y_counterweight_label">
119 <property name="text">
120 <string>Vertical</string>
121 </property>
122 </widget>
123 </item>
124 <item row="1" column="1">
125 <widget class="QSpinBox" name="deadzone_y_counterweight">
126 <property name="alignment"> 100 <property name="alignment">
127 <set>Qt::AlignCenter</set> 101 <set>Qt::AlignCenter</set>
128 </property> 102 </property>
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() {
305 QMessageBox::warning(this, dialog_title, 305 QMessageBox::warning(this, dialog_title,
306 tr("The current mapped device doesn't have a ring attached")); 306 tr("The current mapped device doesn't have a ring attached"));
307 break; 307 break;
308 case Common::Input::DriverResult::InvalidHandle:
309 QMessageBox::warning(this, dialog_title, tr("The current mapped device is not connected"));
310 break;
308 default: 311 default:
309 QMessageBox::warning(this, dialog_title, 312 QMessageBox::warning(this, dialog_title,
310 tr("Unexpected driver result %1").arg(static_cast<int>(result))); 313 tr("Unexpected driver result %1").arg(static_cast<int>(result)));
diff --git a/src/yuzu/qt_common.cpp b/src/yuzu/qt_common.cpp
index 5d0fd7674..413402165 100644
--- a/src/yuzu/qt_common.cpp
+++ b/src/yuzu/qt_common.cpp
@@ -10,6 +10,8 @@
10 10
11#if !defined(WIN32) && !defined(__APPLE__) 11#if !defined(WIN32) && !defined(__APPLE__)
12#include <qpa/qplatformnativeinterface.h> 12#include <qpa/qplatformnativeinterface.h>
13#elif defined(__APPLE__)
14#include <objc/message.h>
13#endif 15#endif
14 16
15namespace QtCommon { 17namespace QtCommon {
@@ -37,9 +39,12 @@ Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window)
37 Core::Frontend::EmuWindow::WindowSystemInfo wsi; 39 Core::Frontend::EmuWindow::WindowSystemInfo wsi;
38 wsi.type = GetWindowSystemType(); 40 wsi.type = GetWindowSystemType();
39 41
42#if defined(WIN32)
40 // Our Win32 Qt external doesn't have the private API. 43 // Our Win32 Qt external doesn't have the private API.
41#if defined(WIN32) || defined(__APPLE__) 44 wsi.render_surface = reinterpret_cast<void*>(window->winId());
42 wsi.render_surface = window ? reinterpret_cast<void*>(window->winId()) : nullptr; 45#elif defined(__APPLE__)
46 wsi.render_surface = reinterpret_cast<void* (*)(id, SEL)>(objc_msgSend)(
47 reinterpret_cast<id>(window->winId()), sel_registerName("layer"));
43#else 48#else
44 QPlatformNativeInterface* pni = QGuiApplication::platformNativeInterface(); 49 QPlatformNativeInterface* pni = QGuiApplication::platformNativeInterface();
45 wsi.display_connection = pni->nativeResourceForWindow("display", window); 50 wsi.display_connection = pni->nativeResourceForWindow("display", window);
diff --git a/src/yuzu/vk_device_info.cpp b/src/yuzu/vk_device_info.cpp
index 7c26a3dc7..e1a0e6a2a 100644
--- a/src/yuzu/vk_device_info.cpp
+++ b/src/yuzu/vk_device_info.cpp
@@ -26,7 +26,10 @@ Record::~Record() = default;
26void PopulateRecords(std::vector<Record>& records, QWindow* window) try { 26void PopulateRecords(std::vector<Record>& records, QWindow* window) try {
27 using namespace Vulkan; 27 using namespace Vulkan;
28 28
29 auto wsi = QtCommon::GetWindowSystemInfo(window); 29 // Create a test window with a Vulkan surface type for checking present modes.
30 QWindow test_window(window);
31 test_window.setSurfaceType(QWindow::VulkanSurface);
32 auto wsi = QtCommon::GetWindowSystemInfo(&test_window);
30 33
31 vk::InstanceDispatch dld; 34 vk::InstanceDispatch dld;
32 const auto library = OpenLibrary(); 35 const auto library = OpenLibrary();