summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/string_util.cpp2
-rw-r--r--src/common/string_util.h3
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/hardware_properties.h20
-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_capabilities.cpp358
-rw-r--r--src/core/hle/kernel/k_capabilities.h295
-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.cpp5
-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.h31
-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/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
85 files changed, 1527 insertions, 536 deletions
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/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/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_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/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 3afda9e3f..513ea485a 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -758,11 +758,12 @@ Core::HID::NpadStyleTag Controller_NPad::GetSupportedStyleSet() const {
758 return hid_core.GetSupportedStyleTag(); 758 return hid_core.GetSupportedStyleTag();
759} 759}
760 760
761void Controller_NPad::SetSupportedNpadIdTypes(u8* data, std::size_t length) { 761void Controller_NPad::SetSupportedNpadIdTypes(std::span<const u8> data) {
762 const auto length = data.size();
762 ASSERT(length > 0 && (length % sizeof(u32)) == 0); 763 ASSERT(length > 0 && (length % sizeof(u32)) == 0);
763 supported_npad_id_types.clear(); 764 supported_npad_id_types.clear();
764 supported_npad_id_types.resize(length / sizeof(u32)); 765 supported_npad_id_types.resize(length / sizeof(u32));
765 std::memcpy(supported_npad_id_types.data(), data, length); 766 std::memcpy(supported_npad_id_types.data(), data.data(), length);
766} 767}
767 768
768void 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 188f6ecfa..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,14 +106,14 @@ 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> 119 requires std::is_trivially_copyable_v<Output>
@@ -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/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