summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/address_space.h7
-rw-r--r--src/common/alignment.h18
-rw-r--r--src/common/atomic_helpers.h2
-rw-r--r--src/common/bit_util.h6
-rw-r--r--src/common/concepts.h6
-rw-r--r--src/common/div_ceil.h4
-rw-r--r--src/common/expected.h60
-rw-r--r--src/common/input.h2
-rw-r--r--src/common/intrusive_red_black_tree.h20
-rw-r--r--src/common/make_unique_for_overwrite.h8
-rw-r--r--src/common/polyfill_ranges.h8
-rw-r--r--src/common/polyfill_thread.h4
-rw-r--r--src/common/settings.h12
-rw-r--r--src/common/string_util.cpp2
-rw-r--r--src/common/string_util.h3
-rw-r--r--src/common/tree.h74
-rw-r--r--src/common/vector_math.h16
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/hardware_properties.h20
-rw-r--r--src/core/hid/emulated_controller.cpp75
-rw-r--r--src/core/hid/emulated_controller.h6
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp30
-rw-r--r--src/core/hle/kernel/hle_ipc.h8
-rw-r--r--src/core/hle/kernel/k_auto_object.h20
-rw-r--r--src/core/hle/kernel/k_capabilities.cpp358
-rw-r--r--src/core/hle/kernel/k_capabilities.h295
-rw-r--r--src/core/hle/kernel/k_priority_queue.h54
-rw-r--r--src/core/hle/kernel/k_scoped_lock.h11
-rw-r--r--src/core/hle/kernel/k_thread.h8
-rw-r--r--src/core/hle/kernel/k_thread_local_page.h6
-rw-r--r--src/core/hle/kernel/svc_types.h5
-rw-r--r--src/core/hle/kernel/svc_version.h58
-rw-r--r--src/core/hle/service/am/am.cpp2
-rw-r--r--src/core/hle/service/audio/audren_u.cpp2
-rw-r--r--src/core/hle/service/audio/hwopus.cpp2
-rw-r--r--src/core/hle/service/es/es.cpp2
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp9
-rw-r--r--src/core/hle/service/glue/arp.cpp3
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp8
-rw-r--r--src/core/hle/service/hid/controllers/npad.h3
-rw-r--r--src/core/hle/service/hid/hid.cpp4
-rw-r--r--src/core/hle/service/hid/hidbus/hidbus_base.h3
-rw-r--r--src/core/hle/service/hid/hidbus/ringcon.cpp2
-rw-r--r--src/core/hle/service/hid/hidbus/ringcon.h3
-rw-r--r--src/core/hle/service/hid/hidbus/starlink.cpp2
-rw-r--r--src/core/hle/service/hid/hidbus/starlink.h2
-rw-r--r--src/core/hle/service/hid/hidbus/stubbed.cpp2
-rw-r--r--src/core/hle/service/hid/hidbus/stubbed.h2
-rw-r--r--src/core/hle/service/jit/jit.cpp4
-rw-r--r--src/core/hle/service/ldn/ldn.cpp4
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdevice.h10
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp8
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.h10
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp26
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h28
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp21
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.h22
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp31
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h32
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp35
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.h36
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp8
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.h10
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp17
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h14
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp10
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h12
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_vic.cpp8
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_vic.h10
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.cpp20
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.h22
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.cpp8
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.h12
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue_producer.cpp4
-rw-r--r--src/core/hle/service/nvflinger/graphic_buffer_producer.cpp2
-rw-r--r--src/core/hle/service/nvflinger/graphic_buffer_producer.h4
-rw-r--r--src/core/hle/service/nvflinger/parcel.h87
-rw-r--r--src/core/hle/service/prepo/prepo.cpp8
-rw-r--r--src/core/hle/service/sockets/bsd.cpp15
-rw-r--r--src/core/hle/service/sockets/bsd.h23
-rw-r--r--src/core/hle/service/sockets/sfdnsres.cpp2
-rw-r--r--src/core/hle/service/ssl/ssl.cpp8
-rw-r--r--src/core/hle/service/vi/vi.cpp4
-rw-r--r--src/core/internal_network/network.cpp4
-rw-r--r--src/core/internal_network/socket_proxy.cpp4
-rw-r--r--src/core/internal_network/socket_proxy.h5
-rw-r--r--src/core/internal_network/sockets.h9
-rw-r--r--src/core/reporter.cpp2
-rw-r--r--src/core/reporter.h4
-rw-r--r--src/input_common/drivers/joycon.cpp4
-rw-r--r--src/input_common/drivers/joycon.h2
-rw-r--r--src/input_common/helpers/joycon_driver.cpp18
-rw-r--r--src/input_common/helpers/joycon_protocol/common_protocol.cpp155
-rw-r--r--src/input_common/helpers/joycon_protocol/common_protocol.h35
-rw-r--r--src/input_common/helpers/joycon_protocol/generic_functions.cpp4
-rw-r--r--src/input_common/helpers/joycon_protocol/irs.cpp13
-rw-r--r--src/input_common/helpers/joycon_protocol/joycon_types.h136
-rw-r--r--src/input_common/helpers/joycon_protocol/nfc.cpp68
-rw-r--r--src/input_common/helpers/joycon_protocol/nfc.h8
-rw-r--r--src/input_common/helpers/joycon_protocol/poller.cpp8
-rw-r--r--src/input_common/helpers/joycon_protocol/ringcon.cpp12
-rw-r--r--src/input_common/input_poller.cpp30
-rw-r--r--src/shader_recompiler/backend/glasm/emit_glasm_image.cpp10
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_image.cpp32
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_image.cpp25
-rw-r--r--src/shader_recompiler/backend/spirv/spirv_emit_context.cpp1
-rw-r--r--src/shader_recompiler/backend/spirv/spirv_emit_context.h1
-rw-r--r--src/shader_recompiler/frontend/ir/ir_emitter.h3
-rw-r--r--src/shader_recompiler/frontend/ir/value.h13
-rw-r--r--src/shader_recompiler/object_pool.h4
-rw-r--r--src/video_core/host_shaders/CMakeLists.txt2
-rw-r--r--src/video_core/host_shaders/vulkan_color_clear.frag14
-rw-r--r--src/video_core/host_shaders/vulkan_color_clear.vert10
-rw-r--r--src/video_core/renderer_vulkan/blit_image.cpp126
-rw-r--r--src/video_core/renderer_vulkan/blit_image.h10
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp10
-rw-r--r--src/video_core/texture_cache/descriptor_table.h4
-rw-r--r--src/video_core/texture_cache/slot_vector.h2
-rw-r--r--src/yuzu/configuration/configure_input_player.cpp17
-rw-r--r--src/yuzu/configuration/configure_input_player_widget.cpp35
-rw-r--r--src/yuzu/configuration/configure_input_player_widget.h2
121 files changed, 1901 insertions, 775 deletions
diff --git a/src/common/address_space.h b/src/common/address_space.h
index 9222b2fdc..8683c23c3 100644
--- a/src/common/address_space.h
+++ b/src/common/address_space.h
@@ -12,7 +12,8 @@
12 12
13namespace Common { 13namespace Common {
14template <typename VaType, size_t AddressSpaceBits> 14template <typename VaType, size_t AddressSpaceBits>
15concept AddressSpaceValid = std::is_unsigned_v<VaType> && sizeof(VaType) * 8 >= AddressSpaceBits; 15concept AddressSpaceValid = std::is_unsigned_v<VaType> && sizeof(VaType) * 8 >=
16AddressSpaceBits;
16 17
17struct EmptyStruct {}; 18struct EmptyStruct {};
18 19
@@ -21,7 +22,7 @@ struct EmptyStruct {};
21 */ 22 */
22template <typename VaType, VaType UnmappedVa, typename PaType, PaType UnmappedPa, 23template <typename VaType, VaType UnmappedVa, typename PaType, PaType UnmappedPa,
23 bool PaContigSplit, size_t AddressSpaceBits, typename ExtraBlockInfo = EmptyStruct> 24 bool PaContigSplit, size_t AddressSpaceBits, typename ExtraBlockInfo = EmptyStruct>
24requires AddressSpaceValid<VaType, AddressSpaceBits> 25 requires AddressSpaceValid<VaType, AddressSpaceBits>
25class FlatAddressSpaceMap { 26class FlatAddressSpaceMap {
26public: 27public:
27 /// The maximum VA that this AS can technically reach 28 /// The maximum VA that this AS can technically reach
@@ -109,7 +110,7 @@ private:
109 * initial, fast linear pass and a subsequent slower pass that iterates until it finds a free block 110 * initial, fast linear pass and a subsequent slower pass that iterates until it finds a free block
110 */ 111 */
111template <typename VaType, VaType UnmappedVa, size_t AddressSpaceBits> 112template <typename VaType, VaType UnmappedVa, size_t AddressSpaceBits>
112requires AddressSpaceValid<VaType, AddressSpaceBits> 113 requires AddressSpaceValid<VaType, AddressSpaceBits>
113class FlatAllocator 114class FlatAllocator
114 : public FlatAddressSpaceMap<VaType, UnmappedVa, bool, false, false, AddressSpaceBits> { 115 : public FlatAddressSpaceMap<VaType, UnmappedVa, bool, false, false, AddressSpaceBits> {
115private: 116private:
diff --git a/src/common/alignment.h b/src/common/alignment.h
index 7e897334b..fa715d497 100644
--- a/src/common/alignment.h
+++ b/src/common/alignment.h
@@ -10,7 +10,7 @@
10namespace Common { 10namespace Common {
11 11
12template <typename T> 12template <typename T>
13requires std::is_unsigned_v<T> 13 requires std::is_unsigned_v<T>
14[[nodiscard]] constexpr T AlignUp(T value, size_t size) { 14[[nodiscard]] constexpr T AlignUp(T value, size_t size) {
15 auto mod{static_cast<T>(value % size)}; 15 auto mod{static_cast<T>(value % size)};
16 value -= mod; 16 value -= mod;
@@ -18,31 +18,31 @@ requires std::is_unsigned_v<T>
18} 18}
19 19
20template <typename T> 20template <typename T>
21requires std::is_unsigned_v<T> 21 requires std::is_unsigned_v<T>
22[[nodiscard]] constexpr T AlignUpLog2(T value, size_t align_log2) { 22[[nodiscard]] constexpr T AlignUpLog2(T value, size_t align_log2) {
23 return static_cast<T>((value + ((1ULL << align_log2) - 1)) >> align_log2 << align_log2); 23 return static_cast<T>((value + ((1ULL << align_log2) - 1)) >> align_log2 << align_log2);
24} 24}
25 25
26template <typename T> 26template <typename T>
27requires std::is_unsigned_v<T> 27 requires std::is_unsigned_v<T>
28[[nodiscard]] constexpr T AlignDown(T value, size_t size) { 28[[nodiscard]] constexpr T AlignDown(T value, size_t size) {
29 return static_cast<T>(value - value % size); 29 return static_cast<T>(value - value % size);
30} 30}
31 31
32template <typename T> 32template <typename T>
33requires std::is_unsigned_v<T> 33 requires std::is_unsigned_v<T>
34[[nodiscard]] constexpr bool Is4KBAligned(T value) { 34[[nodiscard]] constexpr bool Is4KBAligned(T value) {
35 return (value & 0xFFF) == 0; 35 return (value & 0xFFF) == 0;
36} 36}
37 37
38template <typename T> 38template <typename T>
39requires std::is_unsigned_v<T> 39 requires std::is_unsigned_v<T>
40[[nodiscard]] constexpr bool IsWordAligned(T value) { 40[[nodiscard]] constexpr bool IsWordAligned(T value) {
41 return (value & 0b11) == 0; 41 return (value & 0b11) == 0;
42} 42}
43 43
44template <typename T> 44template <typename T>
45requires std::is_integral_v<T> 45 requires std::is_integral_v<T>
46[[nodiscard]] constexpr bool IsAligned(T value, size_t alignment) { 46[[nodiscard]] constexpr bool IsAligned(T value, size_t alignment) {
47 using U = typename std::make_unsigned_t<T>; 47 using U = typename std::make_unsigned_t<T>;
48 const U mask = static_cast<U>(alignment - 1); 48 const U mask = static_cast<U>(alignment - 1);
@@ -50,7 +50,7 @@ requires std::is_integral_v<T>
50} 50}
51 51
52template <typename T, typename U> 52template <typename T, typename U>
53requires std::is_integral_v<T> 53 requires std::is_integral_v<T>
54[[nodiscard]] constexpr T DivideUp(T x, U y) { 54[[nodiscard]] constexpr T DivideUp(T x, U y) {
55 return (x + (y - 1)) / y; 55 return (x + (y - 1)) / y;
56} 56}
@@ -73,11 +73,11 @@ public:
73 constexpr AlignmentAllocator(const AlignmentAllocator<T2, Align>&) noexcept {} 73 constexpr AlignmentAllocator(const AlignmentAllocator<T2, Align>&) noexcept {}
74 74
75 [[nodiscard]] T* allocate(size_type n) { 75 [[nodiscard]] T* allocate(size_type n) {
76 return static_cast<T*>(::operator new (n * sizeof(T), std::align_val_t{Align})); 76 return static_cast<T*>(::operator new(n * sizeof(T), std::align_val_t{Align}));
77 } 77 }
78 78
79 void deallocate(T* p, size_type n) { 79 void deallocate(T* p, size_type n) {
80 ::operator delete (p, n * sizeof(T), std::align_val_t{Align}); 80 ::operator delete(p, n * sizeof(T), std::align_val_t{Align});
81 } 81 }
82 82
83 template <typename T2> 83 template <typename T2>
diff --git a/src/common/atomic_helpers.h b/src/common/atomic_helpers.h
index aef3b66a4..d997f10ba 100644
--- a/src/common/atomic_helpers.h
+++ b/src/common/atomic_helpers.h
@@ -75,7 +75,7 @@ extern "C" void AnnotateHappensAfter(const char*, int, void*);
75#if defined(AE_VCPP) || defined(AE_ICC) 75#if defined(AE_VCPP) || defined(AE_ICC)
76#define AE_FORCEINLINE __forceinline 76#define AE_FORCEINLINE __forceinline
77#elif defined(AE_GCC) 77#elif defined(AE_GCC)
78//#define AE_FORCEINLINE __attribute__((always_inline)) 78// #define AE_FORCEINLINE __attribute__((always_inline))
79#define AE_FORCEINLINE inline 79#define AE_FORCEINLINE inline
80#else 80#else
81#define AE_FORCEINLINE inline 81#define AE_FORCEINLINE inline
diff --git a/src/common/bit_util.h b/src/common/bit_util.h
index e4e6287f3..13368b439 100644
--- a/src/common/bit_util.h
+++ b/src/common/bit_util.h
@@ -45,19 +45,19 @@ template <typename T>
45} 45}
46 46
47template <typename T> 47template <typename T>
48requires std::is_unsigned_v<T> 48 requires std::is_unsigned_v<T>
49[[nodiscard]] constexpr bool IsPow2(T value) { 49[[nodiscard]] constexpr bool IsPow2(T value) {
50 return std::has_single_bit(value); 50 return std::has_single_bit(value);
51} 51}
52 52
53template <typename T> 53template <typename T>
54requires std::is_integral_v<T> 54 requires std::is_integral_v<T>
55[[nodiscard]] T NextPow2(T value) { 55[[nodiscard]] T NextPow2(T value) {
56 return static_cast<T>(1ULL << ((8U * sizeof(T)) - std::countl_zero(value - 1U))); 56 return static_cast<T>(1ULL << ((8U * sizeof(T)) - std::countl_zero(value - 1U)));
57} 57}
58 58
59template <size_t bit_index, typename T> 59template <size_t bit_index, typename T>
60requires std::is_integral_v<T> 60 requires std::is_integral_v<T>
61[[nodiscard]] constexpr bool Bit(const T value) { 61[[nodiscard]] constexpr bool Bit(const T value) {
62 static_assert(bit_index < BitSize<T>(), "bit_index must be smaller than size of T"); 62 static_assert(bit_index < BitSize<T>(), "bit_index must be smaller than size of T");
63 return ((value >> bit_index) & T(1)) == T(1); 63 return ((value >> bit_index) & T(1)) == T(1);
diff --git a/src/common/concepts.h b/src/common/concepts.h
index a9acff3e7..61df1d32a 100644
--- a/src/common/concepts.h
+++ b/src/common/concepts.h
@@ -16,9 +16,9 @@ concept IsContiguousContainer = std::contiguous_iterator<typename T::iterator>;
16// is available on all supported platforms. 16// is available on all supported platforms.
17template <typename Derived, typename Base> 17template <typename Derived, typename Base>
18concept DerivedFrom = requires { 18concept DerivedFrom = requires {
19 std::is_base_of_v<Base, Derived>; 19 std::is_base_of_v<Base, Derived>;
20 std::is_convertible_v<const volatile Derived*, const volatile Base*>; 20 std::is_convertible_v<const volatile Derived*, const volatile Base*>;
21}; 21 };
22 22
23// TODO: Replace with std::convertible_to when libc++ implements it. 23// TODO: Replace with std::convertible_to when libc++ implements it.
24template <typename From, typename To> 24template <typename From, typename To>
diff --git a/src/common/div_ceil.h b/src/common/div_ceil.h
index eebc279c2..c12477d42 100644
--- a/src/common/div_ceil.h
+++ b/src/common/div_ceil.h
@@ -10,14 +10,14 @@ namespace Common {
10 10
11/// Ceiled integer division. 11/// Ceiled integer division.
12template <typename N, typename D> 12template <typename N, typename D>
13requires std::is_integral_v<N> && std::is_unsigned_v<D> 13 requires std::is_integral_v<N> && std::is_unsigned_v<D>
14[[nodiscard]] constexpr N DivCeil(N number, D divisor) { 14[[nodiscard]] constexpr N DivCeil(N number, D divisor) {
15 return static_cast<N>((static_cast<D>(number) + divisor - 1) / divisor); 15 return static_cast<N>((static_cast<D>(number) + divisor - 1) / divisor);
16} 16}
17 17
18/// Ceiled integer division with logarithmic divisor in base 2 18/// Ceiled integer division with logarithmic divisor in base 2
19template <typename N, typename D> 19template <typename N, typename D>
20requires std::is_integral_v<N> && std::is_unsigned_v<D> 20 requires std::is_integral_v<N> && std::is_unsigned_v<D>
21[[nodiscard]] constexpr N DivCeilLog2(N value, D alignment_log2) { 21[[nodiscard]] constexpr N DivCeilLog2(N value, D alignment_log2) {
22 return static_cast<N>((static_cast<D>(value) + (D(1) << alignment_log2) - 1) >> alignment_log2); 22 return static_cast<N>((static_cast<D>(value) + (D(1) << alignment_log2) - 1) >> alignment_log2);
23} 23}
diff --git a/src/common/expected.h b/src/common/expected.h
index 6e6c86ee7..5fccfbcbd 100644
--- a/src/common/expected.h
+++ b/src/common/expected.h
@@ -64,7 +64,7 @@ struct no_init_t {
64 * Additionally, this requires E to be trivially destructible 64 * Additionally, this requires E to be trivially destructible
65 */ 65 */
66template <typename T, typename E, bool = std::is_trivially_destructible_v<T>> 66template <typename T, typename E, bool = std::is_trivially_destructible_v<T>>
67requires std::is_trivially_destructible_v<E> 67 requires std::is_trivially_destructible_v<E>
68struct expected_storage_base { 68struct expected_storage_base {
69 constexpr expected_storage_base() : m_val{T{}}, m_has_val{true} {} 69 constexpr expected_storage_base() : m_val{T{}}, m_has_val{true} {}
70 70
@@ -111,7 +111,7 @@ struct expected_storage_base {
111 * Additionally, this requires E to be trivially destructible 111 * Additionally, this requires E to be trivially destructible
112 */ 112 */
113template <typename T, typename E> 113template <typename T, typename E>
114requires std::is_trivially_destructible_v<E> 114 requires std::is_trivially_destructible_v<E>
115struct expected_storage_base<T, E, true> { 115struct expected_storage_base<T, E, true> {
116 constexpr expected_storage_base() : m_val{T{}}, m_has_val{true} {} 116 constexpr expected_storage_base() : m_val{T{}}, m_has_val{true} {}
117 117
@@ -251,7 +251,7 @@ struct expected_operations_base : expected_storage_base<T, E> {
251 * Additionally, this requires E to be trivially copy constructible 251 * Additionally, this requires E to be trivially copy constructible
252 */ 252 */
253template <typename T, typename E, bool = std::is_trivially_copy_constructible_v<T>> 253template <typename T, typename E, bool = std::is_trivially_copy_constructible_v<T>>
254requires std::is_trivially_copy_constructible_v<E> 254 requires std::is_trivially_copy_constructible_v<E>
255struct expected_copy_base : expected_operations_base<T, E> { 255struct expected_copy_base : expected_operations_base<T, E> {
256 using expected_operations_base<T, E>::expected_operations_base; 256 using expected_operations_base<T, E>::expected_operations_base;
257}; 257};
@@ -261,7 +261,7 @@ struct expected_copy_base : expected_operations_base<T, E> {
261 * Additionally, this requires E to be trivially copy constructible 261 * Additionally, this requires E to be trivially copy constructible
262 */ 262 */
263template <typename T, typename E> 263template <typename T, typename E>
264requires std::is_trivially_copy_constructible_v<E> 264 requires std::is_trivially_copy_constructible_v<E>
265struct expected_copy_base<T, E, false> : expected_operations_base<T, E> { 265struct expected_copy_base<T, E, false> : expected_operations_base<T, E> {
266 using expected_operations_base<T, E>::expected_operations_base; 266 using expected_operations_base<T, E>::expected_operations_base;
267 267
@@ -289,7 +289,7 @@ struct expected_copy_base<T, E, false> : expected_operations_base<T, E> {
289 * Additionally, this requires E to be trivially move constructible 289 * Additionally, this requires E to be trivially move constructible
290 */ 290 */
291template <typename T, typename E, bool = std::is_trivially_move_constructible_v<T>> 291template <typename T, typename E, bool = std::is_trivially_move_constructible_v<T>>
292requires std::is_trivially_move_constructible_v<E> 292 requires std::is_trivially_move_constructible_v<E>
293struct expected_move_base : expected_copy_base<T, E> { 293struct expected_move_base : expected_copy_base<T, E> {
294 using expected_copy_base<T, E>::expected_copy_base; 294 using expected_copy_base<T, E>::expected_copy_base;
295}; 295};
@@ -299,7 +299,7 @@ struct expected_move_base : expected_copy_base<T, E> {
299 * Additionally, this requires E to be trivially move constructible 299 * Additionally, this requires E to be trivially move constructible
300 */ 300 */
301template <typename T, typename E> 301template <typename T, typename E>
302requires std::is_trivially_move_constructible_v<E> 302 requires std::is_trivially_move_constructible_v<E>
303struct expected_move_base<T, E, false> : expected_copy_base<T, E> { 303struct expected_move_base<T, E, false> : expected_copy_base<T, E> {
304 using expected_copy_base<T, E>::expected_copy_base; 304 using expected_copy_base<T, E>::expected_copy_base;
305 305
@@ -330,9 +330,9 @@ template <typename T, typename E,
330 bool = std::conjunction_v<std::is_trivially_copy_assignable<T>, 330 bool = std::conjunction_v<std::is_trivially_copy_assignable<T>,
331 std::is_trivially_copy_constructible<T>, 331 std::is_trivially_copy_constructible<T>,
332 std::is_trivially_destructible<T>>> 332 std::is_trivially_destructible<T>>>
333requires std::conjunction_v<std::is_trivially_copy_assignable<E>, 333 requires std::conjunction_v<std::is_trivially_copy_assignable<E>,
334 std::is_trivially_copy_constructible<E>, 334 std::is_trivially_copy_constructible<E>,
335 std::is_trivially_destructible<E>> 335 std::is_trivially_destructible<E>>
336struct expected_copy_assign_base : expected_move_base<T, E> { 336struct expected_copy_assign_base : expected_move_base<T, E> {
337 using expected_move_base<T, E>::expected_move_base; 337 using expected_move_base<T, E>::expected_move_base;
338}; 338};
@@ -342,9 +342,9 @@ struct expected_copy_assign_base : expected_move_base<T, E> {
342 * Additionally, this requires E to be trivially copy assignable 342 * Additionally, this requires E to be trivially copy assignable
343 */ 343 */
344template <typename T, typename E> 344template <typename T, typename E>
345requires std::conjunction_v<std::is_trivially_copy_assignable<E>, 345 requires std::conjunction_v<std::is_trivially_copy_assignable<E>,
346 std::is_trivially_copy_constructible<E>, 346 std::is_trivially_copy_constructible<E>,
347 std::is_trivially_destructible<E>> 347 std::is_trivially_destructible<E>>
348struct expected_copy_assign_base<T, E, false> : expected_move_base<T, E> { 348struct expected_copy_assign_base<T, E, false> : expected_move_base<T, E> {
349 using expected_move_base<T, E>::expected_move_base; 349 using expected_move_base<T, E>::expected_move_base;
350 350
@@ -371,9 +371,9 @@ template <typename T, typename E,
371 bool = std::conjunction_v<std::is_trivially_move_assignable<T>, 371 bool = std::conjunction_v<std::is_trivially_move_assignable<T>,
372 std::is_trivially_move_constructible<T>, 372 std::is_trivially_move_constructible<T>,
373 std::is_trivially_destructible<T>>> 373 std::is_trivially_destructible<T>>>
374requires std::conjunction_v<std::is_trivially_move_assignable<E>, 374 requires std::conjunction_v<std::is_trivially_move_assignable<E>,
375 std::is_trivially_move_constructible<E>, 375 std::is_trivially_move_constructible<E>,
376 std::is_trivially_destructible<E>> 376 std::is_trivially_destructible<E>>
377struct expected_move_assign_base : expected_copy_assign_base<T, E> { 377struct expected_move_assign_base : expected_copy_assign_base<T, E> {
378 using expected_copy_assign_base<T, E>::expected_copy_assign_base; 378 using expected_copy_assign_base<T, E>::expected_copy_assign_base;
379}; 379};
@@ -383,9 +383,9 @@ struct expected_move_assign_base : expected_copy_assign_base<T, E> {
383 * Additionally, this requires E to be trivially move assignable 383 * Additionally, this requires E to be trivially move assignable
384 */ 384 */
385template <typename T, typename E> 385template <typename T, typename E>
386requires std::conjunction_v<std::is_trivially_move_assignable<E>, 386 requires std::conjunction_v<std::is_trivially_move_assignable<E>,
387 std::is_trivially_move_constructible<E>, 387 std::is_trivially_move_constructible<E>,
388 std::is_trivially_destructible<E>> 388 std::is_trivially_destructible<E>>
389struct expected_move_assign_base<T, E, false> : expected_copy_assign_base<T, E> { 389struct expected_move_assign_base<T, E, false> : expected_copy_assign_base<T, E> {
390 using expected_copy_assign_base<T, E>::expected_copy_assign_base; 390 using expected_copy_assign_base<T, E>::expected_copy_assign_base;
391 391
@@ -412,7 +412,7 @@ struct expected_move_assign_base<T, E, false> : expected_copy_assign_base<T, E>
412 */ 412 */
413template <typename T, typename E, bool EnableCopy = std::is_copy_constructible_v<T>, 413template <typename T, typename E, bool EnableCopy = std::is_copy_constructible_v<T>,
414 bool EnableMove = std::is_move_constructible_v<T>> 414 bool EnableMove = std::is_move_constructible_v<T>>
415requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>> 415 requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>>
416struct expected_delete_ctor_base { 416struct expected_delete_ctor_base {
417 expected_delete_ctor_base() = default; 417 expected_delete_ctor_base() = default;
418 expected_delete_ctor_base(const expected_delete_ctor_base&) = default; 418 expected_delete_ctor_base(const expected_delete_ctor_base&) = default;
@@ -422,7 +422,7 @@ struct expected_delete_ctor_base {
422}; 422};
423 423
424template <typename T, typename E> 424template <typename T, typename E>
425requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>> 425 requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>>
426struct expected_delete_ctor_base<T, E, true, false> { 426struct expected_delete_ctor_base<T, E, true, false> {
427 expected_delete_ctor_base() = default; 427 expected_delete_ctor_base() = default;
428 expected_delete_ctor_base(const expected_delete_ctor_base&) = default; 428 expected_delete_ctor_base(const expected_delete_ctor_base&) = default;
@@ -432,7 +432,7 @@ struct expected_delete_ctor_base<T, E, true, false> {
432}; 432};
433 433
434template <typename T, typename E> 434template <typename T, typename E>
435requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>> 435 requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>>
436struct expected_delete_ctor_base<T, E, false, true> { 436struct expected_delete_ctor_base<T, E, false, true> {
437 expected_delete_ctor_base() = default; 437 expected_delete_ctor_base() = default;
438 expected_delete_ctor_base(const expected_delete_ctor_base&) = delete; 438 expected_delete_ctor_base(const expected_delete_ctor_base&) = delete;
@@ -442,7 +442,7 @@ struct expected_delete_ctor_base<T, E, false, true> {
442}; 442};
443 443
444template <typename T, typename E> 444template <typename T, typename E>
445requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>> 445 requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>>
446struct expected_delete_ctor_base<T, E, false, false> { 446struct expected_delete_ctor_base<T, E, false, false> {
447 expected_delete_ctor_base() = default; 447 expected_delete_ctor_base() = default;
448 expected_delete_ctor_base(const expected_delete_ctor_base&) = delete; 448 expected_delete_ctor_base(const expected_delete_ctor_base&) = delete;
@@ -460,8 +460,8 @@ template <
460 typename T, typename E, 460 typename T, typename E,
461 bool EnableCopy = std::conjunction_v<std::is_copy_constructible<T>, std::is_copy_assignable<T>>, 461 bool EnableCopy = std::conjunction_v<std::is_copy_constructible<T>, std::is_copy_assignable<T>>,
462 bool EnableMove = std::conjunction_v<std::is_move_constructible<T>, std::is_move_assignable<T>>> 462 bool EnableMove = std::conjunction_v<std::is_move_constructible<T>, std::is_move_assignable<T>>>
463requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>, 463 requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>,
464 std::is_copy_assignable<E>, std::is_move_assignable<E>> 464 std::is_copy_assignable<E>, std::is_move_assignable<E>>
465struct expected_delete_assign_base { 465struct expected_delete_assign_base {
466 expected_delete_assign_base() = default; 466 expected_delete_assign_base() = default;
467 expected_delete_assign_base(const expected_delete_assign_base&) = default; 467 expected_delete_assign_base(const expected_delete_assign_base&) = default;
@@ -471,8 +471,8 @@ struct expected_delete_assign_base {
471}; 471};
472 472
473template <typename T, typename E> 473template <typename T, typename E>
474requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>, 474 requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>,
475 std::is_copy_assignable<E>, std::is_move_assignable<E>> 475 std::is_copy_assignable<E>, std::is_move_assignable<E>>
476struct expected_delete_assign_base<T, E, true, false> { 476struct expected_delete_assign_base<T, E, true, false> {
477 expected_delete_assign_base() = default; 477 expected_delete_assign_base() = default;
478 expected_delete_assign_base(const expected_delete_assign_base&) = default; 478 expected_delete_assign_base(const expected_delete_assign_base&) = default;
@@ -482,8 +482,8 @@ struct expected_delete_assign_base<T, E, true, false> {
482}; 482};
483 483
484template <typename T, typename E> 484template <typename T, typename E>
485requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>, 485 requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>,
486 std::is_copy_assignable<E>, std::is_move_assignable<E>> 486 std::is_copy_assignable<E>, std::is_move_assignable<E>>
487struct expected_delete_assign_base<T, E, false, true> { 487struct expected_delete_assign_base<T, E, false, true> {
488 expected_delete_assign_base() = default; 488 expected_delete_assign_base() = default;
489 expected_delete_assign_base(const expected_delete_assign_base&) = default; 489 expected_delete_assign_base(const expected_delete_assign_base&) = default;
@@ -493,8 +493,8 @@ struct expected_delete_assign_base<T, E, false, true> {
493}; 493};
494 494
495template <typename T, typename E> 495template <typename T, typename E>
496requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>, 496 requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>,
497 std::is_copy_assignable<E>, std::is_move_assignable<E>> 497 std::is_copy_assignable<E>, std::is_move_assignable<E>>
498struct expected_delete_assign_base<T, E, false, false> { 498struct expected_delete_assign_base<T, E, false, false> {
499 expected_delete_assign_base() = default; 499 expected_delete_assign_base() = default;
500 expected_delete_assign_base(const expected_delete_assign_base&) = default; 500 expected_delete_assign_base(const expected_delete_assign_base&) = default;
diff --git a/src/common/input.h b/src/common/input.h
index d61cd7ca8..b5748a6c8 100644
--- a/src/common/input.h
+++ b/src/common/input.h
@@ -130,6 +130,8 @@ struct ButtonStatus {
130 bool inverted{}; 130 bool inverted{};
131 // Press once to activate, press again to release 131 // Press once to activate, press again to release
132 bool toggle{}; 132 bool toggle{};
133 // Spams the button when active
134 bool turbo{};
133 // Internal lock for the toggle status 135 // Internal lock for the toggle status
134 bool locked{}; 136 bool locked{};
135}; 137};
diff --git a/src/common/intrusive_red_black_tree.h b/src/common/intrusive_red_black_tree.h
index 93046615e..5f6b34e82 100644
--- a/src/common/intrusive_red_black_tree.h
+++ b/src/common/intrusive_red_black_tree.h
@@ -242,19 +242,21 @@ public:
242 242
243template <typename T> 243template <typename T>
244concept HasRedBlackKeyType = requires { 244concept HasRedBlackKeyType = requires {
245 { std::is_same<typename T::RedBlackKeyType, void>::value } -> std::convertible_to<bool>; 245 {
246}; 246 std::is_same<typename T::RedBlackKeyType, void>::value
247 } -> std::convertible_to<bool>;
248 };
247 249
248namespace impl { 250namespace impl {
249 251
250 template <typename T, typename Default> 252template <typename T, typename Default>
251 consteval auto* GetRedBlackKeyType() { 253consteval auto* GetRedBlackKeyType() {
252 if constexpr (HasRedBlackKeyType<T>) { 254 if constexpr (HasRedBlackKeyType<T>) {
253 return static_cast<typename T::RedBlackKeyType*>(nullptr); 255 return static_cast<typename T::RedBlackKeyType*>(nullptr);
254 } else { 256 } else {
255 return static_cast<Default*>(nullptr); 257 return static_cast<Default*>(nullptr);
256 }
257 } 258 }
259}
258 260
259} // namespace impl 261} // namespace impl
260 262
diff --git a/src/common/make_unique_for_overwrite.h b/src/common/make_unique_for_overwrite.h
index c7413cf51..17f81bba4 100644
--- a/src/common/make_unique_for_overwrite.h
+++ b/src/common/make_unique_for_overwrite.h
@@ -9,17 +9,19 @@
9namespace Common { 9namespace Common {
10 10
11template <class T> 11template <class T>
12requires(!std::is_array_v<T>) std::unique_ptr<T> make_unique_for_overwrite() { 12 requires(!std::is_array_v<T>)
13std::unique_ptr<T> make_unique_for_overwrite() {
13 return std::unique_ptr<T>(new T); 14 return std::unique_ptr<T>(new T);
14} 15}
15 16
16template <class T> 17template <class T>
17requires std::is_unbounded_array_v<T> std::unique_ptr<T> make_unique_for_overwrite(std::size_t n) { 18 requires std::is_unbounded_array_v<T>
19std::unique_ptr<T> make_unique_for_overwrite(std::size_t n) {
18 return std::unique_ptr<T>(new std::remove_extent_t<T>[n]); 20 return std::unique_ptr<T>(new std::remove_extent_t<T>[n]);
19} 21}
20 22
21template <class T, class... Args> 23template <class T, class... Args>
22requires std::is_bounded_array_v<T> 24 requires std::is_bounded_array_v<T>
23void make_unique_for_overwrite(Args&&...) = delete; 25void make_unique_for_overwrite(Args&&...) = delete;
24 26
25} // namespace Common 27} // namespace Common
diff --git a/src/common/polyfill_ranges.h b/src/common/polyfill_ranges.h
index ca44bfaef..512dbcbcb 100644
--- a/src/common/polyfill_ranges.h
+++ b/src/common/polyfill_ranges.h
@@ -18,9 +18,9 @@ namespace ranges {
18 18
19template <typename T> 19template <typename T>
20concept range = requires(T& t) { 20concept range = requires(T& t) {
21 begin(t); 21 begin(t);
22 end(t); 22 end(t);
23}; 23 };
24 24
25template <typename T> 25template <typename T>
26concept input_range = range<T>; 26concept input_range = range<T>;
@@ -421,7 +421,7 @@ struct generate_fn {
421 } 421 }
422 422
423 template <typename R, std::copy_constructible F> 423 template <typename R, std::copy_constructible F>
424 requires std::invocable<F&> && ranges::output_range<R> 424 requires std::invocable<F&> && ranges::output_range<R>
425 constexpr ranges::iterator_t<R> operator()(R&& r, F gen) const { 425 constexpr ranges::iterator_t<R> operator()(R&& r, F gen) const {
426 return operator()(ranges::begin(r), ranges::end(r), std::move(gen)); 426 return operator()(ranges::begin(r), ranges::end(r), std::move(gen));
427 } 427 }
diff --git a/src/common/polyfill_thread.h b/src/common/polyfill_thread.h
index b4c94a5fc..b5ef055db 100644
--- a/src/common/polyfill_thread.h
+++ b/src/common/polyfill_thread.h
@@ -213,7 +213,7 @@ public:
213 using callback_type = Callback; 213 using callback_type = Callback;
214 214
215 template <typename C> 215 template <typename C>
216 requires constructible_from<Callback, C> 216 requires constructible_from<Callback, C>
217 explicit stop_callback(const stop_token& st, 217 explicit stop_callback(const stop_token& st,
218 C&& cb) noexcept(is_nothrow_constructible_v<Callback, C>) 218 C&& cb) noexcept(is_nothrow_constructible_v<Callback, C>)
219 : m_stop_state(st.m_stop_state) { 219 : m_stop_state(st.m_stop_state) {
@@ -222,7 +222,7 @@ public:
222 } 222 }
223 } 223 }
224 template <typename C> 224 template <typename C>
225 requires constructible_from<Callback, C> 225 requires constructible_from<Callback, C>
226 explicit stop_callback(stop_token&& st, 226 explicit stop_callback(stop_token&& st,
227 C&& cb) noexcept(is_nothrow_constructible_v<Callback, C>) 227 C&& cb) noexcept(is_nothrow_constructible_v<Callback, C>)
228 : m_stop_state(move(st.m_stop_state)) { 228 : m_stop_state(move(st.m_stop_state)) {
diff --git a/src/common/settings.h b/src/common/settings.h
index 4b4da4da2..64db66f37 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -131,7 +131,8 @@ public:
131 * @param default_val Intial value of the setting, and default value of the setting 131 * @param default_val Intial value of the setting, and default value of the setting
132 * @param name Label for the setting 132 * @param name Label for the setting
133 */ 133 */
134 explicit Setting(const Type& default_val, const std::string& name) requires(!ranged) 134 explicit Setting(const Type& default_val, const std::string& name)
135 requires(!ranged)
135 : value{default_val}, default_value{default_val}, label{name} {} 136 : value{default_val}, default_value{default_val}, label{name} {}
136 virtual ~Setting() = default; 137 virtual ~Setting() = default;
137 138
@@ -144,7 +145,8 @@ public:
144 * @param name Label for the setting 145 * @param name Label for the setting
145 */ 146 */
146 explicit Setting(const Type& default_val, const Type& min_val, const Type& max_val, 147 explicit Setting(const Type& default_val, const Type& min_val, const Type& max_val,
147 const std::string& name) requires(ranged) 148 const std::string& name)
149 requires(ranged)
148 : value{default_val}, 150 : value{default_val},
149 default_value{default_val}, maximum{max_val}, minimum{min_val}, label{name} {} 151 default_value{default_val}, maximum{max_val}, minimum{min_val}, label{name} {}
150 152
@@ -232,7 +234,8 @@ public:
232 * @param default_val Intial value of the setting, and default value of the setting 234 * @param default_val Intial value of the setting, and default value of the setting
233 * @param name Label for the setting 235 * @param name Label for the setting
234 */ 236 */
235 explicit SwitchableSetting(const Type& default_val, const std::string& name) requires(!ranged) 237 explicit SwitchableSetting(const Type& default_val, const std::string& name)
238 requires(!ranged)
236 : Setting<Type>{default_val, name} {} 239 : Setting<Type>{default_val, name} {}
237 virtual ~SwitchableSetting() = default; 240 virtual ~SwitchableSetting() = default;
238 241
@@ -245,7 +248,8 @@ public:
245 * @param name Label for the setting 248 * @param name Label for the setting
246 */ 249 */
247 explicit SwitchableSetting(const Type& default_val, const Type& min_val, const Type& max_val, 250 explicit SwitchableSetting(const Type& default_val, const Type& min_val, const Type& max_val,
248 const std::string& name) requires(ranged) 251 const std::string& name)
252 requires(ranged)
249 : Setting<Type, true>{default_val, min_val, max_val, name} {} 253 : Setting<Type, true>{default_val, min_val, max_val, name} {}
250 254
251 /** 255 /**
diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp
index b26db4796..e0b6180c5 100644
--- a/src/common/string_util.cpp
+++ b/src/common/string_util.cpp
@@ -30,7 +30,7 @@ std::string ToUpper(std::string str) {
30 return str; 30 return str;
31} 31}
32 32
33std::string StringFromBuffer(const std::vector<u8>& data) { 33std::string StringFromBuffer(std::span<const u8> data) {
34 return std::string(data.begin(), std::find(data.begin(), data.end(), '\0')); 34 return std::string(data.begin(), std::find(data.begin(), data.end(), '\0'));
35} 35}
36 36
diff --git a/src/common/string_util.h b/src/common/string_util.h
index ce18a33cf..f8aecc875 100644
--- a/src/common/string_util.h
+++ b/src/common/string_util.h
@@ -5,6 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include <cstddef> 7#include <cstddef>
8#include <span>
8#include <string> 9#include <string>
9#include <vector> 10#include <vector>
10#include "common/common_types.h" 11#include "common/common_types.h"
@@ -17,7 +18,7 @@ namespace Common {
17/// Make a string uppercase 18/// Make a string uppercase
18[[nodiscard]] std::string ToUpper(std::string str); 19[[nodiscard]] std::string ToUpper(std::string str);
19 20
20[[nodiscard]] std::string StringFromBuffer(const std::vector<u8>& data); 21[[nodiscard]] std::string StringFromBuffer(std::span<const u8> data);
21 22
22[[nodiscard]] std::string StripSpaces(const std::string& s); 23[[nodiscard]] std::string StripSpaces(const std::string& s);
23[[nodiscard]] std::string StripQuotes(const std::string& s); 24[[nodiscard]] std::string StripQuotes(const std::string& s);
diff --git a/src/common/tree.h b/src/common/tree.h
index f77859209..f4fc43de3 100644
--- a/src/common/tree.h
+++ b/src/common/tree.h
@@ -103,12 +103,12 @@ concept IsRBEntry = CheckRBEntry<T>::value;
103 103
104template <typename T> 104template <typename T>
105concept HasRBEntry = requires(T& t, const T& ct) { 105concept HasRBEntry = requires(T& t, const T& ct) {
106 { t.GetRBEntry() } -> std::same_as<RBEntry<T>&>; 106 { t.GetRBEntry() } -> std::same_as<RBEntry<T>&>;
107 { ct.GetRBEntry() } -> std::same_as<const RBEntry<T>&>; 107 { ct.GetRBEntry() } -> std::same_as<const RBEntry<T>&>;
108}; 108 };
109 109
110template <typename T> 110template <typename T>
111requires HasRBEntry<T> 111 requires HasRBEntry<T>
112class RBHead { 112class RBHead {
113private: 113private:
114 T* m_rbh_root = nullptr; 114 T* m_rbh_root = nullptr;
@@ -130,90 +130,90 @@ public:
130}; 130};
131 131
132template <typename T> 132template <typename T>
133requires HasRBEntry<T> 133 requires HasRBEntry<T>
134[[nodiscard]] constexpr RBEntry<T>& RB_ENTRY(T* t) { 134[[nodiscard]] constexpr RBEntry<T>& RB_ENTRY(T* t) {
135 return t->GetRBEntry(); 135 return t->GetRBEntry();
136} 136}
137template <typename T> 137template <typename T>
138requires HasRBEntry<T> 138 requires HasRBEntry<T>
139[[nodiscard]] constexpr const RBEntry<T>& RB_ENTRY(const T* t) { 139[[nodiscard]] constexpr const RBEntry<T>& RB_ENTRY(const T* t) {
140 return t->GetRBEntry(); 140 return t->GetRBEntry();
141} 141}
142 142
143template <typename T> 143template <typename T>
144requires HasRBEntry<T> 144 requires HasRBEntry<T>
145[[nodiscard]] constexpr T* RB_LEFT(T* t) { 145[[nodiscard]] constexpr T* RB_LEFT(T* t) {
146 return RB_ENTRY(t).Left(); 146 return RB_ENTRY(t).Left();
147} 147}
148template <typename T> 148template <typename T>
149requires HasRBEntry<T> 149 requires HasRBEntry<T>
150[[nodiscard]] constexpr const T* RB_LEFT(const T* t) { 150[[nodiscard]] constexpr const T* RB_LEFT(const T* t) {
151 return RB_ENTRY(t).Left(); 151 return RB_ENTRY(t).Left();
152} 152}
153 153
154template <typename T> 154template <typename T>
155requires HasRBEntry<T> 155 requires HasRBEntry<T>
156[[nodiscard]] constexpr T* RB_RIGHT(T* t) { 156[[nodiscard]] constexpr T* RB_RIGHT(T* t) {
157 return RB_ENTRY(t).Right(); 157 return RB_ENTRY(t).Right();
158} 158}
159template <typename T> 159template <typename T>
160requires HasRBEntry<T> 160 requires HasRBEntry<T>
161[[nodiscard]] constexpr const T* RB_RIGHT(const T* t) { 161[[nodiscard]] constexpr const T* RB_RIGHT(const T* t) {
162 return RB_ENTRY(t).Right(); 162 return RB_ENTRY(t).Right();
163} 163}
164 164
165template <typename T> 165template <typename T>
166requires HasRBEntry<T> 166 requires HasRBEntry<T>
167[[nodiscard]] constexpr T* RB_PARENT(T* t) { 167[[nodiscard]] constexpr T* RB_PARENT(T* t) {
168 return RB_ENTRY(t).Parent(); 168 return RB_ENTRY(t).Parent();
169} 169}
170template <typename T> 170template <typename T>
171requires HasRBEntry<T> 171 requires HasRBEntry<T>
172[[nodiscard]] constexpr const T* RB_PARENT(const T* t) { 172[[nodiscard]] constexpr const T* RB_PARENT(const T* t) {
173 return RB_ENTRY(t).Parent(); 173 return RB_ENTRY(t).Parent();
174} 174}
175 175
176template <typename T> 176template <typename T>
177requires HasRBEntry<T> 177 requires HasRBEntry<T>
178constexpr void RB_SET_LEFT(T* t, T* e) { 178constexpr void RB_SET_LEFT(T* t, T* e) {
179 RB_ENTRY(t).SetLeft(e); 179 RB_ENTRY(t).SetLeft(e);
180} 180}
181template <typename T> 181template <typename T>
182requires HasRBEntry<T> 182 requires HasRBEntry<T>
183constexpr void RB_SET_RIGHT(T* t, T* e) { 183constexpr void RB_SET_RIGHT(T* t, T* e) {
184 RB_ENTRY(t).SetRight(e); 184 RB_ENTRY(t).SetRight(e);
185} 185}
186template <typename T> 186template <typename T>
187requires HasRBEntry<T> 187 requires HasRBEntry<T>
188constexpr void RB_SET_PARENT(T* t, T* e) { 188constexpr void RB_SET_PARENT(T* t, T* e) {
189 RB_ENTRY(t).SetParent(e); 189 RB_ENTRY(t).SetParent(e);
190} 190}
191 191
192template <typename T> 192template <typename T>
193requires HasRBEntry<T> 193 requires HasRBEntry<T>
194[[nodiscard]] constexpr bool RB_IS_BLACK(const T* t) { 194[[nodiscard]] constexpr bool RB_IS_BLACK(const T* t) {
195 return RB_ENTRY(t).IsBlack(); 195 return RB_ENTRY(t).IsBlack();
196} 196}
197template <typename T> 197template <typename T>
198requires HasRBEntry<T> 198 requires HasRBEntry<T>
199[[nodiscard]] constexpr bool RB_IS_RED(const T* t) { 199[[nodiscard]] constexpr bool RB_IS_RED(const T* t) {
200 return RB_ENTRY(t).IsRed(); 200 return RB_ENTRY(t).IsRed();
201} 201}
202 202
203template <typename T> 203template <typename T>
204requires HasRBEntry<T> 204 requires HasRBEntry<T>
205[[nodiscard]] constexpr RBColor RB_COLOR(const T* t) { 205[[nodiscard]] constexpr RBColor RB_COLOR(const T* t) {
206 return RB_ENTRY(t).Color(); 206 return RB_ENTRY(t).Color();
207} 207}
208 208
209template <typename T> 209template <typename T>
210requires HasRBEntry<T> 210 requires HasRBEntry<T>
211constexpr void RB_SET_COLOR(T* t, RBColor c) { 211constexpr void RB_SET_COLOR(T* t, RBColor c) {
212 RB_ENTRY(t).SetColor(c); 212 RB_ENTRY(t).SetColor(c);
213} 213}
214 214
215template <typename T> 215template <typename T>
216requires HasRBEntry<T> 216 requires HasRBEntry<T>
217constexpr void RB_SET(T* elm, T* parent) { 217constexpr void RB_SET(T* elm, T* parent) {
218 auto& rb_entry = RB_ENTRY(elm); 218 auto& rb_entry = RB_ENTRY(elm);
219 rb_entry.SetParent(parent); 219 rb_entry.SetParent(parent);
@@ -223,14 +223,14 @@ constexpr void RB_SET(T* elm, T* parent) {
223} 223}
224 224
225template <typename T> 225template <typename T>
226requires HasRBEntry<T> 226 requires HasRBEntry<T>
227constexpr void RB_SET_BLACKRED(T* black, T* red) { 227constexpr void RB_SET_BLACKRED(T* black, T* red) {
228 RB_SET_COLOR(black, RBColor::RB_BLACK); 228 RB_SET_COLOR(black, RBColor::RB_BLACK);
229 RB_SET_COLOR(red, RBColor::RB_RED); 229 RB_SET_COLOR(red, RBColor::RB_RED);
230} 230}
231 231
232template <typename T> 232template <typename T>
233requires HasRBEntry<T> 233 requires HasRBEntry<T>
234constexpr void RB_ROTATE_LEFT(RBHead<T>& head, T* elm, T*& tmp) { 234constexpr void RB_ROTATE_LEFT(RBHead<T>& head, T* elm, T*& tmp) {
235 tmp = RB_RIGHT(elm); 235 tmp = RB_RIGHT(elm);
236 if (RB_SET_RIGHT(elm, RB_LEFT(tmp)); RB_RIGHT(elm) != nullptr) { 236 if (RB_SET_RIGHT(elm, RB_LEFT(tmp)); RB_RIGHT(elm) != nullptr) {
@@ -252,7 +252,7 @@ constexpr void RB_ROTATE_LEFT(RBHead<T>& head, T* elm, T*& tmp) {
252} 252}
253 253
254template <typename T> 254template <typename T>
255requires HasRBEntry<T> 255 requires HasRBEntry<T>
256constexpr void RB_ROTATE_RIGHT(RBHead<T>& head, T* elm, T*& tmp) { 256constexpr void RB_ROTATE_RIGHT(RBHead<T>& head, T* elm, T*& tmp) {
257 tmp = RB_LEFT(elm); 257 tmp = RB_LEFT(elm);
258 if (RB_SET_LEFT(elm, RB_RIGHT(tmp)); RB_LEFT(elm) != nullptr) { 258 if (RB_SET_LEFT(elm, RB_RIGHT(tmp)); RB_LEFT(elm) != nullptr) {
@@ -274,7 +274,7 @@ constexpr void RB_ROTATE_RIGHT(RBHead<T>& head, T* elm, T*& tmp) {
274} 274}
275 275
276template <typename T> 276template <typename T>
277requires HasRBEntry<T> 277 requires HasRBEntry<T>
278constexpr void RB_REMOVE_COLOR(RBHead<T>& head, T* parent, T* elm) { 278constexpr void RB_REMOVE_COLOR(RBHead<T>& head, T* parent, T* elm) {
279 T* tmp; 279 T* tmp;
280 while ((elm == nullptr || RB_IS_BLACK(elm)) && elm != head.Root()) { 280 while ((elm == nullptr || RB_IS_BLACK(elm)) && elm != head.Root()) {
@@ -358,7 +358,7 @@ constexpr void RB_REMOVE_COLOR(RBHead<T>& head, T* parent, T* elm) {
358} 358}
359 359
360template <typename T> 360template <typename T>
361requires HasRBEntry<T> 361 requires HasRBEntry<T>
362constexpr T* RB_REMOVE(RBHead<T>& head, T* elm) { 362constexpr T* RB_REMOVE(RBHead<T>& head, T* elm) {
363 T* child = nullptr; 363 T* child = nullptr;
364 T* parent = nullptr; 364 T* parent = nullptr;
@@ -451,7 +451,7 @@ constexpr T* RB_REMOVE(RBHead<T>& head, T* elm) {
451} 451}
452 452
453template <typename T> 453template <typename T>
454requires HasRBEntry<T> 454 requires HasRBEntry<T>
455constexpr void RB_INSERT_COLOR(RBHead<T>& head, T* elm) { 455constexpr void RB_INSERT_COLOR(RBHead<T>& head, T* elm) {
456 T *parent = nullptr, *tmp = nullptr; 456 T *parent = nullptr, *tmp = nullptr;
457 while ((parent = RB_PARENT(elm)) != nullptr && RB_IS_RED(parent)) { 457 while ((parent = RB_PARENT(elm)) != nullptr && RB_IS_RED(parent)) {
@@ -499,7 +499,7 @@ constexpr void RB_INSERT_COLOR(RBHead<T>& head, T* elm) {
499} 499}
500 500
501template <typename T, typename Compare> 501template <typename T, typename Compare>
502requires HasRBEntry<T> 502 requires HasRBEntry<T>
503constexpr T* RB_INSERT(RBHead<T>& head, T* elm, Compare cmp) { 503constexpr T* RB_INSERT(RBHead<T>& head, T* elm, Compare cmp) {
504 T* parent = nullptr; 504 T* parent = nullptr;
505 T* tmp = head.Root(); 505 T* tmp = head.Root();
@@ -534,7 +534,7 @@ constexpr T* RB_INSERT(RBHead<T>& head, T* elm, Compare cmp) {
534} 534}
535 535
536template <typename T, typename Compare> 536template <typename T, typename Compare>
537requires HasRBEntry<T> 537 requires HasRBEntry<T>
538constexpr T* RB_FIND(RBHead<T>& head, T* elm, Compare cmp) { 538constexpr T* RB_FIND(RBHead<T>& head, T* elm, Compare cmp) {
539 T* tmp = head.Root(); 539 T* tmp = head.Root();
540 540
@@ -553,7 +553,7 @@ constexpr T* RB_FIND(RBHead<T>& head, T* elm, Compare cmp) {
553} 553}
554 554
555template <typename T, typename Compare> 555template <typename T, typename Compare>
556requires HasRBEntry<T> 556 requires HasRBEntry<T>
557constexpr T* RB_NFIND(RBHead<T>& head, T* elm, Compare cmp) { 557constexpr T* RB_NFIND(RBHead<T>& head, T* elm, Compare cmp) {
558 T* tmp = head.Root(); 558 T* tmp = head.Root();
559 T* res = nullptr; 559 T* res = nullptr;
@@ -574,7 +574,7 @@ constexpr T* RB_NFIND(RBHead<T>& head, T* elm, Compare cmp) {
574} 574}
575 575
576template <typename T, typename U, typename Compare> 576template <typename T, typename U, typename Compare>
577requires HasRBEntry<T> 577 requires HasRBEntry<T>
578constexpr T* RB_FIND_KEY(RBHead<T>& head, const U& key, Compare cmp) { 578constexpr T* RB_FIND_KEY(RBHead<T>& head, const U& key, Compare cmp) {
579 T* tmp = head.Root(); 579 T* tmp = head.Root();
580 580
@@ -593,7 +593,7 @@ constexpr T* RB_FIND_KEY(RBHead<T>& head, const U& key, Compare cmp) {
593} 593}
594 594
595template <typename T, typename U, typename Compare> 595template <typename T, typename U, typename Compare>
596requires HasRBEntry<T> 596 requires HasRBEntry<T>
597constexpr T* RB_NFIND_KEY(RBHead<T>& head, const U& key, Compare cmp) { 597constexpr T* RB_NFIND_KEY(RBHead<T>& head, const U& key, Compare cmp) {
598 T* tmp = head.Root(); 598 T* tmp = head.Root();
599 T* res = nullptr; 599 T* res = nullptr;
@@ -614,7 +614,7 @@ constexpr T* RB_NFIND_KEY(RBHead<T>& head, const U& key, Compare cmp) {
614} 614}
615 615
616template <typename T, typename Compare> 616template <typename T, typename Compare>
617requires HasRBEntry<T> 617 requires HasRBEntry<T>
618constexpr T* RB_FIND_EXISTING(RBHead<T>& head, T* elm, Compare cmp) { 618constexpr T* RB_FIND_EXISTING(RBHead<T>& head, T* elm, Compare cmp) {
619 T* tmp = head.Root(); 619 T* tmp = head.Root();
620 620
@@ -631,7 +631,7 @@ constexpr T* RB_FIND_EXISTING(RBHead<T>& head, T* elm, Compare cmp) {
631} 631}
632 632
633template <typename T, typename U, typename Compare> 633template <typename T, typename U, typename Compare>
634requires HasRBEntry<T> 634 requires HasRBEntry<T>
635constexpr T* RB_FIND_EXISTING_KEY(RBHead<T>& head, const U& key, Compare cmp) { 635constexpr T* RB_FIND_EXISTING_KEY(RBHead<T>& head, const U& key, Compare cmp) {
636 T* tmp = head.Root(); 636 T* tmp = head.Root();
637 637
@@ -648,7 +648,7 @@ constexpr T* RB_FIND_EXISTING_KEY(RBHead<T>& head, const U& key, Compare cmp) {
648} 648}
649 649
650template <typename T> 650template <typename T>
651requires HasRBEntry<T> 651 requires HasRBEntry<T>
652constexpr T* RB_NEXT(T* elm) { 652constexpr T* RB_NEXT(T* elm) {
653 if (RB_RIGHT(elm)) { 653 if (RB_RIGHT(elm)) {
654 elm = RB_RIGHT(elm); 654 elm = RB_RIGHT(elm);
@@ -669,7 +669,7 @@ constexpr T* RB_NEXT(T* elm) {
669} 669}
670 670
671template <typename T> 671template <typename T>
672requires HasRBEntry<T> 672 requires HasRBEntry<T>
673constexpr T* RB_PREV(T* elm) { 673constexpr T* RB_PREV(T* elm) {
674 if (RB_LEFT(elm)) { 674 if (RB_LEFT(elm)) {
675 elm = RB_LEFT(elm); 675 elm = RB_LEFT(elm);
@@ -690,7 +690,7 @@ constexpr T* RB_PREV(T* elm) {
690} 690}
691 691
692template <typename T> 692template <typename T>
693requires HasRBEntry<T> 693 requires HasRBEntry<T>
694constexpr T* RB_MIN(RBHead<T>& head) { 694constexpr T* RB_MIN(RBHead<T>& head) {
695 T* tmp = head.Root(); 695 T* tmp = head.Root();
696 T* parent = nullptr; 696 T* parent = nullptr;
@@ -704,7 +704,7 @@ constexpr T* RB_MIN(RBHead<T>& head) {
704} 704}
705 705
706template <typename T> 706template <typename T>
707requires HasRBEntry<T> 707 requires HasRBEntry<T>
708constexpr T* RB_MAX(RBHead<T>& head) { 708constexpr T* RB_MAX(RBHead<T>& head) {
709 T* tmp = head.Root(); 709 T* tmp = head.Root();
710 T* parent = nullptr; 710 T* parent = nullptr;
diff --git a/src/common/vector_math.h b/src/common/vector_math.h
index e62eeea2e..0e2095c45 100644
--- a/src/common/vector_math.h
+++ b/src/common/vector_math.h
@@ -348,9 +348,7 @@ public:
348// _DEFINE_SWIZZLER2 defines a single such function, DEFINE_SWIZZLER2 defines all of them for all 348// _DEFINE_SWIZZLER2 defines a single such function, DEFINE_SWIZZLER2 defines all of them for all
349// component names (x<->r) and permutations (xy<->yx) 349// component names (x<->r) and permutations (xy<->yx)
350#define _DEFINE_SWIZZLER2(a, b, name) \ 350#define _DEFINE_SWIZZLER2(a, b, name) \
351 [[nodiscard]] constexpr Vec2<T> name() const { \ 351 [[nodiscard]] constexpr Vec2<T> name() const { return Vec2<T>(a, b); }
352 return Vec2<T>(a, b); \
353 }
354#define DEFINE_SWIZZLER2(a, b, a2, b2, a3, b3, a4, b4) \ 352#define DEFINE_SWIZZLER2(a, b, a2, b2, a3, b3, a4, b4) \
355 _DEFINE_SWIZZLER2(a, b, a##b); \ 353 _DEFINE_SWIZZLER2(a, b, a##b); \
356 _DEFINE_SWIZZLER2(a, b, a2##b2); \ 354 _DEFINE_SWIZZLER2(a, b, a2##b2); \
@@ -543,9 +541,7 @@ public:
543// DEFINE_SWIZZLER2_COMP2 defines two component functions for all component names (x<->r) and 541// DEFINE_SWIZZLER2_COMP2 defines two component functions for all component names (x<->r) and
544// permutations (xy<->yx) 542// permutations (xy<->yx)
545#define _DEFINE_SWIZZLER2(a, b, name) \ 543#define _DEFINE_SWIZZLER2(a, b, name) \
546 [[nodiscard]] constexpr Vec2<T> name() const { \ 544 [[nodiscard]] constexpr Vec2<T> name() const { return Vec2<T>(a, b); }
547 return Vec2<T>(a, b); \
548 }
549#define DEFINE_SWIZZLER2_COMP1(a, a2) \ 545#define DEFINE_SWIZZLER2_COMP1(a, a2) \
550 _DEFINE_SWIZZLER2(a, a, a##a); \ 546 _DEFINE_SWIZZLER2(a, a, a##a); \
551 _DEFINE_SWIZZLER2(a, a, a2##a2) 547 _DEFINE_SWIZZLER2(a, a, a2##a2)
@@ -570,9 +566,7 @@ public:
570#undef _DEFINE_SWIZZLER2 566#undef _DEFINE_SWIZZLER2
571 567
572#define _DEFINE_SWIZZLER3(a, b, c, name) \ 568#define _DEFINE_SWIZZLER3(a, b, c, name) \
573 [[nodiscard]] constexpr Vec3<T> name() const { \ 569 [[nodiscard]] constexpr Vec3<T> name() const { return Vec3<T>(a, b, c); }
574 return Vec3<T>(a, b, c); \
575 }
576#define DEFINE_SWIZZLER3_COMP1(a, a2) \ 570#define DEFINE_SWIZZLER3_COMP1(a, a2) \
577 _DEFINE_SWIZZLER3(a, a, a, a##a##a); \ 571 _DEFINE_SWIZZLER3(a, a, a, a##a##a); \
578 _DEFINE_SWIZZLER3(a, a, a, a2##a2##a2) 572 _DEFINE_SWIZZLER3(a, a, a, a2##a2##a2)
@@ -641,8 +635,8 @@ template <typename T>
641 635
642// linear interpolation via float: 0.0=begin, 1.0=end 636// linear interpolation via float: 0.0=begin, 1.0=end
643template <typename X> 637template <typename X>
644[[nodiscard]] constexpr decltype(X{} * float{} + X{} * float{}) 638[[nodiscard]] constexpr decltype(X{} * float{} + X{} * float{}) Lerp(const X& begin, const X& end,
645 Lerp(const X& begin, const X& end, const float t) { 639 const float t) {
646 return begin * (1.f - t) + end * t; 640 return begin * (1.f - t) + end * t;
647} 641}
648 642
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 5afdeb5ff..3eee1cfbe 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -182,6 +182,8 @@ add_library(core STATIC
182 hle/kernel/k_auto_object_container.cpp 182 hle/kernel/k_auto_object_container.cpp
183 hle/kernel/k_auto_object_container.h 183 hle/kernel/k_auto_object_container.h
184 hle/kernel/k_affinity_mask.h 184 hle/kernel/k_affinity_mask.h
185 hle/kernel/k_capabilities.cpp
186 hle/kernel/k_capabilities.h
185 hle/kernel/k_class_token.cpp 187 hle/kernel/k_class_token.cpp
186 hle/kernel/k_class_token.h 188 hle/kernel/k_class_token.h
187 hle/kernel/k_client_port.cpp 189 hle/kernel/k_client_port.cpp
diff --git a/src/core/hardware_properties.h b/src/core/hardware_properties.h
index 13cbdb734..45567b840 100644
--- a/src/core/hardware_properties.h
+++ b/src/core/hardware_properties.h
@@ -25,6 +25,26 @@ constexpr std::array<s32, Common::BitSize<u64>()> VirtualToPhysicalCoreMap{
25 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 25 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,
26}; 26};
27 27
28static constexpr inline size_t NumVirtualCores = Common::BitSize<u64>();
29
30static constexpr inline u64 VirtualCoreMask = [] {
31 u64 mask = 0;
32 for (size_t i = 0; i < NumVirtualCores; ++i) {
33 mask |= (UINT64_C(1) << i);
34 }
35 return mask;
36}();
37
38static constexpr inline u64 ConvertVirtualCoreMaskToPhysical(u64 v_core_mask) {
39 u64 p_core_mask = 0;
40 while (v_core_mask != 0) {
41 const u64 next = std::countr_zero(v_core_mask);
42 v_core_mask &= ~(static_cast<u64>(1) << next);
43 p_core_mask |= (static_cast<u64>(1) << VirtualToPhysicalCoreMap[next]);
44 }
45 return p_core_mask;
46}
47
28// Cortex-A57 supports 4 memory watchpoints 48// Cortex-A57 supports 4 memory watchpoints
29constexpr u64 NUM_WATCHPOINTS = 4; 49constexpr u64 NUM_WATCHPOINTS = 4;
30 50
diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp
index 0e06468da..631aa6ad2 100644
--- a/src/core/hid/emulated_controller.cpp
+++ b/src/core/hid/emulated_controller.cpp
@@ -12,6 +12,7 @@
12namespace Core::HID { 12namespace Core::HID {
13constexpr s32 HID_JOYSTICK_MAX = 0x7fff; 13constexpr s32 HID_JOYSTICK_MAX = 0x7fff;
14constexpr s32 HID_TRIGGER_MAX = 0x7fff; 14constexpr s32 HID_TRIGGER_MAX = 0x7fff;
15constexpr u32 TURBO_BUTTON_DELAY = 4;
15// Use a common UUID for TAS and Virtual Gamepad 16// Use a common UUID for TAS and Virtual Gamepad
16constexpr Common::UUID TAS_UUID = 17constexpr Common::UUID TAS_UUID =
17 Common::UUID{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xA5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}; 18 Common::UUID{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xA5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
@@ -447,6 +448,7 @@ void EmulatedController::ReloadInput() {
447 }, 448 },
448 }); 449 });
449 } 450 }
451 turbo_button_state = 0;
450} 452}
451 453
452void EmulatedController::UnloadInput() { 454void EmulatedController::UnloadInput() {
@@ -687,6 +689,7 @@ void EmulatedController::SetButton(const Common::Input::CallbackStatus& callback
687 } 689 }
688 690
689 current_status.toggle = new_status.toggle; 691 current_status.toggle = new_status.toggle;
692 current_status.turbo = new_status.turbo;
690 current_status.uuid = uuid; 693 current_status.uuid = uuid;
691 694
692 // Update button status with current 695 // Update button status with current
@@ -1548,7 +1551,7 @@ NpadButtonState EmulatedController::GetNpadButtons() const {
1548 if (is_configuring) { 1551 if (is_configuring) {
1549 return {}; 1552 return {};
1550 } 1553 }
1551 return controller.npad_button_state; 1554 return {controller.npad_button_state.raw & GetTurboButtonMask()};
1552} 1555}
1553 1556
1554DebugPadButton EmulatedController::GetDebugPadButtons() const { 1557DebugPadButton EmulatedController::GetDebugPadButtons() const {
@@ -1656,4 +1659,74 @@ void EmulatedController::DeleteCallback(int key) {
1656 } 1659 }
1657 callback_list.erase(iterator); 1660 callback_list.erase(iterator);
1658} 1661}
1662
1663void EmulatedController::TurboButtonUpdate() {
1664 turbo_button_state = (turbo_button_state + 1) % (TURBO_BUTTON_DELAY * 2);
1665}
1666
1667NpadButton EmulatedController::GetTurboButtonMask() const {
1668 // Apply no mask when disabled
1669 if (turbo_button_state < TURBO_BUTTON_DELAY) {
1670 return {NpadButton::All};
1671 }
1672
1673 NpadButtonState button_mask{};
1674 for (std::size_t index = 0; index < controller.button_values.size(); ++index) {
1675 if (!controller.button_values[index].turbo) {
1676 continue;
1677 }
1678
1679 switch (index) {
1680 case Settings::NativeButton::A:
1681 button_mask.a.Assign(1);
1682 break;
1683 case Settings::NativeButton::B:
1684 button_mask.b.Assign(1);
1685 break;
1686 case Settings::NativeButton::X:
1687 button_mask.x.Assign(1);
1688 break;
1689 case Settings::NativeButton::Y:
1690 button_mask.y.Assign(1);
1691 break;
1692 case Settings::NativeButton::L:
1693 button_mask.l.Assign(1);
1694 break;
1695 case Settings::NativeButton::R:
1696 button_mask.r.Assign(1);
1697 break;
1698 case Settings::NativeButton::ZL:
1699 button_mask.zl.Assign(1);
1700 break;
1701 case Settings::NativeButton::ZR:
1702 button_mask.zr.Assign(1);
1703 break;
1704 case Settings::NativeButton::DLeft:
1705 button_mask.left.Assign(1);
1706 break;
1707 case Settings::NativeButton::DUp:
1708 button_mask.up.Assign(1);
1709 break;
1710 case Settings::NativeButton::DRight:
1711 button_mask.right.Assign(1);
1712 break;
1713 case Settings::NativeButton::DDown:
1714 button_mask.down.Assign(1);
1715 break;
1716 case Settings::NativeButton::SL:
1717 button_mask.left_sl.Assign(1);
1718 button_mask.right_sl.Assign(1);
1719 break;
1720 case Settings::NativeButton::SR:
1721 button_mask.left_sr.Assign(1);
1722 button_mask.right_sr.Assign(1);
1723 break;
1724 default:
1725 break;
1726 }
1727 }
1728
1729 return static_cast<NpadButton>(~button_mask.raw);
1730}
1731
1659} // namespace Core::HID 1732} // namespace Core::HID
diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h
index 3ac77b2b5..b02bf35c4 100644
--- a/src/core/hid/emulated_controller.h
+++ b/src/core/hid/emulated_controller.h
@@ -411,6 +411,9 @@ public:
411 */ 411 */
412 void DeleteCallback(int key); 412 void DeleteCallback(int key);
413 413
414 /// Swaps the state of the turbo buttons
415 void TurboButtonUpdate();
416
414private: 417private:
415 /// creates input devices from params 418 /// creates input devices from params
416 void LoadDevices(); 419 void LoadDevices();
@@ -511,6 +514,8 @@ private:
511 */ 514 */
512 void TriggerOnChange(ControllerTriggerType type, bool is_service_update); 515 void TriggerOnChange(ControllerTriggerType type, bool is_service_update);
513 516
517 NpadButton GetTurboButtonMask() const;
518
514 const NpadIdType npad_id_type; 519 const NpadIdType npad_id_type;
515 NpadStyleIndex npad_type{NpadStyleIndex::None}; 520 NpadStyleIndex npad_type{NpadStyleIndex::None};
516 NpadStyleIndex original_npad_type{NpadStyleIndex::None}; 521 NpadStyleIndex original_npad_type{NpadStyleIndex::None};
@@ -520,6 +525,7 @@ private:
520 bool system_buttons_enabled{true}; 525 bool system_buttons_enabled{true};
521 f32 motion_sensitivity{0.01f}; 526 f32 motion_sensitivity{0.01f};
522 bool force_update_motion{false}; 527 bool force_update_motion{false};
528 u32 turbo_button_state{0};
523 529
524 // Temporary values to avoid doing changes while the controller is in configuring mode 530 // Temporary values to avoid doing changes while the controller is in configuring mode
525 NpadStyleIndex tmp_npad_type{NpadStyleIndex::None}; 531 NpadStyleIndex tmp_npad_type{NpadStyleIndex::None};
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index 738b6d0f1..494151eef 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -11,6 +11,7 @@
11#include "common/common_funcs.h" 11#include "common/common_funcs.h"
12#include "common/common_types.h" 12#include "common/common_types.h"
13#include "common/logging/log.h" 13#include "common/logging/log.h"
14#include "common/scratch_buffer.h"
14#include "core/hle/ipc_helpers.h" 15#include "core/hle/ipc_helpers.h"
15#include "core/hle/kernel/hle_ipc.h" 16#include "core/hle/kernel/hle_ipc.h"
16#include "core/hle/kernel/k_auto_object.h" 17#include "core/hle/kernel/k_auto_object.h"
@@ -325,7 +326,7 @@ Result HLERequestContext::WriteToOutgoingCommandBuffer(KThread& requesting_threa
325 return ResultSuccess; 326 return ResultSuccess;
326} 327}
327 328
328std::vector<u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) const { 329std::vector<u8> HLERequestContext::ReadBufferCopy(std::size_t buffer_index) const {
329 const bool is_buffer_a{BufferDescriptorA().size() > buffer_index && 330 const bool is_buffer_a{BufferDescriptorA().size() > buffer_index &&
330 BufferDescriptorA()[buffer_index].Size()}; 331 BufferDescriptorA()[buffer_index].Size()};
331 if (is_buffer_a) { 332 if (is_buffer_a) {
@@ -345,6 +346,33 @@ std::vector<u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) const {
345 } 346 }
346} 347}
347 348
349std::span<const u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) const {
350 static thread_local std::array<Common::ScratchBuffer<u8>, 2> read_buffer_a;
351 static thread_local std::array<Common::ScratchBuffer<u8>, 2> read_buffer_x;
352
353 const bool is_buffer_a{BufferDescriptorA().size() > buffer_index &&
354 BufferDescriptorA()[buffer_index].Size()};
355 if (is_buffer_a) {
356 ASSERT_OR_EXECUTE_MSG(
357 BufferDescriptorA().size() > buffer_index, { return {}; },
358 "BufferDescriptorA invalid buffer_index {}", buffer_index);
359 auto& read_buffer = read_buffer_a[buffer_index];
360 read_buffer.resize_destructive(BufferDescriptorA()[buffer_index].Size());
361 memory.ReadBlock(BufferDescriptorA()[buffer_index].Address(), read_buffer.data(),
362 read_buffer.size());
363 return read_buffer;
364 } else {
365 ASSERT_OR_EXECUTE_MSG(
366 BufferDescriptorX().size() > buffer_index, { return {}; },
367 "BufferDescriptorX invalid buffer_index {}", buffer_index);
368 auto& read_buffer = read_buffer_x[buffer_index];
369 read_buffer.resize_destructive(BufferDescriptorX()[buffer_index].Size());
370 memory.ReadBlock(BufferDescriptorX()[buffer_index].Address(), read_buffer.data(),
371 read_buffer.size());
372 return read_buffer;
373 }
374}
375
348std::size_t HLERequestContext::WriteBuffer(const void* buffer, std::size_t size, 376std::size_t HLERequestContext::WriteBuffer(const void* buffer, std::size_t size,
349 std::size_t buffer_index) const { 377 std::size_t buffer_index) const {
350 if (size == 0) { 378 if (size == 0) {
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h
index e252b5f4b..5bf4f171b 100644
--- a/src/core/hle/kernel/hle_ipc.h
+++ b/src/core/hle/kernel/hle_ipc.h
@@ -7,6 +7,7 @@
7#include <functional> 7#include <functional>
8#include <memory> 8#include <memory>
9#include <optional> 9#include <optional>
10#include <span>
10#include <string> 11#include <string>
11#include <type_traits> 12#include <type_traits>
12#include <vector> 13#include <vector>
@@ -270,8 +271,11 @@ public:
270 return domain_message_header.has_value(); 271 return domain_message_header.has_value();
271 } 272 }
272 273
273 /// Helper function to read a buffer using the appropriate buffer descriptor 274 /// Helper function to get a span of a buffer using the appropriate buffer descriptor
274 [[nodiscard]] std::vector<u8> ReadBuffer(std::size_t buffer_index = 0) const; 275 [[nodiscard]] std::span<const u8> ReadBuffer(std::size_t buffer_index = 0) const;
276
277 /// Helper function to read a copy of a buffer using the appropriate buffer descriptor
278 [[nodiscard]] std::vector<u8> ReadBufferCopy(std::size_t buffer_index = 0) const;
275 279
276 /// Helper function to write a buffer using the appropriate buffer descriptor 280 /// Helper function to write a buffer using the appropriate buffer descriptor
277 std::size_t WriteBuffer(const void* buffer, std::size_t size, 281 std::size_t WriteBuffer(const void* buffer, std::size_t size,
diff --git a/src/core/hle/kernel/k_auto_object.h b/src/core/hle/kernel/k_auto_object.h
index 2827763d5..e8118c2b8 100644
--- a/src/core/hle/kernel/k_auto_object.h
+++ b/src/core/hle/kernel/k_auto_object.h
@@ -24,9 +24,7 @@ private:
24 friend class ::Kernel::KClassTokenGenerator; \ 24 friend class ::Kernel::KClassTokenGenerator; \
25 static constexpr inline auto ObjectType = ::Kernel::KClassTokenGenerator::ObjectType::CLASS; \ 25 static constexpr inline auto ObjectType = ::Kernel::KClassTokenGenerator::ObjectType::CLASS; \
26 static constexpr inline const char* const TypeName = #CLASS; \ 26 static constexpr inline const char* const TypeName = #CLASS; \
27 static constexpr inline ClassTokenType ClassToken() { \ 27 static constexpr inline ClassTokenType ClassToken() { return ::Kernel::ClassToken<CLASS>; } \
28 return ::Kernel::ClassToken<CLASS>; \
29 } \
30 \ 28 \
31public: \ 29public: \
32 YUZU_NON_COPYABLE(CLASS); \ 30 YUZU_NON_COPYABLE(CLASS); \
@@ -37,15 +35,9 @@ public:
37 constexpr ClassTokenType Token = ClassToken(); \ 35 constexpr ClassTokenType Token = ClassToken(); \
38 return TypeObj(TypeName, Token); \ 36 return TypeObj(TypeName, Token); \
39 } \ 37 } \
40 static constexpr const char* GetStaticTypeName() { \ 38 static constexpr const char* GetStaticTypeName() { return TypeName; } \
41 return TypeName; \ 39 virtual TypeObj GetTypeObj() ATTRIBUTE { return GetStaticTypeObj(); } \
42 } \ 40 virtual const char* GetTypeName() ATTRIBUTE { return GetStaticTypeName(); } \
43 virtual TypeObj GetTypeObj() ATTRIBUTE { \
44 return GetStaticTypeObj(); \
45 } \
46 virtual const char* GetTypeName() ATTRIBUTE { \
47 return GetStaticTypeName(); \
48 } \
49 \ 41 \
50private: \ 42private: \
51 constexpr bool operator!=(const TypeObj& rhs) 43 constexpr bool operator!=(const TypeObj& rhs)
@@ -245,8 +237,8 @@ public:
245 } 237 }
246 238
247 template <typename U> 239 template <typename U>
248 requires(std::derived_from<T, U> || 240 requires(std::derived_from<T, U> || std::derived_from<U, T>)
249 std::derived_from<U, T>) constexpr KScopedAutoObject(KScopedAutoObject<U>&& rhs) { 241 constexpr KScopedAutoObject(KScopedAutoObject<U>&& rhs) {
250 if constexpr (std::derived_from<U, T>) { 242 if constexpr (std::derived_from<U, T>) {
251 // Upcast. 243 // Upcast.
252 m_obj = rhs.m_obj; 244 m_obj = rhs.m_obj;
diff --git a/src/core/hle/kernel/k_capabilities.cpp b/src/core/hle/kernel/k_capabilities.cpp
new file mode 100644
index 000000000..64f1d7371
--- /dev/null
+++ b/src/core/hle/kernel/k_capabilities.cpp
@@ -0,0 +1,358 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hardware_properties.h"
5#include "core/hle/kernel/k_capabilities.h"
6#include "core/hle/kernel/k_memory_layout.h"
7#include "core/hle/kernel/k_page_table.h"
8#include "core/hle/kernel/kernel.h"
9#include "core/hle/kernel/svc_results.h"
10#include "core/hle/kernel/svc_version.h"
11
12namespace Kernel {
13
14Result KCapabilities::InitializeForKIP(std::span<const u32> kern_caps, KPageTable* page_table) {
15 // We're initializing an initial process.
16 m_svc_access_flags.reset();
17 m_irq_access_flags.reset();
18 m_debug_capabilities = 0;
19 m_handle_table_size = 0;
20 m_intended_kernel_version = 0;
21 m_program_type = 0;
22
23 // Initial processes may run on all cores.
24 constexpr u64 VirtMask = Core::Hardware::VirtualCoreMask;
25 constexpr u64 PhysMask = Core::Hardware::ConvertVirtualCoreMaskToPhysical(VirtMask);
26
27 m_core_mask = VirtMask;
28 m_phys_core_mask = PhysMask;
29
30 // Initial processes may use any user priority they like.
31 m_priority_mask = ~0xFULL;
32
33 // Here, Nintendo sets the kernel version to the current kernel version.
34 // We will follow suit and set the version to the highest supported kernel version.
35 KernelVersion intended_kernel_version{};
36 intended_kernel_version.major_version.Assign(Svc::SupportedKernelMajorVersion);
37 intended_kernel_version.minor_version.Assign(Svc::SupportedKernelMinorVersion);
38 m_intended_kernel_version = intended_kernel_version.raw;
39
40 // Parse the capabilities array.
41 R_RETURN(this->SetCapabilities(kern_caps, page_table));
42}
43
44Result KCapabilities::InitializeForUser(std::span<const u32> user_caps, KPageTable* page_table) {
45 // We're initializing a user process.
46 m_svc_access_flags.reset();
47 m_irq_access_flags.reset();
48 m_debug_capabilities = 0;
49 m_handle_table_size = 0;
50 m_intended_kernel_version = 0;
51 m_program_type = 0;
52
53 // User processes must specify what cores/priorities they can use.
54 m_core_mask = 0;
55 m_priority_mask = 0;
56
57 // Parse the user capabilities array.
58 R_RETURN(this->SetCapabilities(user_caps, page_table));
59}
60
61Result KCapabilities::SetCorePriorityCapability(const u32 cap) {
62 // We can't set core/priority if we've already set them.
63 R_UNLESS(m_core_mask == 0, ResultInvalidArgument);
64 R_UNLESS(m_priority_mask == 0, ResultInvalidArgument);
65
66 // Validate the core/priority.
67 CorePriority pack{cap};
68 const u32 min_core = pack.minimum_core_id;
69 const u32 max_core = pack.maximum_core_id;
70 const u32 max_prio = pack.lowest_thread_priority;
71 const u32 min_prio = pack.highest_thread_priority;
72
73 R_UNLESS(min_core <= max_core, ResultInvalidCombination);
74 R_UNLESS(min_prio <= max_prio, ResultInvalidCombination);
75 R_UNLESS(max_core < Core::Hardware::NumVirtualCores, ResultInvalidCoreId);
76
77 ASSERT(max_prio < Common::BitSize<u64>());
78
79 // Set core mask.
80 for (auto core_id = min_core; core_id <= max_core; core_id++) {
81 m_core_mask |= (1ULL << core_id);
82 }
83 ASSERT((m_core_mask & Core::Hardware::VirtualCoreMask) == m_core_mask);
84
85 // Set physical core mask.
86 m_phys_core_mask = Core::Hardware::ConvertVirtualCoreMaskToPhysical(m_core_mask);
87
88 // Set priority mask.
89 for (auto prio = min_prio; prio <= max_prio; prio++) {
90 m_priority_mask |= (1ULL << prio);
91 }
92
93 // We must have some core/priority we can use.
94 R_UNLESS(m_core_mask != 0, ResultInvalidArgument);
95 R_UNLESS(m_priority_mask != 0, ResultInvalidArgument);
96
97 // Processes must not have access to kernel thread priorities.
98 R_UNLESS((m_priority_mask & 0xF) == 0, ResultInvalidArgument);
99
100 R_SUCCEED();
101}
102
103Result KCapabilities::SetSyscallMaskCapability(const u32 cap, u32& set_svc) {
104 // Validate the index.
105 SyscallMask pack{cap};
106 const u32 mask = pack.mask;
107 const u32 index = pack.index;
108
109 const u32 index_flag = (1U << index);
110 R_UNLESS((set_svc & index_flag) == 0, ResultInvalidCombination);
111 set_svc |= index_flag;
112
113 // Set SVCs.
114 for (size_t i = 0; i < decltype(SyscallMask::mask)::bits; i++) {
115 const u32 svc_id = static_cast<u32>(decltype(SyscallMask::mask)::bits * index + i);
116 if (mask & (1U << i)) {
117 R_UNLESS(this->SetSvcAllowed(svc_id), ResultOutOfRange);
118 }
119 }
120
121 R_SUCCEED();
122}
123
124Result KCapabilities::MapRange_(const u32 cap, const u32 size_cap, KPageTable* page_table) {
125 const auto range_pack = MapRange{cap};
126 const auto size_pack = MapRangeSize{size_cap};
127
128 // Get/validate address/size
129 const u64 phys_addr = range_pack.address.Value() * PageSize;
130
131 // Validate reserved bits are unused.
132 R_UNLESS(size_pack.reserved.Value() == 0, ResultOutOfRange);
133
134 const size_t num_pages = size_pack.pages;
135 const size_t size = num_pages * PageSize;
136 R_UNLESS(num_pages != 0, ResultInvalidSize);
137 R_UNLESS(phys_addr < phys_addr + size, ResultInvalidAddress);
138 R_UNLESS(((phys_addr + size - 1) & ~PhysicalMapAllowedMask) == 0, ResultInvalidAddress);
139
140 // Do the mapping.
141 [[maybe_unused]] const KMemoryPermission perm = range_pack.read_only.Value()
142 ? KMemoryPermission::UserRead
143 : KMemoryPermission::UserReadWrite;
144 if (MapRangeSize{size_cap}.normal) {
145 // R_RETURN(page_table->MapStatic(phys_addr, size, perm));
146 } else {
147 // R_RETURN(page_table->MapIo(phys_addr, size, perm));
148 }
149
150 UNIMPLEMENTED();
151 R_SUCCEED();
152}
153
154Result KCapabilities::MapIoPage_(const u32 cap, KPageTable* page_table) {
155 // Get/validate address/size
156 const u64 phys_addr = MapIoPage{cap}.address.Value() * PageSize;
157 const size_t num_pages = 1;
158 const size_t size = num_pages * PageSize;
159 R_UNLESS(num_pages != 0, ResultInvalidSize);
160 R_UNLESS(phys_addr < phys_addr + size, ResultInvalidAddress);
161 R_UNLESS(((phys_addr + size - 1) & ~PhysicalMapAllowedMask) == 0, ResultInvalidAddress);
162
163 // Do the mapping.
164 // R_RETURN(page_table->MapIo(phys_addr, size, KMemoryPermission_UserReadWrite));
165
166 UNIMPLEMENTED();
167 R_SUCCEED();
168}
169
170template <typename F>
171Result KCapabilities::ProcessMapRegionCapability(const u32 cap, F f) {
172 // Define the allowed memory regions.
173 constexpr std::array<KMemoryRegionType, 4> MemoryRegions{
174 KMemoryRegionType_None,
175 KMemoryRegionType_KernelTraceBuffer,
176 KMemoryRegionType_OnMemoryBootImage,
177 KMemoryRegionType_DTB,
178 };
179
180 // Extract regions/read only.
181 const MapRegion pack{cap};
182 const std::array<RegionType, 3> types{pack.region0, pack.region1, pack.region2};
183 const std::array<u32, 3> ro{pack.read_only0, pack.read_only1, pack.read_only2};
184
185 for (size_t i = 0; i < types.size(); i++) {
186 const auto type = types[i];
187 const auto perm = ro[i] ? KMemoryPermission::UserRead : KMemoryPermission::UserReadWrite;
188 switch (type) {
189 case RegionType::NoMapping:
190 break;
191 case RegionType::KernelTraceBuffer:
192 case RegionType::OnMemoryBootImage:
193 case RegionType::DTB:
194 R_TRY(f(MemoryRegions[static_cast<u32>(type)], perm));
195 break;
196 default:
197 R_THROW(ResultNotFound);
198 }
199 }
200
201 R_SUCCEED();
202}
203
204Result KCapabilities::MapRegion_(const u32 cap, KPageTable* page_table) {
205 // Map each region into the process's page table.
206 R_RETURN(ProcessMapRegionCapability(
207 cap, [](KMemoryRegionType region_type, KMemoryPermission perm) -> Result {
208 // R_RETURN(page_table->MapRegion(region_type, perm));
209 UNIMPLEMENTED();
210 R_SUCCEED();
211 }));
212}
213
214Result KCapabilities::CheckMapRegion(KernelCore& kernel, const u32 cap) {
215 // Check that each region has a physical backing store.
216 R_RETURN(ProcessMapRegionCapability(
217 cap, [&](KMemoryRegionType region_type, KMemoryPermission perm) -> Result {
218 R_UNLESS(kernel.MemoryLayout().GetPhysicalMemoryRegionTree().FindFirstDerived(
219 region_type) != nullptr,
220 ResultOutOfRange);
221 R_SUCCEED();
222 }));
223}
224
225Result KCapabilities::SetInterruptPairCapability(const u32 cap) {
226 // Extract interrupts.
227 const InterruptPair pack{cap};
228 const std::array<u32, 2> ids{pack.interrupt_id0, pack.interrupt_id1};
229
230 for (size_t i = 0; i < ids.size(); i++) {
231 if (ids[i] != PaddingInterruptId) {
232 UNIMPLEMENTED();
233 // R_UNLESS(Kernel::GetInterruptManager().IsInterruptDefined(ids[i]), ResultOutOfRange);
234 // R_UNLESS(this->SetInterruptPermitted(ids[i]), ResultOutOfRange);
235 }
236 }
237
238 R_SUCCEED();
239}
240
241Result KCapabilities::SetProgramTypeCapability(const u32 cap) {
242 // Validate.
243 const ProgramType pack{cap};
244 R_UNLESS(pack.reserved == 0, ResultReservedUsed);
245
246 m_program_type = pack.type;
247 R_SUCCEED();
248}
249
250Result KCapabilities::SetKernelVersionCapability(const u32 cap) {
251 // Ensure we haven't set our version before.
252 R_UNLESS(KernelVersion{m_intended_kernel_version}.major_version == 0, ResultInvalidArgument);
253
254 // Set, ensure that we set a valid version.
255 m_intended_kernel_version = cap;
256 R_UNLESS(KernelVersion{m_intended_kernel_version}.major_version != 0, ResultInvalidArgument);
257
258 R_SUCCEED();
259}
260
261Result KCapabilities::SetHandleTableCapability(const u32 cap) {
262 // Validate.
263 const HandleTable pack{cap};
264 R_UNLESS(pack.reserved == 0, ResultReservedUsed);
265
266 m_handle_table_size = pack.size;
267 R_SUCCEED();
268}
269
270Result KCapabilities::SetDebugFlagsCapability(const u32 cap) {
271 // Validate.
272 const DebugFlags pack{cap};
273 R_UNLESS(pack.reserved == 0, ResultReservedUsed);
274
275 DebugFlags debug_capabilities{m_debug_capabilities};
276 debug_capabilities.allow_debug.Assign(pack.allow_debug);
277 debug_capabilities.force_debug.Assign(pack.force_debug);
278 m_debug_capabilities = debug_capabilities.raw;
279
280 R_SUCCEED();
281}
282
283Result KCapabilities::SetCapability(const u32 cap, u32& set_flags, u32& set_svc,
284 KPageTable* page_table) {
285 // Validate this is a capability we can act on.
286 const auto type = GetCapabilityType(cap);
287 R_UNLESS(type != CapabilityType::Invalid, ResultInvalidArgument);
288
289 // If the type is padding, we have no work to do.
290 R_SUCCEED_IF(type == CapabilityType::Padding);
291
292 // Check that we haven't already processed this capability.
293 const auto flag = GetCapabilityFlag(type);
294 R_UNLESS(((set_flags & InitializeOnceFlags) & flag) == 0, ResultInvalidCombination);
295 set_flags |= flag;
296
297 // Process the capability.
298 switch (type) {
299 case CapabilityType::CorePriority:
300 R_RETURN(this->SetCorePriorityCapability(cap));
301 case CapabilityType::SyscallMask:
302 R_RETURN(this->SetSyscallMaskCapability(cap, set_svc));
303 case CapabilityType::MapIoPage:
304 R_RETURN(this->MapIoPage_(cap, page_table));
305 case CapabilityType::MapRegion:
306 R_RETURN(this->MapRegion_(cap, page_table));
307 case CapabilityType::InterruptPair:
308 R_RETURN(this->SetInterruptPairCapability(cap));
309 case CapabilityType::ProgramType:
310 R_RETURN(this->SetProgramTypeCapability(cap));
311 case CapabilityType::KernelVersion:
312 R_RETURN(this->SetKernelVersionCapability(cap));
313 case CapabilityType::HandleTable:
314 R_RETURN(this->SetHandleTableCapability(cap));
315 case CapabilityType::DebugFlags:
316 R_RETURN(this->SetDebugFlagsCapability(cap));
317 default:
318 R_THROW(ResultInvalidArgument);
319 }
320}
321
322Result KCapabilities::SetCapabilities(std::span<const u32> caps, KPageTable* page_table) {
323 u32 set_flags = 0, set_svc = 0;
324
325 for (size_t i = 0; i < caps.size(); i++) {
326 const u32 cap{caps[i]};
327
328 if (GetCapabilityType(cap) == CapabilityType::MapRange) {
329 // Check that the pair cap exists.
330 R_UNLESS((++i) < caps.size(), ResultInvalidCombination);
331
332 // Check the pair cap is a map range cap.
333 const u32 size_cap{caps[i]};
334 R_UNLESS(GetCapabilityType(size_cap) == CapabilityType::MapRange,
335 ResultInvalidCombination);
336
337 // Map the range.
338 R_TRY(this->MapRange_(cap, size_cap, page_table));
339 } else {
340 R_TRY(this->SetCapability(cap, set_flags, set_svc, page_table));
341 }
342 }
343
344 R_SUCCEED();
345}
346
347Result KCapabilities::CheckCapabilities(KernelCore& kernel, std::span<const u32> caps) {
348 for (auto cap : caps) {
349 // Check the capability refers to a valid region.
350 if (GetCapabilityType(cap) == CapabilityType::MapRegion) {
351 R_TRY(CheckMapRegion(kernel, cap));
352 }
353 }
354
355 R_SUCCEED();
356}
357
358} // namespace Kernel
diff --git a/src/core/hle/kernel/k_capabilities.h b/src/core/hle/kernel/k_capabilities.h
new file mode 100644
index 000000000..cd96f8d23
--- /dev/null
+++ b/src/core/hle/kernel/k_capabilities.h
@@ -0,0 +1,295 @@
1
2// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
3// SPDX-License-Identifier: GPL-2.0-or-later
4
5#pragma once
6
7#include <bitset>
8#include <span>
9
10#include "common/bit_field.h"
11#include "common/common_types.h"
12
13#include "core/hle/kernel/svc_types.h"
14#include "core/hle/result.h"
15
16namespace Kernel {
17
18class KPageTable;
19class KernelCore;
20
21class KCapabilities {
22public:
23 constexpr explicit KCapabilities() = default;
24
25 Result InitializeForKIP(std::span<const u32> kern_caps, KPageTable* page_table);
26 Result InitializeForUser(std::span<const u32> user_caps, KPageTable* page_table);
27
28 static Result CheckCapabilities(KernelCore& kernel, std::span<const u32> user_caps);
29
30 constexpr u64 GetCoreMask() const {
31 return m_core_mask;
32 }
33
34 constexpr u64 GetPhysicalCoreMask() const {
35 return m_phys_core_mask;
36 }
37
38 constexpr u64 GetPriorityMask() const {
39 return m_priority_mask;
40 }
41
42 constexpr s32 GetHandleTableSize() const {
43 return m_handle_table_size;
44 }
45
46 constexpr const Svc::SvcAccessFlagSet& GetSvcPermissions() const {
47 return m_svc_access_flags;
48 }
49
50 constexpr bool IsPermittedSvc(u32 id) const {
51 return (id < m_svc_access_flags.size()) && m_svc_access_flags[id];
52 }
53
54 constexpr bool IsPermittedInterrupt(u32 id) const {
55 return (id < m_irq_access_flags.size()) && m_irq_access_flags[id];
56 }
57
58 constexpr bool IsPermittedDebug() const {
59 return DebugFlags{m_debug_capabilities}.allow_debug.Value() != 0;
60 }
61
62 constexpr bool CanForceDebug() const {
63 return DebugFlags{m_debug_capabilities}.force_debug.Value() != 0;
64 }
65
66 constexpr u32 GetIntendedKernelMajorVersion() const {
67 return KernelVersion{m_intended_kernel_version}.major_version;
68 }
69
70 constexpr u32 GetIntendedKernelMinorVersion() const {
71 return KernelVersion{m_intended_kernel_version}.minor_version;
72 }
73
74private:
75 static constexpr size_t InterruptIdCount = 0x400;
76 using InterruptFlagSet = std::bitset<InterruptIdCount>;
77
78 enum class CapabilityType : u32 {
79 CorePriority = (1U << 3) - 1,
80 SyscallMask = (1U << 4) - 1,
81 MapRange = (1U << 6) - 1,
82 MapIoPage = (1U << 7) - 1,
83 MapRegion = (1U << 10) - 1,
84 InterruptPair = (1U << 11) - 1,
85 ProgramType = (1U << 13) - 1,
86 KernelVersion = (1U << 14) - 1,
87 HandleTable = (1U << 15) - 1,
88 DebugFlags = (1U << 16) - 1,
89
90 Invalid = 0U,
91 Padding = ~0U,
92 };
93
94 using RawCapabilityValue = u32;
95
96 static constexpr CapabilityType GetCapabilityType(const RawCapabilityValue value) {
97 return static_cast<CapabilityType>((~value & (value + 1)) - 1);
98 }
99
100 static constexpr u32 GetCapabilityFlag(CapabilityType type) {
101 return static_cast<u32>(type) + 1;
102 }
103
104 template <CapabilityType Type>
105 static constexpr inline u32 CapabilityFlag = static_cast<u32>(Type) + 1;
106
107 template <CapabilityType Type>
108 static constexpr inline u32 CapabilityId = std::countr_zero(CapabilityFlag<Type>);
109
110 union CorePriority {
111 static_assert(CapabilityId<CapabilityType::CorePriority> + 1 == 4);
112
113 RawCapabilityValue raw;
114 BitField<0, 4, CapabilityType> id;
115 BitField<4, 6, u32> lowest_thread_priority;
116 BitField<10, 6, u32> highest_thread_priority;
117 BitField<16, 8, u32> minimum_core_id;
118 BitField<24, 8, u32> maximum_core_id;
119 };
120
121 union SyscallMask {
122 static_assert(CapabilityId<CapabilityType::SyscallMask> + 1 == 5);
123
124 RawCapabilityValue raw;
125 BitField<0, 5, CapabilityType> id;
126 BitField<5, 24, u32> mask;
127 BitField<29, 3, u32> index;
128 };
129
130 // #undef MESOSPHERE_ENABLE_LARGE_PHYSICAL_ADDRESS_CAPABILITIES
131 static constexpr u64 PhysicalMapAllowedMask = (1ULL << 36) - 1;
132
133 union MapRange {
134 static_assert(CapabilityId<CapabilityType::MapRange> + 1 == 7);
135
136 RawCapabilityValue raw;
137 BitField<0, 7, CapabilityType> id;
138 BitField<7, 24, u32> address;
139 BitField<31, 1, u32> read_only;
140 };
141
142 union MapRangeSize {
143 static_assert(CapabilityId<CapabilityType::MapRange> + 1 == 7);
144
145 RawCapabilityValue raw;
146 BitField<0, 7, CapabilityType> id;
147 BitField<7, 20, u32> pages;
148 BitField<27, 4, u32> reserved;
149 BitField<31, 1, u32> normal;
150 };
151
152 union MapIoPage {
153 static_assert(CapabilityId<CapabilityType::MapIoPage> + 1 == 8);
154
155 RawCapabilityValue raw;
156 BitField<0, 8, CapabilityType> id;
157 BitField<8, 24, u32> address;
158 };
159
160 enum class RegionType : u32 {
161 NoMapping = 0,
162 KernelTraceBuffer = 1,
163 OnMemoryBootImage = 2,
164 DTB = 3,
165 };
166
167 union MapRegion {
168 static_assert(CapabilityId<CapabilityType::MapRegion> + 1 == 11);
169
170 RawCapabilityValue raw;
171 BitField<0, 11, CapabilityType> id;
172 BitField<11, 6, RegionType> region0;
173 BitField<17, 1, u32> read_only0;
174 BitField<18, 6, RegionType> region1;
175 BitField<24, 1, u32> read_only1;
176 BitField<25, 6, RegionType> region2;
177 BitField<31, 1, u32> read_only2;
178 };
179
180 union InterruptPair {
181 static_assert(CapabilityId<CapabilityType::InterruptPair> + 1 == 12);
182
183 RawCapabilityValue raw;
184 BitField<0, 12, CapabilityType> id;
185 BitField<12, 10, u32> interrupt_id0;
186 BitField<22, 10, u32> interrupt_id1;
187 };
188
189 union ProgramType {
190 static_assert(CapabilityId<CapabilityType::ProgramType> + 1 == 14);
191
192 RawCapabilityValue raw;
193 BitField<0, 14, CapabilityType> id;
194 BitField<14, 3, u32> type;
195 BitField<17, 15, u32> reserved;
196 };
197
198 union KernelVersion {
199 static_assert(CapabilityId<CapabilityType::KernelVersion> + 1 == 15);
200
201 RawCapabilityValue raw;
202 BitField<0, 15, CapabilityType> id;
203 BitField<15, 4, u32> major_version;
204 BitField<19, 13, u32> minor_version;
205 };
206
207 union HandleTable {
208 static_assert(CapabilityId<CapabilityType::HandleTable> + 1 == 16);
209
210 RawCapabilityValue raw;
211 BitField<0, 16, CapabilityType> id;
212 BitField<16, 10, u32> size;
213 BitField<26, 6, u32> reserved;
214 };
215
216 union DebugFlags {
217 static_assert(CapabilityId<CapabilityType::DebugFlags> + 1 == 17);
218
219 RawCapabilityValue raw;
220 BitField<0, 17, CapabilityType> id;
221 BitField<17, 1, u32> allow_debug;
222 BitField<18, 1, u32> force_debug;
223 BitField<19, 13, u32> reserved;
224 };
225
226 static_assert(sizeof(CorePriority) == 4);
227 static_assert(sizeof(SyscallMask) == 4);
228 static_assert(sizeof(MapRange) == 4);
229 static_assert(sizeof(MapRangeSize) == 4);
230 static_assert(sizeof(MapIoPage) == 4);
231 static_assert(sizeof(MapRegion) == 4);
232 static_assert(sizeof(InterruptPair) == 4);
233 static_assert(sizeof(ProgramType) == 4);
234 static_assert(sizeof(KernelVersion) == 4);
235 static_assert(sizeof(HandleTable) == 4);
236 static_assert(sizeof(DebugFlags) == 4);
237
238 static constexpr u32 InitializeOnceFlags =
239 CapabilityFlag<CapabilityType::CorePriority> | CapabilityFlag<CapabilityType::ProgramType> |
240 CapabilityFlag<CapabilityType::KernelVersion> |
241 CapabilityFlag<CapabilityType::HandleTable> | CapabilityFlag<CapabilityType::DebugFlags>;
242
243 static const u32 PaddingInterruptId = 0x3FF;
244 static_assert(PaddingInterruptId < InterruptIdCount);
245
246private:
247 constexpr bool SetSvcAllowed(u32 id) {
248 if (id < m_svc_access_flags.size()) [[likely]] {
249 m_svc_access_flags[id] = true;
250 return true;
251 } else {
252 return false;
253 }
254 }
255
256 constexpr bool SetInterruptPermitted(u32 id) {
257 if (id < m_irq_access_flags.size()) [[likely]] {
258 m_irq_access_flags[id] = true;
259 return true;
260 } else {
261 return false;
262 }
263 }
264
265 Result SetCorePriorityCapability(const u32 cap);
266 Result SetSyscallMaskCapability(const u32 cap, u32& set_svc);
267 Result MapRange_(const u32 cap, const u32 size_cap, KPageTable* page_table);
268 Result MapIoPage_(const u32 cap, KPageTable* page_table);
269 Result MapRegion_(const u32 cap, KPageTable* page_table);
270 Result SetInterruptPairCapability(const u32 cap);
271 Result SetProgramTypeCapability(const u32 cap);
272 Result SetKernelVersionCapability(const u32 cap);
273 Result SetHandleTableCapability(const u32 cap);
274 Result SetDebugFlagsCapability(const u32 cap);
275
276 template <typename F>
277 static Result ProcessMapRegionCapability(const u32 cap, F f);
278 static Result CheckMapRegion(KernelCore& kernel, const u32 cap);
279
280 Result SetCapability(const u32 cap, u32& set_flags, u32& set_svc, KPageTable* page_table);
281 Result SetCapabilities(std::span<const u32> caps, KPageTable* page_table);
282
283private:
284 Svc::SvcAccessFlagSet m_svc_access_flags{};
285 InterruptFlagSet m_irq_access_flags{};
286 u64 m_core_mask{};
287 u64 m_phys_core_mask{};
288 u64 m_priority_mask{};
289 u32 m_debug_capabilities{};
290 s32 m_handle_table_size{};
291 u32 m_intended_kernel_version{};
292 u32 m_program_type{};
293};
294
295} // namespace Kernel
diff --git a/src/core/hle/kernel/k_priority_queue.h b/src/core/hle/kernel/k_priority_queue.h
index cb2512b0b..645c5b531 100644
--- a/src/core/hle/kernel/k_priority_queue.h
+++ b/src/core/hle/kernel/k_priority_queue.h
@@ -17,35 +17,41 @@ namespace Kernel {
17class KThread; 17class KThread;
18 18
19template <typename T> 19template <typename T>
20concept KPriorityQueueAffinityMask = !std::is_reference_v<T> && requires(T & t) { 20concept KPriorityQueueAffinityMask = !
21 { t.GetAffinityMask() } -> Common::ConvertibleTo<u64>; 21std::is_reference_v<T>&& requires(T& t) {
22 {t.SetAffinityMask(0)}; 22 { t.GetAffinityMask() } -> Common::ConvertibleTo<u64>;
23 { t.SetAffinityMask(0) };
23 24
24 { t.GetAffinity(0) } -> std::same_as<bool>; 25 { t.GetAffinity(0) } -> std::same_as<bool>;
25 {t.SetAffinity(0, false)}; 26 { t.SetAffinity(0, false) };
26 {t.SetAll()}; 27 { t.SetAll() };
27}; 28 };
28 29
29template <typename T> 30template <typename T>
30concept KPriorityQueueMember = !std::is_reference_v<T> && requires(T & t) { 31concept KPriorityQueueMember = !
31 {typename T::QueueEntry()}; 32std::is_reference_v<T>&& requires(T& t) {
32 {(typename T::QueueEntry()).Initialize()}; 33 { typename T::QueueEntry() };
33 {(typename T::QueueEntry()).SetPrev(std::addressof(t))}; 34 { (typename T::QueueEntry()).Initialize() };
34 {(typename T::QueueEntry()).SetNext(std::addressof(t))}; 35 { (typename T::QueueEntry()).SetPrev(std::addressof(t)) };
35 { (typename T::QueueEntry()).GetNext() } -> std::same_as<T*>; 36 { (typename T::QueueEntry()).SetNext(std::addressof(t)) };
36 { (typename T::QueueEntry()).GetPrev() } -> std::same_as<T*>; 37 { (typename T::QueueEntry()).GetNext() } -> std::same_as<T*>;
37 { t.GetPriorityQueueEntry(0) } -> std::same_as<typename T::QueueEntry&>; 38 { (typename T::QueueEntry()).GetPrev() } -> std::same_as<T*>;
38 39 {
39 {t.GetAffinityMask()}; 40 t.GetPriorityQueueEntry(0)
40 { std::remove_cvref_t<decltype(t.GetAffinityMask())>() } -> KPriorityQueueAffinityMask; 41 } -> std::same_as<typename T::QueueEntry&>;
41 42
42 { t.GetActiveCore() } -> Common::ConvertibleTo<s32>; 43 { t.GetAffinityMask() };
43 { t.GetPriority() } -> Common::ConvertibleTo<s32>; 44 {
44 { t.IsDummyThread() } -> Common::ConvertibleTo<bool>; 45 std::remove_cvref_t<decltype(t.GetAffinityMask())>()
45}; 46 } -> KPriorityQueueAffinityMask;
47
48 { t.GetActiveCore() } -> Common::ConvertibleTo<s32>;
49 { t.GetPriority() } -> Common::ConvertibleTo<s32>;
50 { t.IsDummyThread() } -> Common::ConvertibleTo<bool>;
51 };
46 52
47template <typename Member, size_t NumCores_, int LowestPriority, int HighestPriority> 53template <typename Member, size_t NumCores_, int LowestPriority, int HighestPriority>
48requires KPriorityQueueMember<Member> 54 requires KPriorityQueueMember<Member>
49class KPriorityQueue { 55class KPriorityQueue {
50public: 56public:
51 using AffinityMaskType = std::remove_cv_t< 57 using AffinityMaskType = std::remove_cv_t<
diff --git a/src/core/hle/kernel/k_scoped_lock.h b/src/core/hle/kernel/k_scoped_lock.h
index 857e21156..59b3e32ae 100644
--- a/src/core/hle/kernel/k_scoped_lock.h
+++ b/src/core/hle/kernel/k_scoped_lock.h
@@ -9,13 +9,14 @@
9namespace Kernel { 9namespace Kernel {
10 10
11template <typename T> 11template <typename T>
12concept KLockable = !std::is_reference_v<T> && requires(T & t) { 12concept KLockable = !
13 { t.Lock() } -> std::same_as<void>; 13std::is_reference_v<T>&& requires(T& t) {
14 { t.Unlock() } -> std::same_as<void>; 14 { t.Lock() } -> std::same_as<void>;
15}; 15 { t.Unlock() } -> std::same_as<void>;
16 };
16 17
17template <typename T> 18template <typename T>
18requires KLockable<T> 19 requires KLockable<T>
19class [[nodiscard]] KScopedLock { 20class [[nodiscard]] KScopedLock {
20public: 21public:
21 explicit KScopedLock(T* l) : lock_ptr(l) { 22 explicit KScopedLock(T* l) : lock_ptr(l) {
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h
index 9d771de0e..8b8dc51be 100644
--- a/src/core/hle/kernel/k_thread.h
+++ b/src/core/hle/kernel/k_thread.h
@@ -677,7 +677,7 @@ private:
677 union SyncObjectBuffer { 677 union SyncObjectBuffer {
678 std::array<KSynchronizationObject*, Svc::ArgumentHandleCountMax> sync_objects{}; 678 std::array<KSynchronizationObject*, Svc::ArgumentHandleCountMax> sync_objects{};
679 std::array<Handle, 679 std::array<Handle,
680 Svc::ArgumentHandleCountMax*(sizeof(KSynchronizationObject*) / sizeof(Handle))> 680 Svc::ArgumentHandleCountMax * (sizeof(KSynchronizationObject*) / sizeof(Handle))>
681 handles; 681 handles;
682 constexpr SyncObjectBuffer() {} 682 constexpr SyncObjectBuffer() {}
683 }; 683 };
@@ -698,10 +698,8 @@ private:
698 }; 698 };
699 699
700 template <typename T> 700 template <typename T>
701 requires( 701 requires(std::same_as<T, KThread> || std::same_as<T, RedBlackKeyType>)
702 std::same_as<T, KThread> || 702 static constexpr int Compare(const T& lhs, const KThread& rhs) {
703 std::same_as<T, RedBlackKeyType>) static constexpr int Compare(const T& lhs,
704 const KThread& rhs) {
705 const u64 l_key = lhs.GetConditionVariableKey(); 703 const u64 l_key = lhs.GetConditionVariableKey();
706 const u64 r_key = rhs.GetConditionVariableKey(); 704 const u64 r_key = rhs.GetConditionVariableKey();
707 705
diff --git a/src/core/hle/kernel/k_thread_local_page.h b/src/core/hle/kernel/k_thread_local_page.h
index fe0cff084..71254eb55 100644
--- a/src/core/hle/kernel/k_thread_local_page.h
+++ b/src/core/hle/kernel/k_thread_local_page.h
@@ -70,10 +70,8 @@ public:
70 } 70 }
71 71
72 template <typename T> 72 template <typename T>
73 requires(std::same_as<T, KThreadLocalPage> || 73 requires(std::same_as<T, KThreadLocalPage> || std::same_as<T, RedBlackKeyType>)
74 std::same_as<T, RedBlackKeyType>) static constexpr int Compare(const T& lhs, 74 static constexpr int Compare(const T& lhs, const KThreadLocalPage& rhs) {
75 const KThreadLocalPage&
76 rhs) {
77 const VAddr lval = GetRedBlackKey(lhs); 75 const VAddr lval = GetRedBlackKey(lhs);
78 const VAddr rval = GetRedBlackKey(rhs); 76 const VAddr rval = GetRedBlackKey(rhs);
79 77
diff --git a/src/core/hle/kernel/svc_types.h b/src/core/hle/kernel/svc_types.h
index 33eebcef6..9c2f9998a 100644
--- a/src/core/hle/kernel/svc_types.h
+++ b/src/core/hle/kernel/svc_types.h
@@ -3,6 +3,8 @@
3 3
4#pragma once 4#pragma once
5 5
6#include <bitset>
7
6#include "common/common_funcs.h" 8#include "common/common_funcs.h"
7#include "common/common_types.h" 9#include "common/common_types.h"
8 10
@@ -592,4 +594,7 @@ struct CreateProcessParameter {
592}; 594};
593static_assert(sizeof(CreateProcessParameter) == 0x30); 595static_assert(sizeof(CreateProcessParameter) == 0x30);
594 596
597constexpr size_t NumSupervisorCalls = 0xC0;
598using SvcAccessFlagSet = std::bitset<NumSupervisorCalls>;
599
595} // namespace Kernel::Svc 600} // namespace Kernel::Svc
diff --git a/src/core/hle/kernel/svc_version.h b/src/core/hle/kernel/svc_version.h
new file mode 100644
index 000000000..e4f47b34b
--- /dev/null
+++ b/src/core/hle/kernel/svc_version.h
@@ -0,0 +1,58 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/bit_field.h"
7#include "common/common_types.h"
8#include "common/literals.h"
9
10namespace Kernel::Svc {
11
12constexpr inline u32 ConvertToSvcMajorVersion(u32 sdk) {
13 return sdk + 4;
14}
15constexpr inline u32 ConvertToSdkMajorVersion(u32 svc) {
16 return svc - 4;
17}
18
19constexpr inline u32 ConvertToSvcMinorVersion(u32 sdk) {
20 return sdk;
21}
22constexpr inline u32 ConvertToSdkMinorVersion(u32 svc) {
23 return svc;
24}
25
26union KernelVersion {
27 u32 value;
28 BitField<0, 4, u32> minor_version;
29 BitField<4, 13, u32> major_version;
30};
31
32constexpr inline u32 EncodeKernelVersion(u32 major, u32 minor) {
33 return decltype(KernelVersion::minor_version)::FormatValue(minor) |
34 decltype(KernelVersion::major_version)::FormatValue(major);
35}
36
37constexpr inline u32 GetKernelMajorVersion(u32 encoded) {
38 return std::bit_cast<decltype(KernelVersion::major_version)>(encoded).Value();
39}
40
41constexpr inline u32 GetKernelMinorVersion(u32 encoded) {
42 return std::bit_cast<decltype(KernelVersion::minor_version)>(encoded).Value();
43}
44
45// Nintendo doesn't support programs targeting SVC versions < 3.0.
46constexpr inline u32 RequiredKernelMajorVersion = 3;
47constexpr inline u32 RequiredKernelMinorVersion = 0;
48constexpr inline u32 RequiredKernelVersion =
49 EncodeKernelVersion(RequiredKernelMajorVersion, RequiredKernelMinorVersion);
50
51// This is the highest SVC version supported, to be updated on new kernel releases.
52// NOTE: Official kernel versions have SVC major = SDK major + 4, SVC minor = SDK minor.
53constexpr inline u32 SupportedKernelMajorVersion = ConvertToSvcMajorVersion(15);
54constexpr inline u32 SupportedKernelMinorVersion = ConvertToSvcMinorVersion(3);
55constexpr inline u32 SupportedKernelVersion =
56 EncodeKernelVersion(SupportedKernelMajorVersion, SupportedKernelMinorVersion);
57
58} // namespace Kernel::Svc
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 22999c942..ebcf6e164 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -1124,7 +1124,7 @@ void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) {
1124 IPC::RequestParser rp{ctx}; 1124 IPC::RequestParser rp{ctx};
1125 1125
1126 const u64 offset{rp.Pop<u64>()}; 1126 const u64 offset{rp.Pop<u64>()};
1127 const std::vector<u8> data{ctx.ReadBuffer()}; 1127 const auto data{ctx.ReadBuffer()};
1128 const std::size_t size{std::min<u64>(data.size(), backing.GetSize() - offset)}; 1128 const std::size_t size{std::min<u64>(data.size(), backing.GetSize() - offset)};
1129 1129
1130 LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, size); 1130 LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, size);
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index 3a1c231b6..0ee28752c 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -112,7 +112,7 @@ private:
112 void RequestUpdate(Kernel::HLERequestContext& ctx) { 112 void RequestUpdate(Kernel::HLERequestContext& ctx) {
113 LOG_TRACE(Service_Audio, "called"); 113 LOG_TRACE(Service_Audio, "called");
114 114
115 std::vector<u8> input{ctx.ReadBuffer(0)}; 115 const auto input{ctx.ReadBuffer(0)};
116 116
117 // These buffers are written manually to avoid an issue with WriteBuffer throwing errors for 117 // These buffers are written manually to avoid an issue with WriteBuffer throwing errors for
118 // checking size 0. Performance size is 0 for most games. 118 // checking size 0. Performance size is 0 for most games.
diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp
index 825fb8bcc..e01f87356 100644
--- a/src/core/hle/service/audio/hwopus.cpp
+++ b/src/core/hle/service/audio/hwopus.cpp
@@ -93,7 +93,7 @@ private:
93 ctx.WriteBuffer(samples); 93 ctx.WriteBuffer(samples);
94 } 94 }
95 95
96 bool DecodeOpusData(u32& consumed, u32& sample_count, const std::vector<u8>& input, 96 bool DecodeOpusData(u32& consumed, u32& sample_count, std::span<const u8> input,
97 std::vector<opus_int16>& output, u64* out_performance_time) const { 97 std::vector<opus_int16>& output, u64* out_performance_time) const {
98 const auto start_time = std::chrono::steady_clock::now(); 98 const auto start_time = std::chrono::steady_clock::now();
99 const std::size_t raw_output_sz = output.size() * sizeof(opus_int16); 99 const std::size_t raw_output_sz = output.size() * sizeof(opus_int16);
diff --git a/src/core/hle/service/es/es.cpp b/src/core/hle/service/es/es.cpp
index d183e5829..fb8686859 100644
--- a/src/core/hle/service/es/es.cpp
+++ b/src/core/hle/service/es/es.cpp
@@ -122,7 +122,7 @@ private:
122 122
123 void ImportTicket(Kernel::HLERequestContext& ctx) { 123 void ImportTicket(Kernel::HLERequestContext& ctx) {
124 const auto ticket = ctx.ReadBuffer(); 124 const auto ticket = ctx.ReadBuffer();
125 const auto cert = ctx.ReadBuffer(1); 125 [[maybe_unused]] const auto cert = ctx.ReadBuffer(1);
126 126
127 if (ticket.size() < sizeof(Core::Crypto::Ticket)) { 127 if (ticket.size() < sizeof(Core::Crypto::Ticket)) {
128 LOG_ERROR(Service_ETicket, "The input buffer is not large enough!"); 128 LOG_ERROR(Service_ETicket, "The input buffer is not large enough!");
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index fbb16a7da..cab44bf9c 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -190,7 +190,7 @@ private:
190 return; 190 return;
191 } 191 }
192 192
193 const std::vector<u8> data = ctx.ReadBuffer(); 193 const auto data = ctx.ReadBuffer();
194 194
195 ASSERT_MSG( 195 ASSERT_MSG(
196 static_cast<s64>(data.size()) <= length, 196 static_cast<s64>(data.size()) <= length,
@@ -401,11 +401,8 @@ public:
401 } 401 }
402 402
403 void RenameFile(Kernel::HLERequestContext& ctx) { 403 void RenameFile(Kernel::HLERequestContext& ctx) {
404 std::vector<u8> buffer = ctx.ReadBuffer(0); 404 const std::string src_name = Common::StringFromBuffer(ctx.ReadBuffer(0));
405 const std::string src_name = Common::StringFromBuffer(buffer); 405 const std::string dst_name = Common::StringFromBuffer(ctx.ReadBuffer(1));
406
407 buffer = ctx.ReadBuffer(1);
408 const std::string dst_name = Common::StringFromBuffer(buffer);
409 406
410 LOG_DEBUG(Service_FS, "called. file '{}' to file '{}'", src_name, dst_name); 407 LOG_DEBUG(Service_FS, "called. file '{}' to file '{}'", src_name, dst_name);
411 408
diff --git a/src/core/hle/service/glue/arp.cpp b/src/core/hle/service/glue/arp.cpp
index 49b6d45fe..ce21b69e3 100644
--- a/src/core/hle/service/glue/arp.cpp
+++ b/src/core/hle/service/glue/arp.cpp
@@ -228,7 +228,8 @@ private:
228 return; 228 return;
229 } 229 }
230 230
231 control = ctx.ReadBuffer(); 231 // TODO: Can this be a span?
232 control = ctx.ReadBufferCopy();
232 233
233 IPC::ResponseBuilder rb{ctx, 2}; 234 IPC::ResponseBuilder rb{ctx, 2};
234 rb.Push(ResultSuccess); 235 rb.Push(ResultSuccess);
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 5713f1288..513ea485a 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -428,6 +428,9 @@ void Controller_NPad::RequestPadStateUpdate(Core::HID::NpadIdType npad_id) {
428 return; 428 return;
429 } 429 }
430 430
431 // This function is unique to yuzu for the turbo buttons to work properly
432 controller.device->TurboButtonUpdate();
433
431 auto& pad_entry = controller.npad_pad_state; 434 auto& pad_entry = controller.npad_pad_state;
432 auto& trigger_entry = controller.npad_trigger_state; 435 auto& trigger_entry = controller.npad_trigger_state;
433 const auto button_state = controller.device->GetNpadButtons(); 436 const auto button_state = controller.device->GetNpadButtons();
@@ -755,11 +758,12 @@ Core::HID::NpadStyleTag Controller_NPad::GetSupportedStyleSet() const {
755 return hid_core.GetSupportedStyleTag(); 758 return hid_core.GetSupportedStyleTag();
756} 759}
757 760
758void Controller_NPad::SetSupportedNpadIdTypes(u8* data, std::size_t length) { 761void Controller_NPad::SetSupportedNpadIdTypes(std::span<const u8> data) {
762 const auto length = data.size();
759 ASSERT(length > 0 && (length % sizeof(u32)) == 0); 763 ASSERT(length > 0 && (length % sizeof(u32)) == 0);
760 supported_npad_id_types.clear(); 764 supported_npad_id_types.clear();
761 supported_npad_id_types.resize(length / sizeof(u32)); 765 supported_npad_id_types.resize(length / sizeof(u32));
762 std::memcpy(supported_npad_id_types.data(), data, length); 766 std::memcpy(supported_npad_id_types.data(), data.data(), length);
763} 767}
764 768
765void Controller_NPad::GetSupportedNpadIdTypes(u32* data, std::size_t max_length) { 769void Controller_NPad::GetSupportedNpadIdTypes(u32* data, std::size_t max_length) {
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index 1a589cca2..1f7d33459 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -6,6 +6,7 @@
6#include <array> 6#include <array>
7#include <atomic> 7#include <atomic>
8#include <mutex> 8#include <mutex>
9#include <span>
9 10
10#include "common/bit_field.h" 11#include "common/bit_field.h"
11#include "common/common_types.h" 12#include "common/common_types.h"
@@ -95,7 +96,7 @@ public:
95 void SetSupportedStyleSet(Core::HID::NpadStyleTag style_set); 96 void SetSupportedStyleSet(Core::HID::NpadStyleTag style_set);
96 Core::HID::NpadStyleTag GetSupportedStyleSet() const; 97 Core::HID::NpadStyleTag GetSupportedStyleSet() const;
97 98
98 void SetSupportedNpadIdTypes(u8* data, std::size_t length); 99 void SetSupportedNpadIdTypes(std::span<const u8> data);
99 void GetSupportedNpadIdTypes(u32* data, std::size_t max_length); 100 void GetSupportedNpadIdTypes(u32* data, std::size_t max_length);
100 std::size_t GetSupportedNpadIdTypesSize() const; 101 std::size_t GetSupportedNpadIdTypesSize() const;
101 102
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index bf28440c6..f15f1a6bb 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -1026,7 +1026,7 @@ void Hid::SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) {
1026 const auto applet_resource_user_id{rp.Pop<u64>()}; 1026 const auto applet_resource_user_id{rp.Pop<u64>()};
1027 1027
1028 applet_resource->GetController<Controller_NPad>(HidController::NPad) 1028 applet_resource->GetController<Controller_NPad>(HidController::NPad)
1029 .SetSupportedNpadIdTypes(ctx.ReadBuffer().data(), ctx.GetReadBufferSize()); 1029 .SetSupportedNpadIdTypes(ctx.ReadBuffer());
1030 1030
1031 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 1031 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
1032 1032
@@ -2104,7 +2104,7 @@ void Hid::WritePalmaRgbLedPatternEntry(Kernel::HLERequestContext& ctx) {
2104 const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()}; 2104 const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
2105 const auto unknown{rp.Pop<u64>()}; 2105 const auto unknown{rp.Pop<u64>()};
2106 2106
2107 const auto buffer = ctx.ReadBuffer(); 2107 [[maybe_unused]] const auto buffer = ctx.ReadBuffer();
2108 2108
2109 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}, unknown={}", 2109 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}, unknown={}",
2110 connection_handle.npad_id, unknown); 2110 connection_handle.npad_id, unknown);
diff --git a/src/core/hle/service/hid/hidbus/hidbus_base.h b/src/core/hle/service/hid/hidbus/hidbus_base.h
index d3960f506..65e301137 100644
--- a/src/core/hle/service/hid/hidbus/hidbus_base.h
+++ b/src/core/hle/service/hid/hidbus/hidbus_base.h
@@ -4,6 +4,7 @@
4#pragma once 4#pragma once
5 5
6#include <array> 6#include <array>
7#include <span>
7#include "common/common_types.h" 8#include "common/common_types.h"
8#include "core/hle/result.h" 9#include "core/hle/result.h"
9 10
@@ -150,7 +151,7 @@ public:
150 } 151 }
151 152
152 // Assigns a command from data 153 // Assigns a command from data
153 virtual bool SetCommand(const std::vector<u8>& data) { 154 virtual bool SetCommand(std::span<const u8> data) {
154 return {}; 155 return {};
155 } 156 }
156 157
diff --git a/src/core/hle/service/hid/hidbus/ringcon.cpp b/src/core/hle/service/hid/hidbus/ringcon.cpp
index 78ed47014..35847cbdd 100644
--- a/src/core/hle/service/hid/hidbus/ringcon.cpp
+++ b/src/core/hle/service/hid/hidbus/ringcon.cpp
@@ -116,7 +116,7 @@ std::vector<u8> RingController::GetReply() const {
116 } 116 }
117} 117}
118 118
119bool RingController::SetCommand(const std::vector<u8>& data) { 119bool RingController::SetCommand(std::span<const u8> data) {
120 if (data.size() < 4) { 120 if (data.size() < 4) {
121 LOG_ERROR(Service_HID, "Command size not supported {}", data.size()); 121 LOG_ERROR(Service_HID, "Command size not supported {}", data.size());
122 command = RingConCommands::Error; 122 command = RingConCommands::Error;
diff --git a/src/core/hle/service/hid/hidbus/ringcon.h b/src/core/hle/service/hid/hidbus/ringcon.h
index 845ce85a5..c2fb386b1 100644
--- a/src/core/hle/service/hid/hidbus/ringcon.h
+++ b/src/core/hle/service/hid/hidbus/ringcon.h
@@ -4,6 +4,7 @@
4#pragma once 4#pragma once
5 5
6#include <array> 6#include <array>
7#include <span>
7 8
8#include "common/common_types.h" 9#include "common/common_types.h"
9#include "core/hle/service/hid/hidbus/hidbus_base.h" 10#include "core/hle/service/hid/hidbus/hidbus_base.h"
@@ -31,7 +32,7 @@ public:
31 u8 GetDeviceId() const override; 32 u8 GetDeviceId() const override;
32 33
33 // Assigns a command from data 34 // Assigns a command from data
34 bool SetCommand(const std::vector<u8>& data) override; 35 bool SetCommand(std::span<const u8> data) override;
35 36
36 // Returns a reply from a command 37 // Returns a reply from a command
37 std::vector<u8> GetReply() const override; 38 std::vector<u8> GetReply() const override;
diff --git a/src/core/hle/service/hid/hidbus/starlink.cpp b/src/core/hle/service/hid/hidbus/starlink.cpp
index dd439f60a..d0e760314 100644
--- a/src/core/hle/service/hid/hidbus/starlink.cpp
+++ b/src/core/hle/service/hid/hidbus/starlink.cpp
@@ -42,7 +42,7 @@ std::vector<u8> Starlink::GetReply() const {
42 return {}; 42 return {};
43} 43}
44 44
45bool Starlink::SetCommand(const std::vector<u8>& data) { 45bool Starlink::SetCommand(std::span<const u8> data) {
46 LOG_ERROR(Service_HID, "Command not implemented"); 46 LOG_ERROR(Service_HID, "Command not implemented");
47 return false; 47 return false;
48} 48}
diff --git a/src/core/hle/service/hid/hidbus/starlink.h b/src/core/hle/service/hid/hidbus/starlink.h
index 0b1b7ba49..07c800e6e 100644
--- a/src/core/hle/service/hid/hidbus/starlink.h
+++ b/src/core/hle/service/hid/hidbus/starlink.h
@@ -29,7 +29,7 @@ public:
29 u8 GetDeviceId() const override; 29 u8 GetDeviceId() const override;
30 30
31 // Assigns a command from data 31 // Assigns a command from data
32 bool SetCommand(const std::vector<u8>& data) override; 32 bool SetCommand(std::span<const u8> data) override;
33 33
34 // Returns a reply from a command 34 // Returns a reply from a command
35 std::vector<u8> GetReply() const override; 35 std::vector<u8> GetReply() const override;
diff --git a/src/core/hle/service/hid/hidbus/stubbed.cpp b/src/core/hle/service/hid/hidbus/stubbed.cpp
index e477443e3..07632c872 100644
--- a/src/core/hle/service/hid/hidbus/stubbed.cpp
+++ b/src/core/hle/service/hid/hidbus/stubbed.cpp
@@ -43,7 +43,7 @@ std::vector<u8> HidbusStubbed::GetReply() const {
43 return {}; 43 return {};
44} 44}
45 45
46bool HidbusStubbed::SetCommand(const std::vector<u8>& data) { 46bool HidbusStubbed::SetCommand(std::span<const u8> data) {
47 LOG_ERROR(Service_HID, "Command not implemented"); 47 LOG_ERROR(Service_HID, "Command not implemented");
48 return false; 48 return false;
49} 49}
diff --git a/src/core/hle/service/hid/hidbus/stubbed.h b/src/core/hle/service/hid/hidbus/stubbed.h
index 91165ceff..38eaa0ecc 100644
--- a/src/core/hle/service/hid/hidbus/stubbed.h
+++ b/src/core/hle/service/hid/hidbus/stubbed.h
@@ -29,7 +29,7 @@ public:
29 u8 GetDeviceId() const override; 29 u8 GetDeviceId() const override;
30 30
31 // Assigns a command from data 31 // Assigns a command from data
32 bool SetCommand(const std::vector<u8>& data) override; 32 bool SetCommand(std::span<const u8> data) override;
33 33
34 // Returns a reply from a command 34 // Returns a reply from a command
35 std::vector<u8> GetReply() const override; 35 std::vector<u8> GetReply() const override;
diff --git a/src/core/hle/service/jit/jit.cpp b/src/core/hle/service/jit/jit.cpp
index 8f2920c51..1295a44c7 100644
--- a/src/core/hle/service/jit/jit.cpp
+++ b/src/core/hle/service/jit/jit.cpp
@@ -62,7 +62,7 @@ public:
62 const auto parameters{rp.PopRaw<InputParameters>()}; 62 const auto parameters{rp.PopRaw<InputParameters>()};
63 63
64 // Optional input/output buffers 64 // Optional input/output buffers
65 std::vector<u8> input_buffer{ctx.CanReadBuffer() ? ctx.ReadBuffer() : std::vector<u8>()}; 65 const auto input_buffer{ctx.CanReadBuffer() ? ctx.ReadBuffer() : std::span<const u8>()};
66 std::vector<u8> output_buffer(ctx.CanWriteBuffer() ? ctx.GetWriteBufferSize() : 0); 66 std::vector<u8> output_buffer(ctx.CanWriteBuffer() ? ctx.GetWriteBufferSize() : 0);
67 67
68 // Function call prototype: 68 // Function call prototype:
@@ -132,7 +132,7 @@ public:
132 const auto command{rp.PopRaw<u64>()}; 132 const auto command{rp.PopRaw<u64>()};
133 133
134 // Optional input/output buffers 134 // Optional input/output buffers
135 std::vector<u8> input_buffer{ctx.CanReadBuffer() ? ctx.ReadBuffer() : std::vector<u8>()}; 135 const auto input_buffer{ctx.CanReadBuffer() ? ctx.ReadBuffer() : std::span<const u8>()};
136 std::vector<u8> output_buffer(ctx.CanWriteBuffer() ? ctx.GetWriteBufferSize() : 0); 136 std::vector<u8> output_buffer(ctx.CanWriteBuffer() ? ctx.GetWriteBufferSize() : 0);
137 137
138 // Function call prototype: 138 // Function call prototype:
diff --git a/src/core/hle/service/ldn/ldn.cpp b/src/core/hle/service/ldn/ldn.cpp
index c49c61cff..e5099d61f 100644
--- a/src/core/hle/service/ldn/ldn.cpp
+++ b/src/core/hle/service/ldn/ldn.cpp
@@ -412,7 +412,7 @@ public:
412 } 412 }
413 413
414 void SetAdvertiseData(Kernel::HLERequestContext& ctx) { 414 void SetAdvertiseData(Kernel::HLERequestContext& ctx) {
415 std::vector<u8> read_buffer = ctx.ReadBuffer(); 415 const auto read_buffer = ctx.ReadBuffer();
416 416
417 IPC::ResponseBuilder rb{ctx, 2}; 417 IPC::ResponseBuilder rb{ctx, 2};
418 rb.Push(lan_discovery.SetAdvertiseData(read_buffer)); 418 rb.Push(lan_discovery.SetAdvertiseData(read_buffer));
@@ -464,7 +464,7 @@ public:
464 parameters.security_config.passphrase_size, 464 parameters.security_config.passphrase_size,
465 parameters.security_config.security_mode, parameters.local_communication_version); 465 parameters.security_config.security_mode, parameters.local_communication_version);
466 466
467 const std::vector<u8> read_buffer = ctx.ReadBuffer(); 467 const auto read_buffer = ctx.ReadBuffer();
468 if (read_buffer.size() != sizeof(NetworkInfo)) { 468 if (read_buffer.size() != sizeof(NetworkInfo)) {
469 LOG_ERROR(Frontend, "NetworkInfo doesn't match read_buffer size!"); 469 LOG_ERROR(Frontend, "NetworkInfo doesn't match read_buffer size!");
470 IPC::ResponseBuilder rb{ctx, 2}; 470 IPC::ResponseBuilder rb{ctx, 2};
diff --git a/src/core/hle/service/nvdrv/devices/nvdevice.h b/src/core/hle/service/nvdrv/devices/nvdevice.h
index 204b0e757..c562e04d2 100644
--- a/src/core/hle/service/nvdrv/devices/nvdevice.h
+++ b/src/core/hle/service/nvdrv/devices/nvdevice.h
@@ -3,7 +3,9 @@
3 3
4#pragma once 4#pragma once
5 5
6#include <span>
6#include <vector> 7#include <vector>
8
7#include "common/common_types.h" 9#include "common/common_types.h"
8#include "core/hle/service/nvdrv/nvdata.h" 10#include "core/hle/service/nvdrv/nvdata.h"
9 11
@@ -31,7 +33,7 @@ public:
31 * @param output A buffer where the output data will be written to. 33 * @param output A buffer where the output data will be written to.
32 * @returns The result code of the ioctl. 34 * @returns The result code of the ioctl.
33 */ 35 */
34 virtual NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 36 virtual NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
35 std::vector<u8>& output) = 0; 37 std::vector<u8>& output) = 0;
36 38
37 /** 39 /**
@@ -42,8 +44,8 @@ public:
42 * @param output A buffer where the output data will be written to. 44 * @param output A buffer where the output data will be written to.
43 * @returns The result code of the ioctl. 45 * @returns The result code of the ioctl.
44 */ 46 */
45 virtual NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 47 virtual NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
46 const std::vector<u8>& inline_input, std::vector<u8>& output) = 0; 48 std::span<const u8> inline_input, std::vector<u8>& output) = 0;
47 49
48 /** 50 /**
49 * Handles an ioctl3 request. 51 * Handles an ioctl3 request.
@@ -53,7 +55,7 @@ public:
53 * @param inline_output A buffer where the inlined output data will be written to. 55 * @param inline_output A buffer where the inlined output data will be written to.
54 * @returns The result code of the ioctl. 56 * @returns The result code of the ioctl.
55 */ 57 */
56 virtual NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 58 virtual NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input,
57 std::vector<u8>& output, std::vector<u8>& inline_output) = 0; 59 std::vector<u8>& output, std::vector<u8>& inline_output) = 0;
58 60
59 /** 61 /**
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
index 4122fc98d..5a5b2e305 100644
--- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
@@ -17,19 +17,19 @@ nvdisp_disp0::nvdisp_disp0(Core::System& system_, NvCore::Container& core)
17 : nvdevice{system_}, container{core}, nvmap{core.GetNvMapFile()} {} 17 : nvdevice{system_}, container{core}, nvmap{core.GetNvMapFile()} {}
18nvdisp_disp0::~nvdisp_disp0() = default; 18nvdisp_disp0::~nvdisp_disp0() = default;
19 19
20NvResult nvdisp_disp0::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 20NvResult nvdisp_disp0::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
21 std::vector<u8>& output) { 21 std::vector<u8>& output) {
22 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); 22 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
23 return NvResult::NotImplemented; 23 return NvResult::NotImplemented;
24} 24}
25 25
26NvResult nvdisp_disp0::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 26NvResult nvdisp_disp0::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
27 const std::vector<u8>& inline_input, std::vector<u8>& output) { 27 std::span<const u8> inline_input, std::vector<u8>& output) {
28 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); 28 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
29 return NvResult::NotImplemented; 29 return NvResult::NotImplemented;
30} 30}
31 31
32NvResult nvdisp_disp0::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 32NvResult nvdisp_disp0::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input,
33 std::vector<u8>& output, std::vector<u8>& inline_output) { 33 std::vector<u8>& output, std::vector<u8>& inline_output) {
34 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); 34 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
35 return NvResult::NotImplemented; 35 return NvResult::NotImplemented;
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
index 04217ab12..81bd7960a 100644
--- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
+++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
@@ -25,12 +25,12 @@ public:
25 explicit nvdisp_disp0(Core::System& system_, NvCore::Container& core); 25 explicit nvdisp_disp0(Core::System& system_, NvCore::Container& core);
26 ~nvdisp_disp0() override; 26 ~nvdisp_disp0() override;
27 27
28 NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 28 NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
29 std::vector<u8>& output) override; 29 std::vector<u8>& output) override;
30 NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 30 NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
31 const std::vector<u8>& inline_input, std::vector<u8>& output) override; 31 std::span<const u8> inline_input, std::vector<u8>& output) override;
32 NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 32 NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output,
33 std::vector<u8>& output, std::vector<u8>& inline_output) override; 33 std::vector<u8>& inline_output) override;
34 34
35 void OnOpen(DeviceFD fd) override; 35 void OnOpen(DeviceFD fd) override;
36 void OnClose(DeviceFD fd) override; 36 void OnClose(DeviceFD fd) override;
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
index b635e6ed1..681bd0867 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
@@ -27,7 +27,7 @@ nvhost_as_gpu::nvhost_as_gpu(Core::System& system_, Module& module_, NvCore::Con
27 27
28nvhost_as_gpu::~nvhost_as_gpu() = default; 28nvhost_as_gpu::~nvhost_as_gpu() = default;
29 29
30NvResult nvhost_as_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 30NvResult nvhost_as_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
31 std::vector<u8>& output) { 31 std::vector<u8>& output) {
32 switch (command.group) { 32 switch (command.group) {
33 case 'A': 33 case 'A':
@@ -60,13 +60,13 @@ NvResult nvhost_as_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>
60 return NvResult::NotImplemented; 60 return NvResult::NotImplemented;
61} 61}
62 62
63NvResult nvhost_as_gpu::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 63NvResult nvhost_as_gpu::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
64 const std::vector<u8>& inline_input, std::vector<u8>& output) { 64 std::span<const u8> inline_input, std::vector<u8>& output) {
65 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); 65 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
66 return NvResult::NotImplemented; 66 return NvResult::NotImplemented;
67} 67}
68 68
69NvResult nvhost_as_gpu::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 69NvResult nvhost_as_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input,
70 std::vector<u8>& output, std::vector<u8>& inline_output) { 70 std::vector<u8>& output, std::vector<u8>& inline_output) {
71 switch (command.group) { 71 switch (command.group) {
72 case 'A': 72 case 'A':
@@ -87,7 +87,7 @@ NvResult nvhost_as_gpu::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>
87void nvhost_as_gpu::OnOpen(DeviceFD fd) {} 87void nvhost_as_gpu::OnOpen(DeviceFD fd) {}
88void nvhost_as_gpu::OnClose(DeviceFD fd) {} 88void nvhost_as_gpu::OnClose(DeviceFD fd) {}
89 89
90NvResult nvhost_as_gpu::AllocAsEx(const std::vector<u8>& input, std::vector<u8>& output) { 90NvResult nvhost_as_gpu::AllocAsEx(std::span<const u8> input, std::vector<u8>& output) {
91 IoctlAllocAsEx params{}; 91 IoctlAllocAsEx params{};
92 std::memcpy(&params, input.data(), input.size()); 92 std::memcpy(&params, input.data(), input.size());
93 93
@@ -141,7 +141,7 @@ NvResult nvhost_as_gpu::AllocAsEx(const std::vector<u8>& input, std::vector<u8>&
141 return NvResult::Success; 141 return NvResult::Success;
142} 142}
143 143
144NvResult nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output) { 144NvResult nvhost_as_gpu::AllocateSpace(std::span<const u8> input, std::vector<u8>& output) {
145 IoctlAllocSpace params{}; 145 IoctlAllocSpace params{};
146 std::memcpy(&params, input.data(), input.size()); 146 std::memcpy(&params, input.data(), input.size());
147 147
@@ -220,7 +220,7 @@ void nvhost_as_gpu::FreeMappingLocked(u64 offset) {
220 mapping_map.erase(offset); 220 mapping_map.erase(offset);
221} 221}
222 222
223NvResult nvhost_as_gpu::FreeSpace(const std::vector<u8>& input, std::vector<u8>& output) { 223NvResult nvhost_as_gpu::FreeSpace(std::span<const u8> input, std::vector<u8>& output) {
224 IoctlFreeSpace params{}; 224 IoctlFreeSpace params{};
225 std::memcpy(&params, input.data(), input.size()); 225 std::memcpy(&params, input.data(), input.size());
226 226
@@ -266,7 +266,7 @@ NvResult nvhost_as_gpu::FreeSpace(const std::vector<u8>& input, std::vector<u8>&
266 return NvResult::Success; 266 return NvResult::Success;
267} 267}
268 268
269NvResult nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) { 269NvResult nvhost_as_gpu::Remap(std::span<const u8> input, std::vector<u8>& output) {
270 const auto num_entries = input.size() / sizeof(IoctlRemapEntry); 270 const auto num_entries = input.size() / sizeof(IoctlRemapEntry);
271 271
272 LOG_DEBUG(Service_NVDRV, "called, num_entries=0x{:X}", num_entries); 272 LOG_DEBUG(Service_NVDRV, "called, num_entries=0x{:X}", num_entries);
@@ -320,7 +320,7 @@ NvResult nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& out
320 return NvResult::Success; 320 return NvResult::Success;
321} 321}
322 322
323NvResult nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) { 323NvResult nvhost_as_gpu::MapBufferEx(std::span<const u8> input, std::vector<u8>& output) {
324 IoctlMapBufferEx params{}; 324 IoctlMapBufferEx params{};
325 std::memcpy(&params, input.data(), input.size()); 325 std::memcpy(&params, input.data(), input.size());
326 326
@@ -424,7 +424,7 @@ NvResult nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8
424 return NvResult::Success; 424 return NvResult::Success;
425} 425}
426 426
427NvResult nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) { 427NvResult nvhost_as_gpu::UnmapBuffer(std::span<const u8> input, std::vector<u8>& output) {
428 IoctlUnmapBuffer params{}; 428 IoctlUnmapBuffer params{};
429 std::memcpy(&params, input.data(), input.size()); 429 std::memcpy(&params, input.data(), input.size());
430 430
@@ -463,7 +463,7 @@ NvResult nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8
463 return NvResult::Success; 463 return NvResult::Success;
464} 464}
465 465
466NvResult nvhost_as_gpu::BindChannel(const std::vector<u8>& input, std::vector<u8>& output) { 466NvResult nvhost_as_gpu::BindChannel(std::span<const u8> input, std::vector<u8>& output) {
467 IoctlBindChannel params{}; 467 IoctlBindChannel params{};
468 std::memcpy(&params, input.data(), input.size()); 468 std::memcpy(&params, input.data(), input.size());
469 LOG_DEBUG(Service_NVDRV, "called, fd={:X}", params.fd); 469 LOG_DEBUG(Service_NVDRV, "called, fd={:X}", params.fd);
@@ -492,7 +492,7 @@ void nvhost_as_gpu::GetVARegionsImpl(IoctlGetVaRegions& params) {
492 }; 492 };
493} 493}
494 494
495NvResult nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& output) { 495NvResult nvhost_as_gpu::GetVARegions(std::span<const u8> input, std::vector<u8>& output) {
496 IoctlGetVaRegions params{}; 496 IoctlGetVaRegions params{};
497 std::memcpy(&params, input.data(), input.size()); 497 std::memcpy(&params, input.data(), input.size());
498 498
@@ -511,7 +511,7 @@ NvResult nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u
511 return NvResult::Success; 511 return NvResult::Success;
512} 512}
513 513
514NvResult nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& output, 514NvResult nvhost_as_gpu::GetVARegions(std::span<const u8> input, std::vector<u8>& output,
515 std::vector<u8>& inline_output) { 515 std::vector<u8>& inline_output) {
516 IoctlGetVaRegions params{}; 516 IoctlGetVaRegions params{};
517 std::memcpy(&params, input.data(), input.size()); 517 std::memcpy(&params, input.data(), input.size());
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
index 86fe71c75..1aba8d579 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
@@ -47,12 +47,12 @@ public:
47 explicit nvhost_as_gpu(Core::System& system_, Module& module, NvCore::Container& core); 47 explicit nvhost_as_gpu(Core::System& system_, Module& module, NvCore::Container& core);
48 ~nvhost_as_gpu() override; 48 ~nvhost_as_gpu() override;
49 49
50 NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 50 NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
51 std::vector<u8>& output) override; 51 std::vector<u8>& output) override;
52 NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 52 NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
53 const std::vector<u8>& inline_input, std::vector<u8>& output) override; 53 std::span<const u8> inline_input, std::vector<u8>& output) override;
54 NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 54 NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output,
55 std::vector<u8>& output, std::vector<u8>& inline_output) override; 55 std::vector<u8>& inline_output) override;
56 56
57 void OnOpen(DeviceFD fd) override; 57 void OnOpen(DeviceFD fd) override;
58 void OnClose(DeviceFD fd) override; 58 void OnClose(DeviceFD fd) override;
@@ -138,17 +138,17 @@ private:
138 static_assert(sizeof(IoctlGetVaRegions) == 16 + sizeof(VaRegion) * 2, 138 static_assert(sizeof(IoctlGetVaRegions) == 16 + sizeof(VaRegion) * 2,
139 "IoctlGetVaRegions is incorrect size"); 139 "IoctlGetVaRegions is incorrect size");
140 140
141 NvResult AllocAsEx(const std::vector<u8>& input, std::vector<u8>& output); 141 NvResult AllocAsEx(std::span<const u8> input, std::vector<u8>& output);
142 NvResult AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output); 142 NvResult AllocateSpace(std::span<const u8> input, std::vector<u8>& output);
143 NvResult Remap(const std::vector<u8>& input, std::vector<u8>& output); 143 NvResult Remap(std::span<const u8> input, std::vector<u8>& output);
144 NvResult MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output); 144 NvResult MapBufferEx(std::span<const u8> input, std::vector<u8>& output);
145 NvResult UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output); 145 NvResult UnmapBuffer(std::span<const u8> input, std::vector<u8>& output);
146 NvResult FreeSpace(const std::vector<u8>& input, std::vector<u8>& output); 146 NvResult FreeSpace(std::span<const u8> input, std::vector<u8>& output);
147 NvResult BindChannel(const std::vector<u8>& input, std::vector<u8>& output); 147 NvResult BindChannel(std::span<const u8> input, std::vector<u8>& output);
148 148
149 void GetVARegionsImpl(IoctlGetVaRegions& params); 149 void GetVARegionsImpl(IoctlGetVaRegions& params);
150 NvResult GetVARegions(const std::vector<u8>& input, std::vector<u8>& output); 150 NvResult GetVARegions(std::span<const u8> input, std::vector<u8>& output);
151 NvResult GetVARegions(const std::vector<u8>& input, std::vector<u8>& output, 151 NvResult GetVARegions(std::span<const u8> input, std::vector<u8>& output,
152 std::vector<u8>& inline_output); 152 std::vector<u8>& inline_output);
153 153
154 void FreeMappingLocked(u64 offset); 154 void FreeMappingLocked(u64 offset);
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
index eee11fab8..0cdde82a7 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
@@ -34,7 +34,7 @@ nvhost_ctrl::~nvhost_ctrl() {
34 } 34 }
35} 35}
36 36
37NvResult nvhost_ctrl::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 37NvResult nvhost_ctrl::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
38 std::vector<u8>& output) { 38 std::vector<u8>& output) {
39 switch (command.group) { 39 switch (command.group) {
40 case 0x0: 40 case 0x0:
@@ -63,13 +63,13 @@ NvResult nvhost_ctrl::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>&
63 return NvResult::NotImplemented; 63 return NvResult::NotImplemented;
64} 64}
65 65
66NvResult nvhost_ctrl::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 66NvResult nvhost_ctrl::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
67 const std::vector<u8>& inline_input, std::vector<u8>& output) { 67 std::span<const u8> inline_input, std::vector<u8>& output) {
68 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); 68 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
69 return NvResult::NotImplemented; 69 return NvResult::NotImplemented;
70} 70}
71 71
72NvResult nvhost_ctrl::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 72NvResult nvhost_ctrl::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input,
73 std::vector<u8>& output, std::vector<u8>& inline_outpu) { 73 std::vector<u8>& output, std::vector<u8>& inline_outpu) {
74 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); 74 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
75 return NvResult::NotImplemented; 75 return NvResult::NotImplemented;
@@ -79,7 +79,7 @@ void nvhost_ctrl::OnOpen(DeviceFD fd) {}
79 79
80void nvhost_ctrl::OnClose(DeviceFD fd) {} 80void nvhost_ctrl::OnClose(DeviceFD fd) {}
81 81
82NvResult nvhost_ctrl::NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output) { 82NvResult nvhost_ctrl::NvOsGetConfigU32(std::span<const u8> input, std::vector<u8>& output) {
83 IocGetConfigParams params{}; 83 IocGetConfigParams params{};
84 std::memcpy(&params, input.data(), sizeof(params)); 84 std::memcpy(&params, input.data(), sizeof(params));
85 LOG_TRACE(Service_NVDRV, "called, setting={}!{}", params.domain_str.data(), 85 LOG_TRACE(Service_NVDRV, "called, setting={}!{}", params.domain_str.data(),
@@ -87,7 +87,7 @@ NvResult nvhost_ctrl::NvOsGetConfigU32(const std::vector<u8>& input, std::vector
87 return NvResult::ConfigVarNotFound; // Returns error on production mode 87 return NvResult::ConfigVarNotFound; // Returns error on production mode
88} 88}
89 89
90NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, 90NvResult nvhost_ctrl::IocCtrlEventWait(std::span<const u8> input, std::vector<u8>& output,
91 bool is_allocation) { 91 bool is_allocation) {
92 IocCtrlEventWaitParams params{}; 92 IocCtrlEventWaitParams params{};
93 std::memcpy(&params, input.data(), sizeof(params)); 93 std::memcpy(&params, input.data(), sizeof(params));
@@ -231,7 +231,7 @@ NvResult nvhost_ctrl::FreeEvent(u32 slot) {
231 return NvResult::Success; 231 return NvResult::Success;
232} 232}
233 233
234NvResult nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output) { 234NvResult nvhost_ctrl::IocCtrlEventRegister(std::span<const u8> input, std::vector<u8>& output) {
235 IocCtrlEventRegisterParams params{}; 235 IocCtrlEventRegisterParams params{};
236 std::memcpy(&params, input.data(), sizeof(params)); 236 std::memcpy(&params, input.data(), sizeof(params));
237 const u32 event_id = params.user_event_id; 237 const u32 event_id = params.user_event_id;
@@ -252,8 +252,7 @@ NvResult nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::ve
252 return NvResult::Success; 252 return NvResult::Success;
253} 253}
254 254
255NvResult nvhost_ctrl::IocCtrlEventUnregister(const std::vector<u8>& input, 255NvResult nvhost_ctrl::IocCtrlEventUnregister(std::span<const u8> input, std::vector<u8>& output) {
256 std::vector<u8>& output) {
257 IocCtrlEventUnregisterParams params{}; 256 IocCtrlEventUnregisterParams params{};
258 std::memcpy(&params, input.data(), sizeof(params)); 257 std::memcpy(&params, input.data(), sizeof(params));
259 const u32 event_id = params.user_event_id & 0x00FF; 258 const u32 event_id = params.user_event_id & 0x00FF;
@@ -263,7 +262,7 @@ NvResult nvhost_ctrl::IocCtrlEventUnregister(const std::vector<u8>& input,
263 return FreeEvent(event_id); 262 return FreeEvent(event_id);
264} 263}
265 264
266NvResult nvhost_ctrl::IocCtrlEventUnregisterBatch(const std::vector<u8>& input, 265NvResult nvhost_ctrl::IocCtrlEventUnregisterBatch(std::span<const u8> input,
267 std::vector<u8>& output) { 266 std::vector<u8>& output) {
268 IocCtrlEventUnregisterBatchParams params{}; 267 IocCtrlEventUnregisterBatchParams params{};
269 std::memcpy(&params, input.data(), sizeof(params)); 268 std::memcpy(&params, input.data(), sizeof(params));
@@ -282,7 +281,7 @@ NvResult nvhost_ctrl::IocCtrlEventUnregisterBatch(const std::vector<u8>& input,
282 return NvResult::Success; 281 return NvResult::Success;
283} 282}
284 283
285NvResult nvhost_ctrl::IocCtrlClearEventWait(const std::vector<u8>& input, std::vector<u8>& output) { 284NvResult nvhost_ctrl::IocCtrlClearEventWait(std::span<const u8> input, std::vector<u8>& output) {
286 IocCtrlEventClearParams params{}; 285 IocCtrlEventClearParams params{};
287 std::memcpy(&params, input.data(), sizeof(params)); 286 std::memcpy(&params, input.data(), sizeof(params));
288 287
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
index 0b56d7070..dd2e7888a 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
@@ -25,12 +25,12 @@ public:
25 NvCore::Container& core); 25 NvCore::Container& core);
26 ~nvhost_ctrl() override; 26 ~nvhost_ctrl() override;
27 27
28 NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 28 NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
29 std::vector<u8>& output) override; 29 std::vector<u8>& output) override;
30 NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 30 NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
31 const std::vector<u8>& inline_input, std::vector<u8>& output) override; 31 std::span<const u8> inline_input, std::vector<u8>& output) override;
32 NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 32 NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output,
33 std::vector<u8>& output, std::vector<u8>& inline_output) override; 33 std::vector<u8>& inline_output) override;
34 34
35 void OnOpen(DeviceFD fd) override; 35 void OnOpen(DeviceFD fd) override;
36 void OnClose(DeviceFD fd) override; 36 void OnClose(DeviceFD fd) override;
@@ -186,13 +186,13 @@ private:
186 static_assert(sizeof(IocCtrlEventUnregisterBatchParams) == 8, 186 static_assert(sizeof(IocCtrlEventUnregisterBatchParams) == 8,
187 "IocCtrlEventKill is incorrect size"); 187 "IocCtrlEventKill is incorrect size");
188 188
189 NvResult NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output); 189 NvResult NvOsGetConfigU32(std::span<const u8> input, std::vector<u8>& output);
190 NvResult IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, 190 NvResult IocCtrlEventWait(std::span<const u8> input, std::vector<u8>& output,
191 bool is_allocation); 191 bool is_allocation);
192 NvResult IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output); 192 NvResult IocCtrlEventRegister(std::span<const u8> input, std::vector<u8>& output);
193 NvResult IocCtrlEventUnregister(const std::vector<u8>& input, std::vector<u8>& output); 193 NvResult IocCtrlEventUnregister(std::span<const u8> input, std::vector<u8>& output);
194 NvResult IocCtrlEventUnregisterBatch(const std::vector<u8>& input, std::vector<u8>& output); 194 NvResult IocCtrlEventUnregisterBatch(std::span<const u8> input, std::vector<u8>& output);
195 NvResult IocCtrlClearEventWait(const std::vector<u8>& input, std::vector<u8>& output); 195 NvResult IocCtrlClearEventWait(std::span<const u8> input, std::vector<u8>& output);
196 196
197 NvResult FreeEvent(u32 slot); 197 NvResult FreeEvent(u32 slot);
198 198
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
index b97813fbc..be3c083db 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
@@ -21,7 +21,7 @@ nvhost_ctrl_gpu::~nvhost_ctrl_gpu() {
21 events_interface.FreeEvent(unknown_event); 21 events_interface.FreeEvent(unknown_event);
22} 22}
23 23
24NvResult nvhost_ctrl_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 24NvResult nvhost_ctrl_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
25 std::vector<u8>& output) { 25 std::vector<u8>& output) {
26 switch (command.group) { 26 switch (command.group) {
27 case 'G': 27 case 'G':
@@ -53,13 +53,13 @@ NvResult nvhost_ctrl_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u
53 return NvResult::NotImplemented; 53 return NvResult::NotImplemented;
54} 54}
55 55
56NvResult nvhost_ctrl_gpu::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 56NvResult nvhost_ctrl_gpu::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
57 const std::vector<u8>& inline_input, std::vector<u8>& output) { 57 std::span<const u8> inline_input, std::vector<u8>& output) {
58 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); 58 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
59 return NvResult::NotImplemented; 59 return NvResult::NotImplemented;
60} 60}
61 61
62NvResult nvhost_ctrl_gpu::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 62NvResult nvhost_ctrl_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input,
63 std::vector<u8>& output, std::vector<u8>& inline_output) { 63 std::vector<u8>& output, std::vector<u8>& inline_output) {
64 switch (command.group) { 64 switch (command.group) {
65 case 'G': 65 case 'G':
@@ -82,8 +82,7 @@ NvResult nvhost_ctrl_gpu::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u
82void nvhost_ctrl_gpu::OnOpen(DeviceFD fd) {} 82void nvhost_ctrl_gpu::OnOpen(DeviceFD fd) {}
83void nvhost_ctrl_gpu::OnClose(DeviceFD fd) {} 83void nvhost_ctrl_gpu::OnClose(DeviceFD fd) {}
84 84
85NvResult nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, 85NvResult nvhost_ctrl_gpu::GetCharacteristics(std::span<const u8> input, std::vector<u8>& output) {
86 std::vector<u8>& output) {
87 LOG_DEBUG(Service_NVDRV, "called"); 86 LOG_DEBUG(Service_NVDRV, "called");
88 IoctlCharacteristics params{}; 87 IoctlCharacteristics params{};
89 std::memcpy(&params, input.data(), input.size()); 88 std::memcpy(&params, input.data(), input.size());
@@ -128,7 +127,7 @@ NvResult nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input,
128 return NvResult::Success; 127 return NvResult::Success;
129} 128}
130 129
131NvResult nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output, 130NvResult nvhost_ctrl_gpu::GetCharacteristics(std::span<const u8> input, std::vector<u8>& output,
132 std::vector<u8>& inline_output) { 131 std::vector<u8>& inline_output) {
133 LOG_DEBUG(Service_NVDRV, "called"); 132 LOG_DEBUG(Service_NVDRV, "called");
134 IoctlCharacteristics params{}; 133 IoctlCharacteristics params{};
@@ -176,7 +175,7 @@ NvResult nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::
176 return NvResult::Success; 175 return NvResult::Success;
177} 176}
178 177
179NvResult nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output) { 178NvResult nvhost_ctrl_gpu::GetTPCMasks(std::span<const u8> input, std::vector<u8>& output) {
180 IoctlGpuGetTpcMasksArgs params{}; 179 IoctlGpuGetTpcMasksArgs params{};
181 std::memcpy(&params, input.data(), input.size()); 180 std::memcpy(&params, input.data(), input.size());
182 LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size=0x{:X}", params.mask_buffer_size); 181 LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size=0x{:X}", params.mask_buffer_size);
@@ -187,7 +186,7 @@ NvResult nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<
187 return NvResult::Success; 186 return NvResult::Success;
188} 187}
189 188
190NvResult nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output, 189NvResult nvhost_ctrl_gpu::GetTPCMasks(std::span<const u8> input, std::vector<u8>& output,
191 std::vector<u8>& inline_output) { 190 std::vector<u8>& inline_output) {
192 IoctlGpuGetTpcMasksArgs params{}; 191 IoctlGpuGetTpcMasksArgs params{};
193 std::memcpy(&params, input.data(), input.size()); 192 std::memcpy(&params, input.data(), input.size());
@@ -200,7 +199,7 @@ NvResult nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<
200 return NvResult::Success; 199 return NvResult::Success;
201} 200}
202 201
203NvResult nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output) { 202NvResult nvhost_ctrl_gpu::GetActiveSlotMask(std::span<const u8> input, std::vector<u8>& output) {
204 LOG_DEBUG(Service_NVDRV, "called"); 203 LOG_DEBUG(Service_NVDRV, "called");
205 204
206 IoctlActiveSlotMask params{}; 205 IoctlActiveSlotMask params{};
@@ -213,7 +212,7 @@ NvResult nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::v
213 return NvResult::Success; 212 return NvResult::Success;
214} 213}
215 214
216NvResult nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output) { 215NvResult nvhost_ctrl_gpu::ZCullGetCtxSize(std::span<const u8> input, std::vector<u8>& output) {
217 LOG_DEBUG(Service_NVDRV, "called"); 216 LOG_DEBUG(Service_NVDRV, "called");
218 217
219 IoctlZcullGetCtxSize params{}; 218 IoctlZcullGetCtxSize params{};
@@ -225,7 +224,7 @@ NvResult nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vec
225 return NvResult::Success; 224 return NvResult::Success;
226} 225}
227 226
228NvResult nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output) { 227NvResult nvhost_ctrl_gpu::ZCullGetInfo(std::span<const u8> input, std::vector<u8>& output) {
229 LOG_DEBUG(Service_NVDRV, "called"); 228 LOG_DEBUG(Service_NVDRV, "called");
230 229
231 IoctlNvgpuGpuZcullGetInfoArgs params{}; 230 IoctlNvgpuGpuZcullGetInfoArgs params{};
@@ -248,7 +247,7 @@ NvResult nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector
248 return NvResult::Success; 247 return NvResult::Success;
249} 248}
250 249
251NvResult nvhost_ctrl_gpu::ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output) { 250NvResult nvhost_ctrl_gpu::ZBCSetTable(std::span<const u8> input, std::vector<u8>& output) {
252 LOG_WARNING(Service_NVDRV, "(STUBBED) called"); 251 LOG_WARNING(Service_NVDRV, "(STUBBED) called");
253 252
254 IoctlZbcSetTable params{}; 253 IoctlZbcSetTable params{};
@@ -264,7 +263,7 @@ NvResult nvhost_ctrl_gpu::ZBCSetTable(const std::vector<u8>& input, std::vector<
264 return NvResult::Success; 263 return NvResult::Success;
265} 264}
266 265
267NvResult nvhost_ctrl_gpu::ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output) { 266NvResult nvhost_ctrl_gpu::ZBCQueryTable(std::span<const u8> input, std::vector<u8>& output) {
268 LOG_WARNING(Service_NVDRV, "(STUBBED) called"); 267 LOG_WARNING(Service_NVDRV, "(STUBBED) called");
269 268
270 IoctlZbcQueryTable params{}; 269 IoctlZbcQueryTable params{};
@@ -274,7 +273,7 @@ NvResult nvhost_ctrl_gpu::ZBCQueryTable(const std::vector<u8>& input, std::vecto
274 return NvResult::Success; 273 return NvResult::Success;
275} 274}
276 275
277NvResult nvhost_ctrl_gpu::FlushL2(const std::vector<u8>& input, std::vector<u8>& output) { 276NvResult nvhost_ctrl_gpu::FlushL2(std::span<const u8> input, std::vector<u8>& output) {
278 LOG_WARNING(Service_NVDRV, "(STUBBED) called"); 277 LOG_WARNING(Service_NVDRV, "(STUBBED) called");
279 278
280 IoctlFlushL2 params{}; 279 IoctlFlushL2 params{};
@@ -284,7 +283,7 @@ NvResult nvhost_ctrl_gpu::FlushL2(const std::vector<u8>& input, std::vector<u8>&
284 return NvResult::Success; 283 return NvResult::Success;
285} 284}
286 285
287NvResult nvhost_ctrl_gpu::GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output) { 286NvResult nvhost_ctrl_gpu::GetGpuTime(std::span<const u8> input, std::vector<u8>& output) {
288 LOG_DEBUG(Service_NVDRV, "called"); 287 LOG_DEBUG(Service_NVDRV, "called");
289 288
290 IoctlGetGpuTime params{}; 289 IoctlGetGpuTime params{};
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
index 1e8f254e2..b9333d9d3 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
@@ -21,12 +21,12 @@ public:
21 explicit nvhost_ctrl_gpu(Core::System& system_, EventInterface& events_interface_); 21 explicit nvhost_ctrl_gpu(Core::System& system_, EventInterface& events_interface_);
22 ~nvhost_ctrl_gpu() override; 22 ~nvhost_ctrl_gpu() override;
23 23
24 NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 24 NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
25 std::vector<u8>& output) override; 25 std::vector<u8>& output) override;
26 NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 26 NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
27 const std::vector<u8>& inline_input, std::vector<u8>& output) override; 27 std::span<const u8> inline_input, std::vector<u8>& output) override;
28 NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 28 NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output,
29 std::vector<u8>& output, std::vector<u8>& inline_output) override; 29 std::vector<u8>& inline_output) override;
30 30
31 void OnOpen(DeviceFD fd) override; 31 void OnOpen(DeviceFD fd) override;
32 void OnClose(DeviceFD fd) override; 32 void OnClose(DeviceFD fd) override;
@@ -151,21 +151,21 @@ private:
151 }; 151 };
152 static_assert(sizeof(IoctlGetGpuTime) == 0x10, "IoctlGetGpuTime is incorrect size"); 152 static_assert(sizeof(IoctlGetGpuTime) == 0x10, "IoctlGetGpuTime is incorrect size");
153 153
154 NvResult GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output); 154 NvResult GetCharacteristics(std::span<const u8> input, std::vector<u8>& output);
155 NvResult GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output, 155 NvResult GetCharacteristics(std::span<const u8> input, std::vector<u8>& output,
156 std::vector<u8>& inline_output); 156 std::vector<u8>& inline_output);
157 157
158 NvResult GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output); 158 NvResult GetTPCMasks(std::span<const u8> input, std::vector<u8>& output);
159 NvResult GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output, 159 NvResult GetTPCMasks(std::span<const u8> input, std::vector<u8>& output,
160 std::vector<u8>& inline_output); 160 std::vector<u8>& inline_output);
161 161
162 NvResult GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output); 162 NvResult GetActiveSlotMask(std::span<const u8> input, std::vector<u8>& output);
163 NvResult ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output); 163 NvResult ZCullGetCtxSize(std::span<const u8> input, std::vector<u8>& output);
164 NvResult ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output); 164 NvResult ZCullGetInfo(std::span<const u8> input, std::vector<u8>& output);
165 NvResult ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output); 165 NvResult ZBCSetTable(std::span<const u8> input, std::vector<u8>& output);
166 NvResult ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output); 166 NvResult ZBCQueryTable(std::span<const u8> input, std::vector<u8>& output);
167 NvResult FlushL2(const std::vector<u8>& input, std::vector<u8>& output); 167 NvResult FlushL2(std::span<const u8> input, std::vector<u8>& output);
168 NvResult GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output); 168 NvResult GetGpuTime(std::span<const u8> input, std::vector<u8>& output);
169 169
170 EventInterface& events_interface; 170 EventInterface& events_interface;
171 171
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
index e123564c6..d2308fffc 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
@@ -46,7 +46,7 @@ nvhost_gpu::~nvhost_gpu() {
46 syncpoint_manager.FreeSyncpoint(channel_syncpoint); 46 syncpoint_manager.FreeSyncpoint(channel_syncpoint);
47} 47}
48 48
49NvResult nvhost_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 49NvResult nvhost_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
50 std::vector<u8>& output) { 50 std::vector<u8>& output) {
51 switch (command.group) { 51 switch (command.group) {
52 case 0x0: 52 case 0x0:
@@ -98,8 +98,8 @@ NvResult nvhost_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& i
98 return NvResult::NotImplemented; 98 return NvResult::NotImplemented;
99}; 99};
100 100
101NvResult nvhost_gpu::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 101NvResult nvhost_gpu::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
102 const std::vector<u8>& inline_input, std::vector<u8>& output) { 102 std::span<const u8> inline_input, std::vector<u8>& output) {
103 switch (command.group) { 103 switch (command.group) {
104 case 'H': 104 case 'H':
105 switch (command.cmd) { 105 switch (command.cmd) {
@@ -112,7 +112,7 @@ NvResult nvhost_gpu::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& i
112 return NvResult::NotImplemented; 112 return NvResult::NotImplemented;
113} 113}
114 114
115NvResult nvhost_gpu::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 115NvResult nvhost_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input,
116 std::vector<u8>& output, std::vector<u8>& inline_output) { 116 std::vector<u8>& output, std::vector<u8>& inline_output) {
117 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); 117 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
118 return NvResult::NotImplemented; 118 return NvResult::NotImplemented;
@@ -121,7 +121,7 @@ NvResult nvhost_gpu::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& i
121void nvhost_gpu::OnOpen(DeviceFD fd) {} 121void nvhost_gpu::OnOpen(DeviceFD fd) {}
122void nvhost_gpu::OnClose(DeviceFD fd) {} 122void nvhost_gpu::OnClose(DeviceFD fd) {}
123 123
124NvResult nvhost_gpu::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) { 124NvResult nvhost_gpu::SetNVMAPfd(std::span<const u8> input, std::vector<u8>& output) {
125 IoctlSetNvmapFD params{}; 125 IoctlSetNvmapFD params{};
126 std::memcpy(&params, input.data(), input.size()); 126 std::memcpy(&params, input.data(), input.size());
127 LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); 127 LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
@@ -130,7 +130,7 @@ NvResult nvhost_gpu::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& o
130 return NvResult::Success; 130 return NvResult::Success;
131} 131}
132 132
133NvResult nvhost_gpu::SetClientData(const std::vector<u8>& input, std::vector<u8>& output) { 133NvResult nvhost_gpu::SetClientData(std::span<const u8> input, std::vector<u8>& output) {
134 LOG_DEBUG(Service_NVDRV, "called"); 134 LOG_DEBUG(Service_NVDRV, "called");
135 135
136 IoctlClientData params{}; 136 IoctlClientData params{};
@@ -139,7 +139,7 @@ NvResult nvhost_gpu::SetClientData(const std::vector<u8>& input, std::vector<u8>
139 return NvResult::Success; 139 return NvResult::Success;
140} 140}
141 141
142NvResult nvhost_gpu::GetClientData(const std::vector<u8>& input, std::vector<u8>& output) { 142NvResult nvhost_gpu::GetClientData(std::span<const u8> input, std::vector<u8>& output) {
143 LOG_DEBUG(Service_NVDRV, "called"); 143 LOG_DEBUG(Service_NVDRV, "called");
144 144
145 IoctlClientData params{}; 145 IoctlClientData params{};
@@ -149,7 +149,7 @@ NvResult nvhost_gpu::GetClientData(const std::vector<u8>& input, std::vector<u8>
149 return NvResult::Success; 149 return NvResult::Success;
150} 150}
151 151
152NvResult nvhost_gpu::ZCullBind(const std::vector<u8>& input, std::vector<u8>& output) { 152NvResult nvhost_gpu::ZCullBind(std::span<const u8> input, std::vector<u8>& output) {
153 std::memcpy(&zcull_params, input.data(), input.size()); 153 std::memcpy(&zcull_params, input.data(), input.size());
154 LOG_DEBUG(Service_NVDRV, "called, gpu_va={:X}, mode={:X}", zcull_params.gpu_va, 154 LOG_DEBUG(Service_NVDRV, "called, gpu_va={:X}, mode={:X}", zcull_params.gpu_va,
155 zcull_params.mode); 155 zcull_params.mode);
@@ -158,7 +158,7 @@ NvResult nvhost_gpu::ZCullBind(const std::vector<u8>& input, std::vector<u8>& ou
158 return NvResult::Success; 158 return NvResult::Success;
159} 159}
160 160
161NvResult nvhost_gpu::SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>& output) { 161NvResult nvhost_gpu::SetErrorNotifier(std::span<const u8> input, std::vector<u8>& output) {
162 IoctlSetErrorNotifier params{}; 162 IoctlSetErrorNotifier params{};
163 std::memcpy(&params, input.data(), input.size()); 163 std::memcpy(&params, input.data(), input.size());
164 LOG_WARNING(Service_NVDRV, "(STUBBED) called, offset={:X}, size={:X}, mem={:X}", params.offset, 164 LOG_WARNING(Service_NVDRV, "(STUBBED) called, offset={:X}, size={:X}, mem={:X}", params.offset,
@@ -168,14 +168,14 @@ NvResult nvhost_gpu::SetErrorNotifier(const std::vector<u8>& input, std::vector<
168 return NvResult::Success; 168 return NvResult::Success;
169} 169}
170 170
171NvResult nvhost_gpu::SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output) { 171NvResult nvhost_gpu::SetChannelPriority(std::span<const u8> input, std::vector<u8>& output) {
172 std::memcpy(&channel_priority, input.data(), input.size()); 172 std::memcpy(&channel_priority, input.data(), input.size());
173 LOG_DEBUG(Service_NVDRV, "(STUBBED) called, priority={:X}", channel_priority); 173 LOG_DEBUG(Service_NVDRV, "(STUBBED) called, priority={:X}", channel_priority);
174 174
175 return NvResult::Success; 175 return NvResult::Success;
176} 176}
177 177
178NvResult nvhost_gpu::AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output) { 178NvResult nvhost_gpu::AllocGPFIFOEx2(std::span<const u8> input, std::vector<u8>& output) {
179 IoctlAllocGpfifoEx2 params{}; 179 IoctlAllocGpfifoEx2 params{};
180 std::memcpy(&params, input.data(), input.size()); 180 std::memcpy(&params, input.data(), input.size());
181 LOG_WARNING(Service_NVDRV, 181 LOG_WARNING(Service_NVDRV,
@@ -197,7 +197,7 @@ NvResult nvhost_gpu::AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8
197 return NvResult::Success; 197 return NvResult::Success;
198} 198}
199 199
200NvResult nvhost_gpu::AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output) { 200NvResult nvhost_gpu::AllocateObjectContext(std::span<const u8> input, std::vector<u8>& output) {
201 IoctlAllocObjCtx params{}; 201 IoctlAllocObjCtx params{};
202 std::memcpy(&params, input.data(), input.size()); 202 std::memcpy(&params, input.data(), input.size());
203 LOG_WARNING(Service_NVDRV, "(STUBBED) called, class_num={:X}, flags={:X}", params.class_num, 203 LOG_WARNING(Service_NVDRV, "(STUBBED) called, class_num={:X}, flags={:X}", params.class_num,
@@ -293,7 +293,7 @@ NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>
293 return NvResult::Success; 293 return NvResult::Success;
294} 294}
295 295
296NvResult nvhost_gpu::SubmitGPFIFOBase(const std::vector<u8>& input, std::vector<u8>& output, 296NvResult nvhost_gpu::SubmitGPFIFOBase(std::span<const u8> input, std::vector<u8>& output,
297 bool kickoff) { 297 bool kickoff) {
298 if (input.size() < sizeof(IoctlSubmitGpfifo)) { 298 if (input.size() < sizeof(IoctlSubmitGpfifo)) {
299 UNIMPLEMENTED(); 299 UNIMPLEMENTED();
@@ -314,8 +314,7 @@ NvResult nvhost_gpu::SubmitGPFIFOBase(const std::vector<u8>& input, std::vector<
314 return SubmitGPFIFOImpl(params, output, std::move(entries)); 314 return SubmitGPFIFOImpl(params, output, std::move(entries));
315} 315}
316 316
317NvResult nvhost_gpu::SubmitGPFIFOBase(const std::vector<u8>& input, 317NvResult nvhost_gpu::SubmitGPFIFOBase(std::span<const u8> input, std::span<const u8> input_inline,
318 const std::vector<u8>& input_inline,
319 std::vector<u8>& output) { 318 std::vector<u8>& output) {
320 if (input.size() < sizeof(IoctlSubmitGpfifo)) { 319 if (input.size() < sizeof(IoctlSubmitGpfifo)) {
321 UNIMPLEMENTED(); 320 UNIMPLEMENTED();
@@ -328,7 +327,7 @@ NvResult nvhost_gpu::SubmitGPFIFOBase(const std::vector<u8>& input,
328 return SubmitGPFIFOImpl(params, output, std::move(entries)); 327 return SubmitGPFIFOImpl(params, output, std::move(entries));
329} 328}
330 329
331NvResult nvhost_gpu::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) { 330NvResult nvhost_gpu::GetWaitbase(std::span<const u8> input, std::vector<u8>& output) {
332 IoctlGetWaitbase params{}; 331 IoctlGetWaitbase params{};
333 std::memcpy(&params, input.data(), sizeof(IoctlGetWaitbase)); 332 std::memcpy(&params, input.data(), sizeof(IoctlGetWaitbase));
334 LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown); 333 LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown);
@@ -338,7 +337,7 @@ NvResult nvhost_gpu::GetWaitbase(const std::vector<u8>& input, std::vector<u8>&
338 return NvResult::Success; 337 return NvResult::Success;
339} 338}
340 339
341NvResult nvhost_gpu::ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output) { 340NvResult nvhost_gpu::ChannelSetTimeout(std::span<const u8> input, std::vector<u8>& output) {
342 IoctlChannelSetTimeout params{}; 341 IoctlChannelSetTimeout params{};
343 std::memcpy(&params, input.data(), sizeof(IoctlChannelSetTimeout)); 342 std::memcpy(&params, input.data(), sizeof(IoctlChannelSetTimeout));
344 LOG_INFO(Service_NVDRV, "called, timeout=0x{:X}", params.timeout); 343 LOG_INFO(Service_NVDRV, "called, timeout=0x{:X}", params.timeout);
@@ -346,7 +345,7 @@ NvResult nvhost_gpu::ChannelSetTimeout(const std::vector<u8>& input, std::vector
346 return NvResult::Success; 345 return NvResult::Success;
347} 346}
348 347
349NvResult nvhost_gpu::ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output) { 348NvResult nvhost_gpu::ChannelSetTimeslice(std::span<const u8> input, std::vector<u8>& output) {
350 IoctlSetTimeslice params{}; 349 IoctlSetTimeslice params{};
351 std::memcpy(&params, input.data(), sizeof(IoctlSetTimeslice)); 350 std::memcpy(&params, input.data(), sizeof(IoctlSetTimeslice));
352 LOG_INFO(Service_NVDRV, "called, timeslice=0x{:X}", params.timeslice); 351 LOG_INFO(Service_NVDRV, "called, timeslice=0x{:X}", params.timeslice);
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
index 1e4ecd55b..3ca58202d 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
@@ -40,12 +40,12 @@ public:
40 NvCore::Container& core); 40 NvCore::Container& core);
41 ~nvhost_gpu() override; 41 ~nvhost_gpu() override;
42 42
43 NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 43 NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
44 std::vector<u8>& output) override; 44 std::vector<u8>& output) override;
45 NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 45 NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
46 const std::vector<u8>& inline_input, std::vector<u8>& output) override; 46 std::span<const u8> inline_input, std::vector<u8>& output) override;
47 NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 47 NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output,
48 std::vector<u8>& output, std::vector<u8>& inline_output) override; 48 std::vector<u8>& inline_output) override;
49 49
50 void OnOpen(DeviceFD fd) override; 50 void OnOpen(DeviceFD fd) override;
51 void OnClose(DeviceFD fd) override; 51 void OnClose(DeviceFD fd) override;
@@ -186,23 +186,23 @@ private:
186 u32_le channel_priority{}; 186 u32_le channel_priority{};
187 u32_le channel_timeslice{}; 187 u32_le channel_timeslice{};
188 188
189 NvResult SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output); 189 NvResult SetNVMAPfd(std::span<const u8> input, std::vector<u8>& output);
190 NvResult SetClientData(const std::vector<u8>& input, std::vector<u8>& output); 190 NvResult SetClientData(std::span<const u8> input, std::vector<u8>& output);
191 NvResult GetClientData(const std::vector<u8>& input, std::vector<u8>& output); 191 NvResult GetClientData(std::span<const u8> input, std::vector<u8>& output);
192 NvResult ZCullBind(const std::vector<u8>& input, std::vector<u8>& output); 192 NvResult ZCullBind(std::span<const u8> input, std::vector<u8>& output);
193 NvResult SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>& output); 193 NvResult SetErrorNotifier(std::span<const u8> input, std::vector<u8>& output);
194 NvResult SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output); 194 NvResult SetChannelPriority(std::span<const u8> input, std::vector<u8>& output);
195 NvResult AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output); 195 NvResult AllocGPFIFOEx2(std::span<const u8> input, std::vector<u8>& output);
196 NvResult AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output); 196 NvResult AllocateObjectContext(std::span<const u8> input, std::vector<u8>& output);
197 NvResult SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& output, 197 NvResult SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& output,
198 Tegra::CommandList&& entries); 198 Tegra::CommandList&& entries);
199 NvResult SubmitGPFIFOBase(const std::vector<u8>& input, std::vector<u8>& output, 199 NvResult SubmitGPFIFOBase(std::span<const u8> input, std::vector<u8>& output,
200 bool kickoff = false); 200 bool kickoff = false);
201 NvResult SubmitGPFIFOBase(const std::vector<u8>& input, const std::vector<u8>& input_inline, 201 NvResult SubmitGPFIFOBase(std::span<const u8> input, std::span<const u8> input_inline,
202 std::vector<u8>& output); 202 std::vector<u8>& output);
203 NvResult GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output); 203 NvResult GetWaitbase(std::span<const u8> input, std::vector<u8>& output);
204 NvResult ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output); 204 NvResult ChannelSetTimeout(std::span<const u8> input, std::vector<u8>& output);
205 NvResult ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output); 205 NvResult ChannelSetTimeslice(std::span<const u8> input, std::vector<u8>& output);
206 206
207 EventInterface& events_interface; 207 EventInterface& events_interface;
208 NvCore::Container& core; 208 NvCore::Container& core;
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
index 1703f9cc3..0c7aee1b8 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
@@ -15,7 +15,7 @@ nvhost_nvdec::nvhost_nvdec(Core::System& system_, NvCore::Container& core_)
15 : nvhost_nvdec_common{system_, core_, NvCore::ChannelType::NvDec} {} 15 : nvhost_nvdec_common{system_, core_, NvCore::ChannelType::NvDec} {}
16nvhost_nvdec::~nvhost_nvdec() = default; 16nvhost_nvdec::~nvhost_nvdec() = default;
17 17
18NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 18NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
19 std::vector<u8>& output) { 19 std::vector<u8>& output) {
20 switch (command.group) { 20 switch (command.group) {
21 case 0x0: 21 case 0x0:
@@ -55,13 +55,13 @@ NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>&
55 return NvResult::NotImplemented; 55 return NvResult::NotImplemented;
56} 56}
57 57
58NvResult nvhost_nvdec::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 58NvResult nvhost_nvdec::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
59 const std::vector<u8>& inline_input, std::vector<u8>& output) { 59 std::span<const u8> inline_input, std::vector<u8>& output) {
60 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); 60 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
61 return NvResult::NotImplemented; 61 return NvResult::NotImplemented;
62} 62}
63 63
64NvResult nvhost_nvdec::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 64NvResult nvhost_nvdec::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input,
65 std::vector<u8>& output, std::vector<u8>& inline_output) { 65 std::vector<u8>& output, std::vector<u8>& inline_output) {
66 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); 66 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
67 return NvResult::NotImplemented; 67 return NvResult::NotImplemented;
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
index c1b4e53e8..0d615bbcb 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
@@ -13,12 +13,12 @@ public:
13 explicit nvhost_nvdec(Core::System& system_, NvCore::Container& core); 13 explicit nvhost_nvdec(Core::System& system_, NvCore::Container& core);
14 ~nvhost_nvdec() override; 14 ~nvhost_nvdec() override;
15 15
16 NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 16 NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
17 std::vector<u8>& output) override; 17 std::vector<u8>& output) override;
18 NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 18 NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
19 const std::vector<u8>& inline_input, std::vector<u8>& output) override; 19 std::span<const u8> inline_input, std::vector<u8>& output) override;
20 NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 20 NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output,
21 std::vector<u8>& output, std::vector<u8>& inline_output) override; 21 std::vector<u8>& inline_output) override;
22 22
23 void OnOpen(DeviceFD fd) override; 23 void OnOpen(DeviceFD fd) override;
24 void OnClose(DeviceFD fd) override; 24 void OnClose(DeviceFD fd) override;
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
index 99eede702..7bcef105b 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
@@ -23,7 +23,7 @@ namespace {
23// Copies count amount of type T from the input vector into the dst vector. 23// Copies count amount of type T from the input vector into the dst vector.
24// Returns the number of bytes written into dst. 24// Returns the number of bytes written into dst.
25template <typename T> 25template <typename T>
26std::size_t SliceVectors(const std::vector<u8>& input, std::vector<T>& dst, std::size_t count, 26std::size_t SliceVectors(std::span<const u8> input, std::vector<T>& dst, std::size_t count,
27 std::size_t offset) { 27 std::size_t offset) {
28 if (dst.empty()) { 28 if (dst.empty()) {
29 return 0; 29 return 0;
@@ -63,7 +63,7 @@ nvhost_nvdec_common::~nvhost_nvdec_common() {
63 core.Host1xDeviceFile().syncpts_accumulated.push_back(channel_syncpoint); 63 core.Host1xDeviceFile().syncpts_accumulated.push_back(channel_syncpoint);
64} 64}
65 65
66NvResult nvhost_nvdec_common::SetNVMAPfd(const std::vector<u8>& input) { 66NvResult nvhost_nvdec_common::SetNVMAPfd(std::span<const u8> input) {
67 IoctlSetNvmapFD params{}; 67 IoctlSetNvmapFD params{};
68 std::memcpy(&params, input.data(), sizeof(IoctlSetNvmapFD)); 68 std::memcpy(&params, input.data(), sizeof(IoctlSetNvmapFD));
69 LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); 69 LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
@@ -72,7 +72,7 @@ NvResult nvhost_nvdec_common::SetNVMAPfd(const std::vector<u8>& input) {
72 return NvResult::Success; 72 return NvResult::Success;
73} 73}
74 74
75NvResult nvhost_nvdec_common::Submit(DeviceFD fd, const std::vector<u8>& input, 75NvResult nvhost_nvdec_common::Submit(DeviceFD fd, std::span<const u8> input,
76 std::vector<u8>& output) { 76 std::vector<u8>& output) {
77 IoctlSubmit params{}; 77 IoctlSubmit params{};
78 std::memcpy(&params, input.data(), sizeof(IoctlSubmit)); 78 std::memcpy(&params, input.data(), sizeof(IoctlSubmit));
@@ -121,7 +121,7 @@ NvResult nvhost_nvdec_common::Submit(DeviceFD fd, const std::vector<u8>& input,
121 return NvResult::Success; 121 return NvResult::Success;
122} 122}
123 123
124NvResult nvhost_nvdec_common::GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output) { 124NvResult nvhost_nvdec_common::GetSyncpoint(std::span<const u8> input, std::vector<u8>& output) {
125 IoctlGetSyncpoint params{}; 125 IoctlGetSyncpoint params{};
126 std::memcpy(&params, input.data(), sizeof(IoctlGetSyncpoint)); 126 std::memcpy(&params, input.data(), sizeof(IoctlGetSyncpoint));
127 LOG_DEBUG(Service_NVDRV, "called GetSyncpoint, id={}", params.param); 127 LOG_DEBUG(Service_NVDRV, "called GetSyncpoint, id={}", params.param);
@@ -133,7 +133,7 @@ NvResult nvhost_nvdec_common::GetSyncpoint(const std::vector<u8>& input, std::ve
133 return NvResult::Success; 133 return NvResult::Success;
134} 134}
135 135
136NvResult nvhost_nvdec_common::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) { 136NvResult nvhost_nvdec_common::GetWaitbase(std::span<const u8> input, std::vector<u8>& output) {
137 IoctlGetWaitbase params{}; 137 IoctlGetWaitbase params{};
138 LOG_CRITICAL(Service_NVDRV, "called WAITBASE"); 138 LOG_CRITICAL(Service_NVDRV, "called WAITBASE");
139 std::memcpy(&params, input.data(), sizeof(IoctlGetWaitbase)); 139 std::memcpy(&params, input.data(), sizeof(IoctlGetWaitbase));
@@ -142,7 +142,7 @@ NvResult nvhost_nvdec_common::GetWaitbase(const std::vector<u8>& input, std::vec
142 return NvResult::Success; 142 return NvResult::Success;
143} 143}
144 144
145NvResult nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vector<u8>& output) { 145NvResult nvhost_nvdec_common::MapBuffer(std::span<const u8> input, std::vector<u8>& output) {
146 IoctlMapBuffer params{}; 146 IoctlMapBuffer params{};
147 std::memcpy(&params, input.data(), sizeof(IoctlMapBuffer)); 147 std::memcpy(&params, input.data(), sizeof(IoctlMapBuffer));
148 std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries); 148 std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries);
@@ -159,7 +159,7 @@ NvResult nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vecto
159 return NvResult::Success; 159 return NvResult::Success;
160} 160}
161 161
162NvResult nvhost_nvdec_common::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) { 162NvResult nvhost_nvdec_common::UnmapBuffer(std::span<const u8> input, std::vector<u8>& output) {
163 IoctlMapBuffer params{}; 163 IoctlMapBuffer params{};
164 std::memcpy(&params, input.data(), sizeof(IoctlMapBuffer)); 164 std::memcpy(&params, input.data(), sizeof(IoctlMapBuffer));
165 std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries); 165 std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries);
@@ -173,8 +173,7 @@ NvResult nvhost_nvdec_common::UnmapBuffer(const std::vector<u8>& input, std::vec
173 return NvResult::Success; 173 return NvResult::Success;
174} 174}
175 175
176NvResult nvhost_nvdec_common::SetSubmitTimeout(const std::vector<u8>& input, 176NvResult nvhost_nvdec_common::SetSubmitTimeout(std::span<const u8> input, std::vector<u8>& output) {
177 std::vector<u8>& output) {
178 std::memcpy(&submit_timeout, input.data(), input.size()); 177 std::memcpy(&submit_timeout, input.data(), input.size());
179 LOG_WARNING(Service_NVDRV, "(STUBBED) called"); 178 LOG_WARNING(Service_NVDRV, "(STUBBED) called");
180 return NvResult::Success; 179 return NvResult::Success;
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h
index fe76100c8..5af26a26f 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h
@@ -107,13 +107,13 @@ protected:
107 static_assert(sizeof(IoctlMapBuffer) == 0x0C, "IoctlMapBuffer is incorrect size"); 107 static_assert(sizeof(IoctlMapBuffer) == 0x0C, "IoctlMapBuffer is incorrect size");
108 108
109 /// Ioctl command implementations 109 /// Ioctl command implementations
110 NvResult SetNVMAPfd(const std::vector<u8>& input); 110 NvResult SetNVMAPfd(std::span<const u8> input);
111 NvResult Submit(DeviceFD fd, const std::vector<u8>& input, std::vector<u8>& output); 111 NvResult Submit(DeviceFD fd, std::span<const u8> input, std::vector<u8>& output);
112 NvResult GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output); 112 NvResult GetSyncpoint(std::span<const u8> input, std::vector<u8>& output);
113 NvResult GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output); 113 NvResult GetWaitbase(std::span<const u8> input, std::vector<u8>& output);
114 NvResult MapBuffer(const std::vector<u8>& input, std::vector<u8>& output); 114 NvResult MapBuffer(std::span<const u8> input, std::vector<u8>& output);
115 NvResult UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output); 115 NvResult UnmapBuffer(std::span<const u8> input, std::vector<u8>& output);
116 NvResult SetSubmitTimeout(const std::vector<u8>& input, std::vector<u8>& output); 116 NvResult SetSubmitTimeout(std::span<const u8> input, std::vector<u8>& output);
117 117
118 Kernel::KEvent* QueryEvent(u32 event_id) override; 118 Kernel::KEvent* QueryEvent(u32 event_id) override;
119 119
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
index bdbc2f9e1..39f30e7c8 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
@@ -12,7 +12,7 @@ namespace Service::Nvidia::Devices {
12nvhost_nvjpg::nvhost_nvjpg(Core::System& system_) : nvdevice{system_} {} 12nvhost_nvjpg::nvhost_nvjpg(Core::System& system_) : nvdevice{system_} {}
13nvhost_nvjpg::~nvhost_nvjpg() = default; 13nvhost_nvjpg::~nvhost_nvjpg() = default;
14 14
15NvResult nvhost_nvjpg::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 15NvResult nvhost_nvjpg::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
16 std::vector<u8>& output) { 16 std::vector<u8>& output) {
17 switch (command.group) { 17 switch (command.group) {
18 case 'H': 18 case 'H':
@@ -31,13 +31,13 @@ NvResult nvhost_nvjpg::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>&
31 return NvResult::NotImplemented; 31 return NvResult::NotImplemented;
32} 32}
33 33
34NvResult nvhost_nvjpg::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 34NvResult nvhost_nvjpg::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
35 const std::vector<u8>& inline_input, std::vector<u8>& output) { 35 std::span<const u8> inline_input, std::vector<u8>& output) {
36 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); 36 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
37 return NvResult::NotImplemented; 37 return NvResult::NotImplemented;
38} 38}
39 39
40NvResult nvhost_nvjpg::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 40NvResult nvhost_nvjpg::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input,
41 std::vector<u8>& output, std::vector<u8>& inline_output) { 41 std::vector<u8>& output, std::vector<u8>& inline_output) {
42 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); 42 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
43 return NvResult::NotImplemented; 43 return NvResult::NotImplemented;
@@ -46,7 +46,7 @@ NvResult nvhost_nvjpg::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>&
46void nvhost_nvjpg::OnOpen(DeviceFD fd) {} 46void nvhost_nvjpg::OnOpen(DeviceFD fd) {}
47void nvhost_nvjpg::OnClose(DeviceFD fd) {} 47void nvhost_nvjpg::OnClose(DeviceFD fd) {}
48 48
49NvResult nvhost_nvjpg::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) { 49NvResult nvhost_nvjpg::SetNVMAPfd(std::span<const u8> input, std::vector<u8>& output) {
50 IoctlSetNvmapFD params{}; 50 IoctlSetNvmapFD params{};
51 std::memcpy(&params, input.data(), input.size()); 51 std::memcpy(&params, input.data(), input.size());
52 LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); 52 LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h
index 440e7d371..41b57e872 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h
@@ -15,12 +15,12 @@ public:
15 explicit nvhost_nvjpg(Core::System& system_); 15 explicit nvhost_nvjpg(Core::System& system_);
16 ~nvhost_nvjpg() override; 16 ~nvhost_nvjpg() override;
17 17
18 NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 18 NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
19 std::vector<u8>& output) override; 19 std::vector<u8>& output) override;
20 NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 20 NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
21 const std::vector<u8>& inline_input, std::vector<u8>& output) override; 21 std::span<const u8> inline_input, std::vector<u8>& output) override;
22 NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 22 NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output,
23 std::vector<u8>& output, std::vector<u8>& inline_output) override; 23 std::vector<u8>& inline_output) override;
24 24
25 void OnOpen(DeviceFD fd) override; 25 void OnOpen(DeviceFD fd) override;
26 void OnClose(DeviceFD fd) override; 26 void OnClose(DeviceFD fd) override;
@@ -33,7 +33,7 @@ private:
33 33
34 s32_le nvmap_fd{}; 34 s32_le nvmap_fd{};
35 35
36 NvResult SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output); 36 NvResult SetNVMAPfd(std::span<const u8> input, std::vector<u8>& output);
37}; 37};
38 38
39} // namespace Service::Nvidia::Devices 39} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
index 73f97136e..b0ea402a7 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
@@ -15,7 +15,7 @@ nvhost_vic::nvhost_vic(Core::System& system_, NvCore::Container& core_)
15 15
16nvhost_vic::~nvhost_vic() = default; 16nvhost_vic::~nvhost_vic() = default;
17 17
18NvResult nvhost_vic::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 18NvResult nvhost_vic::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
19 std::vector<u8>& output) { 19 std::vector<u8>& output) {
20 switch (command.group) { 20 switch (command.group) {
21 case 0x0: 21 case 0x0:
@@ -55,13 +55,13 @@ NvResult nvhost_vic::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& i
55 return NvResult::NotImplemented; 55 return NvResult::NotImplemented;
56} 56}
57 57
58NvResult nvhost_vic::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 58NvResult nvhost_vic::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
59 const std::vector<u8>& inline_input, std::vector<u8>& output) { 59 std::span<const u8> inline_input, std::vector<u8>& output) {
60 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); 60 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
61 return NvResult::NotImplemented; 61 return NvResult::NotImplemented;
62} 62}
63 63
64NvResult nvhost_vic::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 64NvResult nvhost_vic::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input,
65 std::vector<u8>& output, std::vector<u8>& inline_output) { 65 std::vector<u8>& output, std::vector<u8>& inline_output) {
66 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); 66 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
67 return NvResult::NotImplemented; 67 return NvResult::NotImplemented;
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.h b/src/core/hle/service/nvdrv/devices/nvhost_vic.h
index f164caafb..b5e350a83 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_vic.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.h
@@ -12,12 +12,12 @@ public:
12 explicit nvhost_vic(Core::System& system_, NvCore::Container& core); 12 explicit nvhost_vic(Core::System& system_, NvCore::Container& core);
13 ~nvhost_vic(); 13 ~nvhost_vic();
14 14
15 NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 15 NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
16 std::vector<u8>& output) override; 16 std::vector<u8>& output) override;
17 NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 17 NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
18 const std::vector<u8>& inline_input, std::vector<u8>& output) override; 18 std::span<const u8> inline_input, std::vector<u8>& output) override;
19 NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 19 NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output,
20 std::vector<u8>& output, std::vector<u8>& inline_output) override; 20 std::vector<u8>& inline_output) override;
21 21
22 void OnOpen(DeviceFD fd) override; 22 void OnOpen(DeviceFD fd) override;
23 void OnClose(DeviceFD fd) override; 23 void OnClose(DeviceFD fd) override;
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp
index fa29db758..29c1e0f01 100644
--- a/src/core/hle/service/nvdrv/devices/nvmap.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp
@@ -25,7 +25,7 @@ nvmap::nvmap(Core::System& system_, NvCore::Container& container_)
25 25
26nvmap::~nvmap() = default; 26nvmap::~nvmap() = default;
27 27
28NvResult nvmap::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 28NvResult nvmap::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
29 std::vector<u8>& output) { 29 std::vector<u8>& output) {
30 switch (command.group) { 30 switch (command.group) {
31 case 0x1: 31 case 0x1:
@@ -54,13 +54,13 @@ NvResult nvmap::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
54 return NvResult::NotImplemented; 54 return NvResult::NotImplemented;
55} 55}
56 56
57NvResult nvmap::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 57NvResult nvmap::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
58 const std::vector<u8>& inline_input, std::vector<u8>& output) { 58 std::span<const u8> inline_input, std::vector<u8>& output) {
59 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); 59 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
60 return NvResult::NotImplemented; 60 return NvResult::NotImplemented;
61} 61}
62 62
63NvResult nvmap::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 63NvResult nvmap::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input,
64 std::vector<u8>& output, std::vector<u8>& inline_output) { 64 std::vector<u8>& output, std::vector<u8>& inline_output) {
65 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); 65 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
66 return NvResult::NotImplemented; 66 return NvResult::NotImplemented;
@@ -69,7 +69,7 @@ NvResult nvmap::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
69void nvmap::OnOpen(DeviceFD fd) {} 69void nvmap::OnOpen(DeviceFD fd) {}
70void nvmap::OnClose(DeviceFD fd) {} 70void nvmap::OnClose(DeviceFD fd) {}
71 71
72NvResult nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) { 72NvResult nvmap::IocCreate(std::span<const u8> input, std::vector<u8>& output) {
73 IocCreateParams params; 73 IocCreateParams params;
74 std::memcpy(&params, input.data(), sizeof(params)); 74 std::memcpy(&params, input.data(), sizeof(params));
75 LOG_DEBUG(Service_NVDRV, "called, size=0x{:08X}", params.size); 75 LOG_DEBUG(Service_NVDRV, "called, size=0x{:08X}", params.size);
@@ -89,7 +89,7 @@ NvResult nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output)
89 return NvResult::Success; 89 return NvResult::Success;
90} 90}
91 91
92NvResult nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) { 92NvResult nvmap::IocAlloc(std::span<const u8> input, std::vector<u8>& output) {
93 IocAllocParams params; 93 IocAllocParams params;
94 std::memcpy(&params, input.data(), sizeof(params)); 94 std::memcpy(&params, input.data(), sizeof(params));
95 LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.address); 95 LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.address);
@@ -137,7 +137,7 @@ NvResult nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output)
137 return result; 137 return result;
138} 138}
139 139
140NvResult nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) { 140NvResult nvmap::IocGetId(std::span<const u8> input, std::vector<u8>& output) {
141 IocGetIdParams params; 141 IocGetIdParams params;
142 std::memcpy(&params, input.data(), sizeof(params)); 142 std::memcpy(&params, input.data(), sizeof(params));
143 143
@@ -161,7 +161,7 @@ NvResult nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output)
161 return NvResult::Success; 161 return NvResult::Success;
162} 162}
163 163
164NvResult nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) { 164NvResult nvmap::IocFromId(std::span<const u8> input, std::vector<u8>& output) {
165 IocFromIdParams params; 165 IocFromIdParams params;
166 std::memcpy(&params, input.data(), sizeof(params)); 166 std::memcpy(&params, input.data(), sizeof(params));
167 167
@@ -192,7 +192,7 @@ NvResult nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output)
192 return NvResult::Success; 192 return NvResult::Success;
193} 193}
194 194
195NvResult nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) { 195NvResult nvmap::IocParam(std::span<const u8> input, std::vector<u8>& output) {
196 enum class ParamTypes { Size = 1, Alignment = 2, Base = 3, Heap = 4, Kind = 5, Compr = 6 }; 196 enum class ParamTypes { Size = 1, Alignment = 2, Base = 3, Heap = 4, Kind = 5, Compr = 6 };
197 197
198 IocParamParams params; 198 IocParamParams params;
@@ -241,7 +241,7 @@ NvResult nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output)
241 return NvResult::Success; 241 return NvResult::Success;
242} 242}
243 243
244NvResult nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) { 244NvResult nvmap::IocFree(std::span<const u8> input, std::vector<u8>& output) {
245 IocFreeParams params; 245 IocFreeParams params;
246 std::memcpy(&params, input.data(), sizeof(params)); 246 std::memcpy(&params, input.data(), sizeof(params));
247 247
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.h b/src/core/hle/service/nvdrv/devices/nvmap.h
index e9bfd0358..82bd3b118 100644
--- a/src/core/hle/service/nvdrv/devices/nvmap.h
+++ b/src/core/hle/service/nvdrv/devices/nvmap.h
@@ -26,12 +26,12 @@ public:
26 nvmap(const nvmap&) = delete; 26 nvmap(const nvmap&) = delete;
27 nvmap& operator=(const nvmap&) = delete; 27 nvmap& operator=(const nvmap&) = delete;
28 28
29 NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 29 NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
30 std::vector<u8>& output) override; 30 std::vector<u8>& output) override;
31 NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 31 NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
32 const std::vector<u8>& inline_input, std::vector<u8>& output) override; 32 std::span<const u8> inline_input, std::vector<u8>& output) override;
33 NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 33 NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output,
34 std::vector<u8>& output, std::vector<u8>& inline_output) override; 34 std::vector<u8>& inline_output) override;
35 35
36 void OnOpen(DeviceFD fd) override; 36 void OnOpen(DeviceFD fd) override;
37 void OnClose(DeviceFD fd) override; 37 void OnClose(DeviceFD fd) override;
@@ -106,12 +106,12 @@ private:
106 }; 106 };
107 static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size"); 107 static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size");
108 108
109 NvResult IocCreate(const std::vector<u8>& input, std::vector<u8>& output); 109 NvResult IocCreate(std::span<const u8> input, std::vector<u8>& output);
110 NvResult IocAlloc(const std::vector<u8>& input, std::vector<u8>& output); 110 NvResult IocAlloc(std::span<const u8> input, std::vector<u8>& output);
111 NvResult IocGetId(const std::vector<u8>& input, std::vector<u8>& output); 111 NvResult IocGetId(std::span<const u8> input, std::vector<u8>& output);
112 NvResult IocFromId(const std::vector<u8>& input, std::vector<u8>& output); 112 NvResult IocFromId(std::span<const u8> input, std::vector<u8>& output);
113 NvResult IocParam(const std::vector<u8>& input, std::vector<u8>& output); 113 NvResult IocParam(std::span<const u8> input, std::vector<u8>& output);
114 NvResult IocFree(const std::vector<u8>& input, std::vector<u8>& output); 114 NvResult IocFree(std::span<const u8> input, std::vector<u8>& output);
115 115
116 NvCore::Container& container; 116 NvCore::Container& container;
117 NvCore::NvMap& file; 117 NvCore::NvMap& file;
diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp
index 6fc8565c0..52d27e755 100644
--- a/src/core/hle/service/nvdrv/nvdrv.cpp
+++ b/src/core/hle/service/nvdrv/nvdrv.cpp
@@ -124,7 +124,7 @@ DeviceFD Module::Open(const std::string& device_name) {
124 return fd; 124 return fd;
125} 125}
126 126
127NvResult Module::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 127NvResult Module::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
128 std::vector<u8>& output) { 128 std::vector<u8>& output) {
129 if (fd < 0) { 129 if (fd < 0) {
130 LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); 130 LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd);
@@ -141,8 +141,8 @@ NvResult Module::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input
141 return itr->second->Ioctl1(fd, command, input, output); 141 return itr->second->Ioctl1(fd, command, input, output);
142} 142}
143 143
144NvResult Module::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 144NvResult Module::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
145 const std::vector<u8>& inline_input, std::vector<u8>& output) { 145 std::span<const u8> inline_input, std::vector<u8>& output) {
146 if (fd < 0) { 146 if (fd < 0) {
147 LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); 147 LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd);
148 return NvResult::InvalidState; 148 return NvResult::InvalidState;
@@ -158,7 +158,7 @@ NvResult Module::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input
158 return itr->second->Ioctl2(fd, command, input, inline_input, output); 158 return itr->second->Ioctl2(fd, command, input, inline_input, output);
159} 159}
160 160
161NvResult Module::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 161NvResult Module::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input,
162 std::vector<u8>& output, std::vector<u8>& inline_output) { 162 std::vector<u8>& output, std::vector<u8>& inline_output) {
163 if (fd < 0) { 163 if (fd < 0) {
164 LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); 164 LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd);
diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h
index f3c81bd88..b09b6e585 100644
--- a/src/core/hle/service/nvdrv/nvdrv.h
+++ b/src/core/hle/service/nvdrv/nvdrv.h
@@ -7,6 +7,7 @@
7#include <functional> 7#include <functional>
8#include <list> 8#include <list>
9#include <memory> 9#include <memory>
10#include <span>
10#include <string> 11#include <string>
11#include <unordered_map> 12#include <unordered_map>
12#include <vector> 13#include <vector>
@@ -79,14 +80,13 @@ public:
79 DeviceFD Open(const std::string& device_name); 80 DeviceFD Open(const std::string& device_name);
80 81
81 /// Sends an ioctl command to the specified file descriptor. 82 /// Sends an ioctl command to the specified file descriptor.
82 NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 83 NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output);
83 std::vector<u8>& output);
84 84
85 NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 85 NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
86 const std::vector<u8>& inline_input, std::vector<u8>& output); 86 std::span<const u8> inline_input, std::vector<u8>& output);
87 87
88 NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 88 NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output,
89 std::vector<u8>& output, std::vector<u8>& inline_output); 89 std::vector<u8>& inline_output);
90 90
91 /// Closes a device file descriptor and returns operation success. 91 /// Closes a device file descriptor and returns operation success.
92 NvResult Close(DeviceFD fd); 92 NvResult Close(DeviceFD fd);
diff --git a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp
index e601b5da1..bcbe05b0d 100644
--- a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp
+++ b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp
@@ -815,8 +815,8 @@ Status BufferQueueProducer::SetPreallocatedBuffer(s32 slot,
815 815
816void BufferQueueProducer::Transact(Kernel::HLERequestContext& ctx, TransactionId code, u32 flags) { 816void BufferQueueProducer::Transact(Kernel::HLERequestContext& ctx, TransactionId code, u32 flags) {
817 Status status{Status::NoError}; 817 Status status{Status::NoError};
818 Parcel parcel_in{ctx.ReadBuffer()}; 818 InputParcel parcel_in{ctx.ReadBuffer()};
819 Parcel parcel_out{}; 819 OutputParcel parcel_out{};
820 820
821 switch (code) { 821 switch (code) {
822 case TransactionId::Connect: { 822 case TransactionId::Connect: {
diff --git a/src/core/hle/service/nvflinger/graphic_buffer_producer.cpp b/src/core/hle/service/nvflinger/graphic_buffer_producer.cpp
index 4043c91f1..769e8c0a3 100644
--- a/src/core/hle/service/nvflinger/graphic_buffer_producer.cpp
+++ b/src/core/hle/service/nvflinger/graphic_buffer_producer.cpp
@@ -9,7 +9,7 @@
9 9
10namespace Service::android { 10namespace Service::android {
11 11
12QueueBufferInput::QueueBufferInput(Parcel& parcel) { 12QueueBufferInput::QueueBufferInput(InputParcel& parcel) {
13 parcel.ReadFlattened(*this); 13 parcel.ReadFlattened(*this);
14} 14}
15 15
diff --git a/src/core/hle/service/nvflinger/graphic_buffer_producer.h b/src/core/hle/service/nvflinger/graphic_buffer_producer.h
index 6ea327bbe..2969f0fd5 100644
--- a/src/core/hle/service/nvflinger/graphic_buffer_producer.h
+++ b/src/core/hle/service/nvflinger/graphic_buffer_producer.h
@@ -14,11 +14,11 @@
14 14
15namespace Service::android { 15namespace Service::android {
16 16
17class Parcel; 17class InputParcel;
18 18
19#pragma pack(push, 1) 19#pragma pack(push, 1)
20struct QueueBufferInput final { 20struct QueueBufferInput final {
21 explicit QueueBufferInput(Parcel& parcel); 21 explicit QueueBufferInput(InputParcel& parcel);
22 22
23 void Deflate(s64* timestamp_, bool* is_auto_timestamp_, Common::Rectangle<s32>* crop_, 23 void Deflate(s64* timestamp_, bool* is_auto_timestamp_, Common::Rectangle<s32>* crop_,
24 NativeWindowScalingMode* scaling_mode_, NativeWindowTransform* transform_, 24 NativeWindowScalingMode* scaling_mode_, NativeWindowTransform* transform_,
diff --git a/src/core/hle/service/nvflinger/parcel.h b/src/core/hle/service/nvflinger/parcel.h
index f3fa2587d..d1b6201e0 100644
--- a/src/core/hle/service/nvflinger/parcel.h
+++ b/src/core/hle/service/nvflinger/parcel.h
@@ -4,6 +4,7 @@
4#pragma once 4#pragma once
5 5
6#include <memory> 6#include <memory>
7#include <span>
7#include <vector> 8#include <vector>
8 9
9#include "common/alignment.h" 10#include "common/alignment.h"
@@ -12,18 +13,17 @@
12 13
13namespace Service::android { 14namespace Service::android {
14 15
15class Parcel final { 16struct ParcelHeader {
16public: 17 u32 data_size;
17 static constexpr std::size_t DefaultBufferSize = 0x40; 18 u32 data_offset;
18 19 u32 objects_size;
19 Parcel() : buffer(DefaultBufferSize) {} 20 u32 objects_offset;
20 21};
21 template <typename T> 22static_assert(sizeof(ParcelHeader) == 16, "ParcelHeader has wrong size");
22 explicit Parcel(const T& out_data) : buffer(DefaultBufferSize) {
23 Write(out_data);
24 }
25 23
26 explicit Parcel(std::vector<u8> in_data) : buffer(std::move(in_data)) { 24class InputParcel final {
25public:
26 explicit InputParcel(std::span<const u8> in_data) : read_buffer(std::move(in_data)) {
27 DeserializeHeader(); 27 DeserializeHeader();
28 [[maybe_unused]] const std::u16string token = ReadInterfaceToken(); 28 [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
29 } 29 }
@@ -31,9 +31,9 @@ public:
31 template <typename T> 31 template <typename T>
32 void Read(T& val) { 32 void Read(T& val) {
33 static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable."); 33 static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable.");
34 ASSERT(read_index + sizeof(T) <= buffer.size()); 34 ASSERT(read_index + sizeof(T) <= read_buffer.size());
35 35
36 std::memcpy(&val, buffer.data() + read_index, sizeof(T)); 36 std::memcpy(&val, read_buffer.data() + read_index, sizeof(T));
37 read_index += sizeof(T); 37 read_index += sizeof(T);
38 read_index = Common::AlignUp(read_index, 4); 38 read_index = Common::AlignUp(read_index, 4);
39 } 39 }
@@ -62,10 +62,10 @@ public:
62 template <typename T> 62 template <typename T>
63 T ReadUnaligned() { 63 T ReadUnaligned() {
64 static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable."); 64 static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable.");
65 ASSERT(read_index + sizeof(T) <= buffer.size()); 65 ASSERT(read_index + sizeof(T) <= read_buffer.size());
66 66
67 T val; 67 T val;
68 std::memcpy(&val, buffer.data() + read_index, sizeof(T)); 68 std::memcpy(&val, read_buffer.data() + read_index, sizeof(T));
69 read_index += sizeof(T); 69 read_index += sizeof(T);
70 return val; 70 return val;
71 } 71 }
@@ -101,6 +101,31 @@ public:
101 return token; 101 return token;
102 } 102 }
103 103
104 void DeserializeHeader() {
105 ASSERT(read_buffer.size() > sizeof(ParcelHeader));
106
107 ParcelHeader header{};
108 std::memcpy(&header, read_buffer.data(), sizeof(ParcelHeader));
109
110 read_index = header.data_offset;
111 }
112
113private:
114 std::span<const u8> read_buffer;
115 std::size_t read_index = 0;
116};
117
118class OutputParcel final {
119public:
120 static constexpr std::size_t DefaultBufferSize = 0x40;
121
122 OutputParcel() : buffer(DefaultBufferSize) {}
123
124 template <typename T>
125 explicit OutputParcel(const T& out_data) : buffer(DefaultBufferSize) {
126 Write(out_data);
127 }
128
104 template <typename T> 129 template <typename T>
105 void Write(const T& val) { 130 void Write(const T& val) {
106 static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable."); 131 static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable.");
@@ -133,40 +158,20 @@ public:
133 WriteObject(ptr.get()); 158 WriteObject(ptr.get());
134 } 159 }
135 160
136 void DeserializeHeader() {
137 ASSERT(buffer.size() > sizeof(Header));
138
139 Header header{};
140 std::memcpy(&header, buffer.data(), sizeof(Header));
141
142 read_index = header.data_offset;
143 }
144
145 std::vector<u8> Serialize() const { 161 std::vector<u8> Serialize() const {
146 ASSERT(read_index == 0); 162 ParcelHeader header{};
147 163 header.data_size = static_cast<u32>(write_index - sizeof(ParcelHeader));
148 Header header{}; 164 header.data_offset = sizeof(ParcelHeader);
149 header.data_size = static_cast<u32>(write_index - sizeof(Header));
150 header.data_offset = sizeof(Header);
151 header.objects_size = 4; 165 header.objects_size = 4;
152 header.objects_offset = static_cast<u32>(sizeof(Header) + header.data_size); 166 header.objects_offset = static_cast<u32>(sizeof(ParcelHeader) + header.data_size);
153 std::memcpy(buffer.data(), &header, sizeof(Header)); 167 std::memcpy(buffer.data(), &header, sizeof(ParcelHeader));
154 168
155 return buffer; 169 return buffer;
156 } 170 }
157 171
158private: 172private:
159 struct Header {
160 u32 data_size;
161 u32 data_offset;
162 u32 objects_size;
163 u32 objects_offset;
164 };
165 static_assert(sizeof(Header) == 16, "ParcelHeader has wrong size");
166
167 mutable std::vector<u8> buffer; 173 mutable std::vector<u8> buffer;
168 std::size_t read_index = 0; 174 std::size_t write_index = sizeof(ParcelHeader);
169 std::size_t write_index = sizeof(Header);
170}; 175};
171 176
172} // namespace Service::android 177} // namespace Service::android
diff --git a/src/core/hle/service/prepo/prepo.cpp b/src/core/hle/service/prepo/prepo.cpp
index 78f897d3e..01040b32a 100644
--- a/src/core/hle/service/prepo/prepo.cpp
+++ b/src/core/hle/service/prepo/prepo.cpp
@@ -63,7 +63,7 @@ private:
63 return ctx.ReadBuffer(1); 63 return ctx.ReadBuffer(1);
64 } 64 }
65 65
66 return std::vector<u8>{}; 66 return std::span<const u8>{};
67 }(); 67 }();
68 68
69 LOG_DEBUG(Service_PREPO, 69 LOG_DEBUG(Service_PREPO,
@@ -90,7 +90,7 @@ private:
90 return ctx.ReadBuffer(1); 90 return ctx.ReadBuffer(1);
91 } 91 }
92 92
93 return std::vector<u8>{}; 93 return std::span<const u8>{};
94 }(); 94 }();
95 95
96 LOG_DEBUG(Service_PREPO, 96 LOG_DEBUG(Service_PREPO,
@@ -142,7 +142,7 @@ private:
142 return ctx.ReadBuffer(1); 142 return ctx.ReadBuffer(1);
143 } 143 }
144 144
145 return std::vector<u8>{}; 145 return std::span<const u8>{};
146 }(); 146 }();
147 147
148 LOG_DEBUG(Service_PREPO, "called, title_id={:016X}, data1_size={:016X}, data2_size={:016X}", 148 LOG_DEBUG(Service_PREPO, "called, title_id={:016X}, data1_size={:016X}, data2_size={:016X}",
@@ -166,7 +166,7 @@ private:
166 return ctx.ReadBuffer(1); 166 return ctx.ReadBuffer(1);
167 } 167 }
168 168
169 return std::vector<u8>{}; 169 return std::span<const u8>{};
170 }(); 170 }();
171 171
172 LOG_DEBUG(Service_PREPO, 172 LOG_DEBUG(Service_PREPO,
diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp
index 9e94a462f..bdb499268 100644
--- a/src/core/hle/service/sockets/bsd.cpp
+++ b/src/core/hle/service/sockets/bsd.cpp
@@ -208,7 +208,6 @@ void BSD::Bind(Kernel::HLERequestContext& ctx) {
208 const s32 fd = rp.Pop<s32>(); 208 const s32 fd = rp.Pop<s32>();
209 209
210 LOG_DEBUG(Service, "called. fd={} addrlen={}", fd, ctx.GetReadBufferSize()); 210 LOG_DEBUG(Service, "called. fd={} addrlen={}", fd, ctx.GetReadBufferSize());
211
212 BuildErrnoResponse(ctx, BindImpl(fd, ctx.ReadBuffer())); 211 BuildErrnoResponse(ctx, BindImpl(fd, ctx.ReadBuffer()));
213} 212}
214 213
@@ -312,7 +311,7 @@ void BSD::SetSockOpt(Kernel::HLERequestContext& ctx) {
312 const u32 level = rp.Pop<u32>(); 311 const u32 level = rp.Pop<u32>();
313 const OptName optname = static_cast<OptName>(rp.Pop<u32>()); 312 const OptName optname = static_cast<OptName>(rp.Pop<u32>());
314 313
315 const std::vector<u8> buffer = ctx.ReadBuffer(); 314 const auto buffer = ctx.ReadBuffer();
316 const u8* optval = buffer.empty() ? nullptr : buffer.data(); 315 const u8* optval = buffer.empty() ? nullptr : buffer.data();
317 size_t optlen = buffer.size(); 316 size_t optlen = buffer.size();
318 317
@@ -489,7 +488,7 @@ std::pair<s32, Errno> BSD::SocketImpl(Domain domain, Type type, Protocol protoco
489 return {fd, Errno::SUCCESS}; 488 return {fd, Errno::SUCCESS};
490} 489}
491 490
492std::pair<s32, Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::vector<u8> read_buffer, 491std::pair<s32, Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::span<const u8> read_buffer,
493 s32 nfds, s32 timeout) { 492 s32 nfds, s32 timeout) {
494 if (write_buffer.size() < nfds * sizeof(PollFD)) { 493 if (write_buffer.size() < nfds * sizeof(PollFD)) {
495 return {-1, Errno::INVAL}; 494 return {-1, Errno::INVAL};
@@ -584,7 +583,7 @@ std::pair<s32, Errno> BSD::AcceptImpl(s32 fd, std::vector<u8>& write_buffer) {
584 return {new_fd, Errno::SUCCESS}; 583 return {new_fd, Errno::SUCCESS};
585} 584}
586 585
587Errno BSD::BindImpl(s32 fd, const std::vector<u8>& addr) { 586Errno BSD::BindImpl(s32 fd, std::span<const u8> addr) {
588 if (!IsFileDescriptorValid(fd)) { 587 if (!IsFileDescriptorValid(fd)) {
589 return Errno::BADF; 588 return Errno::BADF;
590 } 589 }
@@ -595,7 +594,7 @@ Errno BSD::BindImpl(s32 fd, const std::vector<u8>& addr) {
595 return Translate(file_descriptors[fd]->socket->Bind(Translate(addr_in))); 594 return Translate(file_descriptors[fd]->socket->Bind(Translate(addr_in)));
596} 595}
597 596
598Errno BSD::ConnectImpl(s32 fd, const std::vector<u8>& addr) { 597Errno BSD::ConnectImpl(s32 fd, std::span<const u8> addr) {
599 if (!IsFileDescriptorValid(fd)) { 598 if (!IsFileDescriptorValid(fd)) {
600 return Errno::BADF; 599 return Errno::BADF;
601 } 600 }
@@ -800,15 +799,15 @@ std::pair<s32, Errno> BSD::RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& mess
800 return {ret, bsd_errno}; 799 return {ret, bsd_errno};
801} 800}
802 801
803std::pair<s32, Errno> BSD::SendImpl(s32 fd, u32 flags, const std::vector<u8>& message) { 802std::pair<s32, Errno> BSD::SendImpl(s32 fd, u32 flags, std::span<const u8> message) {
804 if (!IsFileDescriptorValid(fd)) { 803 if (!IsFileDescriptorValid(fd)) {
805 return {-1, Errno::BADF}; 804 return {-1, Errno::BADF};
806 } 805 }
807 return Translate(file_descriptors[fd]->socket->Send(message, flags)); 806 return Translate(file_descriptors[fd]->socket->Send(message, flags));
808} 807}
809 808
810std::pair<s32, Errno> BSD::SendToImpl(s32 fd, u32 flags, const std::vector<u8>& message, 809std::pair<s32, Errno> BSD::SendToImpl(s32 fd, u32 flags, std::span<const u8> message,
811 const std::vector<u8>& addr) { 810 std::span<const u8> addr) {
812 if (!IsFileDescriptorValid(fd)) { 811 if (!IsFileDescriptorValid(fd)) {
813 return {-1, Errno::BADF}; 812 return {-1, Errno::BADF};
814 } 813 }
diff --git a/src/core/hle/service/sockets/bsd.h b/src/core/hle/service/sockets/bsd.h
index 81e855e0f..56bb3f8b1 100644
--- a/src/core/hle/service/sockets/bsd.h
+++ b/src/core/hle/service/sockets/bsd.h
@@ -4,6 +4,7 @@
4#pragma once 4#pragma once
5 5
6#include <memory> 6#include <memory>
7#include <span>
7#include <vector> 8#include <vector>
8 9
9#include "common/common_types.h" 10#include "common/common_types.h"
@@ -44,7 +45,7 @@ private:
44 45
45 s32 nfds; 46 s32 nfds;
46 s32 timeout; 47 s32 timeout;
47 std::vector<u8> read_buffer; 48 std::span<const u8> read_buffer;
48 std::vector<u8> write_buffer; 49 std::vector<u8> write_buffer;
49 s32 ret{}; 50 s32 ret{};
50 Errno bsd_errno{}; 51 Errno bsd_errno{};
@@ -65,7 +66,7 @@ private:
65 void Response(Kernel::HLERequestContext& ctx); 66 void Response(Kernel::HLERequestContext& ctx);
66 67
67 s32 fd; 68 s32 fd;
68 std::vector<u8> addr; 69 std::span<const u8> addr;
69 Errno bsd_errno{}; 70 Errno bsd_errno{};
70 }; 71 };
71 72
@@ -98,7 +99,7 @@ private:
98 99
99 s32 fd; 100 s32 fd;
100 u32 flags; 101 u32 flags;
101 std::vector<u8> message; 102 std::span<const u8> message;
102 s32 ret{}; 103 s32 ret{};
103 Errno bsd_errno{}; 104 Errno bsd_errno{};
104 }; 105 };
@@ -109,8 +110,8 @@ private:
109 110
110 s32 fd; 111 s32 fd;
111 u32 flags; 112 u32 flags;
112 std::vector<u8> message; 113 std::span<const u8> message;
113 std::vector<u8> addr; 114 std::span<const u8> addr;
114 s32 ret{}; 115 s32 ret{};
115 Errno bsd_errno{}; 116 Errno bsd_errno{};
116 }; 117 };
@@ -143,11 +144,11 @@ private:
143 void ExecuteWork(Kernel::HLERequestContext& ctx, Work work); 144 void ExecuteWork(Kernel::HLERequestContext& ctx, Work work);
144 145
145 std::pair<s32, Errno> SocketImpl(Domain domain, Type type, Protocol protocol); 146 std::pair<s32, Errno> SocketImpl(Domain domain, Type type, Protocol protocol);
146 std::pair<s32, Errno> PollImpl(std::vector<u8>& write_buffer, std::vector<u8> read_buffer, 147 std::pair<s32, Errno> PollImpl(std::vector<u8>& write_buffer, std::span<const u8> read_buffer,
147 s32 nfds, s32 timeout); 148 s32 nfds, s32 timeout);
148 std::pair<s32, Errno> AcceptImpl(s32 fd, std::vector<u8>& write_buffer); 149 std::pair<s32, Errno> AcceptImpl(s32 fd, std::vector<u8>& write_buffer);
149 Errno BindImpl(s32 fd, const std::vector<u8>& addr); 150 Errno BindImpl(s32 fd, std::span<const u8> addr);
150 Errno ConnectImpl(s32 fd, const std::vector<u8>& addr); 151 Errno ConnectImpl(s32 fd, std::span<const u8> addr);
151 Errno GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer); 152 Errno GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer);
152 Errno GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer); 153 Errno GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer);
153 Errno ListenImpl(s32 fd, s32 backlog); 154 Errno ListenImpl(s32 fd, s32 backlog);
@@ -157,9 +158,9 @@ private:
157 std::pair<s32, Errno> RecvImpl(s32 fd, u32 flags, std::vector<u8>& message); 158 std::pair<s32, Errno> RecvImpl(s32 fd, u32 flags, std::vector<u8>& message);
158 std::pair<s32, Errno> RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& message, 159 std::pair<s32, Errno> RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& message,
159 std::vector<u8>& addr); 160 std::vector<u8>& addr);
160 std::pair<s32, Errno> SendImpl(s32 fd, u32 flags, const std::vector<u8>& message); 161 std::pair<s32, Errno> SendImpl(s32 fd, u32 flags, std::span<const u8> message);
161 std::pair<s32, Errno> SendToImpl(s32 fd, u32 flags, const std::vector<u8>& message, 162 std::pair<s32, Errno> SendToImpl(s32 fd, u32 flags, std::span<const u8> message,
162 const std::vector<u8>& addr); 163 std::span<const u8> addr);
163 Errno CloseImpl(s32 fd); 164 Errno CloseImpl(s32 fd);
164 165
165 s32 FindFreeFileDescriptorHandle() noexcept; 166 s32 FindFreeFileDescriptorHandle() noexcept;
diff --git a/src/core/hle/service/sockets/sfdnsres.cpp b/src/core/hle/service/sockets/sfdnsres.cpp
index 097c37d7a..e96eda7f3 100644
--- a/src/core/hle/service/sockets/sfdnsres.cpp
+++ b/src/core/hle/service/sockets/sfdnsres.cpp
@@ -243,4 +243,4 @@ void SFDNSRES::GetAddrInfoRequestWithOptions(Kernel::HLERequestContext& ctx) {
243 rb.Push(0); 243 rb.Push(0);
244} 244}
245 245
246} // namespace Service::Sockets \ No newline at end of file 246} // namespace Service::Sockets
diff --git a/src/core/hle/service/ssl/ssl.cpp b/src/core/hle/service/ssl/ssl.cpp
index 3735e0452..dcf47083f 100644
--- a/src/core/hle/service/ssl/ssl.cpp
+++ b/src/core/hle/service/ssl/ssl.cpp
@@ -101,7 +101,7 @@ private:
101 void ImportServerPki(Kernel::HLERequestContext& ctx) { 101 void ImportServerPki(Kernel::HLERequestContext& ctx) {
102 IPC::RequestParser rp{ctx}; 102 IPC::RequestParser rp{ctx};
103 const auto certificate_format = rp.PopEnum<CertificateFormat>(); 103 const auto certificate_format = rp.PopEnum<CertificateFormat>();
104 const auto pkcs_12_certificates = ctx.ReadBuffer(0); 104 [[maybe_unused]] const auto pkcs_12_certificates = ctx.ReadBuffer(0);
105 105
106 constexpr u64 server_id = 0; 106 constexpr u64 server_id = 0;
107 107
@@ -113,13 +113,13 @@ private:
113 } 113 }
114 114
115 void ImportClientPki(Kernel::HLERequestContext& ctx) { 115 void ImportClientPki(Kernel::HLERequestContext& ctx) {
116 const auto pkcs_12_certificate = ctx.ReadBuffer(0); 116 [[maybe_unused]] const auto pkcs_12_certificate = ctx.ReadBuffer(0);
117 const auto ascii_password = [&ctx] { 117 [[maybe_unused]] const auto ascii_password = [&ctx] {
118 if (ctx.CanReadBuffer(1)) { 118 if (ctx.CanReadBuffer(1)) {
119 return ctx.ReadBuffer(1); 119 return ctx.ReadBuffer(1);
120 } 120 }
121 121
122 return std::vector<u8>{}; 122 return std::span<const u8>{};
123 }(); 123 }();
124 124
125 constexpr u64 client_id = 0; 125 constexpr u64 client_id = 0;
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index bb283e74e..2fb631183 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -603,7 +603,7 @@ private:
603 return; 603 return;
604 } 604 }
605 605
606 const auto parcel = android::Parcel{NativeWindow{*buffer_queue_id}}; 606 const auto parcel = android::OutputParcel{NativeWindow{*buffer_queue_id}};
607 const auto buffer_size = ctx.WriteBuffer(parcel.Serialize()); 607 const auto buffer_size = ctx.WriteBuffer(parcel.Serialize());
608 608
609 IPC::ResponseBuilder rb{ctx, 4}; 609 IPC::ResponseBuilder rb{ctx, 4};
@@ -649,7 +649,7 @@ private:
649 return; 649 return;
650 } 650 }
651 651
652 const auto parcel = android::Parcel{NativeWindow{*buffer_queue_id}}; 652 const auto parcel = android::OutputParcel{NativeWindow{*buffer_queue_id}};
653 const auto buffer_size = ctx.WriteBuffer(parcel.Serialize()); 653 const auto buffer_size = ctx.WriteBuffer(parcel.Serialize());
654 654
655 IPC::ResponseBuilder rb{ctx, 6}; 655 IPC::ResponseBuilder rb{ctx, 6};
diff --git a/src/core/internal_network/network.cpp b/src/core/internal_network/network.cpp
index 282ea1ff9..7494fb62d 100644
--- a/src/core/internal_network/network.cpp
+++ b/src/core/internal_network/network.cpp
@@ -550,7 +550,7 @@ std::pair<s32, Errno> Socket::RecvFrom(int flags, std::vector<u8>& message, Sock
550 return {-1, GetAndLogLastError()}; 550 return {-1, GetAndLogLastError()};
551} 551}
552 552
553std::pair<s32, Errno> Socket::Send(const std::vector<u8>& message, int flags) { 553std::pair<s32, Errno> Socket::Send(std::span<const u8> message, int flags) {
554 ASSERT(message.size() < static_cast<size_t>(std::numeric_limits<int>::max())); 554 ASSERT(message.size() < static_cast<size_t>(std::numeric_limits<int>::max()));
555 ASSERT(flags == 0); 555 ASSERT(flags == 0);
556 556
@@ -563,7 +563,7 @@ std::pair<s32, Errno> Socket::Send(const std::vector<u8>& message, int flags) {
563 return {-1, GetAndLogLastError()}; 563 return {-1, GetAndLogLastError()};
564} 564}
565 565
566std::pair<s32, Errno> Socket::SendTo(u32 flags, const std::vector<u8>& message, 566std::pair<s32, Errno> Socket::SendTo(u32 flags, std::span<const u8> message,
567 const SockAddrIn* addr) { 567 const SockAddrIn* addr) {
568 ASSERT(flags == 0); 568 ASSERT(flags == 0);
569 569
diff --git a/src/core/internal_network/socket_proxy.cpp b/src/core/internal_network/socket_proxy.cpp
index 1e1c42cea..7a77171c2 100644
--- a/src/core/internal_network/socket_proxy.cpp
+++ b/src/core/internal_network/socket_proxy.cpp
@@ -182,7 +182,7 @@ std::pair<s32, Errno> ProxySocket::ReceivePacket(int flags, std::vector<u8>& mes
182 return {static_cast<u32>(read_bytes), Errno::SUCCESS}; 182 return {static_cast<u32>(read_bytes), Errno::SUCCESS};
183} 183}
184 184
185std::pair<s32, Errno> ProxySocket::Send(const std::vector<u8>& message, int flags) { 185std::pair<s32, Errno> ProxySocket::Send(std::span<const u8> message, int flags) {
186 LOG_WARNING(Network, "(STUBBED) called"); 186 LOG_WARNING(Network, "(STUBBED) called");
187 ASSERT(message.size() < static_cast<size_t>(std::numeric_limits<int>::max())); 187 ASSERT(message.size() < static_cast<size_t>(std::numeric_limits<int>::max()));
188 ASSERT(flags == 0); 188 ASSERT(flags == 0);
@@ -200,7 +200,7 @@ void ProxySocket::SendPacket(ProxyPacket& packet) {
200 } 200 }
201} 201}
202 202
203std::pair<s32, Errno> ProxySocket::SendTo(u32 flags, const std::vector<u8>& message, 203std::pair<s32, Errno> ProxySocket::SendTo(u32 flags, std::span<const u8> message,
204 const SockAddrIn* addr) { 204 const SockAddrIn* addr) {
205 ASSERT(flags == 0); 205 ASSERT(flags == 0);
206 206
diff --git a/src/core/internal_network/socket_proxy.h b/src/core/internal_network/socket_proxy.h
index f12b5f567..9421492bc 100644
--- a/src/core/internal_network/socket_proxy.h
+++ b/src/core/internal_network/socket_proxy.h
@@ -4,6 +4,7 @@
4#pragma once 4#pragma once
5 5
6#include <mutex> 6#include <mutex>
7#include <span>
7#include <vector> 8#include <vector>
8#include <queue> 9#include <queue>
9 10
@@ -48,11 +49,11 @@ public:
48 std::pair<s32, Errno> ReceivePacket(int flags, std::vector<u8>& message, SockAddrIn* addr, 49 std::pair<s32, Errno> ReceivePacket(int flags, std::vector<u8>& message, SockAddrIn* addr,
49 std::size_t max_length); 50 std::size_t max_length);
50 51
51 std::pair<s32, Errno> Send(const std::vector<u8>& message, int flags) override; 52 std::pair<s32, Errno> Send(std::span<const u8> message, int flags) override;
52 53
53 void SendPacket(ProxyPacket& packet); 54 void SendPacket(ProxyPacket& packet);
54 55
55 std::pair<s32, Errno> SendTo(u32 flags, const std::vector<u8>& message, 56 std::pair<s32, Errno> SendTo(u32 flags, std::span<const u8> message,
56 const SockAddrIn* addr) override; 57 const SockAddrIn* addr) override;
57 58
58 Errno SetLinger(bool enable, u32 linger) override; 59 Errno SetLinger(bool enable, u32 linger) override;
diff --git a/src/core/internal_network/sockets.h b/src/core/internal_network/sockets.h
index 2e328c645..4c7489258 100644
--- a/src/core/internal_network/sockets.h
+++ b/src/core/internal_network/sockets.h
@@ -5,6 +5,7 @@
5 5
6#include <map> 6#include <map>
7#include <memory> 7#include <memory>
8#include <span>
8#include <utility> 9#include <utility>
9 10
10#if defined(_WIN32) 11#if defined(_WIN32)
@@ -66,9 +67,9 @@ public:
66 virtual std::pair<s32, Errno> RecvFrom(int flags, std::vector<u8>& message, 67 virtual std::pair<s32, Errno> RecvFrom(int flags, std::vector<u8>& message,
67 SockAddrIn* addr) = 0; 68 SockAddrIn* addr) = 0;
68 69
69 virtual std::pair<s32, Errno> Send(const std::vector<u8>& message, int flags) = 0; 70 virtual std::pair<s32, Errno> Send(std::span<const u8> message, int flags) = 0;
70 71
71 virtual std::pair<s32, Errno> SendTo(u32 flags, const std::vector<u8>& message, 72 virtual std::pair<s32, Errno> SendTo(u32 flags, std::span<const u8> message,
72 const SockAddrIn* addr) = 0; 73 const SockAddrIn* addr) = 0;
73 74
74 virtual Errno SetLinger(bool enable, u32 linger) = 0; 75 virtual Errno SetLinger(bool enable, u32 linger) = 0;
@@ -138,9 +139,9 @@ public:
138 139
139 std::pair<s32, Errno> RecvFrom(int flags, std::vector<u8>& message, SockAddrIn* addr) override; 140 std::pair<s32, Errno> RecvFrom(int flags, std::vector<u8>& message, SockAddrIn* addr) override;
140 141
141 std::pair<s32, Errno> Send(const std::vector<u8>& message, int flags) override; 142 std::pair<s32, Errno> Send(std::span<const u8> message, int flags) override;
142 143
143 std::pair<s32, Errno> SendTo(u32 flags, const std::vector<u8>& message, 144 std::pair<s32, Errno> SendTo(u32 flags, std::span<const u8> message,
144 const SockAddrIn* addr) override; 145 const SockAddrIn* addr) override;
145 146
146 Errno SetLinger(bool enable, u32 linger) override; 147 Errno SetLinger(bool enable, u32 linger) override;
diff --git a/src/core/reporter.cpp b/src/core/reporter.cpp
index 77821e047..59dfb8767 100644
--- a/src/core/reporter.cpp
+++ b/src/core/reporter.cpp
@@ -312,7 +312,7 @@ void Reporter::SaveUnimplementedAppletReport(
312} 312}
313 313
314void Reporter::SavePlayReport(PlayReportType type, u64 title_id, 314void Reporter::SavePlayReport(PlayReportType type, u64 title_id,
315 const std::vector<std::vector<u8>>& data, 315 const std::vector<std::span<const u8>>& data,
316 std::optional<u64> process_id, std::optional<u128> user_id) const { 316 std::optional<u64> process_id, std::optional<u128> user_id) const {
317 if (!IsReportingEnabled()) { 317 if (!IsReportingEnabled()) {
318 return; 318 return;
diff --git a/src/core/reporter.h b/src/core/reporter.h
index 9fdb9d6c1..bb11f8e7c 100644
--- a/src/core/reporter.h
+++ b/src/core/reporter.h
@@ -5,6 +5,7 @@
5 5
6#include <array> 6#include <array>
7#include <optional> 7#include <optional>
8#include <span>
8#include <string> 9#include <string>
9#include <vector> 10#include <vector>
10#include "common/common_types.h" 11#include "common/common_types.h"
@@ -56,7 +57,8 @@ public:
56 System, 57 System,
57 }; 58 };
58 59
59 void SavePlayReport(PlayReportType type, u64 title_id, const std::vector<std::vector<u8>>& data, 60 void SavePlayReport(PlayReportType type, u64 title_id,
61 const std::vector<std::span<const u8>>& data,
60 std::optional<u64> process_id = {}, std::optional<u128> user_id = {}) const; 62 std::optional<u64> process_id = {}, std::optional<u128> user_id = {}) const;
61 63
62 // Used by error applet 64 // Used by error applet
diff --git a/src/input_common/drivers/joycon.cpp b/src/input_common/drivers/joycon.cpp
index cedc94e63..4fcfb4510 100644
--- a/src/input_common/drivers/joycon.cpp
+++ b/src/input_common/drivers/joycon.cpp
@@ -668,12 +668,10 @@ std::string Joycons::JoyconName(Joycon::ControllerType type) const {
668 return "Right Joycon"; 668 return "Right Joycon";
669 case Joycon::ControllerType::Pro: 669 case Joycon::ControllerType::Pro:
670 return "Pro Controller"; 670 return "Pro Controller";
671 case Joycon::ControllerType::Grip:
672 return "Grip Controller";
673 case Joycon::ControllerType::Dual: 671 case Joycon::ControllerType::Dual:
674 return "Dual Joycon"; 672 return "Dual Joycon";
675 default: 673 default:
676 return "Unknown Joycon"; 674 return "Unknown Switch Controller";
677 } 675 }
678} 676}
679} // namespace InputCommon 677} // namespace InputCommon
diff --git a/src/input_common/drivers/joycon.h b/src/input_common/drivers/joycon.h
index 316d383d8..2149ab7fd 100644
--- a/src/input_common/drivers/joycon.h
+++ b/src/input_common/drivers/joycon.h
@@ -15,7 +15,7 @@ using SerialNumber = std::array<u8, 15>;
15struct Battery; 15struct Battery;
16struct Color; 16struct Color;
17struct MotionData; 17struct MotionData;
18enum class ControllerType; 18enum class ControllerType : u8;
19enum class DriverResult; 19enum class DriverResult;
20enum class IrsResolution; 20enum class IrsResolution;
21class JoyconDriver; 21class JoyconDriver;
diff --git a/src/input_common/helpers/joycon_driver.cpp b/src/input_common/helpers/joycon_driver.cpp
index 3775e2d35..8f94c9f45 100644
--- a/src/input_common/helpers/joycon_driver.cpp
+++ b/src/input_common/helpers/joycon_driver.cpp
@@ -162,14 +162,14 @@ void JoyconDriver::InputThread(std::stop_token stop_token) {
162} 162}
163 163
164void JoyconDriver::OnNewData(std::span<u8> buffer) { 164void JoyconDriver::OnNewData(std::span<u8> buffer) {
165 const auto report_mode = static_cast<InputReport>(buffer[0]); 165 const auto report_mode = static_cast<ReportMode>(buffer[0]);
166 166
167 // Packages can be a litte bit inconsistent. Average the delta time to provide a smoother motion 167 // Packages can be a litte bit inconsistent. Average the delta time to provide a smoother motion
168 // experience 168 // experience
169 switch (report_mode) { 169 switch (report_mode) {
170 case InputReport::STANDARD_FULL_60HZ: 170 case ReportMode::STANDARD_FULL_60HZ:
171 case InputReport::NFC_IR_MODE_60HZ: 171 case ReportMode::NFC_IR_MODE_60HZ:
172 case InputReport::SIMPLE_HID_MODE: { 172 case ReportMode::SIMPLE_HID_MODE: {
173 const auto now = std::chrono::steady_clock::now(); 173 const auto now = std::chrono::steady_clock::now();
174 const auto new_delta_time = static_cast<u64>( 174 const auto new_delta_time = static_cast<u64>(
175 std::chrono::duration_cast<std::chrono::microseconds>(now - last_update).count()); 175 std::chrono::duration_cast<std::chrono::microseconds>(now - last_update).count());
@@ -190,7 +190,7 @@ void JoyconDriver::OnNewData(std::span<u8> buffer) {
190 }; 190 };
191 191
192 // TODO: Remove this when calibration is properly loaded and not calculated 192 // TODO: Remove this when calibration is properly loaded and not calculated
193 if (ring_connected && report_mode == InputReport::STANDARD_FULL_60HZ) { 193 if (ring_connected && report_mode == ReportMode::STANDARD_FULL_60HZ) {
194 InputReportActive data{}; 194 InputReportActive data{};
195 memcpy(&data, buffer.data(), sizeof(InputReportActive)); 195 memcpy(&data, buffer.data(), sizeof(InputReportActive));
196 calibration_protocol->GetRingCalibration(ring_calibration, data.ring_input); 196 calibration_protocol->GetRingCalibration(ring_calibration, data.ring_input);
@@ -228,16 +228,16 @@ void JoyconDriver::OnNewData(std::span<u8> buffer) {
228 } 228 }
229 229
230 switch (report_mode) { 230 switch (report_mode) {
231 case InputReport::STANDARD_FULL_60HZ: 231 case ReportMode::STANDARD_FULL_60HZ:
232 joycon_poller->ReadActiveMode(buffer, motion_status, ring_status); 232 joycon_poller->ReadActiveMode(buffer, motion_status, ring_status);
233 break; 233 break;
234 case InputReport::NFC_IR_MODE_60HZ: 234 case ReportMode::NFC_IR_MODE_60HZ:
235 joycon_poller->ReadNfcIRMode(buffer, motion_status); 235 joycon_poller->ReadNfcIRMode(buffer, motion_status);
236 break; 236 break;
237 case InputReport::SIMPLE_HID_MODE: 237 case ReportMode::SIMPLE_HID_MODE:
238 joycon_poller->ReadPassiveMode(buffer); 238 joycon_poller->ReadPassiveMode(buffer);
239 break; 239 break;
240 case InputReport::SUBCMD_REPLY: 240 case ReportMode::SUBCMD_REPLY:
241 LOG_DEBUG(Input, "Unhandled command reply"); 241 LOG_DEBUG(Input, "Unhandled command reply");
242 break; 242 break;
243 default: 243 default:
diff --git a/src/input_common/helpers/joycon_protocol/common_protocol.cpp b/src/input_common/helpers/joycon_protocol/common_protocol.cpp
index 0ef240344..2b42a4555 100644
--- a/src/input_common/helpers/joycon_protocol/common_protocol.cpp
+++ b/src/input_common/helpers/joycon_protocol/common_protocol.cpp
@@ -22,12 +22,9 @@ void JoyconCommonProtocol::SetNonBlocking() {
22} 22}
23 23
24DriverResult JoyconCommonProtocol::GetDeviceType(ControllerType& controller_type) { 24DriverResult JoyconCommonProtocol::GetDeviceType(ControllerType& controller_type) {
25 std::array<u8, 1> buffer{}; 25 const auto result = ReadSPI(SpiAddress::DEVICE_TYPE, controller_type);
26 const auto result = ReadRawSPI(SpiAddress::DEVICE_TYPE, buffer);
27 controller_type = ControllerType::None;
28 26
29 if (result == DriverResult::Success) { 27 if (result == DriverResult::Success) {
30 controller_type = static_cast<ControllerType>(buffer[0]);
31 // Fallback to 3rd party pro controllers 28 // Fallback to 3rd party pro controllers
32 if (controller_type == ControllerType::None) { 29 if (controller_type == ControllerType::None) {
33 controller_type = ControllerType::Pro; 30 controller_type = ControllerType::Pro;
@@ -40,6 +37,7 @@ DriverResult JoyconCommonProtocol::GetDeviceType(ControllerType& controller_type
40DriverResult JoyconCommonProtocol::CheckDeviceAccess(SDL_hid_device_info* device_info) { 37DriverResult JoyconCommonProtocol::CheckDeviceAccess(SDL_hid_device_info* device_info) {
41 ControllerType controller_type{ControllerType::None}; 38 ControllerType controller_type{ControllerType::None};
42 const auto result = GetDeviceType(controller_type); 39 const auto result = GetDeviceType(controller_type);
40
43 if (result != DriverResult::Success || controller_type == ControllerType::None) { 41 if (result != DriverResult::Success || controller_type == ControllerType::None) {
44 return DriverResult::UnsupportedControllerType; 42 return DriverResult::UnsupportedControllerType;
45 } 43 }
@@ -62,7 +60,7 @@ DriverResult JoyconCommonProtocol::SetReportMode(ReportMode report_mode) {
62 return SendSubCommand(SubCommand::SET_REPORT_MODE, buffer); 60 return SendSubCommand(SubCommand::SET_REPORT_MODE, buffer);
63} 61}
64 62
65DriverResult JoyconCommonProtocol::SendData(std::span<const u8> buffer) { 63DriverResult JoyconCommonProtocol::SendRawData(std::span<const u8> buffer) {
66 const auto result = SDL_hid_write(hidapi_handle->handle, buffer.data(), buffer.size()); 64 const auto result = SDL_hid_write(hidapi_handle->handle, buffer.data(), buffer.size());
67 65
68 if (result == -1) { 66 if (result == -1) {
@@ -72,15 +70,15 @@ DriverResult JoyconCommonProtocol::SendData(std::span<const u8> buffer) {
72 return DriverResult::Success; 70 return DriverResult::Success;
73} 71}
74 72
75DriverResult JoyconCommonProtocol::GetSubCommandResponse(SubCommand sc, std::vector<u8>& output) { 73DriverResult JoyconCommonProtocol::GetSubCommandResponse(SubCommand sc,
74 SubCommandResponse& output) {
76 constexpr int timeout_mili = 66; 75 constexpr int timeout_mili = 66;
77 constexpr int MaxTries = 15; 76 constexpr int MaxTries = 15;
78 int tries = 0; 77 int tries = 0;
79 output.resize(MaxSubCommandResponseSize);
80 78
81 do { 79 do {
82 int result = SDL_hid_read_timeout(hidapi_handle->handle, output.data(), 80 int result = SDL_hid_read_timeout(hidapi_handle->handle, reinterpret_cast<u8*>(&output),
83 MaxSubCommandResponseSize, timeout_mili); 81 sizeof(SubCommandResponse), timeout_mili);
84 82
85 if (result < 1) { 83 if (result < 1) {
86 LOG_ERROR(Input, "No response from joycon"); 84 LOG_ERROR(Input, "No response from joycon");
@@ -88,27 +86,28 @@ DriverResult JoyconCommonProtocol::GetSubCommandResponse(SubCommand sc, std::vec
88 if (tries++ > MaxTries) { 86 if (tries++ > MaxTries) {
89 return DriverResult::Timeout; 87 return DriverResult::Timeout;
90 } 88 }
91 } while (output[0] != 0x21 && output[14] != static_cast<u8>(sc)); 89 } while (output.input_report.report_mode != ReportMode::SUBCMD_REPLY &&
92 90 output.sub_command != sc);
93 if (output[0] != 0x21 && output[14] != static_cast<u8>(sc)) {
94 return DriverResult::WrongReply;
95 }
96 91
97 return DriverResult::Success; 92 return DriverResult::Success;
98} 93}
99 94
100DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const u8> buffer, 95DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const u8> buffer,
101 std::vector<u8>& output) { 96 SubCommandResponse& output) {
102 std::vector<u8> local_buffer(MaxResponseSize); 97 SubCommandPacket packet{
103 98 .output_report = OutputReport::RUMBLE_AND_SUBCMD,
104 local_buffer[0] = static_cast<u8>(OutputReport::RUMBLE_AND_SUBCMD); 99 .packet_counter = GetCounter(),
105 local_buffer[1] = GetCounter(); 100 .sub_command = sc,
106 local_buffer[10] = static_cast<u8>(sc); 101 .command_data = {},
107 for (std::size_t i = 0; i < buffer.size(); ++i) { 102 };
108 local_buffer[11 + i] = buffer[i]; 103
104 if (buffer.size() > packet.command_data.size()) {
105 return DriverResult::InvalidParameters;
109 } 106 }
110 107
111 auto result = SendData(local_buffer); 108 memcpy(packet.command_data.data(), buffer.data(), buffer.size());
109
110 auto result = SendData(packet);
112 111
113 if (result != DriverResult::Success) { 112 if (result != DriverResult::Success) {
114 return result; 113 return result;
@@ -120,46 +119,57 @@ DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const
120} 119}
121 120
122DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const u8> buffer) { 121DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const u8> buffer) {
123 std::vector<u8> output; 122 SubCommandResponse output{};
124 return SendSubCommand(sc, buffer, output); 123 return SendSubCommand(sc, buffer, output);
125} 124}
126 125
127DriverResult JoyconCommonProtocol::SendMCUCommand(SubCommand sc, std::span<const u8> buffer) { 126DriverResult JoyconCommonProtocol::SendMCUCommand(SubCommand sc, std::span<const u8> buffer) {
128 std::vector<u8> local_buffer(MaxResponseSize); 127 SubCommandPacket packet{
129 128 .output_report = OutputReport::MCU_DATA,
130 local_buffer[0] = static_cast<u8>(OutputReport::MCU_DATA); 129 .packet_counter = GetCounter(),
131 local_buffer[1] = GetCounter(); 130 .sub_command = sc,
132 local_buffer[10] = static_cast<u8>(sc); 131 .command_data = {},
133 for (std::size_t i = 0; i < buffer.size(); ++i) { 132 };
134 local_buffer[11 + i] = buffer[i]; 133
134 if (buffer.size() > packet.command_data.size()) {
135 return DriverResult::InvalidParameters;
135 } 136 }
136 137
137 return SendData(local_buffer); 138 memcpy(packet.command_data.data(), buffer.data(), buffer.size());
139
140 return SendData(packet);
138} 141}
139 142
140DriverResult JoyconCommonProtocol::SendVibrationReport(std::span<const u8> buffer) { 143DriverResult JoyconCommonProtocol::SendVibrationReport(std::span<const u8> buffer) {
141 std::vector<u8> local_buffer(MaxResponseSize); 144 VibrationPacket packet{
142 145 .output_report = OutputReport::RUMBLE_ONLY,
143 local_buffer[0] = static_cast<u8>(Joycon::OutputReport::RUMBLE_ONLY); 146 .packet_counter = GetCounter(),
144 local_buffer[1] = GetCounter(); 147 .vibration_data = {},
148 };
149
150 if (buffer.size() > packet.vibration_data.size()) {
151 return DriverResult::InvalidParameters;
152 }
145 153
146 memcpy(local_buffer.data() + 2, buffer.data(), buffer.size()); 154 memcpy(packet.vibration_data.data(), buffer.data(), buffer.size());
147 155
148 return SendData(local_buffer); 156 return SendData(packet);
149} 157}
150 158
151DriverResult JoyconCommonProtocol::ReadRawSPI(SpiAddress addr, std::span<u8> output) { 159DriverResult JoyconCommonProtocol::ReadRawSPI(SpiAddress addr, std::span<u8> output) {
152 constexpr std::size_t HeaderSize = 20; 160 constexpr std::size_t HeaderSize = 5;
153 constexpr std::size_t MaxTries = 10; 161 constexpr std::size_t MaxTries = 10;
154 const auto size = output.size();
155 std::size_t tries = 0; 162 std::size_t tries = 0;
156 std::array<u8, 5> buffer = {0x00, 0x00, 0x00, 0x00, static_cast<u8>(size)}; 163 SubCommandResponse response{};
157 std::vector<u8> local_buffer{}; 164 std::array<u8, sizeof(ReadSpiPacket)> buffer{};
158 165 const ReadSpiPacket packet_data{
159 buffer[0] = static_cast<u8>(static_cast<u16>(addr) & 0x00FF); 166 .spi_address = addr,
160 buffer[1] = static_cast<u8>((static_cast<u16>(addr) & 0xFF00) >> 8); 167 .size = static_cast<u8>(output.size()),
168 };
169
170 memcpy(buffer.data(), &packet_data, sizeof(ReadSpiPacket));
161 do { 171 do {
162 const auto result = SendSubCommand(SubCommand::SPI_FLASH_READ, buffer, local_buffer); 172 const auto result = SendSubCommand(SubCommand::SPI_FLASH_READ, buffer, response);
163 if (result != DriverResult::Success) { 173 if (result != DriverResult::Success) {
164 return result; 174 return result;
165 } 175 }
@@ -167,14 +177,14 @@ DriverResult JoyconCommonProtocol::ReadRawSPI(SpiAddress addr, std::span<u8> out
167 if (tries++ > MaxTries) { 177 if (tries++ > MaxTries) {
168 return DriverResult::Timeout; 178 return DriverResult::Timeout;
169 } 179 }
170 } while (local_buffer[15] != buffer[0] || local_buffer[16] != buffer[1]); 180 } while (response.spi_address != addr);
171 181
172 if (local_buffer.size() < size + HeaderSize) { 182 if (response.command_data.size() < packet_data.size + HeaderSize) {
173 return DriverResult::WrongReply; 183 return DriverResult::WrongReply;
174 } 184 }
175 185
176 // Remove header from output 186 // Remove header from output
177 memcpy(output.data(), local_buffer.data() + HeaderSize, size); 187 memcpy(output.data(), response.command_data.data() + HeaderSize, packet_data.size);
178 return DriverResult::Success; 188 return DriverResult::Success;
179} 189}
180 190
@@ -183,7 +193,7 @@ DriverResult JoyconCommonProtocol::EnableMCU(bool enable) {
183 const auto result = SendSubCommand(SubCommand::SET_MCU_STATE, mcu_state); 193 const auto result = SendSubCommand(SubCommand::SET_MCU_STATE, mcu_state);
184 194
185 if (result != DriverResult::Success) { 195 if (result != DriverResult::Success) {
186 LOG_ERROR(Input, "SendMCUData failed with error {}", result); 196 LOG_ERROR(Input, "Failed with error {}", result);
187 } 197 }
188 198
189 return result; 199 return result;
@@ -198,22 +208,21 @@ DriverResult JoyconCommonProtocol::ConfigureMCU(const MCUConfig& config) {
198 const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, config_buffer); 208 const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, config_buffer);
199 209
200 if (result != DriverResult::Success) { 210 if (result != DriverResult::Success) {
201 LOG_ERROR(Input, "Set MCU config failed with error {}", result); 211 LOG_ERROR(Input, "Failed with error {}", result);
202 } 212 }
203 213
204 return result; 214 return result;
205} 215}
206 216
207DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode_, 217DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode,
208 std::vector<u8>& output) { 218 MCUCommandResponse& output) {
209 const int report_mode = static_cast<u8>(report_mode_);
210 constexpr int TimeoutMili = 200; 219 constexpr int TimeoutMili = 200;
211 constexpr int MaxTries = 9; 220 constexpr int MaxTries = 9;
212 int tries = 0; 221 int tries = 0;
213 output.resize(0x170);
214 222
215 do { 223 do {
216 int result = SDL_hid_read_timeout(hidapi_handle->handle, output.data(), 0x170, TimeoutMili); 224 int result = SDL_hid_read_timeout(hidapi_handle->handle, reinterpret_cast<u8*>(&output),
225 sizeof(MCUCommandResponse), TimeoutMili);
217 226
218 if (result < 1) { 227 if (result < 1) {
219 LOG_ERROR(Input, "No response from joycon attempt {}", tries); 228 LOG_ERROR(Input, "No response from joycon attempt {}", tries);
@@ -221,28 +230,29 @@ DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode_,
221 if (tries++ > MaxTries) { 230 if (tries++ > MaxTries) {
222 return DriverResult::Timeout; 231 return DriverResult::Timeout;
223 } 232 }
224 } while (output[0] != report_mode || output[49] == 0xFF); 233 } while (output.input_report.report_mode != report_mode ||
225 234 output.mcu_report == MCUReport::EmptyAwaitingCmd);
226 if (output[0] != report_mode || output[49] == 0xFF) {
227 return DriverResult::WrongReply;
228 }
229 235
230 return DriverResult::Success; 236 return DriverResult::Success;
231} 237}
232 238
233DriverResult JoyconCommonProtocol::SendMCUData(ReportMode report_mode, SubCommand sc, 239DriverResult JoyconCommonProtocol::SendMCUData(ReportMode report_mode, SubCommand sc,
234 std::span<const u8> buffer, 240 std::span<const u8> buffer,
235 std::vector<u8>& output) { 241 MCUCommandResponse& output) {
236 std::vector<u8> local_buffer(MaxResponseSize); 242 SubCommandPacket packet{
237 243 .output_report = OutputReport::MCU_DATA,
238 local_buffer[0] = static_cast<u8>(OutputReport::MCU_DATA); 244 .packet_counter = GetCounter(),
239 local_buffer[1] = GetCounter(); 245 .sub_command = sc,
240 local_buffer[9] = static_cast<u8>(sc); 246 .command_data = {},
241 for (std::size_t i = 0; i < buffer.size(); ++i) { 247 };
242 local_buffer[10 + i] = buffer[i]; 248
249 if (buffer.size() > packet.command_data.size()) {
250 return DriverResult::InvalidParameters;
243 } 251 }
244 252
245 auto result = SendData(local_buffer); 253 memcpy(packet.command_data.data(), buffer.data(), buffer.size());
254
255 auto result = SendData(packet);
246 256
247 if (result != DriverResult::Success) { 257 if (result != DriverResult::Success) {
248 return result; 258 return result;
@@ -254,7 +264,7 @@ DriverResult JoyconCommonProtocol::SendMCUData(ReportMode report_mode, SubComman
254} 264}
255 265
256DriverResult JoyconCommonProtocol::WaitSetMCUMode(ReportMode report_mode, MCUMode mode) { 266DriverResult JoyconCommonProtocol::WaitSetMCUMode(ReportMode report_mode, MCUMode mode) {
257 std::vector<u8> output; 267 MCUCommandResponse output{};
258 constexpr std::size_t MaxTries{8}; 268 constexpr std::size_t MaxTries{8};
259 std::size_t tries{}; 269 std::size_t tries{};
260 270
@@ -269,7 +279,8 @@ DriverResult JoyconCommonProtocol::WaitSetMCUMode(ReportMode report_mode, MCUMod
269 if (tries++ > MaxTries) { 279 if (tries++ > MaxTries) {
270 return DriverResult::WrongReply; 280 return DriverResult::WrongReply;
271 } 281 }
272 } while (output[49] != 1 || output[56] != static_cast<u8>(mode)); 282 } while (output.mcu_report != MCUReport::StateReport ||
283 output.mcu_data[6] != static_cast<u8>(mode));
273 284
274 return DriverResult::Success; 285 return DriverResult::Success;
275} 286}
diff --git a/src/input_common/helpers/joycon_protocol/common_protocol.h b/src/input_common/helpers/joycon_protocol/common_protocol.h
index 75d3f20a4..f44f73ba4 100644
--- a/src/input_common/helpers/joycon_protocol/common_protocol.h
+++ b/src/input_common/helpers/joycon_protocol/common_protocol.h
@@ -57,22 +57,31 @@ public:
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 SendData(std::span<const u8> buffer); 60 DriverResult SendRawData(std::span<const u8> buffer);
61
62 template <typename Output>
63 requires std::is_trivially_copyable_v<Output>
64 DriverResult SendData(const Output& output) {
65 std::array<u8, sizeof(Output)> buffer;
66 std::memcpy(buffer.data(), &output, sizeof(Output));
67 return SendRawData(buffer);
68 }
61 69
62 /** 70 /**
63 * Waits for incoming data of the joycon device that matchs the subcommand 71 * Waits for incoming data of the joycon device that matchs the subcommand
64 * @param sub_command type of data to be returned 72 * @param sub_command type of data to be returned
65 * @returns a buffer containing the responce 73 * @returns a buffer containing the response
66 */ 74 */
67 DriverResult GetSubCommandResponse(SubCommand sub_command, std::vector<u8>& output); 75 DriverResult GetSubCommandResponse(SubCommand sub_command, SubCommandResponse& output);
68 76
69 /** 77 /**
70 * Sends a sub command to the device and waits for it's reply 78 * Sends a sub command to the device and waits for it's reply
71 * @param sc sub command to be send 79 * @param sc sub command to be send
72 * @param buffer data to be send 80 * @param buffer data to be send
73 * @returns output buffer containing the responce 81 * @returns output buffer containing the response
74 */ 82 */
75 DriverResult SendSubCommand(SubCommand sc, std::span<const u8> buffer, std::vector<u8>& output); 83 DriverResult SendSubCommand(SubCommand sc, std::span<const u8> buffer,
84 SubCommandResponse& output);
76 85
77 /** 86 /**
78 * Sends a sub command to the device and waits for it's reply and ignores the output 87 * Sends a sub command to the device and waits for it's reply and ignores the output
@@ -97,18 +106,18 @@ public:
97 /** 106 /**
98 * Reads the SPI memory stored on the joycon 107 * Reads the SPI memory stored on the joycon
99 * @param Initial address location 108 * @param Initial address location
100 * @returns output buffer containing the responce 109 * @returns output buffer containing the response
101 */ 110 */
102 DriverResult ReadRawSPI(SpiAddress addr, std::span<u8> output); 111 DriverResult ReadRawSPI(SpiAddress addr, std::span<u8> output);
103 112
104 /** 113 /**
105 * Reads the SPI memory stored on the joycon 114 * Reads the SPI memory stored on the joycon
106 * @param Initial address location 115 * @param Initial address location
107 * @returns output object containing the responce 116 * @returns output object containing the response
108 */ 117 */
109 template <typename Output> 118 template <typename Output>
110 requires std::is_trivially_copyable_v<Output> DriverResult ReadSPI(SpiAddress addr, 119 requires std::is_trivially_copyable_v<Output>
111 Output& output) { 120 DriverResult ReadSPI(SpiAddress addr, Output& output) {
112 std::array<u8, sizeof(Output)> buffer; 121 std::array<u8, sizeof(Output)> buffer;
113 output = {}; 122 output = {};
114 123
@@ -136,19 +145,19 @@ public:
136 /** 145 /**
137 * Waits until there's MCU data available. On timeout returns error 146 * Waits until there's MCU data available. On timeout returns error
138 * @param report mode of the expected reply 147 * @param report mode of the expected reply
139 * @returns a buffer containing the responce 148 * @returns a buffer containing the response
140 */ 149 */
141 DriverResult GetMCUDataResponse(ReportMode report_mode_, std::vector<u8>& output); 150 DriverResult GetMCUDataResponse(ReportMode report_mode_, MCUCommandResponse& output);
142 151
143 /** 152 /**
144 * Sends data to the MCU chip and waits for it's reply 153 * Sends data to the MCU chip and waits for it's reply
145 * @param report mode of the expected reply 154 * @param report mode of the expected reply
146 * @param sub command to be send 155 * @param sub command to be send
147 * @param buffer data to be send 156 * @param buffer data to be send
148 * @returns output buffer containing the responce 157 * @returns output buffer containing the response
149 */ 158 */
150 DriverResult SendMCUData(ReportMode report_mode, SubCommand sc, std::span<const u8> buffer, 159 DriverResult SendMCUData(ReportMode report_mode, SubCommand sc, std::span<const u8> buffer,
151 std::vector<u8>& output); 160 MCUCommandResponse& output);
152 161
153 /** 162 /**
154 * Wait's until the MCU chip is on the specified mode 163 * Wait's until the MCU chip is on the specified mode
diff --git a/src/input_common/helpers/joycon_protocol/generic_functions.cpp b/src/input_common/helpers/joycon_protocol/generic_functions.cpp
index 484c208e6..548a4b9e3 100644
--- a/src/input_common/helpers/joycon_protocol/generic_functions.cpp
+++ b/src/input_common/helpers/joycon_protocol/generic_functions.cpp
@@ -32,13 +32,13 @@ DriverResult GenericProtocol::TriggersElapsed() {
32 32
33DriverResult GenericProtocol::GetDeviceInfo(DeviceInfo& device_info) { 33DriverResult GenericProtocol::GetDeviceInfo(DeviceInfo& device_info) {
34 ScopedSetBlocking sb(this); 34 ScopedSetBlocking sb(this);
35 std::vector<u8> output; 35 SubCommandResponse output{};
36 36
37 const auto result = SendSubCommand(SubCommand::REQ_DEV_INFO, {}, output); 37 const auto result = SendSubCommand(SubCommand::REQ_DEV_INFO, {}, output);
38 38
39 device_info = {}; 39 device_info = {};
40 if (result == DriverResult::Success) { 40 if (result == DriverResult::Success) {
41 memcpy(&device_info, output.data(), sizeof(DeviceInfo)); 41 device_info = output.device_info;
42 } 42 }
43 43
44 return result; 44 return result;
diff --git a/src/input_common/helpers/joycon_protocol/irs.cpp b/src/input_common/helpers/joycon_protocol/irs.cpp
index 09e17bc5b..731fd5981 100644
--- a/src/input_common/helpers/joycon_protocol/irs.cpp
+++ b/src/input_common/helpers/joycon_protocol/irs.cpp
@@ -132,7 +132,7 @@ DriverResult IrsProtocol::RequestImage(std::span<u8> buffer) {
132DriverResult IrsProtocol::ConfigureIrs() { 132DriverResult 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 std::vector<u8> output; 135 SubCommandResponse output{};
136 std::size_t tries = 0; 136 std::size_t tries = 0;
137 137
138 const IrsConfigure irs_configuration{ 138 const IrsConfigure irs_configuration{
@@ -158,7 +158,7 @@ DriverResult IrsProtocol::ConfigureIrs() {
158 if (tries++ >= max_tries) { 158 if (tries++ >= max_tries) {
159 return DriverResult::WrongReply; 159 return DriverResult::WrongReply;
160 } 160 }
161 } while (output[15] != 0x0b); 161 } while (output.command_data[0] != 0x0b);
162 162
163 return DriverResult::Success; 163 return DriverResult::Success;
164} 164}
@@ -167,7 +167,7 @@ DriverResult IrsProtocol::WriteRegistersStep1() {
167 LOG_DEBUG(Input, "WriteRegistersStep1"); 167 LOG_DEBUG(Input, "WriteRegistersStep1");
168 DriverResult result{DriverResult::Success}; 168 DriverResult result{DriverResult::Success};
169 constexpr std::size_t max_tries = 28; 169 constexpr std::size_t max_tries = 28;
170 std::vector<u8> output; 170 SubCommandResponse output{};
171 std::size_t tries = 0; 171 std::size_t tries = 0;
172 172
173 const IrsWriteRegisters irs_registers{ 173 const IrsWriteRegisters irs_registers{
@@ -218,7 +218,8 @@ DriverResult IrsProtocol::WriteRegistersStep1() {
218 if (tries++ >= max_tries) { 218 if (tries++ >= max_tries) {
219 return DriverResult::WrongReply; 219 return DriverResult::WrongReply;
220 } 220 }
221 } while (!(output[15] == 0x13 && output[17] == 0x07) && output[15] != 0x23); 221 } while (!(output.command_data[0] == 0x13 && output.command_data[2] == 0x07) &&
222 output.command_data[0] != 0x23);
222 223
223 return DriverResult::Success; 224 return DriverResult::Success;
224} 225}
@@ -226,7 +227,7 @@ DriverResult IrsProtocol::WriteRegistersStep1() {
226DriverResult IrsProtocol::WriteRegistersStep2() { 227DriverResult IrsProtocol::WriteRegistersStep2() {
227 LOG_DEBUG(Input, "WriteRegistersStep2"); 228 LOG_DEBUG(Input, "WriteRegistersStep2");
228 constexpr std::size_t max_tries = 28; 229 constexpr std::size_t max_tries = 28;
229 std::vector<u8> output; 230 SubCommandResponse output{};
230 std::size_t tries = 0; 231 std::size_t tries = 0;
231 232
232 const IrsWriteRegisters irs_registers{ 233 const IrsWriteRegisters irs_registers{
@@ -260,7 +261,7 @@ DriverResult IrsProtocol::WriteRegistersStep2() {
260 if (tries++ >= max_tries) { 261 if (tries++ >= max_tries) {
261 return DriverResult::WrongReply; 262 return DriverResult::WrongReply;
262 } 263 }
263 } while (output[15] != 0x13 && output[15] != 0x23); 264 } while (output.command_data[0] != 0x13 && output.command_data[0] != 0x23);
264 265
265 return DriverResult::Success; 266 return DriverResult::Success;
266} 267}
diff --git a/src/input_common/helpers/joycon_protocol/joycon_types.h b/src/input_common/helpers/joycon_protocol/joycon_types.h
index 14b07bfb5..b91934990 100644
--- a/src/input_common/helpers/joycon_protocol/joycon_types.h
+++ b/src/input_common/helpers/joycon_protocol/joycon_types.h
@@ -19,20 +19,24 @@
19namespace InputCommon::Joycon { 19namespace InputCommon::Joycon {
20constexpr u32 MaxErrorCount = 50; 20constexpr u32 MaxErrorCount = 50;
21constexpr u32 MaxBufferSize = 368; 21constexpr u32 MaxBufferSize = 368;
22constexpr u32 MaxResponseSize = 49;
23constexpr u32 MaxSubCommandResponseSize = 64;
24constexpr std::array<u8, 8> DefaultVibrationBuffer{0x0, 0x1, 0x40, 0x40, 0x0, 0x1, 0x40, 0x40}; 22constexpr std::array<u8, 8> DefaultVibrationBuffer{0x0, 0x1, 0x40, 0x40, 0x0, 0x1, 0x40, 0x40};
25 23
26using MacAddress = std::array<u8, 6>; 24using MacAddress = std::array<u8, 6>;
27using SerialNumber = std::array<u8, 15>; 25using SerialNumber = std::array<u8, 15>;
28 26
29enum class ControllerType { 27enum class ControllerType : u8 {
30 None, 28 None = 0x00,
31 Left, 29 Left = 0x01,
32 Right, 30 Right = 0x02,
33 Pro, 31 Pro = 0x03,
34 Grip, 32 Dual = 0x05, // TODO: Verify this id
35 Dual, 33 LarkHvc1 = 0x07,
34 LarkHvc2 = 0x08,
35 LarkNesLeft = 0x09,
36 LarkNesRight = 0x0A,
37 Lucia = 0x0B,
38 Lagon = 0x0C,
39 Lager = 0x0D,
36}; 40};
37 41
38enum class PadAxes { 42enum class PadAxes {
@@ -99,14 +103,6 @@ enum class OutputReport : u8 {
99 USB_CMD = 0x80, 103 USB_CMD = 0x80,
100}; 104};
101 105
102enum class InputReport : u8 {
103 SUBCMD_REPLY = 0x21,
104 STANDARD_FULL_60HZ = 0x30,
105 NFC_IR_MODE_60HZ = 0x31,
106 SIMPLE_HID_MODE = 0x3F,
107 INPUT_USB_RESPONSE = 0x81,
108};
109
110enum class FeatureReport : u8 { 106enum class FeatureReport : u8 {
111 Last_SUBCMD = 0x02, 107 Last_SUBCMD = 0x02,
112 OTA_GW_UPGRADE = 0x70, 108 OTA_GW_UPGRADE = 0x70,
@@ -143,9 +139,10 @@ enum class SubCommand : u8 {
143 ENABLE_VIBRATION = 0x48, 139 ENABLE_VIBRATION = 0x48,
144 GET_REGULATED_VOLTAGE = 0x50, 140 GET_REGULATED_VOLTAGE = 0x50,
145 SET_EXTERNAL_CONFIG = 0x58, 141 SET_EXTERNAL_CONFIG = 0x58,
146 UNKNOWN_RINGCON = 0x59, 142 GET_EXTERNAL_DEVICE_INFO = 0x59,
147 UNKNOWN_RINGCON2 = 0x5A, 143 ENABLE_EXTERNAL_POLLING = 0x5A,
148 UNKNOWN_RINGCON3 = 0x5C, 144 DISABLE_EXTERNAL_POLLING = 0x5B,
145 SET_EXTERNAL_FORMAT_CONFIG = 0x5C,
149}; 146};
150 147
151enum class UsbSubCommand : u8 { 148enum class UsbSubCommand : u8 {
@@ -164,20 +161,26 @@ enum class CalibrationMagic : u8 {
164 USR_MAGIC_1 = 0xA1, 161 USR_MAGIC_1 = 0xA1,
165}; 162};
166 163
167enum class SpiAddress { 164enum class SpiAddress : u16 {
168 SERIAL_NUMBER = 0X6000, 165 MAGIC = 0x0000,
169 DEVICE_TYPE = 0X6012, 166 MAC_ADDRESS = 0x0015,
170 COLOR_EXIST = 0X601B, 167 PAIRING_INFO = 0x2000,
171 FACT_LEFT_DATA = 0X603d, 168 SHIPMENT = 0x5000,
172 FACT_RIGHT_DATA = 0X6046, 169 SERIAL_NUMBER = 0x6000,
173 COLOR_DATA = 0X6050, 170 DEVICE_TYPE = 0x6012,
174 FACT_IMU_DATA = 0X6020, 171 FORMAT_VERSION = 0x601B,
175 USER_LEFT_MAGIC = 0X8010, 172 FACT_IMU_DATA = 0x6020,
176 USER_LEFT_DATA = 0X8012, 173 FACT_LEFT_DATA = 0x603d,
177 USER_RIGHT_MAGIC = 0X801B, 174 FACT_RIGHT_DATA = 0x6046,
178 USER_RIGHT_DATA = 0X801D, 175 COLOR_DATA = 0x6050,
179 USER_IMU_MAGIC = 0X8026, 176 DESIGN_VARIATION = 0x605C,
180 USER_IMU_DATA = 0X8028, 177 SENSOR_DATA = 0x6080,
178 USER_LEFT_MAGIC = 0x8010,
179 USER_LEFT_DATA = 0x8012,
180 USER_RIGHT_MAGIC = 0x801B,
181 USER_RIGHT_DATA = 0x801D,
182 USER_IMU_MAGIC = 0x8026,
183 USER_IMU_DATA = 0x8028,
181}; 184};
182 185
183enum class ReportMode : u8 { 186enum class ReportMode : u8 {
@@ -185,10 +188,12 @@ enum class ReportMode : u8 {
185 ACTIVE_POLLING_NFC_IR_CAMERA_CONFIGURATION = 0x01, 188 ACTIVE_POLLING_NFC_IR_CAMERA_CONFIGURATION = 0x01,
186 ACTIVE_POLLING_NFC_IR_CAMERA_DATA_CONFIGURATION = 0x02, 189 ACTIVE_POLLING_NFC_IR_CAMERA_DATA_CONFIGURATION = 0x02,
187 ACTIVE_POLLING_IR_CAMERA_DATA = 0x03, 190 ACTIVE_POLLING_IR_CAMERA_DATA = 0x03,
191 SUBCMD_REPLY = 0x21,
188 MCU_UPDATE_STATE = 0x23, 192 MCU_UPDATE_STATE = 0x23,
189 STANDARD_FULL_60HZ = 0x30, 193 STANDARD_FULL_60HZ = 0x30,
190 NFC_IR_MODE_60HZ = 0x31, 194 NFC_IR_MODE_60HZ = 0x31,
191 SIMPLE_HID_MODE = 0x3F, 195 SIMPLE_HID_MODE = 0x3F,
196 INPUT_USB_RESPONSE = 0x81,
192}; 197};
193 198
194enum class GyroSensitivity : u8 { 199enum class GyroSensitivity : u8 {
@@ -359,10 +364,16 @@ enum class IrRegistersAddress : u16 {
359 DenoiseColor = 0x6901, 364 DenoiseColor = 0x6901,
360}; 365};
361 366
367enum class ExternalDeviceId : u16 {
368 RingController = 0x2000,
369 Starlink = 0x2800,
370};
371
362enum class DriverResult { 372enum class DriverResult {
363 Success, 373 Success,
364 WrongReply, 374 WrongReply,
365 Timeout, 375 Timeout,
376 InvalidParameters,
366 UnsupportedControllerType, 377 UnsupportedControllerType,
367 HandleInUse, 378 HandleInUse,
368 ErrorReadingData, 379 ErrorReadingData,
@@ -485,7 +496,7 @@ static_assert(sizeof(MCUConfig) == 0x26, "MCUConfig is an invalid size");
485 496
486#pragma pack(push, 1) 497#pragma pack(push, 1)
487struct InputReportPassive { 498struct InputReportPassive {
488 InputReport report_mode; 499 ReportMode report_mode;
489 u16 button_input; 500 u16 button_input;
490 u8 stick_state; 501 u8 stick_state;
491 std::array<u8, 10> unknown_data; 502 std::array<u8, 10> unknown_data;
@@ -493,7 +504,7 @@ struct InputReportPassive {
493static_assert(sizeof(InputReportPassive) == 0xE, "InputReportPassive is an invalid size"); 504static_assert(sizeof(InputReportPassive) == 0xE, "InputReportPassive is an invalid size");
494 505
495struct InputReportActive { 506struct InputReportActive {
496 InputReport report_mode; 507 ReportMode report_mode;
497 u8 packet_id; 508 u8 packet_id;
498 Battery battery_status; 509 Battery battery_status;
499 std::array<u8, 3> button_input; 510 std::array<u8, 3> button_input;
@@ -507,7 +518,7 @@ struct InputReportActive {
507static_assert(sizeof(InputReportActive) == 0x29, "InputReportActive is an invalid size"); 518static_assert(sizeof(InputReportActive) == 0x29, "InputReportActive is an invalid size");
508 519
509struct InputReportNfcIr { 520struct InputReportNfcIr {
510 InputReport report_mode; 521 ReportMode report_mode;
511 u8 packet_id; 522 u8 packet_id;
512 Battery battery_status; 523 Battery battery_status;
513 std::array<u8, 3> button_input; 524 std::array<u8, 3> button_input;
@@ -605,9 +616,11 @@ static_assert(sizeof(FirmwareVersion) == 0x2, "FirmwareVersion is an invalid siz
605 616
606struct DeviceInfo { 617struct DeviceInfo {
607 FirmwareVersion firmware; 618 FirmwareVersion firmware;
619 std::array<u8, 2> unknown_1;
608 MacAddress mac_address; 620 MacAddress mac_address;
621 std::array<u8, 2> unknown_2;
609}; 622};
610static_assert(sizeof(DeviceInfo) == 0x8, "DeviceInfo is an invalid size"); 623static_assert(sizeof(DeviceInfo) == 0xC, "DeviceInfo is an invalid size");
611 624
612struct MotionStatus { 625struct MotionStatus {
613 bool is_enabled; 626 bool is_enabled;
@@ -623,6 +636,53 @@ struct RingStatus {
623 s16 min_value; 636 s16 min_value;
624}; 637};
625 638
639struct VibrationPacket {
640 OutputReport output_report;
641 u8 packet_counter;
642 std::array<u8, 0x8> vibration_data;
643};
644static_assert(sizeof(VibrationPacket) == 0xA, "VibrationPacket is an invalid size");
645
646struct SubCommandPacket {
647 OutputReport output_report;
648 u8 packet_counter;
649 INSERT_PADDING_BYTES(0x8); // This contains vibration data
650 SubCommand sub_command;
651 std::array<u8, 0x26> command_data;
652};
653static_assert(sizeof(SubCommandPacket) == 0x31, "SubCommandPacket is an invalid size");
654
655#pragma pack(push, 1)
656struct ReadSpiPacket {
657 SpiAddress spi_address;
658 INSERT_PADDING_BYTES(0x2);
659 u8 size;
660};
661static_assert(sizeof(ReadSpiPacket) == 0x5, "ReadSpiPacket is an invalid size");
662
663struct SubCommandResponse {
664 InputReportPassive input_report;
665 SubCommand sub_command;
666 union {
667 std::array<u8, 0x30> command_data;
668 SpiAddress spi_address; // Reply from SPI_FLASH_READ subcommand
669 ExternalDeviceId external_device_id; // Reply from GET_EXTERNAL_DEVICE_INFO subcommand
670 DeviceInfo device_info; // Reply from REQ_DEV_INFO subcommand
671 };
672 u8 crc; // This is never used
673};
674static_assert(sizeof(SubCommandResponse) == 0x40, "SubCommandResponse is an invalid size");
675#pragma pack(pop)
676
677struct MCUCommandResponse {
678 InputReportNfcIr input_report;
679 INSERT_PADDING_BYTES(0x8);
680 MCUReport mcu_report;
681 std::array<u8, 0x13D> mcu_data;
682 u8 crc;
683};
684static_assert(sizeof(MCUCommandResponse) == 0x170, "MCUCommandResponse is an invalid size");
685
626struct JoyconCallbacks { 686struct JoyconCallbacks {
627 std::function<void(Battery)> on_battery_data; 687 std::function<void(Battery)> on_battery_data;
628 std::function<void(Color)> on_color_data; 688 std::function<void(Color)> on_color_data;
diff --git a/src/input_common/helpers/joycon_protocol/nfc.cpp b/src/input_common/helpers/joycon_protocol/nfc.cpp
index 5c0f71722..eeba82986 100644
--- a/src/input_common/helpers/joycon_protocol/nfc.cpp
+++ b/src/input_common/helpers/joycon_protocol/nfc.cpp
@@ -110,7 +110,7 @@ bool NfcProtocol::HasAmiibo() {
110 110
111DriverResult NfcProtocol::WaitUntilNfcIsReady() { 111DriverResult NfcProtocol::WaitUntilNfcIsReady() {
112 constexpr std::size_t timeout_limit = 10; 112 constexpr std::size_t timeout_limit = 10;
113 std::vector<u8> output; 113 MCUCommandResponse output{};
114 std::size_t tries = 0; 114 std::size_t tries = 0;
115 115
116 do { 116 do {
@@ -122,8 +122,9 @@ DriverResult NfcProtocol::WaitUntilNfcIsReady() {
122 if (tries++ > timeout_limit) { 122 if (tries++ > timeout_limit) {
123 return DriverResult::Timeout; 123 return DriverResult::Timeout;
124 } 124 }
125 } while (output[49] != 0x2a || (output[51] << 8) + output[50] != 0x0500 || output[55] != 0x31 || 125 } while (output.mcu_report != MCUReport::NFCState ||
126 output[56] != 0x00); 126 (output.mcu_data[1] << 8) + output.mcu_data[0] != 0x0500 ||
127 output.mcu_data[5] != 0x31 || output.mcu_data[6] != 0x00);
127 128
128 return DriverResult::Success; 129 return DriverResult::Success;
129} 130}
@@ -131,7 +132,7 @@ DriverResult NfcProtocol::WaitUntilNfcIsReady() {
131DriverResult NfcProtocol::StartPolling(TagFoundData& data) { 132DriverResult NfcProtocol::StartPolling(TagFoundData& data) {
132 LOG_DEBUG(Input, "Start Polling for tag"); 133 LOG_DEBUG(Input, "Start Polling for tag");
133 constexpr std::size_t timeout_limit = 7; 134 constexpr std::size_t timeout_limit = 7;
134 std::vector<u8> output; 135 MCUCommandResponse output{};
135 std::size_t tries = 0; 136 std::size_t tries = 0;
136 137
137 do { 138 do {
@@ -142,18 +143,20 @@ DriverResult NfcProtocol::StartPolling(TagFoundData& data) {
142 if (tries++ > timeout_limit) { 143 if (tries++ > timeout_limit) {
143 return DriverResult::Timeout; 144 return DriverResult::Timeout;
144 } 145 }
145 } while (output[49] != 0x2a || (output[51] << 8) + output[50] != 0x0500 || output[56] != 0x09); 146 } while (output.mcu_report != MCUReport::NFCState ||
147 (output.mcu_data[1] << 8) + output.mcu_data[0] != 0x0500 ||
148 output.mcu_data[6] != 0x09);
146 149
147 data.type = output[62]; 150 data.type = output.mcu_data[12];
148 data.uuid.resize(output[64]); 151 data.uuid.resize(output.mcu_data[14]);
149 memcpy(data.uuid.data(), output.data() + 65, data.uuid.size()); 152 memcpy(data.uuid.data(), output.mcu_data.data() + 15, data.uuid.size());
150 153
151 return DriverResult::Success; 154 return DriverResult::Success;
152} 155}
153 156
154DriverResult NfcProtocol::ReadTag(const TagFoundData& data) { 157DriverResult NfcProtocol::ReadTag(const TagFoundData& data) {
155 constexpr std::size_t timeout_limit = 10; 158 constexpr std::size_t timeout_limit = 10;
156 std::vector<u8> output; 159 MCUCommandResponse output{};
157 std::size_t tries = 0; 160 std::size_t tries = 0;
158 161
159 std::string uuid_string; 162 std::string uuid_string;
@@ -168,23 +171,24 @@ DriverResult NfcProtocol::ReadTag(const TagFoundData& data) {
168 // Read Tag data 171 // Read Tag data
169 while (true) { 172 while (true) {
170 auto result = SendReadAmiiboRequest(output, ntag_pages); 173 auto result = SendReadAmiiboRequest(output, ntag_pages);
171 const auto mcu_report = static_cast<MCUReport>(output[49]); 174 const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]);
172 const auto nfc_status = static_cast<NFCStatus>(output[56]);
173 175
174 if (result != DriverResult::Success) { 176 if (result != DriverResult::Success) {
175 return result; 177 return result;
176 } 178 }
177 179
178 if ((mcu_report == MCUReport::NFCReadData || mcu_report == MCUReport::NFCState) && 180 if ((output.mcu_report == MCUReport::NFCReadData ||
181 output.mcu_report == MCUReport::NFCState) &&
179 nfc_status == NFCStatus::TagLost) { 182 nfc_status == NFCStatus::TagLost) {
180 return DriverResult::ErrorReadingData; 183 return DriverResult::ErrorReadingData;
181 } 184 }
182 185
183 if (mcu_report == MCUReport::NFCReadData && output[51] == 0x07 && output[52] == 0x01) { 186 if (output.mcu_report == MCUReport::NFCReadData && output.mcu_data[1] == 0x07 &&
187 output.mcu_data[2] == 0x01) {
184 if (data.type != 2) { 188 if (data.type != 2) {
185 continue; 189 continue;
186 } 190 }
187 switch (output[74]) { 191 switch (output.mcu_data[24]) {
188 case 0: 192 case 0:
189 ntag_pages = NFCPages::Block135; 193 ntag_pages = NFCPages::Block135;
190 break; 194 break;
@@ -200,14 +204,14 @@ DriverResult NfcProtocol::ReadTag(const TagFoundData& data) {
200 continue; 204 continue;
201 } 205 }
202 206
203 if (mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::LastPackage) { 207 if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::LastPackage) {
204 // finished 208 // finished
205 SendStopPollingRequest(output); 209 SendStopPollingRequest(output);
206 return DriverResult::Success; 210 return DriverResult::Success;
207 } 211 }
208 212
209 // Ignore other state reports 213 // Ignore other state reports
210 if (mcu_report == MCUReport::NFCState) { 214 if (output.mcu_report == MCUReport::NFCState) {
211 continue; 215 continue;
212 } 216 }
213 217
@@ -221,7 +225,7 @@ DriverResult NfcProtocol::ReadTag(const TagFoundData& data) {
221 225
222DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) { 226DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) {
223 constexpr std::size_t timeout_limit = 10; 227 constexpr std::size_t timeout_limit = 10;
224 std::vector<u8> output; 228 MCUCommandResponse output{};
225 std::size_t tries = 0; 229 std::size_t tries = 0;
226 230
227 NFCPages ntag_pages = NFCPages::Block135; 231 NFCPages ntag_pages = NFCPages::Block135;
@@ -229,36 +233,38 @@ DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) {
229 // Read Tag data 233 // Read Tag data
230 while (true) { 234 while (true) {
231 auto result = SendReadAmiiboRequest(output, ntag_pages); 235 auto result = SendReadAmiiboRequest(output, ntag_pages);
232 const auto mcu_report = static_cast<MCUReport>(output[49]); 236 const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]);
233 const auto nfc_status = static_cast<NFCStatus>(output[56]);
234 237
235 if (result != DriverResult::Success) { 238 if (result != DriverResult::Success) {
236 return result; 239 return result;
237 } 240 }
238 241
239 if ((mcu_report == MCUReport::NFCReadData || mcu_report == MCUReport::NFCState) && 242 if ((output.mcu_report == MCUReport::NFCReadData ||
243 output.mcu_report == MCUReport::NFCState) &&
240 nfc_status == NFCStatus::TagLost) { 244 nfc_status == NFCStatus::TagLost) {
241 return DriverResult::ErrorReadingData; 245 return DriverResult::ErrorReadingData;
242 } 246 }
243 247
244 if (mcu_report == MCUReport::NFCReadData && output[51] == 0x07) { 248 if (output.mcu_report == MCUReport::NFCReadData && output.mcu_data[1] == 0x07) {
245 std::size_t payload_size = (output[54] << 8 | output[55]) & 0x7FF; 249 std::size_t payload_size = (output.mcu_data[4] << 8 | output.mcu_data[5]) & 0x7FF;
246 if (output[52] == 0x01) { 250 if (output.mcu_data[2] == 0x01) {
247 memcpy(ntag_data.data() + ntag_buffer_pos, output.data() + 116, payload_size - 60); 251 memcpy(ntag_data.data() + ntag_buffer_pos, output.mcu_data.data() + 66,
252 payload_size - 60);
248 ntag_buffer_pos += payload_size - 60; 253 ntag_buffer_pos += payload_size - 60;
249 } else { 254 } else {
250 memcpy(ntag_data.data() + ntag_buffer_pos, output.data() + 56, payload_size); 255 memcpy(ntag_data.data() + ntag_buffer_pos, output.mcu_data.data() + 6,
256 payload_size);
251 } 257 }
252 continue; 258 continue;
253 } 259 }
254 260
255 if (mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::LastPackage) { 261 if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::LastPackage) {
256 LOG_INFO(Input, "Finished reading amiibo"); 262 LOG_INFO(Input, "Finished reading amiibo");
257 return DriverResult::Success; 263 return DriverResult::Success;
258 } 264 }
259 265
260 // Ignore other state reports 266 // Ignore other state reports
261 if (mcu_report == MCUReport::NFCState) { 267 if (output.mcu_report == MCUReport::NFCState) {
262 continue; 268 continue;
263 } 269 }
264 270
@@ -270,7 +276,7 @@ DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) {
270 return DriverResult::Success; 276 return DriverResult::Success;
271} 277}
272 278
273DriverResult NfcProtocol::SendStartPollingRequest(std::vector<u8>& output) { 279DriverResult NfcProtocol::SendStartPollingRequest(MCUCommandResponse& output) {
274 NFCRequestState request{ 280 NFCRequestState request{
275 .sub_command = MCUSubCommand::ReadDeviceMode, 281 .sub_command = MCUSubCommand::ReadDeviceMode,
276 .command_argument = NFCReadCommand::StartPolling, 282 .command_argument = NFCReadCommand::StartPolling,
@@ -294,7 +300,7 @@ DriverResult NfcProtocol::SendStartPollingRequest(std::vector<u8>& output) {
294 return SendMCUData(ReportMode::NFC_IR_MODE_60HZ, SubCommand::STATE, request_data, output); 300 return SendMCUData(ReportMode::NFC_IR_MODE_60HZ, SubCommand::STATE, request_data, output);
295} 301}
296 302
297DriverResult NfcProtocol::SendStopPollingRequest(std::vector<u8>& output) { 303DriverResult NfcProtocol::SendStopPollingRequest(MCUCommandResponse& output) {
298 NFCRequestState request{ 304 NFCRequestState request{
299 .sub_command = MCUSubCommand::ReadDeviceMode, 305 .sub_command = MCUSubCommand::ReadDeviceMode,
300 .command_argument = NFCReadCommand::StopPolling, 306 .command_argument = NFCReadCommand::StopPolling,
@@ -311,7 +317,7 @@ DriverResult NfcProtocol::SendStopPollingRequest(std::vector<u8>& output) {
311 return SendMCUData(ReportMode::NFC_IR_MODE_60HZ, SubCommand::STATE, request_data, output); 317 return SendMCUData(ReportMode::NFC_IR_MODE_60HZ, SubCommand::STATE, request_data, output);
312} 318}
313 319
314DriverResult NfcProtocol::SendStartWaitingRecieveRequest(std::vector<u8>& output) { 320DriverResult NfcProtocol::SendStartWaitingRecieveRequest(MCUCommandResponse& output) {
315 NFCRequestState request{ 321 NFCRequestState request{
316 .sub_command = MCUSubCommand::ReadDeviceMode, 322 .sub_command = MCUSubCommand::ReadDeviceMode,
317 .command_argument = NFCReadCommand::StartWaitingRecieve, 323 .command_argument = NFCReadCommand::StartWaitingRecieve,
@@ -328,7 +334,7 @@ DriverResult NfcProtocol::SendStartWaitingRecieveRequest(std::vector<u8>& output
328 return SendMCUData(ReportMode::NFC_IR_MODE_60HZ, SubCommand::STATE, request_data, output); 334 return SendMCUData(ReportMode::NFC_IR_MODE_60HZ, SubCommand::STATE, request_data, output);
329} 335}
330 336
331DriverResult NfcProtocol::SendReadAmiiboRequest(std::vector<u8>& output, NFCPages ntag_pages) { 337DriverResult NfcProtocol::SendReadAmiiboRequest(MCUCommandResponse& output, NFCPages ntag_pages) {
332 NFCRequestState request{ 338 NFCRequestState request{
333 .sub_command = MCUSubCommand::ReadDeviceMode, 339 .sub_command = MCUSubCommand::ReadDeviceMode,
334 .command_argument = NFCReadCommand::Ntag, 340 .command_argument = NFCReadCommand::Ntag,
diff --git a/src/input_common/helpers/joycon_protocol/nfc.h b/src/input_common/helpers/joycon_protocol/nfc.h
index e63665aa9..11e263e07 100644
--- a/src/input_common/helpers/joycon_protocol/nfc.h
+++ b/src/input_common/helpers/joycon_protocol/nfc.h
@@ -45,13 +45,13 @@ private:
45 45
46 DriverResult GetAmiiboData(std::vector<u8>& data); 46 DriverResult GetAmiiboData(std::vector<u8>& data);
47 47
48 DriverResult SendStartPollingRequest(std::vector<u8>& output); 48 DriverResult SendStartPollingRequest(MCUCommandResponse& output);
49 49
50 DriverResult SendStopPollingRequest(std::vector<u8>& output); 50 DriverResult SendStopPollingRequest(MCUCommandResponse& output);
51 51
52 DriverResult SendStartWaitingRecieveRequest(std::vector<u8>& output); 52 DriverResult SendStartWaitingRecieveRequest(MCUCommandResponse& output);
53 53
54 DriverResult SendReadAmiiboRequest(std::vector<u8>& output, NFCPages ntag_pages); 54 DriverResult SendReadAmiiboRequest(MCUCommandResponse& output, NFCPages ntag_pages);
55 55
56 NFCReadBlockCommand GetReadBlockCommand(NFCPages pages) const; 56 NFCReadBlockCommand GetReadBlockCommand(NFCPages pages) const;
57 57
diff --git a/src/input_common/helpers/joycon_protocol/poller.cpp b/src/input_common/helpers/joycon_protocol/poller.cpp
index 7f8e093fa..9bb15e935 100644
--- a/src/input_common/helpers/joycon_protocol/poller.cpp
+++ b/src/input_common/helpers/joycon_protocol/poller.cpp
@@ -31,9 +31,7 @@ void JoyconPoller::ReadActiveMode(std::span<u8> buffer, const MotionStatus& moti
31 case Joycon::ControllerType::Pro: 31 case Joycon::ControllerType::Pro:
32 UpdateActiveProPadInput(data, motion_status); 32 UpdateActiveProPadInput(data, motion_status);
33 break; 33 break;
34 case Joycon::ControllerType::Grip: 34 default:
35 case Joycon::ControllerType::Dual:
36 case Joycon::ControllerType::None:
37 break; 35 break;
38 } 36 }
39 37
@@ -58,9 +56,7 @@ void JoyconPoller::ReadPassiveMode(std::span<u8> buffer) {
58 case Joycon::ControllerType::Pro: 56 case Joycon::ControllerType::Pro:
59 UpdatePasiveProPadInput(data); 57 UpdatePasiveProPadInput(data);
60 break; 58 break;
61 case Joycon::ControllerType::Grip: 59 default:
62 case Joycon::ControllerType::Dual:
63 case Joycon::ControllerType::None:
64 break; 60 break;
65 } 61 }
66} 62}
diff --git a/src/input_common/helpers/joycon_protocol/ringcon.cpp b/src/input_common/helpers/joycon_protocol/ringcon.cpp
index 12f81309e..190cef812 100644
--- a/src/input_common/helpers/joycon_protocol/ringcon.cpp
+++ b/src/input_common/helpers/joycon_protocol/ringcon.cpp
@@ -70,14 +70,12 @@ DriverResult RingConProtocol::StartRingconPolling() {
70DriverResult RingConProtocol::IsRingConnected(bool& is_connected) { 70DriverResult RingConProtocol::IsRingConnected(bool& is_connected) {
71 LOG_DEBUG(Input, "IsRingConnected"); 71 LOG_DEBUG(Input, "IsRingConnected");
72 constexpr std::size_t max_tries = 28; 72 constexpr std::size_t max_tries = 28;
73 constexpr u8 ring_controller_id = 0x20; 73 SubCommandResponse output{};
74 std::vector<u8> output;
75 std::size_t tries = 0; 74 std::size_t tries = 0;
76 is_connected = false; 75 is_connected = false;
77 76
78 do { 77 do {
79 std::array<u8, 1> empty_data{}; 78 const auto result = SendSubCommand(SubCommand::GET_EXTERNAL_DEVICE_INFO, {}, output);
80 const auto result = SendSubCommand(SubCommand::UNKNOWN_RINGCON, empty_data, output);
81 79
82 if (result != DriverResult::Success) { 80 if (result != DriverResult::Success) {
83 return result; 81 return result;
@@ -86,7 +84,7 @@ DriverResult RingConProtocol::IsRingConnected(bool& is_connected) {
86 if (tries++ >= max_tries) { 84 if (tries++ >= max_tries) {
87 return DriverResult::NoDeviceDetected; 85 return DriverResult::NoDeviceDetected;
88 } 86 }
89 } while (output[16] != ring_controller_id); 87 } while (output.external_device_id != ExternalDeviceId::RingController);
90 88
91 is_connected = true; 89 is_connected = true;
92 return DriverResult::Success; 90 return DriverResult::Success;
@@ -100,14 +98,14 @@ DriverResult RingConProtocol::ConfigureRing() {
100 0x00, 0x00, 0x00, 0x0A, 0x64, 0x0B, 0xE6, 0xA9, 0x22, 0x00, 0x00, 0x04, 0x00, 98 0x00, 0x00, 0x00, 0x0A, 0x64, 0x0B, 0xE6, 0xA9, 0x22, 0x00, 0x00, 0x04, 0x00,
101 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0xA8, 0xE1, 0x34, 0x36}; 99 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0xA8, 0xE1, 0x34, 0x36};
102 100
103 const DriverResult result = SendSubCommand(SubCommand::UNKNOWN_RINGCON3, ring_config); 101 const DriverResult result = SendSubCommand(SubCommand::SET_EXTERNAL_FORMAT_CONFIG, ring_config);
104 102
105 if (result != DriverResult::Success) { 103 if (result != DriverResult::Success) {
106 return result; 104 return result;
107 } 105 }
108 106
109 static constexpr std::array<u8, 4> ringcon_data{0x04, 0x01, 0x01, 0x02}; 107 static constexpr std::array<u8, 4> ringcon_data{0x04, 0x01, 0x01, 0x02};
110 return SendSubCommand(SubCommand::UNKNOWN_RINGCON2, ringcon_data); 108 return SendSubCommand(SubCommand::ENABLE_EXTERNAL_POLLING, ringcon_data);
111} 109}
112 110
113bool RingConProtocol::IsEnabled() const { 111bool RingConProtocol::IsEnabled() const {
diff --git a/src/input_common/input_poller.cpp b/src/input_common/input_poller.cpp
index 15cbf7e5f..8c6a6521a 100644
--- a/src/input_common/input_poller.cpp
+++ b/src/input_common/input_poller.cpp
@@ -16,10 +16,10 @@ public:
16 16
17class InputFromButton final : public Common::Input::InputDevice { 17class InputFromButton final : public Common::Input::InputDevice {
18public: 18public:
19 explicit InputFromButton(PadIdentifier identifier_, int button_, bool toggle_, bool inverted_, 19 explicit InputFromButton(PadIdentifier identifier_, int button_, bool turbo_, bool toggle_,
20 InputEngine* input_engine_) 20 bool inverted_, InputEngine* input_engine_)
21 : identifier(identifier_), button(button_), toggle(toggle_), inverted(inverted_), 21 : identifier(identifier_), button(button_), turbo(turbo_), toggle(toggle_),
22 input_engine(input_engine_) { 22 inverted(inverted_), input_engine(input_engine_) {
23 UpdateCallback engine_callback{[this]() { OnChange(); }}; 23 UpdateCallback engine_callback{[this]() { OnChange(); }};
24 const InputIdentifier input_identifier{ 24 const InputIdentifier input_identifier{
25 .identifier = identifier, 25 .identifier = identifier,
@@ -40,6 +40,7 @@ public:
40 .value = input_engine->GetButton(identifier, button), 40 .value = input_engine->GetButton(identifier, button),
41 .inverted = inverted, 41 .inverted = inverted,
42 .toggle = toggle, 42 .toggle = toggle,
43 .turbo = turbo,
43 }; 44 };
44 } 45 }
45 46
@@ -68,6 +69,7 @@ public:
68private: 69private:
69 const PadIdentifier identifier; 70 const PadIdentifier identifier;
70 const int button; 71 const int button;
72 const bool turbo;
71 const bool toggle; 73 const bool toggle;
72 const bool inverted; 74 const bool inverted;
73 int callback_key; 75 int callback_key;
@@ -77,10 +79,10 @@ private:
77 79
78class InputFromHatButton final : public Common::Input::InputDevice { 80class InputFromHatButton final : public Common::Input::InputDevice {
79public: 81public:
80 explicit InputFromHatButton(PadIdentifier identifier_, int button_, u8 direction_, bool toggle_, 82 explicit InputFromHatButton(PadIdentifier identifier_, int button_, u8 direction_, bool turbo_,
81 bool inverted_, InputEngine* input_engine_) 83 bool toggle_, bool inverted_, InputEngine* input_engine_)
82 : identifier(identifier_), button(button_), direction(direction_), toggle(toggle_), 84 : identifier(identifier_), button(button_), direction(direction_), turbo(turbo_),
83 inverted(inverted_), input_engine(input_engine_) { 85 toggle(toggle_), inverted(inverted_), input_engine(input_engine_) {
84 UpdateCallback engine_callback{[this]() { OnChange(); }}; 86 UpdateCallback engine_callback{[this]() { OnChange(); }};
85 const InputIdentifier input_identifier{ 87 const InputIdentifier input_identifier{
86 .identifier = identifier, 88 .identifier = identifier,
@@ -101,6 +103,7 @@ public:
101 .value = input_engine->GetHatButton(identifier, button, direction), 103 .value = input_engine->GetHatButton(identifier, button, direction),
102 .inverted = inverted, 104 .inverted = inverted,
103 .toggle = toggle, 105 .toggle = toggle,
106 .turbo = turbo,
104 }; 107 };
105 } 108 }
106 109
@@ -130,6 +133,7 @@ private:
130 const PadIdentifier identifier; 133 const PadIdentifier identifier;
131 const int button; 134 const int button;
132 const u8 direction; 135 const u8 direction;
136 const bool turbo;
133 const bool toggle; 137 const bool toggle;
134 const bool inverted; 138 const bool inverted;
135 int callback_key; 139 int callback_key;
@@ -853,14 +857,15 @@ std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateButtonDevice(
853 const auto keyboard_key = params.Get("code", 0); 857 const auto keyboard_key = params.Get("code", 0);
854 const auto toggle = params.Get("toggle", false) != 0; 858 const auto toggle = params.Get("toggle", false) != 0;
855 const auto inverted = params.Get("inverted", false) != 0; 859 const auto inverted = params.Get("inverted", false) != 0;
860 const auto turbo = params.Get("turbo", false) != 0;
856 input_engine->PreSetController(identifier); 861 input_engine->PreSetController(identifier);
857 input_engine->PreSetButton(identifier, button_id); 862 input_engine->PreSetButton(identifier, button_id);
858 input_engine->PreSetButton(identifier, keyboard_key); 863 input_engine->PreSetButton(identifier, keyboard_key);
859 if (keyboard_key != 0) { 864 if (keyboard_key != 0) {
860 return std::make_unique<InputFromButton>(identifier, keyboard_key, toggle, inverted, 865 return std::make_unique<InputFromButton>(identifier, keyboard_key, turbo, toggle, inverted,
861 input_engine.get()); 866 input_engine.get());
862 } 867 }
863 return std::make_unique<InputFromButton>(identifier, button_id, toggle, inverted, 868 return std::make_unique<InputFromButton>(identifier, button_id, turbo, toggle, inverted,
864 input_engine.get()); 869 input_engine.get());
865} 870}
866 871
@@ -876,11 +881,12 @@ std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateHatButtonDevice(
876 const auto direction = input_engine->GetHatButtonId(params.Get("direction", "")); 881 const auto direction = input_engine->GetHatButtonId(params.Get("direction", ""));
877 const auto toggle = params.Get("toggle", false) != 0; 882 const auto toggle = params.Get("toggle", false) != 0;
878 const auto inverted = params.Get("inverted", false) != 0; 883 const auto inverted = params.Get("inverted", false) != 0;
884 const auto turbo = params.Get("turbo", false) != 0;
879 885
880 input_engine->PreSetController(identifier); 886 input_engine->PreSetController(identifier);
881 input_engine->PreSetHatButton(identifier, button_id); 887 input_engine->PreSetHatButton(identifier, button_id);
882 return std::make_unique<InputFromHatButton>(identifier, button_id, direction, toggle, inverted, 888 return std::make_unique<InputFromHatButton>(identifier, button_id, direction, turbo, toggle,
883 input_engine.get()); 889 inverted, input_engine.get());
884} 890}
885 891
886std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateStickDevice( 892std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateStickDevice(
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp
index b7bc11416..85ee27333 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp
+++ b/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp
@@ -59,6 +59,13 @@ std::string Image(EmitContext& ctx, IR::TextureInstInfo info,
59 } 59 }
60} 60}
61 61
62bool IsTextureMsaa(EmitContext& ctx, const IR::TextureInstInfo& info) {
63 if (info.type == TextureType::Buffer) {
64 return false;
65 }
66 return ctx.info.texture_descriptors.at(info.descriptor_index).is_multisample;
67}
68
62std::string_view TextureType(IR::TextureInstInfo info, bool is_ms = false) { 69std::string_view TextureType(IR::TextureInstInfo info, bool is_ms = false) {
63 if (info.is_depth) { 70 if (info.is_depth) {
64 switch (info.type) { 71 switch (info.type) {
@@ -535,7 +542,8 @@ void EmitImageQueryDimensions(EmitContext& ctx, IR::Inst& inst, const IR::Value&
535 ScalarS32 lod, [[maybe_unused]] const IR::Value& skip_mips) { 542 ScalarS32 lod, [[maybe_unused]] const IR::Value& skip_mips) {
536 const auto info{inst.Flags<IR::TextureInstInfo>()}; 543 const auto info{inst.Flags<IR::TextureInstInfo>()};
537 const std::string texture{Texture(ctx, info, index)}; 544 const std::string texture{Texture(ctx, info, index)};
538 const std::string_view type{TextureType(info)}; 545 const bool is_msaa{IsTextureMsaa(ctx, info)};
546 const std::string_view type{TextureType(info, is_msaa)};
539 ctx.Add("TXQ {},{},{},{};", inst, lod, texture, type); 547 ctx.Add("TXQ {},{},{},{};", inst, lod, texture, type);
540} 548}
541 549
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp
index 4be2c25ec..f335c8af0 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp
@@ -25,6 +25,13 @@ std::string Image(EmitContext& ctx, const IR::TextureInstInfo& info, const IR::V
25 return fmt::format("img{}{}", def.binding, index_offset); 25 return fmt::format("img{}{}", def.binding, index_offset);
26} 26}
27 27
28bool IsTextureMsaa(EmitContext& ctx, const IR::TextureInstInfo& info) {
29 if (info.type == TextureType::Buffer) {
30 return false;
31 }
32 return ctx.info.texture_descriptors.at(info.descriptor_index).is_multisample;
33}
34
28std::string CastToIntVec(std::string_view value, const IR::TextureInstInfo& info) { 35std::string CastToIntVec(std::string_view value, const IR::TextureInstInfo& info) {
29 switch (info.type) { 36 switch (info.type) {
30 case TextureType::Color1D: 37 case TextureType::Color1D:
@@ -463,26 +470,33 @@ void EmitImageQueryDimensions(EmitContext& ctx, IR::Inst& inst, const IR::Value&
463 std::string_view lod, const IR::Value& skip_mips_val) { 470 std::string_view lod, const IR::Value& skip_mips_val) {
464 const auto info{inst.Flags<IR::TextureInstInfo>()}; 471 const auto info{inst.Flags<IR::TextureInstInfo>()};
465 const auto texture{Texture(ctx, info, index)}; 472 const auto texture{Texture(ctx, info, index)};
473 const bool is_msaa{IsTextureMsaa(ctx, info)};
466 const bool skip_mips{skip_mips_val.U1()}; 474 const bool skip_mips{skip_mips_val.U1()};
467 const auto mips{ 475 const auto mips{skip_mips ? "0u" : fmt::format("uint(textureQueryLevels({}))", texture)};
468 [&] { return skip_mips ? "0u" : fmt::format("uint(textureQueryLevels({}))", texture); }}; 476 if (is_msaa && !skip_mips) {
477 throw NotImplementedException("EmitImageQueryDimensions MSAA QueryLevels");
478 }
479 if (info.type == TextureType::Buffer && !skip_mips) {
480 throw NotImplementedException("EmitImageQueryDimensions TextureType::Buffer QueryLevels");
481 }
482 const bool uses_lod{!is_msaa && info.type != TextureType::Buffer};
483 const auto lod_str{uses_lod ? fmt::format(",int({})", lod) : ""};
469 switch (info.type) { 484 switch (info.type) {
470 case TextureType::Color1D: 485 case TextureType::Color1D:
471 return ctx.AddU32x4("{}=uvec4(uint(textureSize({},int({}))),0u,0u,{});", inst, texture, lod, 486 return ctx.AddU32x4("{}=uvec4(uint(textureSize({}{})),0u,0u,{});", inst, texture, lod_str,
472 mips()); 487 mips);
473 case TextureType::ColorArray1D: 488 case TextureType::ColorArray1D:
474 case TextureType::Color2D: 489 case TextureType::Color2D:
475 case TextureType::ColorCube: 490 case TextureType::ColorCube:
476 case TextureType::Color2DRect: 491 case TextureType::Color2DRect:
477 return ctx.AddU32x4("{}=uvec4(uvec2(textureSize({},int({}))),0u,{});", inst, texture, lod, 492 return ctx.AddU32x4("{}=uvec4(uvec2(textureSize({}{})),0u,{});", inst, texture, lod_str,
478 mips()); 493 mips);
479 case TextureType::ColorArray2D: 494 case TextureType::ColorArray2D:
480 case TextureType::Color3D: 495 case TextureType::Color3D:
481 case TextureType::ColorArrayCube: 496 case TextureType::ColorArrayCube:
482 return ctx.AddU32x4("{}=uvec4(uvec3(textureSize({},int({}))),{});", inst, texture, lod, 497 return ctx.AddU32x4("{}=uvec4(uvec3(textureSize({}{})),{});", inst, texture, lod_str, mips);
483 mips());
484 case TextureType::Buffer: 498 case TextureType::Buffer:
485 throw NotImplementedException("EmitImageQueryDimensions Texture buffers"); 499 return ctx.AddU32x4("{}=uvec4(uint(textureSize({})),0u,0u,{});", inst, texture, mips);
486 } 500 }
487 throw LogicError("Unspecified image type {}", info.type.Value()); 501 throw LogicError("Unspecified image type {}", info.type.Value());
488} 502}
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp
index 3b969d915..02073c420 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp
@@ -201,6 +201,13 @@ Id Image(EmitContext& ctx, const IR::Value& index, IR::TextureInstInfo info) {
201 } 201 }
202} 202}
203 203
204bool IsTextureMsaa(EmitContext& ctx, const IR::TextureInstInfo& info) {
205 if (info.type == TextureType::Buffer) {
206 return false;
207 }
208 return ctx.textures.at(info.descriptor_index).is_multisample;
209}
210
204Id Decorate(EmitContext& ctx, IR::Inst* inst, Id sample) { 211Id Decorate(EmitContext& ctx, IR::Inst* inst, Id sample) {
205 const auto info{inst->Flags<IR::TextureInstInfo>()}; 212 const auto info{inst->Flags<IR::TextureInstInfo>()};
206 if (info.relaxed_precision != 0) { 213 if (info.relaxed_precision != 0) {
@@ -452,24 +459,26 @@ Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& i
452 const Id zero{ctx.u32_zero_value}; 459 const Id zero{ctx.u32_zero_value};
453 const bool skip_mips{skip_mips_val.U1()}; 460 const bool skip_mips{skip_mips_val.U1()};
454 const auto mips{[&] { return skip_mips ? zero : ctx.OpImageQueryLevels(ctx.U32[1], image); }}; 461 const auto mips{[&] { return skip_mips ? zero : ctx.OpImageQueryLevels(ctx.U32[1], image); }};
462 const bool is_msaa{IsTextureMsaa(ctx, info)};
463 const bool uses_lod{!is_msaa && info.type != TextureType::Buffer};
464 const auto query{[&](Id type) {
465 return uses_lod ? ctx.OpImageQuerySizeLod(type, image, lod)
466 : ctx.OpImageQuerySize(type, image);
467 }};
455 switch (info.type) { 468 switch (info.type) {
456 case TextureType::Color1D: 469 case TextureType::Color1D:
457 return ctx.OpCompositeConstruct(ctx.U32[4], ctx.OpImageQuerySizeLod(ctx.U32[1], image, lod), 470 return ctx.OpCompositeConstruct(ctx.U32[4], query(ctx.U32[1]), zero, zero, mips());
458 zero, zero, mips());
459 case TextureType::ColorArray1D: 471 case TextureType::ColorArray1D:
460 case TextureType::Color2D: 472 case TextureType::Color2D:
461 case TextureType::ColorCube: 473 case TextureType::ColorCube:
462 case TextureType::Color2DRect: 474 case TextureType::Color2DRect:
463 return ctx.OpCompositeConstruct(ctx.U32[4], ctx.OpImageQuerySizeLod(ctx.U32[2], image, lod), 475 return ctx.OpCompositeConstruct(ctx.U32[4], query(ctx.U32[2]), zero, mips());
464 zero, mips());
465 case TextureType::ColorArray2D: 476 case TextureType::ColorArray2D:
466 case TextureType::Color3D: 477 case TextureType::Color3D:
467 case TextureType::ColorArrayCube: 478 case TextureType::ColorArrayCube:
468 return ctx.OpCompositeConstruct(ctx.U32[4], ctx.OpImageQuerySizeLod(ctx.U32[3], image, lod), 479 return ctx.OpCompositeConstruct(ctx.U32[4], query(ctx.U32[3]), mips());
469 mips());
470 case TextureType::Buffer: 480 case TextureType::Buffer:
471 return ctx.OpCompositeConstruct(ctx.U32[4], ctx.OpImageQuerySize(ctx.U32[1], image), zero, 481 return ctx.OpCompositeConstruct(ctx.U32[4], query(ctx.U32[1]), zero, zero, mips());
472 zero, mips());
473 } 482 }
474 throw LogicError("Unspecified image type {}", info.type.Value()); 483 throw LogicError("Unspecified image type {}", info.type.Value());
475} 484}
diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp
index 3b97721e1..d48d4860e 100644
--- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp
+++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp
@@ -1288,6 +1288,7 @@ void EmitContext::DefineTextures(const Info& info, u32& binding, u32& scaling_in
1288 .pointer_type = pointer_type, 1288 .pointer_type = pointer_type,
1289 .image_type = image_type, 1289 .image_type = image_type,
1290 .count = desc.count, 1290 .count = desc.count,
1291 .is_multisample = desc.is_multisample,
1291 }); 1292 });
1292 if (profile.supported_spirv >= 0x00010400) { 1293 if (profile.supported_spirv >= 0x00010400) {
1293 interfaces.push_back(id); 1294 interfaces.push_back(id);
diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.h b/src/shader_recompiler/backend/spirv/spirv_emit_context.h
index dbc5c55b9..768a4fbb5 100644
--- a/src/shader_recompiler/backend/spirv/spirv_emit_context.h
+++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.h
@@ -35,6 +35,7 @@ struct TextureDefinition {
35 Id pointer_type; 35 Id pointer_type;
36 Id image_type; 36 Id image_type;
37 u32 count; 37 u32 count;
38 bool is_multisample;
38}; 39};
39 40
40struct TextureBufferDefinition { 41struct TextureBufferDefinition {
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.h b/src/shader_recompiler/frontend/ir/ir_emitter.h
index df158c928..f3c81dbe1 100644
--- a/src/shader_recompiler/frontend/ir/ir_emitter.h
+++ b/src/shader_recompiler/frontend/ir/ir_emitter.h
@@ -409,7 +409,8 @@ private:
409 } 409 }
410 410
411 template <typename T> 411 template <typename T>
412 requires(sizeof(T) <= sizeof(u32) && std::is_trivially_copyable_v<T>) struct Flags { 412 requires(sizeof(T) <= sizeof(u32) && std::is_trivially_copyable_v<T>)
413 struct Flags {
413 Flags() = default; 414 Flags() = default;
414 Flags(T proxy_) : proxy{proxy_} {} 415 Flags(T proxy_) : proxy{proxy_} {}
415 416
diff --git a/src/shader_recompiler/frontend/ir/value.h b/src/shader_recompiler/frontend/ir/value.h
index 883dfa24e..22e89dd1b 100644
--- a/src/shader_recompiler/frontend/ir/value.h
+++ b/src/shader_recompiler/frontend/ir/value.h
@@ -101,9 +101,8 @@ public:
101 TypedValue() = default; 101 TypedValue() = default;
102 102
103 template <IR::Type other_type> 103 template <IR::Type other_type>
104 requires((other_type & type_) != IR::Type::Void) explicit(false) 104 requires((other_type & type_) != IR::Type::Void)
105 TypedValue(const TypedValue<other_type>& value) 105 explicit(false) TypedValue(const TypedValue<other_type>& value) : Value(value) {}
106 : Value(value) {}
107 106
108 explicit TypedValue(const Value& value) : Value(value) { 107 explicit TypedValue(const Value& value) : Value(value) {
109 if ((value.Type() & type_) == IR::Type::Void) { 108 if ((value.Type() & type_) == IR::Type::Void) {
@@ -194,16 +193,16 @@ public:
194 void ReplaceOpcode(IR::Opcode opcode); 193 void ReplaceOpcode(IR::Opcode opcode);
195 194
196 template <typename FlagsType> 195 template <typename FlagsType>
197 requires(sizeof(FlagsType) <= sizeof(u32) && std::is_trivially_copyable_v<FlagsType>) 196 requires(sizeof(FlagsType) <= sizeof(u32) && std::is_trivially_copyable_v<FlagsType>)
198 [[nodiscard]] FlagsType Flags() const noexcept { 197 [[nodiscard]] FlagsType Flags() const noexcept {
199 FlagsType ret; 198 FlagsType ret;
200 std::memcpy(reinterpret_cast<char*>(&ret), &flags, sizeof(ret)); 199 std::memcpy(reinterpret_cast<char*>(&ret), &flags, sizeof(ret));
201 return ret; 200 return ret;
202 } 201 }
203 202
204 template <typename FlagsType> 203 template <typename FlagsType>
205 requires(sizeof(FlagsType) <= sizeof(u32) && 204 requires(sizeof(FlagsType) <= sizeof(u32) && std::is_trivially_copyable_v<FlagsType>)
206 std::is_trivially_copyable_v<FlagsType>) void SetFlags(FlagsType value) noexcept { 205 void SetFlags(FlagsType value) noexcept {
207 std::memcpy(&flags, &value, sizeof(value)); 206 std::memcpy(&flags, &value, sizeof(value));
208 } 207 }
209 208
diff --git a/src/shader_recompiler/object_pool.h b/src/shader_recompiler/object_pool.h
index 2b42c4ba2..5d648b159 100644
--- a/src/shader_recompiler/object_pool.h
+++ b/src/shader_recompiler/object_pool.h
@@ -10,7 +10,7 @@
10namespace Shader { 10namespace Shader {
11 11
12template <typename T> 12template <typename T>
13requires std::is_destructible_v<T> 13 requires std::is_destructible_v<T>
14class ObjectPool { 14class ObjectPool {
15public: 15public:
16 explicit ObjectPool(size_t chunk_size = 8192) : new_chunk_size{chunk_size} { 16 explicit ObjectPool(size_t chunk_size = 8192) : new_chunk_size{chunk_size} {
@@ -18,7 +18,7 @@ public:
18 } 18 }
19 19
20 template <typename... Args> 20 template <typename... Args>
21 requires std::is_constructible_v<T, Args...> 21 requires std::is_constructible_v<T, Args...>
22 [[nodiscard]] T* Create(Args&&... args) { 22 [[nodiscard]] T* Create(Args&&... args) {
23 return std::construct_at(Memory(), std::forward<Args>(args)...); 23 return std::construct_at(Memory(), std::forward<Args>(args)...);
24 } 24 }
diff --git a/src/video_core/host_shaders/CMakeLists.txt b/src/video_core/host_shaders/CMakeLists.txt
index dad7b07d4..52cd5bb81 100644
--- a/src/video_core/host_shaders/CMakeLists.txt
+++ b/src/video_core/host_shaders/CMakeLists.txt
@@ -45,6 +45,8 @@ set(SHADER_FILES
45 smaa_neighborhood_blending.vert 45 smaa_neighborhood_blending.vert
46 smaa_neighborhood_blending.frag 46 smaa_neighborhood_blending.frag
47 vulkan_blit_depth_stencil.frag 47 vulkan_blit_depth_stencil.frag
48 vulkan_color_clear.frag
49 vulkan_color_clear.vert
48 vulkan_fidelityfx_fsr_easu_fp16.comp 50 vulkan_fidelityfx_fsr_easu_fp16.comp
49 vulkan_fidelityfx_fsr_easu_fp32.comp 51 vulkan_fidelityfx_fsr_easu_fp32.comp
50 vulkan_fidelityfx_fsr_rcas_fp16.comp 52 vulkan_fidelityfx_fsr_rcas_fp16.comp
diff --git a/src/video_core/host_shaders/vulkan_color_clear.frag b/src/video_core/host_shaders/vulkan_color_clear.frag
new file mode 100644
index 000000000..617bf01e1
--- /dev/null
+++ b/src/video_core/host_shaders/vulkan_color_clear.frag
@@ -0,0 +1,14 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#version 460 core
5
6layout (push_constant) uniform PushConstants {
7 vec4 clear_color;
8};
9
10layout(location = 0) out vec4 color;
11
12void main() {
13 color = clear_color;
14}
diff --git a/src/video_core/host_shaders/vulkan_color_clear.vert b/src/video_core/host_shaders/vulkan_color_clear.vert
new file mode 100644
index 000000000..d85883141
--- /dev/null
+++ b/src/video_core/host_shaders/vulkan_color_clear.vert
@@ -0,0 +1,10 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#version 460 core
5
6void main() {
7 float x = float((gl_VertexIndex & 1) << 2);
8 float y = float((gl_VertexIndex & 2) << 1);
9 gl_Position = vec4(x - 1.0, y - 1.0, 0.0, 1.0);
10}
diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp
index dd00d3edf..cf2964a3f 100644
--- a/src/video_core/renderer_vulkan/blit_image.cpp
+++ b/src/video_core/renderer_vulkan/blit_image.cpp
@@ -12,6 +12,8 @@
12#include "video_core/host_shaders/convert_s8d24_to_abgr8_frag_spv.h" 12#include "video_core/host_shaders/convert_s8d24_to_abgr8_frag_spv.h"
13#include "video_core/host_shaders/full_screen_triangle_vert_spv.h" 13#include "video_core/host_shaders/full_screen_triangle_vert_spv.h"
14#include "video_core/host_shaders/vulkan_blit_depth_stencil_frag_spv.h" 14#include "video_core/host_shaders/vulkan_blit_depth_stencil_frag_spv.h"
15#include "video_core/host_shaders/vulkan_color_clear_frag_spv.h"
16#include "video_core/host_shaders/vulkan_color_clear_vert_spv.h"
15#include "video_core/renderer_vulkan/blit_image.h" 17#include "video_core/renderer_vulkan/blit_image.h"
16#include "video_core/renderer_vulkan/maxwell_to_vk.h" 18#include "video_core/renderer_vulkan/maxwell_to_vk.h"
17#include "video_core/renderer_vulkan/vk_scheduler.h" 19#include "video_core/renderer_vulkan/vk_scheduler.h"
@@ -69,10 +71,11 @@ constexpr VkDescriptorSetLayoutCreateInfo TWO_TEXTURES_DESCRIPTOR_SET_LAYOUT_CRE
69 .bindingCount = static_cast<u32>(TWO_TEXTURES_DESCRIPTOR_SET_LAYOUT_BINDINGS.size()), 71 .bindingCount = static_cast<u32>(TWO_TEXTURES_DESCRIPTOR_SET_LAYOUT_BINDINGS.size()),
70 .pBindings = TWO_TEXTURES_DESCRIPTOR_SET_LAYOUT_BINDINGS.data(), 72 .pBindings = TWO_TEXTURES_DESCRIPTOR_SET_LAYOUT_BINDINGS.data(),
71}; 73};
72constexpr VkPushConstantRange PUSH_CONSTANT_RANGE{ 74template <VkShaderStageFlags stageFlags, size_t size>
73 .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, 75inline constexpr VkPushConstantRange PUSH_CONSTANT_RANGE{
76 .stageFlags = stageFlags,
74 .offset = 0, 77 .offset = 0,
75 .size = sizeof(PushConstants), 78 .size = static_cast<u32>(size),
76}; 79};
77constexpr VkPipelineVertexInputStateCreateInfo PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO{ 80constexpr VkPipelineVertexInputStateCreateInfo PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO{
78 .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, 81 .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
@@ -125,10 +128,8 @@ constexpr VkPipelineMultisampleStateCreateInfo PIPELINE_MULTISAMPLE_STATE_CREATE
125 .alphaToCoverageEnable = VK_FALSE, 128 .alphaToCoverageEnable = VK_FALSE,
126 .alphaToOneEnable = VK_FALSE, 129 .alphaToOneEnable = VK_FALSE,
127}; 130};
128constexpr std::array DYNAMIC_STATES{ 131constexpr std::array DYNAMIC_STATES{VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR,
129 VK_DYNAMIC_STATE_VIEWPORT, 132 VK_DYNAMIC_STATE_BLEND_CONSTANTS};
130 VK_DYNAMIC_STATE_SCISSOR,
131};
132constexpr VkPipelineDynamicStateCreateInfo PIPELINE_DYNAMIC_STATE_CREATE_INFO{ 133constexpr VkPipelineDynamicStateCreateInfo PIPELINE_DYNAMIC_STATE_CREATE_INFO{
133 .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, 134 .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
134 .pNext = nullptr, 135 .pNext = nullptr,
@@ -205,15 +206,15 @@ inline constexpr VkSamplerCreateInfo SAMPLER_CREATE_INFO{
205}; 206};
206 207
207constexpr VkPipelineLayoutCreateInfo PipelineLayoutCreateInfo( 208constexpr VkPipelineLayoutCreateInfo PipelineLayoutCreateInfo(
208 const VkDescriptorSetLayout* set_layout) { 209 const VkDescriptorSetLayout* set_layout, vk::Span<VkPushConstantRange> push_constants) {
209 return VkPipelineLayoutCreateInfo{ 210 return VkPipelineLayoutCreateInfo{
210 .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, 211 .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
211 .pNext = nullptr, 212 .pNext = nullptr,
212 .flags = 0, 213 .flags = 0,
213 .setLayoutCount = 1, 214 .setLayoutCount = (set_layout != nullptr ? 1u : 0u),
214 .pSetLayouts = set_layout, 215 .pSetLayouts = set_layout,
215 .pushConstantRangeCount = 1, 216 .pushConstantRangeCount = push_constants.size(),
216 .pPushConstantRanges = &PUSH_CONSTANT_RANGE, 217 .pPushConstantRanges = push_constants.data(),
217 }; 218 };
218} 219}
219 220
@@ -302,8 +303,7 @@ void UpdateTwoTexturesDescriptorSet(const Device& device, VkDescriptorSet descri
302 device.GetLogical().UpdateDescriptorSets(write_descriptor_sets, nullptr); 303 device.GetLogical().UpdateDescriptorSets(write_descriptor_sets, nullptr);
303} 304}
304 305
305void BindBlitState(vk::CommandBuffer cmdbuf, VkPipelineLayout layout, const Region2D& dst_region, 306void BindBlitState(vk::CommandBuffer cmdbuf, const Region2D& dst_region) {
306 const Region2D& src_region, const Extent3D& src_size = {1, 1, 1}) {
307 const VkOffset2D offset{ 307 const VkOffset2D offset{
308 .x = std::min(dst_region.start.x, dst_region.end.x), 308 .x = std::min(dst_region.start.x, dst_region.end.x),
309 .y = std::min(dst_region.start.y, dst_region.end.y), 309 .y = std::min(dst_region.start.y, dst_region.end.y),
@@ -325,6 +325,13 @@ void BindBlitState(vk::CommandBuffer cmdbuf, VkPipelineLayout layout, const Regi
325 .offset = offset, 325 .offset = offset,
326 .extent = extent, 326 .extent = extent,
327 }; 327 };
328 cmdbuf.SetViewport(0, viewport);
329 cmdbuf.SetScissor(0, scissor);
330}
331
332void BindBlitState(vk::CommandBuffer cmdbuf, VkPipelineLayout layout, const Region2D& dst_region,
333 const Region2D& src_region, const Extent3D& src_size = {1, 1, 1}) {
334 BindBlitState(cmdbuf, dst_region);
328 const float scale_x = static_cast<float>(src_region.end.x - src_region.start.x) / 335 const float scale_x = static_cast<float>(src_region.end.x - src_region.start.x) /
329 static_cast<float>(src_size.width); 336 static_cast<float>(src_size.width);
330 const float scale_y = static_cast<float>(src_region.end.y - src_region.start.y) / 337 const float scale_y = static_cast<float>(src_region.end.y - src_region.start.y) /
@@ -335,8 +342,6 @@ void BindBlitState(vk::CommandBuffer cmdbuf, VkPipelineLayout layout, const Regi
335 static_cast<float>(src_region.start.y) / 342 static_cast<float>(src_region.start.y) /
336 static_cast<float>(src_size.height)}, 343 static_cast<float>(src_size.height)},
337 }; 344 };
338 cmdbuf.SetViewport(0, viewport);
339 cmdbuf.SetScissor(0, scissor);
340 cmdbuf.PushConstants(layout, VK_SHADER_STAGE_VERTEX_BIT, push_constants); 345 cmdbuf.PushConstants(layout, VK_SHADER_STAGE_VERTEX_BIT, push_constants);
341} 346}
342 347
@@ -408,13 +413,20 @@ BlitImageHelper::BlitImageHelper(const Device& device_, Scheduler& scheduler_,
408 descriptor_pool.Allocator(*one_texture_set_layout, TEXTURE_DESCRIPTOR_BANK_INFO<1>)}, 413 descriptor_pool.Allocator(*one_texture_set_layout, TEXTURE_DESCRIPTOR_BANK_INFO<1>)},
409 two_textures_descriptor_allocator{ 414 two_textures_descriptor_allocator{
410 descriptor_pool.Allocator(*two_textures_set_layout, TEXTURE_DESCRIPTOR_BANK_INFO<2>)}, 415 descriptor_pool.Allocator(*two_textures_set_layout, TEXTURE_DESCRIPTOR_BANK_INFO<2>)},
411 one_texture_pipeline_layout(device.GetLogical().CreatePipelineLayout( 416 one_texture_pipeline_layout(device.GetLogical().CreatePipelineLayout(PipelineLayoutCreateInfo(
412 PipelineLayoutCreateInfo(one_texture_set_layout.address()))), 417 one_texture_set_layout.address(),
413 two_textures_pipeline_layout(device.GetLogical().CreatePipelineLayout( 418 PUSH_CONSTANT_RANGE<VK_SHADER_STAGE_VERTEX_BIT, sizeof(PushConstants)>))),
414 PipelineLayoutCreateInfo(two_textures_set_layout.address()))), 419 two_textures_pipeline_layout(
420 device.GetLogical().CreatePipelineLayout(PipelineLayoutCreateInfo(
421 two_textures_set_layout.address(),
422 PUSH_CONSTANT_RANGE<VK_SHADER_STAGE_VERTEX_BIT, sizeof(PushConstants)>))),
423 clear_color_pipeline_layout(device.GetLogical().CreatePipelineLayout(PipelineLayoutCreateInfo(
424 nullptr, PUSH_CONSTANT_RANGE<VK_SHADER_STAGE_FRAGMENT_BIT, sizeof(float) * 4>))),
415 full_screen_vert(BuildShader(device, FULL_SCREEN_TRIANGLE_VERT_SPV)), 425 full_screen_vert(BuildShader(device, FULL_SCREEN_TRIANGLE_VERT_SPV)),
416 blit_color_to_color_frag(BuildShader(device, BLIT_COLOR_FLOAT_FRAG_SPV)), 426 blit_color_to_color_frag(BuildShader(device, BLIT_COLOR_FLOAT_FRAG_SPV)),
417 blit_depth_stencil_frag(BuildShader(device, VULKAN_BLIT_DEPTH_STENCIL_FRAG_SPV)), 427 blit_depth_stencil_frag(BuildShader(device, VULKAN_BLIT_DEPTH_STENCIL_FRAG_SPV)),
428 clear_color_vert(BuildShader(device, VULKAN_COLOR_CLEAR_VERT_SPV)),
429 clear_color_frag(BuildShader(device, VULKAN_COLOR_CLEAR_FRAG_SPV)),
418 convert_depth_to_float_frag(BuildShader(device, CONVERT_DEPTH_TO_FLOAT_FRAG_SPV)), 430 convert_depth_to_float_frag(BuildShader(device, CONVERT_DEPTH_TO_FLOAT_FRAG_SPV)),
419 convert_float_to_depth_frag(BuildShader(device, CONVERT_FLOAT_TO_DEPTH_FRAG_SPV)), 431 convert_float_to_depth_frag(BuildShader(device, CONVERT_FLOAT_TO_DEPTH_FRAG_SPV)),
420 convert_abgr8_to_d24s8_frag(BuildShader(device, CONVERT_ABGR8_TO_D24S8_FRAG_SPV)), 432 convert_abgr8_to_d24s8_frag(BuildShader(device, CONVERT_ABGR8_TO_D24S8_FRAG_SPV)),
@@ -553,6 +565,30 @@ void BlitImageHelper::ConvertS8D24ToABGR8(const Framebuffer* dst_framebuffer,
553 ConvertDepthStencil(*convert_s8d24_to_abgr8_pipeline, dst_framebuffer, src_image_view); 565 ConvertDepthStencil(*convert_s8d24_to_abgr8_pipeline, dst_framebuffer, src_image_view);
554} 566}
555 567
568void BlitImageHelper::ClearColor(const Framebuffer* dst_framebuffer, u8 color_mask,
569 const std::array<f32, 4>& clear_color,
570 const Region2D& dst_region) {
571 const BlitImagePipelineKey key{
572 .renderpass = dst_framebuffer->RenderPass(),
573 .operation = Tegra::Engines::Fermi2D::Operation::BlendPremult,
574 };
575 const VkPipeline pipeline = FindOrEmplaceClearColorPipeline(key);
576 const VkPipelineLayout layout = *clear_color_pipeline_layout;
577 scheduler.RequestRenderpass(dst_framebuffer);
578 scheduler.Record(
579 [pipeline, layout, color_mask, clear_color, dst_region](vk::CommandBuffer cmdbuf) {
580 cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
581 const std::array blend_color = {
582 (color_mask & 0x1) ? 1.0f : 0.0f, (color_mask & 0x2) ? 1.0f : 0.0f,
583 (color_mask & 0x4) ? 1.0f : 0.0f, (color_mask & 0x8) ? 1.0f : 0.0f};
584 cmdbuf.SetBlendConstants(blend_color.data());
585 BindBlitState(cmdbuf, dst_region);
586 cmdbuf.PushConstants(layout, VK_SHADER_STAGE_FRAGMENT_BIT, clear_color);
587 cmdbuf.Draw(3, 1, 0, 0);
588 });
589 scheduler.InvalidateState();
590}
591
556void BlitImageHelper::Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer, 592void BlitImageHelper::Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
557 const ImageView& src_image_view) { 593 const ImageView& src_image_view) {
558 const VkPipelineLayout layout = *one_texture_pipeline_layout; 594 const VkPipelineLayout layout = *one_texture_pipeline_layout;
@@ -728,6 +764,58 @@ VkPipeline BlitImageHelper::FindOrEmplaceDepthStencilPipeline(const BlitImagePip
728 return *blit_depth_stencil_pipelines.back(); 764 return *blit_depth_stencil_pipelines.back();
729} 765}
730 766
767VkPipeline BlitImageHelper::FindOrEmplaceClearColorPipeline(const BlitImagePipelineKey& key) {
768 const auto it = std::ranges::find(clear_color_keys, key);
769 if (it != clear_color_keys.end()) {
770 return *clear_color_pipelines[std::distance(clear_color_keys.begin(), it)];
771 }
772 clear_color_keys.push_back(key);
773 const std::array stages = MakeStages(*clear_color_vert, *clear_color_frag);
774 const VkPipelineColorBlendAttachmentState color_blend_attachment_state{
775 .blendEnable = VK_TRUE,
776 .srcColorBlendFactor = VK_BLEND_FACTOR_CONSTANT_COLOR,
777 .dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR,
778 .colorBlendOp = VK_BLEND_OP_ADD,
779 .srcAlphaBlendFactor = VK_BLEND_FACTOR_CONSTANT_ALPHA,
780 .dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA,
781 .alphaBlendOp = VK_BLEND_OP_ADD,
782 .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
783 VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
784 };
785 const VkPipelineColorBlendStateCreateInfo color_blend_state_generic_create_info{
786 .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
787 .pNext = nullptr,
788 .flags = 0,
789 .logicOpEnable = VK_FALSE,
790 .logicOp = VK_LOGIC_OP_CLEAR,
791 .attachmentCount = 1,
792 .pAttachments = &color_blend_attachment_state,
793 .blendConstants = {0.0f, 0.0f, 0.0f, 0.0f},
794 };
795 clear_color_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({
796 .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
797 .pNext = nullptr,
798 .flags = 0,
799 .stageCount = static_cast<u32>(stages.size()),
800 .pStages = stages.data(),
801 .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
802 .pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
803 .pTessellationState = nullptr,
804 .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO,
805 .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
806 .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
807 .pDepthStencilState = &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
808 .pColorBlendState = &color_blend_state_generic_create_info,
809 .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
810 .layout = *clear_color_pipeline_layout,
811 .renderPass = key.renderpass,
812 .subpass = 0,
813 .basePipelineHandle = VK_NULL_HANDLE,
814 .basePipelineIndex = 0,
815 }));
816 return *clear_color_pipelines.back();
817}
818
731void BlitImageHelper::ConvertPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass, 819void BlitImageHelper::ConvertPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass,
732 bool is_target_depth) { 820 bool is_target_depth) {
733 if (pipeline) { 821 if (pipeline) {
diff --git a/src/video_core/renderer_vulkan/blit_image.h b/src/video_core/renderer_vulkan/blit_image.h
index be8a9a2f6..2976a7d91 100644
--- a/src/video_core/renderer_vulkan/blit_image.h
+++ b/src/video_core/renderer_vulkan/blit_image.h
@@ -61,6 +61,9 @@ public:
61 61
62 void ConvertS8D24ToABGR8(const Framebuffer* dst_framebuffer, ImageView& src_image_view); 62 void ConvertS8D24ToABGR8(const Framebuffer* dst_framebuffer, ImageView& src_image_view);
63 63
64 void ClearColor(const Framebuffer* dst_framebuffer, u8 color_mask,
65 const std::array<f32, 4>& clear_color, const Region2D& dst_region);
66
64private: 67private:
65 void Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer, 68 void Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
66 const ImageView& src_image_view); 69 const ImageView& src_image_view);
@@ -72,6 +75,8 @@ private:
72 75
73 [[nodiscard]] VkPipeline FindOrEmplaceDepthStencilPipeline(const BlitImagePipelineKey& key); 76 [[nodiscard]] VkPipeline FindOrEmplaceDepthStencilPipeline(const BlitImagePipelineKey& key);
74 77
78 [[nodiscard]] VkPipeline FindOrEmplaceClearColorPipeline(const BlitImagePipelineKey& key);
79
75 void ConvertPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass, bool is_target_depth); 80 void ConvertPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass, bool is_target_depth);
76 81
77 void ConvertDepthToColorPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass); 82 void ConvertDepthToColorPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass);
@@ -97,9 +102,12 @@ private:
97 DescriptorAllocator two_textures_descriptor_allocator; 102 DescriptorAllocator two_textures_descriptor_allocator;
98 vk::PipelineLayout one_texture_pipeline_layout; 103 vk::PipelineLayout one_texture_pipeline_layout;
99 vk::PipelineLayout two_textures_pipeline_layout; 104 vk::PipelineLayout two_textures_pipeline_layout;
105 vk::PipelineLayout clear_color_pipeline_layout;
100 vk::ShaderModule full_screen_vert; 106 vk::ShaderModule full_screen_vert;
101 vk::ShaderModule blit_color_to_color_frag; 107 vk::ShaderModule blit_color_to_color_frag;
102 vk::ShaderModule blit_depth_stencil_frag; 108 vk::ShaderModule blit_depth_stencil_frag;
109 vk::ShaderModule clear_color_vert;
110 vk::ShaderModule clear_color_frag;
103 vk::ShaderModule convert_depth_to_float_frag; 111 vk::ShaderModule convert_depth_to_float_frag;
104 vk::ShaderModule convert_float_to_depth_frag; 112 vk::ShaderModule convert_float_to_depth_frag;
105 vk::ShaderModule convert_abgr8_to_d24s8_frag; 113 vk::ShaderModule convert_abgr8_to_d24s8_frag;
@@ -112,6 +120,8 @@ private:
112 std::vector<vk::Pipeline> blit_color_pipelines; 120 std::vector<vk::Pipeline> blit_color_pipelines;
113 std::vector<BlitImagePipelineKey> blit_depth_stencil_keys; 121 std::vector<BlitImagePipelineKey> blit_depth_stencil_keys;
114 std::vector<vk::Pipeline> blit_depth_stencil_pipelines; 122 std::vector<vk::Pipeline> blit_depth_stencil_pipelines;
123 std::vector<BlitImagePipelineKey> clear_color_keys;
124 std::vector<vk::Pipeline> clear_color_pipelines;
115 vk::Pipeline convert_d32_to_r32_pipeline; 125 vk::Pipeline convert_d32_to_r32_pipeline;
116 vk::Pipeline convert_r32_to_d32_pipeline; 126 vk::Pipeline convert_r32_to_d32_pipeline;
117 vk::Pipeline convert_d16_to_r16_pipeline; 127 vk::Pipeline convert_d16_to_r16_pipeline;
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index 86ef0daeb..719edbcfb 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -394,7 +394,15 @@ void RasterizerVulkan::Clear(u32 layer_count) {
394 cmdbuf.ClearAttachments(attachment, clear_rect); 394 cmdbuf.ClearAttachments(attachment, clear_rect);
395 }); 395 });
396 } else { 396 } else {
397 UNIMPLEMENTED_MSG("Unimplemented Clear only the specified channel"); 397 u8 color_mask = static_cast<u8>(regs.clear_surface.R | regs.clear_surface.G << 1 |
398 regs.clear_surface.B << 2 | regs.clear_surface.A << 3);
399 Region2D dst_region = {
400 Offset2D{.x = clear_rect.rect.offset.x, .y = clear_rect.rect.offset.y},
401 Offset2D{.x = clear_rect.rect.offset.x +
402 static_cast<s32>(clear_rect.rect.extent.width),
403 .y = clear_rect.rect.offset.y +
404 static_cast<s32>(clear_rect.rect.extent.height)}};
405 blit_image.ClearColor(framebuffer, color_mask, regs.clear_color, dst_region);
398 } 406 }
399 } 407 }
400 408
diff --git a/src/video_core/texture_cache/descriptor_table.h b/src/video_core/texture_cache/descriptor_table.h
index ee4240288..1bad83fb4 100644
--- a/src/video_core/texture_cache/descriptor_table.h
+++ b/src/video_core/texture_cache/descriptor_table.h
@@ -19,9 +19,7 @@ public:
19 explicit DescriptorTable(Tegra::MemoryManager& gpu_memory_) : gpu_memory{gpu_memory_} {} 19 explicit DescriptorTable(Tegra::MemoryManager& gpu_memory_) : gpu_memory{gpu_memory_} {}
20 20
21 [[nodiscard]] bool Synchronize(GPUVAddr gpu_addr, u32 limit) { 21 [[nodiscard]] bool Synchronize(GPUVAddr gpu_addr, u32 limit) {
22 [[likely]] if (current_gpu_addr == gpu_addr && current_limit == limit) { 22 [[likely]] if (current_gpu_addr == gpu_addr && current_limit == limit) { return false; }
23 return false;
24 }
25 Refresh(gpu_addr, limit); 23 Refresh(gpu_addr, limit);
26 return true; 24 return true;
27 } 25 }
diff --git a/src/video_core/texture_cache/slot_vector.h b/src/video_core/texture_cache/slot_vector.h
index 1e2aad76a..9df6a2903 100644
--- a/src/video_core/texture_cache/slot_vector.h
+++ b/src/video_core/texture_cache/slot_vector.h
@@ -29,7 +29,7 @@ struct SlotId {
29}; 29};
30 30
31template <class T> 31template <class T>
32requires std::is_nothrow_move_assignable_v<T> && std::is_nothrow_move_constructible_v<T> 32 requires std::is_nothrow_move_assignable_v<T> && std::is_nothrow_move_constructible_v<T>
33class SlotVector { 33class SlotVector {
34public: 34public:
35 class Iterator { 35 class Iterator {
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp
index 4b7e3b01b..723690e71 100644
--- a/src/yuzu/configuration/configure_input_player.cpp
+++ b/src/yuzu/configuration/configure_input_player.cpp
@@ -182,12 +182,13 @@ QString ConfigureInputPlayer::ButtonToText(const Common::ParamPackage& param) {
182 const QString toggle = QString::fromStdString(param.Get("toggle", false) ? "~" : ""); 182 const QString toggle = QString::fromStdString(param.Get("toggle", false) ? "~" : "");
183 const QString inverted = QString::fromStdString(param.Get("inverted", false) ? "!" : ""); 183 const QString inverted = QString::fromStdString(param.Get("inverted", false) ? "!" : "");
184 const QString invert = QString::fromStdString(param.Get("invert", "+") == "-" ? "-" : ""); 184 const QString invert = QString::fromStdString(param.Get("invert", "+") == "-" ? "-" : "");
185 const QString turbo = QString::fromStdString(param.Get("turbo", false) ? "$" : "");
185 const auto common_button_name = input_subsystem->GetButtonName(param); 186 const auto common_button_name = input_subsystem->GetButtonName(param);
186 187
187 // Retrieve the names from Qt 188 // Retrieve the names from Qt
188 if (param.Get("engine", "") == "keyboard") { 189 if (param.Get("engine", "") == "keyboard") {
189 const QString button_str = GetKeyName(param.Get("code", 0)); 190 const QString button_str = GetKeyName(param.Get("code", 0));
190 return QObject::tr("%1%2%3").arg(toggle, inverted, button_str); 191 return QObject::tr("%1%2%3%4").arg(turbo, toggle, inverted, button_str);
191 } 192 }
192 193
193 if (common_button_name == Common::Input::ButtonNames::Invalid) { 194 if (common_button_name == Common::Input::ButtonNames::Invalid) {
@@ -201,7 +202,7 @@ QString ConfigureInputPlayer::ButtonToText(const Common::ParamPackage& param) {
201 if (common_button_name == Common::Input::ButtonNames::Value) { 202 if (common_button_name == Common::Input::ButtonNames::Value) {
202 if (param.Has("hat")) { 203 if (param.Has("hat")) {
203 const QString hat = GetDirectionName(param.Get("direction", "")); 204 const QString hat = GetDirectionName(param.Get("direction", ""));
204 return QObject::tr("%1%2Hat %3").arg(toggle, inverted, hat); 205 return QObject::tr("%1%2%3Hat %4").arg(turbo, toggle, inverted, hat);
205 } 206 }
206 if (param.Has("axis")) { 207 if (param.Has("axis")) {
207 const QString axis = QString::fromStdString(param.Get("axis", "")); 208 const QString axis = QString::fromStdString(param.Get("axis", ""));
@@ -219,13 +220,13 @@ QString ConfigureInputPlayer::ButtonToText(const Common::ParamPackage& param) {
219 } 220 }
220 if (param.Has("button")) { 221 if (param.Has("button")) {
221 const QString button = QString::fromStdString(param.Get("button", "")); 222 const QString button = QString::fromStdString(param.Get("button", ""));
222 return QObject::tr("%1%2Button %3").arg(toggle, inverted, button); 223 return QObject::tr("%1%2%3Button %4").arg(turbo, toggle, inverted, button);
223 } 224 }
224 } 225 }
225 226
226 QString button_name = GetButtonName(common_button_name); 227 QString button_name = GetButtonName(common_button_name);
227 if (param.Has("hat")) { 228 if (param.Has("hat")) {
228 return QObject::tr("%1%2Hat %3").arg(toggle, inverted, button_name); 229 return QObject::tr("%1%2%3Hat %4").arg(turbo, toggle, inverted, button_name);
229 } 230 }
230 if (param.Has("axis")) { 231 if (param.Has("axis")) {
231 return QObject::tr("%1%2Axis %3").arg(toggle, inverted, button_name); 232 return QObject::tr("%1%2Axis %3").arg(toggle, inverted, button_name);
@@ -234,7 +235,7 @@ QString ConfigureInputPlayer::ButtonToText(const Common::ParamPackage& param) {
234 return QObject::tr("%1%2Axis %3").arg(toggle, inverted, button_name); 235 return QObject::tr("%1%2Axis %3").arg(toggle, inverted, button_name);
235 } 236 }
236 if (param.Has("button")) { 237 if (param.Has("button")) {
237 return QObject::tr("%1%2Button %3").arg(toggle, inverted, button_name); 238 return QObject::tr("%1%2%3Button %4").arg(turbo, toggle, inverted, button_name);
238 } 239 }
239 240
240 return QObject::tr("[unknown]"); 241 return QObject::tr("[unknown]");
@@ -395,6 +396,12 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
395 button_map[button_id]->setText(ButtonToText(param)); 396 button_map[button_id]->setText(ButtonToText(param));
396 emulated_controller->SetButtonParam(button_id, param); 397 emulated_controller->SetButtonParam(button_id, param);
397 }); 398 });
399 context_menu.addAction(tr("Turbo button"), [&] {
400 const bool turbo_value = !param.Get("turbo", false);
401 param.Set("turbo", turbo_value);
402 button_map[button_id]->setText(ButtonToText(param));
403 emulated_controller->SetButtonParam(button_id, param);
404 });
398 } 405 }
399 if (param.Has("axis")) { 406 if (param.Has("axis")) {
400 context_menu.addAction(tr("Invert axis"), [&] { 407 context_menu.addAction(tr("Invert axis"), [&] {
diff --git a/src/yuzu/configuration/configure_input_player_widget.cpp b/src/yuzu/configuration/configure_input_player_widget.cpp
index 68af6c20c..c287220fc 100644
--- a/src/yuzu/configuration/configure_input_player_widget.cpp
+++ b/src/yuzu/configuration/configure_input_player_widget.cpp
@@ -81,7 +81,6 @@ void PlayerControlPreview::UpdateColors() {
81 colors.outline = QColor(0, 0, 0); 81 colors.outline = QColor(0, 0, 0);
82 colors.primary = QColor(225, 225, 225); 82 colors.primary = QColor(225, 225, 225);
83 colors.button = QColor(109, 111, 114); 83 colors.button = QColor(109, 111, 114);
84 colors.button2 = QColor(109, 111, 114);
85 colors.button2 = QColor(77, 80, 84); 84 colors.button2 = QColor(77, 80, 84);
86 colors.slider_arrow = QColor(65, 68, 73); 85 colors.slider_arrow = QColor(65, 68, 73);
87 colors.font2 = QColor(0, 0, 0); 86 colors.font2 = QColor(0, 0, 0);
@@ -100,6 +99,7 @@ void PlayerControlPreview::UpdateColors() {
100 colors.led_off = QColor(170, 238, 255); 99 colors.led_off = QColor(170, 238, 255);
101 colors.indicator2 = QColor(59, 165, 93); 100 colors.indicator2 = QColor(59, 165, 93);
102 colors.charging = QColor(250, 168, 26); 101 colors.charging = QColor(250, 168, 26);
102 colors.button_turbo = QColor(217, 158, 4);
103 103
104 colors.left = colors.primary; 104 colors.left = colors.primary;
105 colors.right = colors.primary; 105 colors.right = colors.primary;
@@ -2469,7 +2469,6 @@ void PlayerControlPreview::DrawJoystickDot(QPainter& p, const QPointF center,
2469void PlayerControlPreview::DrawRoundButton(QPainter& p, QPointF center, 2469void PlayerControlPreview::DrawRoundButton(QPainter& p, QPointF center,
2470 const Common::Input::ButtonStatus& pressed, float width, 2470 const Common::Input::ButtonStatus& pressed, float width,
2471 float height, Direction direction, float radius) { 2471 float height, Direction direction, float radius) {
2472 p.setBrush(button_color);
2473 if (pressed.value) { 2472 if (pressed.value) {
2474 switch (direction) { 2473 switch (direction) {
2475 case Direction::Left: 2474 case Direction::Left:
@@ -2487,16 +2486,16 @@ void PlayerControlPreview::DrawRoundButton(QPainter& p, QPointF center,
2487 case Direction::None: 2486 case Direction::None:
2488 break; 2487 break;
2489 } 2488 }
2490 p.setBrush(colors.highlight);
2491 } 2489 }
2492 QRectF rect = {center.x() - width, center.y() - height, width * 2.0f, height * 2.0f}; 2490 QRectF rect = {center.x() - width, center.y() - height, width * 2.0f, height * 2.0f};
2491 p.setBrush(GetButtonColor(button_color, pressed.value, pressed.turbo));
2493 p.drawRoundedRect(rect, radius, radius); 2492 p.drawRoundedRect(rect, radius, radius);
2494} 2493}
2495void PlayerControlPreview::DrawMinusButton(QPainter& p, const QPointF center, 2494void PlayerControlPreview::DrawMinusButton(QPainter& p, const QPointF center,
2496 const Common::Input::ButtonStatus& pressed, 2495 const Common::Input::ButtonStatus& pressed,
2497 int button_size) { 2496 int button_size) {
2498 p.setPen(colors.outline); 2497 p.setPen(colors.outline);
2499 p.setBrush(pressed.value ? colors.highlight : colors.button); 2498 p.setBrush(GetButtonColor(colors.button, pressed.value, pressed.turbo));
2500 DrawRectangle(p, center, button_size, button_size / 3.0f); 2499 DrawRectangle(p, center, button_size, button_size / 3.0f);
2501} 2500}
2502void PlayerControlPreview::DrawPlusButton(QPainter& p, const QPointF center, 2501void PlayerControlPreview::DrawPlusButton(QPainter& p, const QPointF center,
@@ -2504,7 +2503,7 @@ void PlayerControlPreview::DrawPlusButton(QPainter& p, const QPointF center,
2504 int button_size) { 2503 int button_size) {
2505 // Draw outer line 2504 // Draw outer line
2506 p.setPen(colors.outline); 2505 p.setPen(colors.outline);
2507 p.setBrush(pressed.value ? colors.highlight : colors.button); 2506 p.setBrush(GetButtonColor(colors.button, pressed.value, pressed.turbo));
2508 DrawRectangle(p, center, button_size, button_size / 3.0f); 2507 DrawRectangle(p, center, button_size, button_size / 3.0f);
2509 DrawRectangle(p, center, button_size / 3.0f, button_size); 2508 DrawRectangle(p, center, button_size / 3.0f, button_size);
2510 2509
@@ -2526,7 +2525,7 @@ void PlayerControlPreview::DrawGCButtonX(QPainter& p, const QPointF center,
2526 } 2525 }
2527 2526
2528 p.setPen(colors.outline); 2527 p.setPen(colors.outline);
2529 p.setBrush(pressed.value ? colors.highlight : colors.button); 2528 p.setBrush(GetButtonColor(colors.button, pressed.value, pressed.turbo));
2530 DrawPolygon(p, button_x); 2529 DrawPolygon(p, button_x);
2531} 2530}
2532 2531
@@ -2539,7 +2538,7 @@ void PlayerControlPreview::DrawGCButtonY(QPainter& p, const QPointF center,
2539 } 2538 }
2540 2539
2541 p.setPen(colors.outline); 2540 p.setPen(colors.outline);
2542 p.setBrush(pressed.value ? colors.highlight : colors.button); 2541 p.setBrush(GetButtonColor(colors.button, pressed.value, pressed.turbo));
2543 DrawPolygon(p, button_x); 2542 DrawPolygon(p, button_x);
2544} 2543}
2545 2544
@@ -2553,17 +2552,15 @@ void PlayerControlPreview::DrawGCButtonZ(QPainter& p, const QPointF center,
2553 } 2552 }
2554 2553
2555 p.setPen(colors.outline); 2554 p.setPen(colors.outline);
2556 p.setBrush(pressed.value ? colors.highlight : colors.button2); 2555 p.setBrush(GetButtonColor(colors.button2, pressed.value, pressed.turbo));
2557 DrawPolygon(p, button_x); 2556 DrawPolygon(p, button_x);
2558} 2557}
2559 2558
2560void PlayerControlPreview::DrawCircleButton(QPainter& p, const QPointF center, 2559void PlayerControlPreview::DrawCircleButton(QPainter& p, const QPointF center,
2561 const Common::Input::ButtonStatus& pressed, 2560 const Common::Input::ButtonStatus& pressed,
2562 float button_size) { 2561 float button_size) {
2563 p.setBrush(button_color); 2562
2564 if (pressed.value) { 2563 p.setBrush(GetButtonColor(button_color, pressed.value, pressed.turbo));
2565 p.setBrush(colors.highlight);
2566 }
2567 p.drawEllipse(center, button_size, button_size); 2564 p.drawEllipse(center, button_size, button_size);
2568} 2565}
2569 2566
@@ -2620,7 +2617,7 @@ void PlayerControlPreview::DrawArrowButton(QPainter& p, const QPointF center,
2620 2617
2621 // Draw arrow button 2618 // Draw arrow button
2622 p.setPen(pressed.value ? colors.highlight : colors.button); 2619 p.setPen(pressed.value ? colors.highlight : colors.button);
2623 p.setBrush(pressed.value ? colors.highlight : colors.button); 2620 p.setBrush(GetButtonColor(colors.button, pressed.value, pressed.turbo));
2624 DrawPolygon(p, arrow_button); 2621 DrawPolygon(p, arrow_button);
2625 2622
2626 switch (direction) { 2623 switch (direction) {
@@ -2672,10 +2669,20 @@ void PlayerControlPreview::DrawTriggerButton(QPainter& p, const QPointF center,
2672 2669
2673 // Draw arrow button 2670 // Draw arrow button
2674 p.setPen(colors.outline); 2671 p.setPen(colors.outline);
2675 p.setBrush(pressed.value ? colors.highlight : colors.button); 2672 p.setBrush(GetButtonColor(colors.button, pressed.value, pressed.turbo));
2676 DrawPolygon(p, qtrigger_button); 2673 DrawPolygon(p, qtrigger_button);
2677} 2674}
2678 2675
2676QColor PlayerControlPreview::GetButtonColor(QColor default_color, bool is_pressed, bool turbo) {
2677 if (is_pressed && turbo) {
2678 return colors.button_turbo;
2679 }
2680 if (is_pressed) {
2681 return colors.highlight;
2682 }
2683 return default_color;
2684}
2685
2679void PlayerControlPreview::DrawBattery(QPainter& p, QPointF center, 2686void PlayerControlPreview::DrawBattery(QPainter& p, QPointF center,
2680 Common::Input::BatteryLevel battery) { 2687 Common::Input::BatteryLevel battery) {
2681 if (battery == Common::Input::BatteryLevel::None) { 2688 if (battery == Common::Input::BatteryLevel::None) {
diff --git a/src/yuzu/configuration/configure_input_player_widget.h b/src/yuzu/configuration/configure_input_player_widget.h
index b258c6d77..0e9e95e85 100644
--- a/src/yuzu/configuration/configure_input_player_widget.h
+++ b/src/yuzu/configuration/configure_input_player_widget.h
@@ -81,6 +81,7 @@ private:
81 QColor right{}; 81 QColor right{};
82 QColor button{}; 82 QColor button{};
83 QColor button2{}; 83 QColor button2{};
84 QColor button_turbo{};
84 QColor font{}; 85 QColor font{};
85 QColor font2{}; 86 QColor font2{};
86 QColor highlight{}; 87 QColor highlight{};
@@ -183,6 +184,7 @@ private:
183 const Common::Input::ButtonStatus& pressed, float size = 1.0f); 184 const Common::Input::ButtonStatus& pressed, float size = 1.0f);
184 void DrawTriggerButton(QPainter& p, QPointF center, Direction direction, 185 void DrawTriggerButton(QPainter& p, QPointF center, Direction direction,
185 const Common::Input::ButtonStatus& pressed); 186 const Common::Input::ButtonStatus& pressed);
187 QColor GetButtonColor(QColor default_color, bool is_pressed, bool turbo);
186 188
187 // Draw battery functions 189 // Draw battery functions
188 void DrawBattery(QPainter& p, QPointF center, Common::Input::BatteryLevel battery); 190 void DrawBattery(QPainter& p, QPointF center, Common::Input::BatteryLevel battery);