summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/hex_util.h3
-rw-r--r--src/common/typed_address.h82
-rw-r--r--src/core/debugger/gdbstub_arch.cpp4
-rw-r--r--src/core/hle/service/cmif_serialization.h6
-rw-r--r--src/core/hle/service/cmif_types.h27
-rw-r--r--src/core/hle/service/filesystem/fsp/fsp_srv.cpp9
-rw-r--r--src/core/hle/service/glue/time/time_zone_binary.cpp1
-rw-r--r--src/core/hle/service/hid/hid_debug_server.cpp173
-rw-r--r--src/core/hle/service/hid/hid_debug_server.h24
-rw-r--r--src/core/hle/service/hid/irs.cpp588
-rw-r--r--src/core/hle/service/hid/irs.h84
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp6
-rw-r--r--src/core/hle/service/nvnflinger/hardware_composer.cpp50
-rw-r--r--src/core/hle/service/nvnflinger/hardware_composer.h2
-rw-r--r--src/core/hle/service/nvnflinger/nvnflinger.cpp3
-rw-r--r--src/core/memory/cheat_engine.cpp46
-rw-r--r--src/core/memory/cheat_engine.h8
-rw-r--r--src/core/memory/dmnt_cheat_types.h2
-rw-r--r--src/core/memory/dmnt_cheat_vm.cpp74
-rw-r--r--src/core/memory/dmnt_cheat_vm.h22
-rw-r--r--src/hid_core/irsensor/image_transfer_processor.cpp5
-rw-r--r--src/hid_core/irsensor/image_transfer_processor.h4
-rw-r--r--src/hid_core/resource_manager.cpp88
-rw-r--r--src/hid_core/resource_manager.h9
-rw-r--r--src/hid_core/resources/abstracted_pad/abstract_sixaxis_handler.cpp2
-rw-r--r--src/hid_core/resources/digitizer/digitizer.cpp4
-rw-r--r--src/hid_core/resources/digitizer/digitizer.h3
-rw-r--r--src/hid_core/resources/npad/npad.cpp24
-rw-r--r--src/hid_core/resources/npad/npad.h1
-rw-r--r--src/hid_core/resources/six_axis/six_axis.cpp254
-rw-r--r--src/hid_core/resources/touch_screen/touch_screen_resource.cpp8
-rw-r--r--src/hid_core/resources/unique_pad/unique_pad.cpp4
-rw-r--r--src/hid_core/resources/unique_pad/unique_pad.h3
-rw-r--r--src/video_core/host1x/host1x.cpp2
-rw-r--r--src/video_core/memory_manager.cpp17
-rw-r--r--src/video_core/memory_manager.h8
-rw-r--r--src/yuzu/configuration/configure_per_game.cpp3
-rw-r--r--src/yuzu/main.cpp7
-rw-r--r--src/yuzu/multiplayer/lobby.cpp13
-rw-r--r--src/yuzu/multiplayer/lobby_p.h25
-rw-r--r--src/yuzu/uisettings.h14
41 files changed, 839 insertions, 873 deletions
diff --git a/src/common/hex_util.h b/src/common/hex_util.h
index a00904939..618f53152 100644
--- a/src/common/hex_util.h
+++ b/src/common/hex_util.h
@@ -9,6 +9,7 @@
9#include <string> 9#include <string>
10#include <vector> 10#include <vector>
11#include <fmt/format.h> 11#include <fmt/format.h>
12#include "common/assert.h"
12#include "common/common_types.h" 13#include "common/common_types.h"
13 14
14namespace Common { 15namespace Common {
@@ -29,6 +30,8 @@ namespace Common {
29 30
30template <std::size_t Size, bool le = false> 31template <std::size_t Size, bool le = false>
31[[nodiscard]] constexpr std::array<u8, Size> HexStringToArray(std::string_view str) { 32[[nodiscard]] constexpr std::array<u8, Size> HexStringToArray(std::string_view str) {
33 ASSERT_MSG(Size * 2 <= str.size(), "Invalid string size");
34
32 std::array<u8, Size> out{}; 35 std::array<u8, Size> out{};
33 if constexpr (le) { 36 if constexpr (le) {
34 for (std::size_t i = 2 * Size - 2; i <= 2 * Size; i -= 2) { 37 for (std::size_t i = 2 * Size - 2; i <= 2 * Size; i -= 2) {
diff --git a/src/common/typed_address.h b/src/common/typed_address.h
index 64f4a07c2..d5e743583 100644
--- a/src/common/typed_address.h
+++ b/src/common/typed_address.h
@@ -186,68 +186,68 @@ static_assert(std::is_trivially_destructible_v<PhysicalAddress>);
186static_assert(std::is_trivially_destructible_v<VirtualAddress>); 186static_assert(std::is_trivially_destructible_v<VirtualAddress>);
187static_assert(std::is_trivially_destructible_v<ProcessAddress>); 187static_assert(std::is_trivially_destructible_v<ProcessAddress>);
188 188
189static_assert(Null<uint64_t> == 0); 189static_assert(Null<uint64_t> == 0U);
190static_assert(Null<PhysicalAddress> == Null<uint64_t>); 190static_assert(Null<PhysicalAddress> == Null<uint64_t>);
191static_assert(Null<VirtualAddress> == Null<uint64_t>); 191static_assert(Null<VirtualAddress> == Null<uint64_t>);
192static_assert(Null<ProcessAddress> == Null<uint64_t>); 192static_assert(Null<ProcessAddress> == Null<uint64_t>);
193 193
194// Constructor/assignment validations. 194// Constructor/assignment validations.
195static_assert([] { 195static_assert([] {
196 const PhysicalAddress a(5); 196 const PhysicalAddress a(5U);
197 PhysicalAddress b(a); 197 PhysicalAddress b(a);
198 return b; 198 return b;
199}() == PhysicalAddress(5)); 199}() == PhysicalAddress(5U));
200static_assert([] { 200static_assert([] {
201 const PhysicalAddress a(5); 201 const PhysicalAddress a(5U);
202 PhysicalAddress b(10); 202 PhysicalAddress b(10U);
203 b = a; 203 b = a;
204 return b; 204 return b;
205}() == PhysicalAddress(5)); 205}() == PhysicalAddress(5U));
206 206
207// Arithmetic validations. 207// Arithmetic validations.
208static_assert(PhysicalAddress(10) + 5 == PhysicalAddress(15)); 208static_assert(PhysicalAddress(10U) + 5U == PhysicalAddress(15U));
209static_assert(PhysicalAddress(10) - 5 == PhysicalAddress(5)); 209static_assert(PhysicalAddress(10U) - 5U == PhysicalAddress(5U));
210static_assert([] { 210static_assert([] {
211 PhysicalAddress v(10); 211 PhysicalAddress v(10U);
212 v += 5; 212 v += 5U;
213 return v; 213 return v;
214}() == PhysicalAddress(15)); 214}() == PhysicalAddress(15U));
215static_assert([] { 215static_assert([] {
216 PhysicalAddress v(10); 216 PhysicalAddress v(10U);
217 v -= 5; 217 v -= 5U;
218 return v; 218 return v;
219}() == PhysicalAddress(5)); 219}() == PhysicalAddress(5U));
220static_assert(PhysicalAddress(10)++ == PhysicalAddress(10)); 220static_assert(PhysicalAddress(10U)++ == PhysicalAddress(10U));
221static_assert(++PhysicalAddress(10) == PhysicalAddress(11)); 221static_assert(++PhysicalAddress(10U) == PhysicalAddress(11U));
222static_assert(PhysicalAddress(10)-- == PhysicalAddress(10)); 222static_assert(PhysicalAddress(10U)-- == PhysicalAddress(10U));
223static_assert(--PhysicalAddress(10) == PhysicalAddress(9)); 223static_assert(--PhysicalAddress(10U) == PhysicalAddress(9U));
224 224
225// Logical validations. 225// Logical validations.
226static_assert((PhysicalAddress(0b11111111) >> 1) == 0b01111111); 226static_assert((PhysicalAddress(0b11111111U) >> 1) == 0b01111111U);
227static_assert((PhysicalAddress(0b10101010) >> 1) == 0b01010101); 227static_assert((PhysicalAddress(0b10101010U) >> 1) == 0b01010101U);
228static_assert((PhysicalAddress(0b11111111) << 1) == 0b111111110); 228static_assert((PhysicalAddress(0b11111111U) << 1) == 0b111111110U);
229static_assert((PhysicalAddress(0b01010101) << 1) == 0b10101010); 229static_assert((PhysicalAddress(0b01010101U) << 1) == 0b10101010U);
230static_assert((PhysicalAddress(0b11111111) & 0b01010101) == 0b01010101); 230static_assert((PhysicalAddress(0b11111111U) & 0b01010101U) == 0b01010101U);
231static_assert((PhysicalAddress(0b11111111) & 0b10101010) == 0b10101010); 231static_assert((PhysicalAddress(0b11111111U) & 0b10101010U) == 0b10101010U);
232static_assert((PhysicalAddress(0b01010101) & 0b10101010) == 0b00000000); 232static_assert((PhysicalAddress(0b01010101U) & 0b10101010U) == 0b00000000U);
233static_assert((PhysicalAddress(0b00000000) | 0b01010101) == 0b01010101); 233static_assert((PhysicalAddress(0b00000000U) | 0b01010101U) == 0b01010101U);
234static_assert((PhysicalAddress(0b11111111) | 0b01010101) == 0b11111111); 234static_assert((PhysicalAddress(0b11111111U) | 0b01010101U) == 0b11111111U);
235static_assert((PhysicalAddress(0b10101010) | 0b01010101) == 0b11111111); 235static_assert((PhysicalAddress(0b10101010U) | 0b01010101U) == 0b11111111U);
236 236
237// Comparisons. 237// Comparisons.
238static_assert(PhysicalAddress(0) == PhysicalAddress(0)); 238static_assert(PhysicalAddress(0U) == PhysicalAddress(0U));
239static_assert(PhysicalAddress(0) != PhysicalAddress(1)); 239static_assert(PhysicalAddress(0U) != PhysicalAddress(1U));
240static_assert(PhysicalAddress(0) < PhysicalAddress(1)); 240static_assert(PhysicalAddress(0U) < PhysicalAddress(1U));
241static_assert(PhysicalAddress(0) <= PhysicalAddress(1)); 241static_assert(PhysicalAddress(0U) <= PhysicalAddress(1U));
242static_assert(PhysicalAddress(1) > PhysicalAddress(0)); 242static_assert(PhysicalAddress(1U) > PhysicalAddress(0U));
243static_assert(PhysicalAddress(1) >= PhysicalAddress(0)); 243static_assert(PhysicalAddress(1U) >= PhysicalAddress(0U));
244 244
245static_assert(!(PhysicalAddress(0) == PhysicalAddress(1))); 245static_assert(!(PhysicalAddress(0U) == PhysicalAddress(1U)));
246static_assert(!(PhysicalAddress(0) != PhysicalAddress(0))); 246static_assert(!(PhysicalAddress(0U) != PhysicalAddress(0U)));
247static_assert(!(PhysicalAddress(1) < PhysicalAddress(0))); 247static_assert(!(PhysicalAddress(1U) < PhysicalAddress(0U)));
248static_assert(!(PhysicalAddress(1) <= PhysicalAddress(0))); 248static_assert(!(PhysicalAddress(1U) <= PhysicalAddress(0U)));
249static_assert(!(PhysicalAddress(0) > PhysicalAddress(1))); 249static_assert(!(PhysicalAddress(0U) > PhysicalAddress(1U)));
250static_assert(!(PhysicalAddress(0) >= PhysicalAddress(1))); 250static_assert(!(PhysicalAddress(0U) >= PhysicalAddress(1U)));
251 251
252} // namespace Common 252} // namespace Common
253 253
diff --git a/src/core/debugger/gdbstub_arch.cpp b/src/core/debugger/gdbstub_arch.cpp
index f2a407dc8..452f565be 100644
--- a/src/core/debugger/gdbstub_arch.cpp
+++ b/src/core/debugger/gdbstub_arch.cpp
@@ -383,7 +383,7 @@ std::string GDBStubA32::RegRead(const Kernel::KThread* thread, size_t id) const
383 } else if (id == CPSR_REGISTER) { 383 } else if (id == CPSR_REGISTER) {
384 return ValueToHex(context.pstate); 384 return ValueToHex(context.pstate);
385 } else if (id >= D0_REGISTER && id < Q0_REGISTER) { 385 } else if (id >= D0_REGISTER && id < Q0_REGISTER) {
386 return ValueToHex(fprs[id - D0_REGISTER][0]); 386 return ValueToHex(fprs[(id - D0_REGISTER) / 2][(id - D0_REGISTER) % 2]);
387 } else if (id >= Q0_REGISTER && id < FPSCR_REGISTER) { 387 } else if (id >= Q0_REGISTER && id < FPSCR_REGISTER) {
388 return ValueToHex(fprs[id - Q0_REGISTER]); 388 return ValueToHex(fprs[id - Q0_REGISTER]);
389 } else if (id == FPSCR_REGISTER) { 389 } else if (id == FPSCR_REGISTER) {
@@ -406,7 +406,7 @@ void GDBStubA32::RegWrite(Kernel::KThread* thread, size_t id, std::string_view v
406 } else if (id == CPSR_REGISTER) { 406 } else if (id == CPSR_REGISTER) {
407 context.pstate = HexToValue<u32>(value); 407 context.pstate = HexToValue<u32>(value);
408 } else if (id >= D0_REGISTER && id < Q0_REGISTER) { 408 } else if (id >= D0_REGISTER && id < Q0_REGISTER) {
409 fprs[id - D0_REGISTER] = {HexToValue<u64>(value), 0}; 409 fprs[(id - D0_REGISTER) / 2][(id - D0_REGISTER) % 2] = HexToValue<u64>(value);
410 } else if (id >= Q0_REGISTER && id < FPSCR_REGISTER) { 410 } else if (id >= Q0_REGISTER && id < FPSCR_REGISTER) {
411 fprs[id - Q0_REGISTER] = HexToValue<u128>(value); 411 fprs[id - Q0_REGISTER] = HexToValue<u128>(value);
412 } else if (id == FPSCR_REGISTER) { 412 } else if (id == FPSCR_REGISTER) {
diff --git a/src/core/hle/service/cmif_serialization.h b/src/core/hle/service/cmif_serialization.h
index 315475e71..e985fe317 100644
--- a/src/core/hle/service/cmif_serialization.h
+++ b/src/core/hle/service/cmif_serialization.h
@@ -115,6 +115,11 @@ struct ArgumentTraits {
115 static constexpr ArgumentType Type = ArgumentType::InData; 115 static constexpr ArgumentType Type = ArgumentType::InData;
116}; 116};
117 117
118template <typename... Ts>
119consteval bool ConstIfReference() {
120 return ((!std::is_reference_v<Ts> || std::is_const_v<std::remove_reference_t<Ts>>) && ... && true);
121}
122
118struct RequestLayout { 123struct RequestLayout {
119 u32 copy_handle_count; 124 u32 copy_handle_count;
120 u32 move_handle_count; 125 u32 move_handle_count;
@@ -435,6 +440,7 @@ void CmifReplyWrapImpl(HLERequestContext& ctx, T& t, Result (T::*f)(A...)) {
435 } 440 }
436 const bool is_domain = Domain ? ctx.GetManager()->IsDomain() : false; 441 const bool is_domain = Domain ? ctx.GetManager()->IsDomain() : false;
437 442
443 static_assert(ConstIfReference<A...>(), "Arguments taken by reference must be const");
438 using MethodArguments = std::tuple<std::remove_cvref_t<A>...>; 444 using MethodArguments = std::tuple<std::remove_cvref_t<A>...>;
439 445
440 OutTemporaryBuffers buffers{}; 446 OutTemporaryBuffers buffers{};
diff --git a/src/core/hle/service/cmif_types.h b/src/core/hle/service/cmif_types.h
index dc06169f4..84f4c2456 100644
--- a/src/core/hle/service/cmif_types.h
+++ b/src/core/hle/service/cmif_types.h
@@ -4,10 +4,9 @@
4#pragma once 4#pragma once
5 5
6#include <memory> 6#include <memory>
7#include <span>
7 8
8#include "common/common_funcs.h"
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "core/hle/service/hle_ipc.h"
11 10
12namespace Service { 11namespace Service {
13 12
@@ -22,8 +21,10 @@ class Out {
22public: 21public:
23 using Type = T; 22 using Type = T;
24 23
24 /* implicit */ Out(const Out& t) : raw(t.raw) {}
25 /* implicit */ Out(AutoOut<Type>& t) : raw(&t.raw) {} 25 /* implicit */ Out(AutoOut<Type>& t) : raw(&t.raw) {}
26 /* implicit */ Out(Type* t) : raw(t) {} 26 /* implicit */ Out(Type* t) : raw(t) {}
27 Out& operator=(const Out&) = delete;
27 28
28 Type* Get() const { 29 Type* Get() const {
29 return raw; 30 return raw;
@@ -37,6 +38,10 @@ public:
37 return raw; 38 return raw;
38 } 39 }
39 40
41 operator Type*() const {
42 return raw;
43 }
44
40private: 45private:
41 Type* raw; 46 Type* raw;
42}; 47};
@@ -113,8 +118,10 @@ class OutCopyHandle {
113public: 118public:
114 using Type = T*; 119 using Type = T*;
115 120
121 /* implicit */ OutCopyHandle(const OutCopyHandle& t) : raw(t.raw) {}
116 /* implicit */ OutCopyHandle(AutoOut<Type>& t) : raw(&t.raw) {} 122 /* implicit */ OutCopyHandle(AutoOut<Type>& t) : raw(&t.raw) {}
117 /* implicit */ OutCopyHandle(Type* t) : raw(t) {} 123 /* implicit */ OutCopyHandle(Type* t) : raw(t) {}
124 OutCopyHandle& operator=(const OutCopyHandle&) = delete;
118 125
119 Type* Get() const { 126 Type* Get() const {
120 return raw; 127 return raw;
@@ -128,6 +135,10 @@ public:
128 return raw; 135 return raw;
129 } 136 }
130 137
138 operator Type*() const {
139 return raw;
140 }
141
131private: 142private:
132 Type* raw; 143 Type* raw;
133}; 144};
@@ -137,8 +148,10 @@ class OutMoveHandle {
137public: 148public:
138 using Type = T*; 149 using Type = T*;
139 150
151 /* implicit */ OutMoveHandle(const OutMoveHandle& t) : raw(t.raw) {}
140 /* implicit */ OutMoveHandle(AutoOut<Type>& t) : raw(&t.raw) {} 152 /* implicit */ OutMoveHandle(AutoOut<Type>& t) : raw(&t.raw) {}
141 /* implicit */ OutMoveHandle(Type* t) : raw(t) {} 153 /* implicit */ OutMoveHandle(Type* t) : raw(t) {}
154 OutMoveHandle& operator=(const OutMoveHandle&) = delete;
142 155
143 Type* Get() const { 156 Type* Get() const {
144 return raw; 157 return raw;
@@ -152,6 +165,10 @@ public:
152 return raw; 165 return raw;
153 } 166 }
154 167
168 operator Type*() const {
169 return raw;
170 }
171
155private: 172private:
156 Type* raw; 173 Type* raw;
157}; 174};
@@ -248,8 +265,10 @@ public:
248 static constexpr BufferAttr Attr = static_cast<BufferAttr>(A | BufferAttr_In | BufferAttr_FixedSize); 265 static constexpr BufferAttr Attr = static_cast<BufferAttr>(A | BufferAttr_In | BufferAttr_FixedSize);
249 using Type = T; 266 using Type = T;
250 267
268 /* implicit */ OutLargeData(const OutLargeData& t) : raw(t.raw) {}
251 /* implicit */ OutLargeData(Type* t) : raw(t) {} 269 /* implicit */ OutLargeData(Type* t) : raw(t) {}
252 /* implicit */ OutLargeData(AutoOut<T>& t) : raw(&t.raw) {} 270 /* implicit */ OutLargeData(AutoOut<T>& t) : raw(&t.raw) {}
271 OutLargeData& operator=(const OutLargeData&) = delete;
253 272
254 Type* Get() const { 273 Type* Get() const {
255 return raw; 274 return raw;
@@ -263,6 +282,10 @@ public:
263 return raw; 282 return raw;
264 } 283 }
265 284
285 operator Type*() const {
286 return raw;
287 }
288
266private: 289private:
267 Type* raw; 290 Type* raw;
268}; 291};
diff --git a/src/core/hle/service/filesystem/fsp/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp/fsp_srv.cpp
index 5fe534c73..63c2d3a58 100644
--- a/src/core/hle/service/filesystem/fsp/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp/fsp_srv.cpp
@@ -115,6 +115,11 @@ private:
115 if (type->GetName() == "save") { 115 if (type->GetName() == "save") {
116 for (const auto& save_id : type->GetSubdirectories()) { 116 for (const auto& save_id : type->GetSubdirectories()) {
117 for (const auto& user_id : save_id->GetSubdirectories()) { 117 for (const auto& user_id : save_id->GetSubdirectories()) {
118 // Skip non user id subdirectories
119 if (user_id->GetName().size() != 0x20) {
120 continue;
121 }
122
118 const auto save_id_numeric = stoull_be(save_id->GetName()); 123 const auto save_id_numeric = stoull_be(save_id->GetName());
119 auto user_id_numeric = Common::HexStringToArray<0x10>(user_id->GetName()); 124 auto user_id_numeric = Common::HexStringToArray<0x10>(user_id->GetName());
120 std::reverse(user_id_numeric.begin(), user_id_numeric.end()); 125 std::reverse(user_id_numeric.begin(), user_id_numeric.end());
@@ -160,6 +165,10 @@ private:
160 } else if (space == FileSys::SaveDataSpaceId::TemporaryStorage) { 165 } else if (space == FileSys::SaveDataSpaceId::TemporaryStorage) {
161 // Temporary Storage 166 // Temporary Storage
162 for (const auto& user_id : type->GetSubdirectories()) { 167 for (const auto& user_id : type->GetSubdirectories()) {
168 // Skip non user id subdirectories
169 if (user_id->GetName().size() != 0x20) {
170 continue;
171 }
163 for (const auto& title_id : user_id->GetSubdirectories()) { 172 for (const auto& title_id : user_id->GetSubdirectories()) {
164 if (!title_id->GetFiles().empty() || 173 if (!title_id->GetFiles().empty() ||
165 !title_id->GetSubdirectories().empty()) { 174 !title_id->GetSubdirectories().empty()) {
diff --git a/src/core/hle/service/glue/time/time_zone_binary.cpp b/src/core/hle/service/glue/time/time_zone_binary.cpp
index d5f7ca3d2..18c6abd6b 100644
--- a/src/core/hle/service/glue/time/time_zone_binary.cpp
+++ b/src/core/hle/service/glue/time/time_zone_binary.cpp
@@ -65,6 +65,7 @@ Result MountTimeZoneBinary(Core::System& system) {
65 // Validate that the romfs is readable, using invalid firmware keys can cause this to get 65 // Validate that the romfs is readable, using invalid firmware keys can cause this to get
66 // set but the files to be garbage. In that case, we want to hit the next path and 66 // set but the files to be garbage. In that case, we want to hit the next path and
67 // synthesise them instead. 67 // synthesise them instead.
68 g_time_zone_binary_mount_result = ResultSuccess;
68 Service::PSC::Time::LocationName name{"Etc/GMT"}; 69 Service::PSC::Time::LocationName name{"Etc/GMT"};
69 if (!IsTimeZoneBinaryValid(name)) { 70 if (!IsTimeZoneBinaryValid(name)) {
70 ResetTimeZoneBinary(); 71 ResetTimeZoneBinary();
diff --git a/src/core/hle/service/hid/hid_debug_server.cpp b/src/core/hle/service/hid/hid_debug_server.cpp
index 610af34dd..4e2663672 100644
--- a/src/core/hle/service/hid/hid_debug_server.cpp
+++ b/src/core/hle/service/hid/hid_debug_server.cpp
@@ -3,6 +3,7 @@
3 3
4#include <algorithm> 4#include <algorithm>
5 5
6#include "core/hle/service/cmif_serialization.h"
6#include "core/hle/service/hid/hid_debug_server.h" 7#include "core/hle/service/hid/hid_debug_server.h"
7#include "core/hle/service/ipc_helpers.h" 8#include "core/hle/service/ipc_helpers.h"
8#include "hid_core/hid_types.h" 9#include "hid_core/hid_types.h"
@@ -11,7 +12,6 @@
11 12
12#include "hid_core/resources/touch_screen/gesture.h" 13#include "hid_core/resources/touch_screen/gesture.h"
13#include "hid_core/resources/touch_screen/touch_screen.h" 14#include "hid_core/resources/touch_screen/touch_screen.h"
14#include "hid_core/resources/touch_screen/touch_types.h"
15 15
16namespace Service::HID { 16namespace Service::HID {
17 17
@@ -24,14 +24,14 @@ IHidDebugServer::IHidDebugServer(Core::System& system_, std::shared_ptr<Resource
24 {0, nullptr, "DeactivateDebugPad"}, 24 {0, nullptr, "DeactivateDebugPad"},
25 {1, nullptr, "SetDebugPadAutoPilotState"}, 25 {1, nullptr, "SetDebugPadAutoPilotState"},
26 {2, nullptr, "UnsetDebugPadAutoPilotState"}, 26 {2, nullptr, "UnsetDebugPadAutoPilotState"},
27 {10, &IHidDebugServer::DeactivateTouchScreen, "DeactivateTouchScreen"}, 27 {10, C<&IHidDebugServer::DeactivateTouchScreen>, "DeactivateTouchScreen"},
28 {11, &IHidDebugServer::SetTouchScreenAutoPilotState, "SetTouchScreenAutoPilotState"}, 28 {11, C<&IHidDebugServer::SetTouchScreenAutoPilotState>, "SetTouchScreenAutoPilotState"},
29 {12, &IHidDebugServer::UnsetTouchScreenAutoPilotState, "UnsetTouchScreenAutoPilotState"}, 29 {12, C<&IHidDebugServer::UnsetTouchScreenAutoPilotState>, "UnsetTouchScreenAutoPilotState"},
30 {13, &IHidDebugServer::GetTouchScreenConfiguration, "GetTouchScreenConfiguration"}, 30 {13, C<&IHidDebugServer::GetTouchScreenConfiguration>, "GetTouchScreenConfiguration"},
31 {14, &IHidDebugServer::ProcessTouchScreenAutoTune, "ProcessTouchScreenAutoTune"}, 31 {14, C<&IHidDebugServer::ProcessTouchScreenAutoTune>, "ProcessTouchScreenAutoTune"},
32 {15, &IHidDebugServer::ForceStopTouchScreenManagement, "ForceStopTouchScreenManagement"}, 32 {15, C<&IHidDebugServer::ForceStopTouchScreenManagement>, "ForceStopTouchScreenManagement"},
33 {16, &IHidDebugServer::ForceRestartTouchScreenManagement, "ForceRestartTouchScreenManagement"}, 33 {16, C<&IHidDebugServer::ForceRestartTouchScreenManagement>, "ForceRestartTouchScreenManagement"},
34 {17, &IHidDebugServer::IsTouchScreenManaged, "IsTouchScreenManaged"}, 34 {17, C<&IHidDebugServer::IsTouchScreenManaged>, "IsTouchScreenManaged"},
35 {20, nullptr, "DeactivateMouse"}, 35 {20, nullptr, "DeactivateMouse"},
36 {21, nullptr, "SetMouseAutoPilotState"}, 36 {21, nullptr, "SetMouseAutoPilotState"},
37 {22, nullptr, "UnsetMouseAutoPilotState"}, 37 {22, nullptr, "UnsetMouseAutoPilotState"},
@@ -47,7 +47,7 @@ IHidDebugServer::IHidDebugServer(Core::System& system_, std::shared_ptr<Resource
47 {60, nullptr, "ClearNpadSystemCommonPolicy"}, 47 {60, nullptr, "ClearNpadSystemCommonPolicy"},
48 {61, nullptr, "DeactivateNpad"}, 48 {61, nullptr, "DeactivateNpad"},
49 {62, nullptr, "ForceDisconnectNpad"}, 49 {62, nullptr, "ForceDisconnectNpad"},
50 {91, &IHidDebugServer::DeactivateGesture, "DeactivateGesture"}, 50 {91, C<&IHidDebugServer::DeactivateGesture>, "DeactivateGesture"},
51 {110, nullptr, "DeactivateHomeButton"}, 51 {110, nullptr, "DeactivateHomeButton"},
52 {111, nullptr, "SetHomeButtonAutoPilotState"}, 52 {111, nullptr, "SetHomeButtonAutoPilotState"},
53 {112, nullptr, "UnsetHomeButtonAutoPilotState"}, 53 {112, nullptr, "UnsetHomeButtonAutoPilotState"},
@@ -160,169 +160,122 @@ IHidDebugServer::IHidDebugServer(Core::System& system_, std::shared_ptr<Resource
160} 160}
161 161
162IHidDebugServer::~IHidDebugServer() = default; 162IHidDebugServer::~IHidDebugServer() = default;
163void IHidDebugServer::DeactivateTouchScreen(HLERequestContext& ctx) {
164 LOG_INFO(Service_HID, "called");
165 163
166 Result result = ResultSuccess; 164Result IHidDebugServer::DeactivateTouchScreen() {
165 LOG_INFO(Service_HID, "called");
167 166
168 if (!firmware_settings->IsDeviceManaged()) { 167 if (!firmware_settings->IsDeviceManaged()) {
169 result = GetResourceManager()->GetTouchScreen()->Deactivate(); 168 R_RETURN(GetResourceManager()->GetTouchScreen()->Deactivate());
170 } 169 }
171 170
172 IPC::ResponseBuilder rb{ctx, 2}; 171 R_SUCCEED();
173 rb.Push(result);
174} 172}
175 173
176void IHidDebugServer::SetTouchScreenAutoPilotState(HLERequestContext& ctx) { 174Result IHidDebugServer::SetTouchScreenAutoPilotState(
175 InArray<TouchState, BufferAttr_HipcMapAlias> auto_pilot_buffer) {
177 AutoPilotState auto_pilot{}; 176 AutoPilotState auto_pilot{};
178 auto_pilot.count = ctx.GetReadBufferNumElements<TouchState>();
179 const auto buffer = ctx.ReadBuffer();
180 177
181 auto_pilot.count = std::min(auto_pilot.count, static_cast<u64>(auto_pilot.state.size())); 178 auto_pilot.count =
182 memcpy(auto_pilot.state.data(), buffer.data(), auto_pilot.count * sizeof(TouchState)); 179 static_cast<u64>(std::min(auto_pilot_buffer.size(), auto_pilot.state.size()));
180 memcpy(auto_pilot.state.data(), auto_pilot_buffer.data(),
181 auto_pilot.count * sizeof(TouchState));
183 182
184 LOG_INFO(Service_HID, "called, auto_pilot_count={}", auto_pilot.count); 183 LOG_INFO(Service_HID, "called, auto_pilot_count={}", auto_pilot.count);
185 184
186 const Result result = 185 R_RETURN(GetResourceManager()->GetTouchScreen()->SetTouchScreenAutoPilotState(auto_pilot));
187 GetResourceManager()->GetTouchScreen()->SetTouchScreenAutoPilotState(auto_pilot);
188
189 IPC::ResponseBuilder rb{ctx, 2};
190 rb.Push(result);
191} 186}
192 187
193void IHidDebugServer::UnsetTouchScreenAutoPilotState(HLERequestContext& ctx) { 188Result IHidDebugServer::UnsetTouchScreenAutoPilotState() {
194 LOG_INFO(Service_HID, "called"); 189 LOG_INFO(Service_HID, "called");
195 190 R_RETURN(GetResourceManager()->GetTouchScreen()->UnsetTouchScreenAutoPilotState());
196 const Result result = GetResourceManager()->GetTouchScreen()->UnsetTouchScreenAutoPilotState();
197
198 IPC::ResponseBuilder rb{ctx, 2};
199 rb.Push(result);
200} 191}
201 192
202void IHidDebugServer::GetTouchScreenConfiguration(HLERequestContext& ctx) { 193Result IHidDebugServer::GetTouchScreenConfiguration(
203 IPC::RequestParser rp{ctx}; 194 Out<Core::HID::TouchScreenConfigurationForNx> out_touchscreen_config,
204 const auto applet_resource_user_id{rp.Pop<u64>()}; 195 ClientAppletResourceUserId aruid) {
205 196 LOG_INFO(Service_HID, "called, applet_resource_user_id={}", aruid.pid);
206 LOG_INFO(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
207 197
208 Core::HID::TouchScreenConfigurationForNx touchscreen_config{}; 198 R_TRY(GetResourceManager()->GetTouchScreen()->GetTouchScreenConfiguration(
209 const Result result = GetResourceManager()->GetTouchScreen()->GetTouchScreenConfiguration( 199 *out_touchscreen_config, aruid.pid));
210 touchscreen_config, applet_resource_user_id);
211 200
212 if (touchscreen_config.mode != Core::HID::TouchScreenModeForNx::Heat2 && 201 if (out_touchscreen_config->mode != Core::HID::TouchScreenModeForNx::Heat2 &&
213 touchscreen_config.mode != Core::HID::TouchScreenModeForNx::Finger) { 202 out_touchscreen_config->mode != Core::HID::TouchScreenModeForNx::Finger) {
214 touchscreen_config.mode = Core::HID::TouchScreenModeForNx::UseSystemSetting; 203 out_touchscreen_config->mode = Core::HID::TouchScreenModeForNx::UseSystemSetting;
215 } 204 }
216 205
217 IPC::ResponseBuilder rb{ctx, 6}; 206 R_SUCCEED();
218 rb.Push(result);
219 rb.PushRaw(touchscreen_config);
220} 207}
221 208
222void IHidDebugServer::ProcessTouchScreenAutoTune(HLERequestContext& ctx) { 209Result IHidDebugServer::ProcessTouchScreenAutoTune() {
223 LOG_INFO(Service_HID, "called"); 210 LOG_INFO(Service_HID, "called");
224 211 R_RETURN(GetResourceManager()->GetTouchScreen()->ProcessTouchScreenAutoTune());
225 Result result = GetResourceManager()->GetTouchScreen()->ProcessTouchScreenAutoTune();
226
227 IPC::ResponseBuilder rb{ctx, 2};
228 rb.Push(result);
229} 212}
230 213
231void IHidDebugServer::ForceStopTouchScreenManagement(HLERequestContext& ctx) { 214Result IHidDebugServer::ForceStopTouchScreenManagement() {
232 LOG_INFO(Service_HID, "called"); 215 LOG_INFO(Service_HID, "called");
233 216
234 if (!firmware_settings->IsDeviceManaged()) { 217 if (!firmware_settings->IsDeviceManaged()) {
235 IPC::ResponseBuilder rb{ctx, 2}; 218 R_SUCCEED();
236 rb.Push(ResultSuccess);
237 return;
238 } 219 }
239 220
240 Result result = ResultSuccess;
241 bool is_touch_active{};
242 bool is_gesture_active{};
243 auto touch_screen = GetResourceManager()->GetTouchScreen(); 221 auto touch_screen = GetResourceManager()->GetTouchScreen();
244 auto gesture = GetResourceManager()->GetGesture(); 222 auto gesture = GetResourceManager()->GetGesture();
245 223
246 if (firmware_settings->IsTouchI2cManaged()) { 224 if (firmware_settings->IsTouchI2cManaged()) {
247 result = touch_screen->IsActive(is_touch_active); 225 bool is_touch_active{};
248 if (result.IsSuccess()) { 226 bool is_gesture_active{};
249 result = gesture->IsActive(is_gesture_active); 227 R_TRY(touch_screen->IsActive(is_touch_active));
250 } 228 R_TRY(gesture->IsActive(is_gesture_active));
251 if (result.IsSuccess() && is_touch_active) { 229
252 result = touch_screen->Deactivate(); 230 if (is_touch_active) {
231 R_TRY(touch_screen->Deactivate());
253 } 232 }
254 if (result.IsSuccess() && is_gesture_active) { 233 if (is_gesture_active) {
255 result = gesture->Deactivate(); 234 R_TRY(gesture->Deactivate());
256 } 235 }
257 } 236 }
258 237
259 IPC::ResponseBuilder rb{ctx, 2}; 238 R_SUCCEED();
260 rb.Push(result);
261} 239}
262 240
263void IHidDebugServer::ForceRestartTouchScreenManagement(HLERequestContext& ctx) { 241Result IHidDebugServer::ForceRestartTouchScreenManagement(u32 basic_gesture_id,
264 IPC::RequestParser rp{ctx}; 242 ClientAppletResourceUserId aruid) {
265 struct Parameters {
266 u32 basic_gesture_id;
267 INSERT_PADDING_WORDS_NOINIT(1);
268 u64 applet_resource_user_id;
269 };
270 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
271
272 const auto parameters{rp.PopRaw<Parameters>()};
273
274 LOG_INFO(Service_HID, "called, basic_gesture_id={}, applet_resource_user_id={}", 243 LOG_INFO(Service_HID, "called, basic_gesture_id={}, applet_resource_user_id={}",
275 parameters.basic_gesture_id, parameters.applet_resource_user_id); 244 basic_gesture_id, aruid.pid);
276 245
277 Result result = ResultSuccess;
278 auto touch_screen = GetResourceManager()->GetTouchScreen(); 246 auto touch_screen = GetResourceManager()->GetTouchScreen();
279 auto gesture = GetResourceManager()->GetGesture(); 247 auto gesture = GetResourceManager()->GetGesture();
280 248
281 if (firmware_settings->IsDeviceManaged() && firmware_settings->IsTouchI2cManaged()) { 249 if (firmware_settings->IsDeviceManaged() && firmware_settings->IsTouchI2cManaged()) {
282 result = gesture->Activate(); 250 R_TRY(gesture->Activate());
283 if (result.IsSuccess()) { 251 R_TRY(gesture->Activate(aruid.pid, basic_gesture_id));
284 result = 252 R_TRY(touch_screen->Activate());
285 gesture->Activate(parameters.applet_resource_user_id, parameters.basic_gesture_id); 253 R_TRY(touch_screen->Activate(aruid.pid));
286 }
287 if (result.IsSuccess()) {
288 result = touch_screen->Activate();
289 }
290 if (result.IsSuccess()) {
291 result = touch_screen->Activate(parameters.applet_resource_user_id);
292 }
293 } 254 }
294 255
295 IPC::ResponseBuilder rb{ctx, 2}; 256 R_SUCCEED();
296 rb.Push(result);
297} 257}
298 258
299void IHidDebugServer::IsTouchScreenManaged(HLERequestContext& ctx) { 259Result IHidDebugServer::IsTouchScreenManaged(Out<bool> out_is_managed) {
300 LOG_INFO(Service_HID, "called"); 260 LOG_INFO(Service_HID, "called");
301 261
302 bool is_touch_active{}; 262 bool is_touch_active{};
303 bool is_gesture_active{}; 263 bool is_gesture_active{};
264 R_TRY(GetResourceManager()->GetTouchScreen()->IsActive(is_touch_active));
265 R_TRY(GetResourceManager()->GetGesture()->IsActive(is_gesture_active));
304 266
305 Result result = GetResourceManager()->GetTouchScreen()->IsActive(is_touch_active); 267 *out_is_managed = is_touch_active || is_gesture_active;
306 if (result.IsSuccess()) { 268 R_SUCCEED();
307 result = GetResourceManager()->GetGesture()->IsActive(is_gesture_active);
308 }
309
310 IPC::ResponseBuilder rb{ctx, 3};
311 rb.Push(result);
312 rb.Push(is_touch_active | is_gesture_active);
313} 269}
314 270
315void IHidDebugServer::DeactivateGesture(HLERequestContext& ctx) { 271Result IHidDebugServer::DeactivateGesture() {
316 LOG_INFO(Service_HID, "called"); 272 LOG_INFO(Service_HID, "called");
317 273
318 Result result = ResultSuccess;
319
320 if (!firmware_settings->IsDeviceManaged()) { 274 if (!firmware_settings->IsDeviceManaged()) {
321 result = GetResourceManager()->GetGesture()->Deactivate(); 275 R_RETURN(GetResourceManager()->GetGesture()->Deactivate());
322 } 276 }
323 277
324 IPC::ResponseBuilder rb{ctx, 2}; 278 R_SUCCEED();
325 rb.Push(result);
326} 279}
327 280
328std::shared_ptr<ResourceManager> IHidDebugServer::GetResourceManager() { 281std::shared_ptr<ResourceManager> IHidDebugServer::GetResourceManager() {
diff --git a/src/core/hle/service/hid/hid_debug_server.h b/src/core/hle/service/hid/hid_debug_server.h
index 7d5b082b3..3a483f07e 100644
--- a/src/core/hle/service/hid/hid_debug_server.h
+++ b/src/core/hle/service/hid/hid_debug_server.h
@@ -3,7 +3,9 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "core/hle/service/cmif_types.h"
6#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8#include "hid_core/resources/touch_screen/touch_types.h"
7 9
8namespace Core { 10namespace Core {
9class System; 11class System;
@@ -20,15 +22,19 @@ public:
20 ~IHidDebugServer() override; 22 ~IHidDebugServer() override;
21 23
22private: 24private:
23 void DeactivateTouchScreen(HLERequestContext& ctx); 25 Result DeactivateTouchScreen();
24 void SetTouchScreenAutoPilotState(HLERequestContext& ctx); 26 Result SetTouchScreenAutoPilotState(
25 void UnsetTouchScreenAutoPilotState(HLERequestContext& ctx); 27 InArray<TouchState, BufferAttr_HipcMapAlias> auto_pilot_buffer);
26 void GetTouchScreenConfiguration(HLERequestContext& ctx); 28 Result UnsetTouchScreenAutoPilotState();
27 void ProcessTouchScreenAutoTune(HLERequestContext& ctx); 29 Result GetTouchScreenConfiguration(
28 void ForceStopTouchScreenManagement(HLERequestContext& ctx); 30 Out<Core::HID::TouchScreenConfigurationForNx> out_touchscreen_config,
29 void ForceRestartTouchScreenManagement(HLERequestContext& ctx); 31 ClientAppletResourceUserId aruid);
30 void IsTouchScreenManaged(HLERequestContext& ctx); 32 Result ProcessTouchScreenAutoTune();
31 void DeactivateGesture(HLERequestContext& ctx); 33 Result ForceStopTouchScreenManagement();
34 Result ForceRestartTouchScreenManagement(u32 basic_gesture_id,
35 ClientAppletResourceUserId aruid);
36 Result IsTouchScreenManaged(Out<bool> out_is_managed);
37 Result DeactivateGesture();
32 38
33 std::shared_ptr<ResourceManager> GetResourceManager(); 39 std::shared_ptr<ResourceManager> GetResourceManager();
34 40
diff --git a/src/core/hle/service/hid/irs.cpp b/src/core/hle/service/hid/irs.cpp
index 18e544f2f..7d7368ff9 100644
--- a/src/core/hle/service/hid/irs.cpp
+++ b/src/core/hle/service/hid/irs.cpp
@@ -9,6 +9,7 @@
9#include "core/hle/kernel/k_shared_memory.h" 9#include "core/hle/kernel/k_shared_memory.h"
10#include "core/hle/kernel/k_transfer_memory.h" 10#include "core/hle/kernel/k_transfer_memory.h"
11#include "core/hle/kernel/kernel.h" 11#include "core/hle/kernel/kernel.h"
12#include "core/hle/service/cmif_serialization.h"
12#include "core/hle/service/hid/irs.h" 13#include "core/hle/service/hid/irs.h"
13#include "core/hle/service/ipc_helpers.h" 14#include "core/hle/service/ipc_helpers.h"
14#include "core/memory.h" 15#include "core/memory.h"
@@ -28,24 +29,24 @@ namespace Service::IRS {
28IRS::IRS(Core::System& system_) : ServiceFramework{system_, "irs"} { 29IRS::IRS(Core::System& system_) : ServiceFramework{system_, "irs"} {
29 // clang-format off 30 // clang-format off
30 static const FunctionInfo functions[] = { 31 static const FunctionInfo functions[] = {
31 {302, &IRS::ActivateIrsensor, "ActivateIrsensor"}, 32 {302, C<&IRS::ActivateIrsensor>, "ActivateIrsensor"},
32 {303, &IRS::DeactivateIrsensor, "DeactivateIrsensor"}, 33 {303, C<&IRS::DeactivateIrsensor>, "DeactivateIrsensor"},
33 {304, &IRS::GetIrsensorSharedMemoryHandle, "GetIrsensorSharedMemoryHandle"}, 34 {304, C<&IRS::GetIrsensorSharedMemoryHandle>, "GetIrsensorSharedMemoryHandle"},
34 {305, &IRS::StopImageProcessor, "StopImageProcessor"}, 35 {305, C<&IRS::StopImageProcessor>, "StopImageProcessor"},
35 {306, &IRS::RunMomentProcessor, "RunMomentProcessor"}, 36 {306, C<&IRS::RunMomentProcessor>, "RunMomentProcessor"},
36 {307, &IRS::RunClusteringProcessor, "RunClusteringProcessor"}, 37 {307, C<&IRS::RunClusteringProcessor>, "RunClusteringProcessor"},
37 {308, &IRS::RunImageTransferProcessor, "RunImageTransferProcessor"}, 38 {308, C<&IRS::RunImageTransferProcessor>, "RunImageTransferProcessor"},
38 {309, &IRS::GetImageTransferProcessorState, "GetImageTransferProcessorState"}, 39 {309, C<&IRS::GetImageTransferProcessorState>, "GetImageTransferProcessorState"},
39 {310, &IRS::RunTeraPluginProcessor, "RunTeraPluginProcessor"}, 40 {310, C<&IRS::RunTeraPluginProcessor>, "RunTeraPluginProcessor"},
40 {311, &IRS::GetNpadIrCameraHandle, "GetNpadIrCameraHandle"}, 41 {311, C<&IRS::GetNpadIrCameraHandle>, "GetNpadIrCameraHandle"},
41 {312, &IRS::RunPointingProcessor, "RunPointingProcessor"}, 42 {312, C<&IRS::RunPointingProcessor>, "RunPointingProcessor"},
42 {313, &IRS::SuspendImageProcessor, "SuspendImageProcessor"}, 43 {313, C<&IRS::SuspendImageProcessor>, "SuspendImageProcessor"},
43 {314, &IRS::CheckFirmwareVersion, "CheckFirmwareVersion"}, 44 {314, C<&IRS::CheckFirmwareVersion>, "CheckFirmwareVersion"},
44 {315, &IRS::SetFunctionLevel, "SetFunctionLevel"}, 45 {315, C<&IRS::SetFunctionLevel>, "SetFunctionLevel"},
45 {316, &IRS::RunImageTransferExProcessor, "RunImageTransferExProcessor"}, 46 {316, C<&IRS::RunImageTransferExProcessor>, "RunImageTransferExProcessor"},
46 {317, &IRS::RunIrLedProcessor, "RunIrLedProcessor"}, 47 {317, C<&IRS::RunIrLedProcessor>, "RunIrLedProcessor"},
47 {318, &IRS::StopImageProcessorAsync, "StopImageProcessorAsync"}, 48 {318, C<&IRS::StopImageProcessorAsync>, "StopImageProcessorAsync"},
48 {319, &IRS::ActivateIrsensorWithFunctionLevel, "ActivateIrsensorWithFunctionLevel"}, 49 {319, C<&IRS::ActivateIrsensorWithFunctionLevel>, "ActivateIrsensorWithFunctionLevel"},
49 }; 50 };
50 // clang-format on 51 // clang-format on
51 52
@@ -57,489 +58,292 @@ IRS::IRS(Core::System& system_) : ServiceFramework{system_, "irs"} {
57} 58}
58IRS::~IRS() = default; 59IRS::~IRS() = default;
59 60
60void IRS::ActivateIrsensor(HLERequestContext& ctx) { 61Result IRS::ActivateIrsensor(ClientAppletResourceUserId aruid) {
61 IPC::RequestParser rp{ctx}; 62 LOG_WARNING(Service_IRS, "(STUBBED) called, applet_resource_user_id={}", aruid.pid);
62 const auto applet_resource_user_id{rp.Pop<u64>()}; 63 R_SUCCEED();
63
64 LOG_WARNING(Service_IRS, "(STUBBED) called, applet_resource_user_id={}",
65 applet_resource_user_id);
66
67 IPC::ResponseBuilder rb{ctx, 2};
68 rb.Push(ResultSuccess);
69} 64}
70 65
71void IRS::DeactivateIrsensor(HLERequestContext& ctx) { 66Result IRS::DeactivateIrsensor(ClientAppletResourceUserId aruid) {
72 IPC::RequestParser rp{ctx}; 67 LOG_WARNING(Service_IRS, "(STUBBED) called, applet_resource_user_id={}", aruid.pid);
73 const auto applet_resource_user_id{rp.Pop<u64>()}; 68 R_SUCCEED();
74
75 LOG_WARNING(Service_IRS, "(STUBBED) called, applet_resource_user_id={}",
76 applet_resource_user_id);
77
78 IPC::ResponseBuilder rb{ctx, 2};
79 rb.Push(ResultSuccess);
80} 69}
81 70
82void IRS::GetIrsensorSharedMemoryHandle(HLERequestContext& ctx) { 71Result IRS::GetIrsensorSharedMemoryHandle(OutCopyHandle<Kernel::KSharedMemory> out_shared_memory,
83 IPC::RequestParser rp{ctx}; 72 ClientAppletResourceUserId aruid) {
84 const auto applet_resource_user_id{rp.Pop<u64>()}; 73 LOG_DEBUG(Service_IRS, "called, applet_resource_user_id={}", aruid.pid);
85
86 LOG_DEBUG(Service_IRS, "called, applet_resource_user_id={}", applet_resource_user_id);
87 74
88 IPC::ResponseBuilder rb{ctx, 2, 1}; 75 *out_shared_memory = &system.Kernel().GetIrsSharedMem();
89 rb.Push(ResultSuccess); 76 R_SUCCEED();
90 rb.PushCopyObjects(&system.Kernel().GetIrsSharedMem());
91} 77}
92 78
93void IRS::StopImageProcessor(HLERequestContext& ctx) { 79Result IRS::StopImageProcessor(Core::IrSensor::IrCameraHandle camera_handle,
94 IPC::RequestParser rp{ctx}; 80 ClientAppletResourceUserId aruid) {
95 struct Parameters {
96 Core::IrSensor::IrCameraHandle camera_handle;
97 INSERT_PADDING_WORDS_NOINIT(1);
98 u64 applet_resource_user_id;
99 };
100 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
101
102 const auto parameters{rp.PopRaw<Parameters>()};
103
104 LOG_WARNING(Service_IRS, 81 LOG_WARNING(Service_IRS,
105 "(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}", 82 "(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
106 parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, 83 camera_handle.npad_type, camera_handle.npad_id, aruid.pid);
107 parameters.applet_resource_user_id);
108
109 auto result = IsIrCameraHandleValid(parameters.camera_handle);
110 if (result.IsSuccess()) {
111 // TODO: Stop Image processor
112 npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
113 Common::Input::PollingMode::Active);
114 result = ResultSuccess;
115 }
116 84
117 IPC::ResponseBuilder rb{ctx, 2}; 85 R_TRY(IsIrCameraHandleValid(camera_handle));
118 rb.Push(result);
119}
120
121void IRS::RunMomentProcessor(HLERequestContext& ctx) {
122 IPC::RequestParser rp{ctx};
123 struct Parameters {
124 Core::IrSensor::IrCameraHandle camera_handle;
125 INSERT_PADDING_WORDS_NOINIT(1);
126 u64 applet_resource_user_id;
127 Core::IrSensor::PackedMomentProcessorConfig processor_config;
128 };
129 static_assert(sizeof(Parameters) == 0x30, "Parameters has incorrect size.");
130 86
131 const auto parameters{rp.PopRaw<Parameters>()}; 87 // TODO: Stop Image processor
88 npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
89 Common::Input::PollingMode::Active);
90 R_SUCCEED();
91}
132 92
93Result IRS::RunMomentProcessor(
94 Core::IrSensor::IrCameraHandle camera_handle, ClientAppletResourceUserId aruid,
95 const Core::IrSensor::PackedMomentProcessorConfig& processor_config) {
133 LOG_WARNING(Service_IRS, 96 LOG_WARNING(Service_IRS,
134 "(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}", 97 "(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
135 parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, 98 camera_handle.npad_type, camera_handle.npad_id, aruid.pid);
136 parameters.applet_resource_user_id);
137
138 const auto result = IsIrCameraHandleValid(parameters.camera_handle);
139
140 if (result.IsSuccess()) {
141 auto& device = GetIrCameraSharedMemoryDeviceEntry(parameters.camera_handle);
142 MakeProcessorWithCoreContext<MomentProcessor>(parameters.camera_handle, device);
143 auto& image_transfer_processor = GetProcessor<MomentProcessor>(parameters.camera_handle);
144 image_transfer_processor.SetConfig(parameters.processor_config);
145 npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
146 Common::Input::PollingMode::IR);
147 }
148 99
149 IPC::ResponseBuilder rb{ctx, 2}; 100 R_TRY(IsIrCameraHandleValid(camera_handle));
150 rb.Push(result);
151}
152 101
153void IRS::RunClusteringProcessor(HLERequestContext& ctx) { 102 auto& device = GetIrCameraSharedMemoryDeviceEntry(camera_handle);
154 IPC::RequestParser rp{ctx}; 103 MakeProcessorWithCoreContext<MomentProcessor>(camera_handle, device);
155 struct Parameters { 104 auto& image_transfer_processor = GetProcessor<MomentProcessor>(camera_handle);
156 Core::IrSensor::IrCameraHandle camera_handle; 105 image_transfer_processor.SetConfig(processor_config);
157 INSERT_PADDING_WORDS_NOINIT(1); 106 npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
158 u64 applet_resource_user_id; 107 Common::Input::PollingMode::IR);
159 Core::IrSensor::PackedClusteringProcessorConfig processor_config;
160 };
161 static_assert(sizeof(Parameters) == 0x38, "Parameters has incorrect size.");
162 108
163 const auto parameters{rp.PopRaw<Parameters>()}; 109 R_SUCCEED();
110}
164 111
112Result IRS::RunClusteringProcessor(
113 Core::IrSensor::IrCameraHandle camera_handle, ClientAppletResourceUserId aruid,
114 const Core::IrSensor::PackedClusteringProcessorConfig& processor_config) {
165 LOG_WARNING(Service_IRS, 115 LOG_WARNING(Service_IRS,
166 "(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}", 116 "(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
167 parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, 117 camera_handle.npad_type, camera_handle.npad_id, aruid.pid);
168 parameters.applet_resource_user_id);
169
170 auto result = IsIrCameraHandleValid(parameters.camera_handle);
171
172 if (result.IsSuccess()) {
173 auto& device = GetIrCameraSharedMemoryDeviceEntry(parameters.camera_handle);
174 MakeProcessorWithCoreContext<ClusteringProcessor>(parameters.camera_handle, device);
175 auto& image_transfer_processor =
176 GetProcessor<ClusteringProcessor>(parameters.camera_handle);
177 image_transfer_processor.SetConfig(parameters.processor_config);
178 npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
179 Common::Input::PollingMode::IR);
180 }
181 118
182 IPC::ResponseBuilder rb{ctx, 2}; 119 R_TRY(IsIrCameraHandleValid(camera_handle));
183 rb.Push(result);
184}
185 120
186void IRS::RunImageTransferProcessor(HLERequestContext& ctx) { 121 auto& device = GetIrCameraSharedMemoryDeviceEntry(camera_handle);
187 IPC::RequestParser rp{ctx}; 122 MakeProcessorWithCoreContext<ClusteringProcessor>(camera_handle, device);
188 struct Parameters { 123 auto& image_transfer_processor = GetProcessor<ClusteringProcessor>(camera_handle);
189 Core::IrSensor::IrCameraHandle camera_handle; 124 image_transfer_processor.SetConfig(processor_config);
190 INSERT_PADDING_WORDS_NOINIT(1); 125 npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
191 u64 applet_resource_user_id; 126 Common::Input::PollingMode::IR);
192 Core::IrSensor::PackedImageTransferProcessorConfig processor_config;
193 u32 transfer_memory_size;
194 };
195 static_assert(sizeof(Parameters) == 0x30, "Parameters has incorrect size.");
196 127
197 const auto parameters{rp.PopRaw<Parameters>()}; 128 R_SUCCEED();
198 const auto t_mem_handle{ctx.GetCopyHandle(0)}; 129}
199 130
200 auto t_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(t_mem_handle); 131Result IRS::RunImageTransferProcessor(
132 Core::IrSensor::IrCameraHandle camera_handle, ClientAppletResourceUserId aruid,
133 const Core::IrSensor::PackedImageTransferProcessorConfig& processor_config,
134 u64 transfer_memory_size, InCopyHandle<Kernel::KTransferMemory> t_mem) {
201 135
202 if (t_mem.IsNull()) { 136 ASSERT_MSG(t_mem->GetSize() == transfer_memory_size, "t_mem has incorrect size");
203 LOG_ERROR(Service_IRS, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle);
204 IPC::ResponseBuilder rb{ctx, 2};
205 rb.Push(ResultUnknown);
206 return;
207 }
208
209 ASSERT_MSG(t_mem->GetSize() == parameters.transfer_memory_size, "t_mem has incorrect size");
210 137
211 LOG_INFO(Service_IRS, 138 LOG_INFO(Service_IRS,
212 "called, npad_type={}, npad_id={}, transfer_memory_size={}, transfer_memory_size={}, " 139 "called, npad_type={}, npad_id={}, transfer_memory_size={}, transfer_memory_size={}, "
213 "applet_resource_user_id={}", 140 "applet_resource_user_id={}",
214 parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, 141 camera_handle.npad_type, camera_handle.npad_id, transfer_memory_size, t_mem->GetSize(),
215 parameters.transfer_memory_size, t_mem->GetSize(), parameters.applet_resource_user_id); 142 aruid.pid);
216
217 const auto result = IsIrCameraHandleValid(parameters.camera_handle);
218
219 if (result.IsSuccess()) {
220 auto& device = GetIrCameraSharedMemoryDeviceEntry(parameters.camera_handle);
221 MakeProcessorWithCoreContext<ImageTransferProcessor>(parameters.camera_handle, device);
222 auto& image_transfer_processor =
223 GetProcessor<ImageTransferProcessor>(parameters.camera_handle);
224 image_transfer_processor.SetConfig(parameters.processor_config);
225 image_transfer_processor.SetTransferMemoryAddress(t_mem->GetSourceAddress());
226 npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
227 Common::Input::PollingMode::IR);
228 }
229 143
230 IPC::ResponseBuilder rb{ctx, 2}; 144 R_TRY(IsIrCameraHandleValid(camera_handle));
231 rb.Push(result);
232}
233 145
234void IRS::GetImageTransferProcessorState(HLERequestContext& ctx) { 146 auto& device = GetIrCameraSharedMemoryDeviceEntry(camera_handle);
235 IPC::RequestParser rp{ctx}; 147 MakeProcessorWithCoreContext<ImageTransferProcessor>(camera_handle, device);
236 struct Parameters { 148 auto& image_transfer_processor = GetProcessor<ImageTransferProcessor>(camera_handle);
237 Core::IrSensor::IrCameraHandle camera_handle; 149 image_transfer_processor.SetConfig(processor_config);
238 INSERT_PADDING_WORDS_NOINIT(1); 150 image_transfer_processor.SetTransferMemoryAddress(t_mem->GetSourceAddress());
239 u64 applet_resource_user_id; 151 npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
240 }; 152 Common::Input::PollingMode::IR);
241 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
242 153
243 const auto parameters{rp.PopRaw<Parameters>()}; 154 R_SUCCEED();
155}
244 156
157Result IRS::GetImageTransferProcessorState(
158 Out<Core::IrSensor::ImageTransferProcessorState> out_state,
159 Core::IrSensor::IrCameraHandle camera_handle, ClientAppletResourceUserId aruid,
160 OutBuffer<BufferAttr_HipcMapAlias> out_buffer_data) {
245 LOG_DEBUG(Service_IRS, "(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}", 161 LOG_DEBUG(Service_IRS, "(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
246 parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, 162 camera_handle.npad_type, camera_handle.npad_id, aruid.pid);
247 parameters.applet_resource_user_id);
248
249 const auto result = IsIrCameraHandleValid(parameters.camera_handle);
250 if (result.IsError()) {
251 IPC::ResponseBuilder rb{ctx, 2};
252 rb.Push(result);
253 return;
254 }
255 163
256 const auto& device = GetIrCameraSharedMemoryDeviceEntry(parameters.camera_handle); 164 R_TRY(IsIrCameraHandleValid(camera_handle));
257 165
258 if (device.mode != Core::IrSensor::IrSensorMode::ImageTransferProcessor) { 166 const auto& device = GetIrCameraSharedMemoryDeviceEntry(camera_handle);
259 IPC::ResponseBuilder rb{ctx, 2}; 167
260 rb.Push(InvalidProcessorState); 168 R_TRY(IsIrCameraHandleValid(camera_handle));
261 return; 169 R_UNLESS(device.mode == Core::IrSensor::IrSensorMode::ImageTransferProcessor,
262 } 170 InvalidProcessorState);
263 171
264 std::vector<u8> data{}; 172 *out_state = GetProcessor<ImageTransferProcessor>(camera_handle).GetState(out_buffer_data);
265 const auto& image_transfer_processor =
266 GetProcessor<ImageTransferProcessor>(parameters.camera_handle);
267 const auto& state = image_transfer_processor.GetState(data);
268 173
269 ctx.WriteBuffer(data); 174 R_SUCCEED();
270 IPC::ResponseBuilder rb{ctx, 6};
271 rb.Push(ResultSuccess);
272 rb.PushRaw(state);
273} 175}
274 176
275void IRS::RunTeraPluginProcessor(HLERequestContext& ctx) { 177Result IRS::RunTeraPluginProcessor(Core::IrSensor::IrCameraHandle camera_handle,
276 IPC::RequestParser rp{ctx}; 178 Core::IrSensor::PackedTeraPluginProcessorConfig processor_config,
277 struct Parameters { 179 ClientAppletResourceUserId aruid) {
278 Core::IrSensor::IrCameraHandle camera_handle; 180 LOG_WARNING(Service_IRS,
279 Core::IrSensor::PackedTeraPluginProcessorConfig processor_config; 181 "(STUBBED) called, npad_type={}, npad_id={}, mode={}, mcu_version={}.{}, "
280 INSERT_PADDING_WORDS_NOINIT(1); 182 "applet_resource_user_id={}",
281 u64 applet_resource_user_id; 183 camera_handle.npad_type, camera_handle.npad_id, processor_config.mode,
282 }; 184 processor_config.required_mcu_version.major,
283 static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size."); 185 processor_config.required_mcu_version.minor, aruid.pid);
284 186
285 const auto parameters{rp.PopRaw<Parameters>()}; 187 R_TRY(IsIrCameraHandleValid(camera_handle));
286 188
287 LOG_WARNING( 189 auto& device = GetIrCameraSharedMemoryDeviceEntry(camera_handle);
288 Service_IRS, 190 MakeProcessor<TeraPluginProcessor>(camera_handle, device);
289 "(STUBBED) called, npad_type={}, npad_id={}, mode={}, mcu_version={}.{}, " 191 auto& image_transfer_processor = GetProcessor<TeraPluginProcessor>(camera_handle);
290 "applet_resource_user_id={}", 192 image_transfer_processor.SetConfig(processor_config);
291 parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, 193 npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
292 parameters.processor_config.mode, parameters.processor_config.required_mcu_version.major, 194 Common::Input::PollingMode::IR);
293 parameters.processor_config.required_mcu_version.minor, parameters.applet_resource_user_id);
294
295 const auto result = IsIrCameraHandleValid(parameters.camera_handle);
296
297 if (result.IsSuccess()) {
298 auto& device = GetIrCameraSharedMemoryDeviceEntry(parameters.camera_handle);
299 MakeProcessor<TeraPluginProcessor>(parameters.camera_handle, device);
300 auto& image_transfer_processor =
301 GetProcessor<TeraPluginProcessor>(parameters.camera_handle);
302 image_transfer_processor.SetConfig(parameters.processor_config);
303 npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
304 Common::Input::PollingMode::IR);
305 }
306 195
307 IPC::ResponseBuilder rb{ctx, 2}; 196 R_SUCCEED();
308 rb.Push(result);
309} 197}
310 198
311void IRS::GetNpadIrCameraHandle(HLERequestContext& ctx) { 199Result IRS::GetNpadIrCameraHandle(Out<Core::IrSensor::IrCameraHandle> out_camera_handle,
312 IPC::RequestParser rp{ctx}; 200 Core::HID::NpadIdType npad_id) {
313 const auto npad_id{rp.PopEnum<Core::HID::NpadIdType>()}; 201 R_UNLESS(HID::IsNpadIdValid(npad_id), HID::ResultInvalidNpadId);
314
315 if (npad_id > Core::HID::NpadIdType::Player8 && npad_id != Core::HID::NpadIdType::Invalid &&
316 npad_id != Core::HID::NpadIdType::Handheld) {
317 IPC::ResponseBuilder rb{ctx, 2};
318 rb.Push(Service::HID::ResultInvalidNpadId);
319 return;
320 }
321 202
322 Core::IrSensor::IrCameraHandle camera_handle{ 203 *out_camera_handle = {
323 .npad_id = static_cast<u8>(HID::NpadIdTypeToIndex(npad_id)), 204 .npad_id = static_cast<u8>(HID::NpadIdTypeToIndex(npad_id)),
324 .npad_type = Core::HID::NpadStyleIndex::None, 205 .npad_type = Core::HID::NpadStyleIndex::None,
325 }; 206 };
326 207
327 LOG_INFO(Service_IRS, "called, npad_id={}, camera_npad_id={}, camera_npad_type={}", npad_id, 208 LOG_INFO(Service_IRS, "called, npad_id={}, camera_npad_id={}, camera_npad_type={}", npad_id,
328 camera_handle.npad_id, camera_handle.npad_type); 209 out_camera_handle->npad_id, out_camera_handle->npad_type);
329 210
330 IPC::ResponseBuilder rb{ctx, 3}; 211 R_SUCCEED();
331 rb.Push(ResultSuccess);
332 rb.PushRaw(camera_handle);
333} 212}
334 213
335void IRS::RunPointingProcessor(HLERequestContext& ctx) { 214Result IRS::RunPointingProcessor(
336 IPC::RequestParser rp{ctx}; 215 Core::IrSensor::IrCameraHandle camera_handle,
337 const auto camera_handle{rp.PopRaw<Core::IrSensor::IrCameraHandle>()}; 216 const Core::IrSensor::PackedPointingProcessorConfig& processor_config,
338 const auto processor_config{rp.PopRaw<Core::IrSensor::PackedPointingProcessorConfig>()}; 217 ClientAppletResourceUserId aruid) {
339 const auto applet_resource_user_id{rp.Pop<u64>()};
340
341 LOG_WARNING( 218 LOG_WARNING(
342 Service_IRS, 219 Service_IRS,
343 "(STUBBED) called, npad_type={}, npad_id={}, mcu_version={}.{}, applet_resource_user_id={}", 220 "(STUBBED) called, npad_type={}, npad_id={}, mcu_version={}.{}, applet_resource_user_id={}",
344 camera_handle.npad_type, camera_handle.npad_id, processor_config.required_mcu_version.major, 221 camera_handle.npad_type, camera_handle.npad_id, processor_config.required_mcu_version.major,
345 processor_config.required_mcu_version.minor, applet_resource_user_id); 222 processor_config.required_mcu_version.minor, aruid.pid);
346 223
347 auto result = IsIrCameraHandleValid(camera_handle); 224 R_TRY(IsIrCameraHandleValid(camera_handle));
348 225
349 if (result.IsSuccess()) { 226 auto& device = GetIrCameraSharedMemoryDeviceEntry(camera_handle);
350 auto& device = GetIrCameraSharedMemoryDeviceEntry(camera_handle); 227 MakeProcessor<PointingProcessor>(camera_handle, device);
351 MakeProcessor<PointingProcessor>(camera_handle, device); 228 auto& image_transfer_processor = GetProcessor<PointingProcessor>(camera_handle);
352 auto& image_transfer_processor = GetProcessor<PointingProcessor>(camera_handle); 229 image_transfer_processor.SetConfig(processor_config);
353 image_transfer_processor.SetConfig(processor_config); 230 npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
354 npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex, 231 Common::Input::PollingMode::IR);
355 Common::Input::PollingMode::IR);
356 }
357 232
358 IPC::ResponseBuilder rb{ctx, 2}; 233 R_SUCCEED();
359 rb.Push(result);
360} 234}
361 235
362void IRS::SuspendImageProcessor(HLERequestContext& ctx) { 236Result IRS::SuspendImageProcessor(Core::IrSensor::IrCameraHandle camera_handle,
363 IPC::RequestParser rp{ctx}; 237 ClientAppletResourceUserId aruid) {
364 struct Parameters {
365 Core::IrSensor::IrCameraHandle camera_handle;
366 INSERT_PADDING_WORDS_NOINIT(1);
367 u64 applet_resource_user_id;
368 };
369 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
370
371 const auto parameters{rp.PopRaw<Parameters>()};
372
373 LOG_WARNING(Service_IRS, 238 LOG_WARNING(Service_IRS,
374 "(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}", 239 "(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
375 parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, 240 camera_handle.npad_type, camera_handle.npad_id, aruid.pid);
376 parameters.applet_resource_user_id);
377 241
378 auto result = IsIrCameraHandleValid(parameters.camera_handle); 242 R_TRY(IsIrCameraHandleValid(camera_handle));
379 if (result.IsSuccess()) {
380 // TODO: Suspend image processor
381 result = ResultSuccess;
382 }
383 243
384 IPC::ResponseBuilder rb{ctx, 2}; 244 // TODO: Suspend image processor
385 rb.Push(result);
386}
387 245
388void IRS::CheckFirmwareVersion(HLERequestContext& ctx) { 246 R_SUCCEED();
389 IPC::RequestParser rp{ctx}; 247}
390 const auto camera_handle{rp.PopRaw<Core::IrSensor::IrCameraHandle>()};
391 const auto mcu_version{rp.PopRaw<Core::IrSensor::PackedMcuVersion>()};
392 const auto applet_resource_user_id{rp.Pop<u64>()};
393 248
249Result IRS::CheckFirmwareVersion(Core::IrSensor::IrCameraHandle camera_handle,
250 Core::IrSensor::PackedMcuVersion mcu_version,
251 ClientAppletResourceUserId aruid) {
394 LOG_WARNING( 252 LOG_WARNING(
395 Service_IRS, 253 Service_IRS,
396 "(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}, mcu_version={}.{}", 254 "(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}, mcu_version={}.{}",
397 camera_handle.npad_type, camera_handle.npad_id, applet_resource_user_id, mcu_version.major, 255 camera_handle.npad_type, camera_handle.npad_id, aruid.pid, mcu_version.major,
398 mcu_version.minor); 256 mcu_version.minor);
399 257
400 auto result = IsIrCameraHandleValid(camera_handle); 258 R_TRY(IsIrCameraHandleValid(camera_handle));
401 if (result.IsSuccess()) {
402 // TODO: Check firmware version
403 result = ResultSuccess;
404 }
405 259
406 IPC::ResponseBuilder rb{ctx, 2}; 260 // TODO: Check firmware version
407 rb.Push(result);
408}
409 261
410void IRS::SetFunctionLevel(HLERequestContext& ctx) { 262 R_SUCCEED();
411 IPC::RequestParser rp{ctx}; 263}
412 const auto camera_handle{rp.PopRaw<Core::IrSensor::IrCameraHandle>()};
413 const auto function_level{rp.PopRaw<Core::IrSensor::PackedFunctionLevel>()};
414 const auto applet_resource_user_id{rp.Pop<u64>()};
415 264
265Result IRS::SetFunctionLevel(Core::IrSensor::IrCameraHandle camera_handle,
266 Core::IrSensor::PackedFunctionLevel function_level,
267 ClientAppletResourceUserId aruid) {
416 LOG_WARNING( 268 LOG_WARNING(
417 Service_IRS, 269 Service_IRS,
418 "(STUBBED) called, npad_type={}, npad_id={}, function_level={}, applet_resource_user_id={}", 270 "(STUBBED) called, npad_type={}, npad_id={}, function_level={}, applet_resource_user_id={}",
419 camera_handle.npad_type, camera_handle.npad_id, function_level.function_level, 271 camera_handle.npad_type, camera_handle.npad_id, function_level.function_level, aruid.pid);
420 applet_resource_user_id);
421 272
422 auto result = IsIrCameraHandleValid(camera_handle); 273 R_TRY(IsIrCameraHandleValid(camera_handle));
423 if (result.IsSuccess()) {
424 // TODO: Set Function level
425 result = ResultSuccess;
426 }
427 274
428 IPC::ResponseBuilder rb{ctx, 2}; 275 // TODO: Set Function level
429 rb.Push(result);
430}
431 276
432void IRS::RunImageTransferExProcessor(HLERequestContext& ctx) { 277 R_SUCCEED();
433 IPC::RequestParser rp{ctx}; 278}
434 struct Parameters {
435 Core::IrSensor::IrCameraHandle camera_handle;
436 INSERT_PADDING_WORDS_NOINIT(1);
437 u64 applet_resource_user_id;
438 Core::IrSensor::PackedImageTransferProcessorExConfig processor_config;
439 u64 transfer_memory_size;
440 };
441 static_assert(sizeof(Parameters) == 0x38, "Parameters has incorrect size.");
442 279
443 const auto parameters{rp.PopRaw<Parameters>()}; 280Result IRS::RunImageTransferExProcessor(
444 const auto t_mem_handle{ctx.GetCopyHandle(0)}; 281 Core::IrSensor::IrCameraHandle camera_handle, ClientAppletResourceUserId aruid,
282 const Core::IrSensor::PackedImageTransferProcessorExConfig& processor_config,
283 u64 transfer_memory_size, InCopyHandle<Kernel::KTransferMemory> t_mem) {
445 284
446 auto t_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(t_mem_handle); 285 ASSERT_MSG(t_mem->GetSize() == transfer_memory_size, "t_mem has incorrect size");
447 286
448 LOG_INFO(Service_IRS, 287 LOG_INFO(Service_IRS,
449 "called, npad_type={}, npad_id={}, transfer_memory_size={}, " 288 "called, npad_type={}, npad_id={}, transfer_memory_size={}, "
450 "applet_resource_user_id={}", 289 "applet_resource_user_id={}",
451 parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, 290 camera_handle.npad_type, camera_handle.npad_id, transfer_memory_size, aruid.pid);
452 parameters.transfer_memory_size, parameters.applet_resource_user_id);
453
454 auto result = IsIrCameraHandleValid(parameters.camera_handle);
455
456 if (result.IsSuccess()) {
457 auto& device = GetIrCameraSharedMemoryDeviceEntry(parameters.camera_handle);
458 MakeProcessorWithCoreContext<ImageTransferProcessor>(parameters.camera_handle, device);
459 auto& image_transfer_processor =
460 GetProcessor<ImageTransferProcessor>(parameters.camera_handle);
461 image_transfer_processor.SetConfig(parameters.processor_config);
462 image_transfer_processor.SetTransferMemoryAddress(t_mem->GetSourceAddress());
463 npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
464 Common::Input::PollingMode::IR);
465 }
466 291
467 IPC::ResponseBuilder rb{ctx, 2}; 292 R_TRY(IsIrCameraHandleValid(camera_handle));
468 rb.Push(result); 293
469} 294 auto& device = GetIrCameraSharedMemoryDeviceEntry(camera_handle);
295 MakeProcessorWithCoreContext<ImageTransferProcessor>(camera_handle, device);
296 auto& image_transfer_processor = GetProcessor<ImageTransferProcessor>(camera_handle);
297 image_transfer_processor.SetConfig(processor_config);
298 image_transfer_processor.SetTransferMemoryAddress(t_mem->GetSourceAddress());
299 npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
300 Common::Input::PollingMode::IR);
470 301
471void IRS::RunIrLedProcessor(HLERequestContext& ctx) { 302 R_SUCCEED();
472 IPC::RequestParser rp{ctx}; 303}
473 const auto camera_handle{rp.PopRaw<Core::IrSensor::IrCameraHandle>()};
474 const auto processor_config{rp.PopRaw<Core::IrSensor::PackedIrLedProcessorConfig>()};
475 const auto applet_resource_user_id{rp.Pop<u64>()};
476 304
305Result IRS::RunIrLedProcessor(Core::IrSensor::IrCameraHandle camera_handle,
306 Core::IrSensor::PackedIrLedProcessorConfig processor_config,
307 ClientAppletResourceUserId aruid) {
477 LOG_WARNING(Service_IRS, 308 LOG_WARNING(Service_IRS,
478 "(STUBBED) called, npad_type={}, npad_id={}, light_target={}, mcu_version={}.{} " 309 "(STUBBED) called, npad_type={}, npad_id={}, light_target={}, mcu_version={}.{} "
479 "applet_resource_user_id={}", 310 "applet_resource_user_id={}",
480 camera_handle.npad_type, camera_handle.npad_id, processor_config.light_target, 311 camera_handle.npad_type, camera_handle.npad_id, processor_config.light_target,
481 processor_config.required_mcu_version.major, 312 processor_config.required_mcu_version.major,
482 processor_config.required_mcu_version.minor, applet_resource_user_id); 313 processor_config.required_mcu_version.minor, aruid.pid);
483 314
484 auto result = IsIrCameraHandleValid(camera_handle); 315 R_TRY(IsIrCameraHandleValid(camera_handle));
485 316
486 if (result.IsSuccess()) { 317 auto& device = GetIrCameraSharedMemoryDeviceEntry(camera_handle);
487 auto& device = GetIrCameraSharedMemoryDeviceEntry(camera_handle); 318 MakeProcessor<IrLedProcessor>(camera_handle, device);
488 MakeProcessor<IrLedProcessor>(camera_handle, device); 319 auto& image_transfer_processor = GetProcessor<IrLedProcessor>(camera_handle);
489 auto& image_transfer_processor = GetProcessor<IrLedProcessor>(camera_handle); 320 image_transfer_processor.SetConfig(processor_config);
490 image_transfer_processor.SetConfig(processor_config); 321 npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
491 npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex, 322 Common::Input::PollingMode::IR);
492 Common::Input::PollingMode::IR);
493 }
494 323
495 IPC::ResponseBuilder rb{ctx, 2}; 324 R_SUCCEED();
496 rb.Push(result);
497} 325}
498 326
499void IRS::StopImageProcessorAsync(HLERequestContext& ctx) { 327Result IRS::StopImageProcessorAsync(Core::IrSensor::IrCameraHandle camera_handle,
500 IPC::RequestParser rp{ctx}; 328 ClientAppletResourceUserId aruid) {
501 struct Parameters {
502 Core::IrSensor::IrCameraHandle camera_handle;
503 INSERT_PADDING_WORDS_NOINIT(1);
504 u64 applet_resource_user_id;
505 };
506 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
507
508 const auto parameters{rp.PopRaw<Parameters>()};
509
510 LOG_WARNING(Service_IRS, 329 LOG_WARNING(Service_IRS,
511 "(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}", 330 "(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
512 parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, 331 camera_handle.npad_type, camera_handle.npad_id, aruid.pid);
513 parameters.applet_resource_user_id);
514
515 auto result = IsIrCameraHandleValid(parameters.camera_handle);
516 if (result.IsSuccess()) {
517 // TODO: Stop image processor async
518 npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
519 Common::Input::PollingMode::Active);
520 result = ResultSuccess;
521 }
522 332
523 IPC::ResponseBuilder rb{ctx, 2}; 333 R_TRY(IsIrCameraHandleValid(camera_handle));
524 rb.Push(result);
525}
526 334
527void IRS::ActivateIrsensorWithFunctionLevel(HLERequestContext& ctx) { 335 // TODO: Stop image processor async
528 IPC::RequestParser rp{ctx}; 336 npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
529 struct Parameters { 337 Common::Input::PollingMode::Active);
530 Core::IrSensor::PackedFunctionLevel function_level;
531 INSERT_PADDING_WORDS_NOINIT(1);
532 u64 applet_resource_user_id;
533 };
534 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
535 338
536 const auto parameters{rp.PopRaw<Parameters>()}; 339 R_SUCCEED();
340}
537 341
342Result IRS::ActivateIrsensorWithFunctionLevel(Core::IrSensor::PackedFunctionLevel function_level,
343 ClientAppletResourceUserId aruid) {
538 LOG_WARNING(Service_IRS, "(STUBBED) called, function_level={}, applet_resource_user_id={}", 344 LOG_WARNING(Service_IRS, "(STUBBED) called, function_level={}, applet_resource_user_id={}",
539 parameters.function_level.function_level, parameters.applet_resource_user_id); 345 function_level.function_level, aruid.pid);
540 346 R_SUCCEED();
541 IPC::ResponseBuilder rb{ctx, 2};
542 rb.Push(ResultSuccess);
543} 347}
544 348
545Result IRS::IsIrCameraHandleValid(const Core::IrSensor::IrCameraHandle& camera_handle) const { 349Result IRS::IsIrCameraHandleValid(const Core::IrSensor::IrCameraHandle& camera_handle) const {
diff --git a/src/core/hle/service/hid/irs.h b/src/core/hle/service/hid/irs.h
index 06b7279ee..58dfee6c3 100644
--- a/src/core/hle/service/hid/irs.h
+++ b/src/core/hle/service/hid/irs.h
@@ -4,6 +4,7 @@
4#pragma once 4#pragma once
5 5
6#include "core/core.h" 6#include "core/core.h"
7#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/service.h" 8#include "core/hle/service/service.h"
8#include "hid_core/hid_types.h" 9#include "hid_core/hid_types.h"
9#include "hid_core/irsensor/irs_types.h" 10#include "hid_core/irsensor/irs_types.h"
@@ -35,26 +36,73 @@ private:
35 }; 36 };
36 static_assert(sizeof(StatusManager) == 0x8000, "StatusManager is an invalid size"); 37 static_assert(sizeof(StatusManager) == 0x8000, "StatusManager is an invalid size");
37 38
38 void ActivateIrsensor(HLERequestContext& ctx); 39 Result ActivateIrsensor(ClientAppletResourceUserId aruid);
39 void DeactivateIrsensor(HLERequestContext& ctx); 40
40 void GetIrsensorSharedMemoryHandle(HLERequestContext& ctx); 41 Result DeactivateIrsensor(ClientAppletResourceUserId aruid);
41 void StopImageProcessor(HLERequestContext& ctx); 42
42 void RunMomentProcessor(HLERequestContext& ctx); 43 Result GetIrsensorSharedMemoryHandle(OutCopyHandle<Kernel::KSharedMemory> out_shared_memory,
43 void RunClusteringProcessor(HLERequestContext& ctx); 44 ClientAppletResourceUserId aruid);
44 void RunImageTransferProcessor(HLERequestContext& ctx); 45 Result StopImageProcessor(Core::IrSensor::IrCameraHandle camera_handle,
45 void GetImageTransferProcessorState(HLERequestContext& ctx); 46 ClientAppletResourceUserId aruid);
46 void RunTeraPluginProcessor(HLERequestContext& ctx); 47
47 void GetNpadIrCameraHandle(HLERequestContext& ctx); 48 Result RunMomentProcessor(Core::IrSensor::IrCameraHandle camera_handle,
48 void RunPointingProcessor(HLERequestContext& ctx); 49 ClientAppletResourceUserId aruid,
49 void SuspendImageProcessor(HLERequestContext& ctx); 50 const Core::IrSensor::PackedMomentProcessorConfig& processor_config);
50 void CheckFirmwareVersion(HLERequestContext& ctx); 51
51 void SetFunctionLevel(HLERequestContext& ctx); 52 Result RunClusteringProcessor(
52 void RunImageTransferExProcessor(HLERequestContext& ctx); 53 Core::IrSensor::IrCameraHandle camera_handle, ClientAppletResourceUserId aruid,
53 void RunIrLedProcessor(HLERequestContext& ctx); 54 const Core::IrSensor::PackedClusteringProcessorConfig& processor_config);
54 void StopImageProcessorAsync(HLERequestContext& ctx); 55
55 void ActivateIrsensorWithFunctionLevel(HLERequestContext& ctx); 56 Result RunImageTransferProcessor(
57 Core::IrSensor::IrCameraHandle camera_handle, ClientAppletResourceUserId aruid,
58 const Core::IrSensor::PackedImageTransferProcessorConfig& processor_config,
59 u64 transfer_memory_size, InCopyHandle<Kernel::KTransferMemory> t_mem);
60
61 Result GetImageTransferProcessorState(
62 Out<Core::IrSensor::ImageTransferProcessorState> out_state,
63 Core::IrSensor::IrCameraHandle camera_handle, ClientAppletResourceUserId aruid,
64 OutBuffer<BufferAttr_HipcMapAlias> out_buffer_data);
65
66 Result RunTeraPluginProcessor(Core::IrSensor::IrCameraHandle camera_handle,
67 Core::IrSensor::PackedTeraPluginProcessorConfig processor_config,
68 ClientAppletResourceUserId aruid);
69
70 Result GetNpadIrCameraHandle(Out<Core::IrSensor::IrCameraHandle> out_camera_handle,
71 Core::HID::NpadIdType npad_id);
72
73 Result RunPointingProcessor(
74 Core::IrSensor::IrCameraHandle camera_handle,
75 const Core::IrSensor::PackedPointingProcessorConfig& processor_config,
76 ClientAppletResourceUserId aruid);
77
78 Result SuspendImageProcessor(Core::IrSensor::IrCameraHandle camera_handle,
79 ClientAppletResourceUserId aruid);
80
81 Result CheckFirmwareVersion(Core::IrSensor::IrCameraHandle camera_handle,
82 Core::IrSensor::PackedMcuVersion mcu_version,
83 ClientAppletResourceUserId aruid);
84
85 Result SetFunctionLevel(Core::IrSensor::IrCameraHandle camera_handle,
86 Core::IrSensor::PackedFunctionLevel function_level,
87 ClientAppletResourceUserId aruid);
88
89 Result RunImageTransferExProcessor(
90 Core::IrSensor::IrCameraHandle camera_handle, ClientAppletResourceUserId aruid,
91 const Core::IrSensor::PackedImageTransferProcessorExConfig& processor_config,
92 u64 transfer_memory_size, InCopyHandle<Kernel::KTransferMemory> t_mem);
93
94 Result RunIrLedProcessor(Core::IrSensor::IrCameraHandle camera_handle,
95 Core::IrSensor::PackedIrLedProcessorConfig processor_config,
96 ClientAppletResourceUserId aruid);
97
98 Result StopImageProcessorAsync(Core::IrSensor::IrCameraHandle camera_handle,
99 ClientAppletResourceUserId aruid);
100
101 Result ActivateIrsensorWithFunctionLevel(Core::IrSensor::PackedFunctionLevel function_level,
102 ClientAppletResourceUserId aruid);
56 103
57 Result IsIrCameraHandleValid(const Core::IrSensor::IrCameraHandle& camera_handle) const; 104 Result IsIrCameraHandleValid(const Core::IrSensor::IrCameraHandle& camera_handle) const;
105
58 Core::IrSensor::DeviceFormat& GetIrCameraSharedMemoryDeviceEntry( 106 Core::IrSensor::DeviceFormat& GetIrCameraSharedMemoryDeviceEntry(
59 const Core::IrSensor::IrCameraHandle& camera_handle); 107 const Core::IrSensor::IrCameraHandle& camera_handle);
60 108
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 e6646ba04..68fe38874 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
@@ -123,6 +123,8 @@ NvResult nvhost_as_gpu::AllocAsEx(IoctlAllocAsEx& params) {
123 vm.va_range_end = params.va_range_end; 123 vm.va_range_end = params.va_range_end;
124 } 124 }
125 125
126 const u64 max_big_page_bits = Common::Log2Ceil64(vm.va_range_end);
127
126 const auto start_pages{static_cast<u32>(vm.va_range_start >> VM::PAGE_SIZE_BITS)}; 128 const auto start_pages{static_cast<u32>(vm.va_range_start >> VM::PAGE_SIZE_BITS)};
127 const auto end_pages{static_cast<u32>(vm.va_range_split >> VM::PAGE_SIZE_BITS)}; 129 const auto end_pages{static_cast<u32>(vm.va_range_split >> VM::PAGE_SIZE_BITS)};
128 vm.small_page_allocator = std::make_shared<VM::Allocator>(start_pages, end_pages); 130 vm.small_page_allocator = std::make_shared<VM::Allocator>(start_pages, end_pages);
@@ -132,8 +134,8 @@ NvResult nvhost_as_gpu::AllocAsEx(IoctlAllocAsEx& params) {
132 static_cast<u32>((vm.va_range_end - vm.va_range_split) >> vm.big_page_size_bits)}; 134 static_cast<u32>((vm.va_range_end - vm.va_range_split) >> vm.big_page_size_bits)};
133 vm.big_page_allocator = std::make_unique<VM::Allocator>(start_big_pages, end_big_pages); 135 vm.big_page_allocator = std::make_unique<VM::Allocator>(start_big_pages, end_big_pages);
134 136
135 gmmu = std::make_shared<Tegra::MemoryManager>(system, 40, vm.big_page_size_bits, 137 gmmu = std::make_shared<Tegra::MemoryManager>(system, max_big_page_bits, vm.va_range_split,
136 VM::PAGE_SIZE_BITS); 138 vm.big_page_size_bits, VM::PAGE_SIZE_BITS);
137 system.GPU().InitAddressSpace(*gmmu); 139 system.GPU().InitAddressSpace(*gmmu);
138 vm.initialised = true; 140 vm.initialised = true;
139 141
diff --git a/src/core/hle/service/nvnflinger/hardware_composer.cpp b/src/core/hle/service/nvnflinger/hardware_composer.cpp
index c720dd1f8..ba2b5c28c 100644
--- a/src/core/hle/service/nvnflinger/hardware_composer.cpp
+++ b/src/core/hle/service/nvnflinger/hardware_composer.cpp
@@ -7,7 +7,6 @@
7#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h" 7#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h"
8#include "core/hle/service/nvnflinger/buffer_item.h" 8#include "core/hle/service/nvnflinger/buffer_item.h"
9#include "core/hle/service/nvnflinger/buffer_item_consumer.h" 9#include "core/hle/service/nvnflinger/buffer_item_consumer.h"
10#include "core/hle/service/nvnflinger/buffer_queue_producer.h"
11#include "core/hle/service/nvnflinger/hardware_composer.h" 10#include "core/hle/service/nvnflinger/hardware_composer.h"
12#include "core/hle/service/nvnflinger/hwc_layer.h" 11#include "core/hle/service/nvnflinger/hwc_layer.h"
13#include "core/hle/service/nvnflinger/ui/graphic_buffer.h" 12#include "core/hle/service/nvnflinger/ui/graphic_buffer.h"
@@ -46,31 +45,9 @@ HardwareComposer::HardwareComposer() = default;
46HardwareComposer::~HardwareComposer() = default; 45HardwareComposer::~HardwareComposer() = default;
47 46
48u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, VI::Display& display, 47u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, VI::Display& display,
49 Nvidia::Devices::nvdisp_disp0& nvdisp, u32 frame_advance) { 48 Nvidia::Devices::nvdisp_disp0& nvdisp) {
50 boost::container::small_vector<HwcLayer, 2> composition_stack; 49 boost::container::small_vector<HwcLayer, 2> composition_stack;
51 50
52 m_frame_number += frame_advance;
53
54 // Release any necessary framebuffers.
55 for (auto& [layer_id, framebuffer] : m_framebuffers) {
56 if (framebuffer.release_frame_number > m_frame_number) {
57 // Not yet ready to release this framebuffer.
58 continue;
59 }
60
61 if (!framebuffer.is_acquired) {
62 // Already released.
63 continue;
64 }
65
66 if (auto* layer = display.FindLayer(layer_id); layer != nullptr) {
67 // TODO: support release fence
68 // This is needed to prevent screen tearing
69 layer->GetConsumer().ReleaseBuffer(framebuffer.item, android::Fence::NoFence());
70 framebuffer.is_acquired = false;
71 }
72 }
73
74 // Set default speed limit to 100%. 51 // Set default speed limit to 100%.
75 *out_speed_scale = 1.0f; 52 *out_speed_scale = 1.0f;
76 53
@@ -142,7 +119,30 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, VI::Display& display,
142 MicroProfileFlip(); 119 MicroProfileFlip();
143 120
144 // Advance by at least one frame. 121 // Advance by at least one frame.
145 return swap_interval.value_or(1); 122 const u32 frame_advance = swap_interval.value_or(1);
123 m_frame_number += frame_advance;
124
125 // Release any necessary framebuffers.
126 for (auto& [layer_id, framebuffer] : m_framebuffers) {
127 if (framebuffer.release_frame_number > m_frame_number) {
128 // Not yet ready to release this framebuffer.
129 continue;
130 }
131
132 if (!framebuffer.is_acquired) {
133 // Already released.
134 continue;
135 }
136
137 if (auto* layer = display.FindLayer(layer_id); layer != nullptr) {
138 // TODO: support release fence
139 // This is needed to prevent screen tearing
140 layer->GetConsumer().ReleaseBuffer(framebuffer.item, android::Fence::NoFence());
141 framebuffer.is_acquired = false;
142 }
143 }
144
145 return frame_advance;
146} 146}
147 147
148void HardwareComposer::RemoveLayerLocked(VI::Display& display, LayerId layer_id) { 148void HardwareComposer::RemoveLayerLocked(VI::Display& display, LayerId layer_id) {
diff --git a/src/core/hle/service/nvnflinger/hardware_composer.h b/src/core/hle/service/nvnflinger/hardware_composer.h
index ddab94ac9..28392c512 100644
--- a/src/core/hle/service/nvnflinger/hardware_composer.h
+++ b/src/core/hle/service/nvnflinger/hardware_composer.h
@@ -27,7 +27,7 @@ public:
27 ~HardwareComposer(); 27 ~HardwareComposer();
28 28
29 u32 ComposeLocked(f32* out_speed_scale, VI::Display& display, 29 u32 ComposeLocked(f32* out_speed_scale, VI::Display& display,
30 Nvidia::Devices::nvdisp_disp0& nvdisp, u32 frame_advance); 30 Nvidia::Devices::nvdisp_disp0& nvdisp);
31 void RemoveLayerLocked(VI::Display& display, LayerId layer_id); 31 void RemoveLayerLocked(VI::Display& display, LayerId layer_id);
32 32
33private: 33private:
diff --git a/src/core/hle/service/nvnflinger/nvnflinger.cpp b/src/core/hle/service/nvnflinger/nvnflinger.cpp
index a4e848882..d8ba89d43 100644
--- a/src/core/hle/service/nvnflinger/nvnflinger.cpp
+++ b/src/core/hle/service/nvnflinger/nvnflinger.cpp
@@ -291,8 +291,7 @@ void Nvnflinger::Compose() {
291 auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>(disp_fd); 291 auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>(disp_fd);
292 ASSERT(nvdisp); 292 ASSERT(nvdisp);
293 293
294 swap_interval = display.GetComposer().ComposeLocked(&compose_speed_scale, display, *nvdisp, 294 swap_interval = display.GetComposer().ComposeLocked(&compose_speed_scale, display, *nvdisp);
295 swap_interval);
296 } 295 }
297} 296}
298 297
diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp
index 96fa7fa3a..14d1a3840 100644
--- a/src/core/memory/cheat_engine.cpp
+++ b/src/core/memory/cheat_engine.cpp
@@ -9,6 +9,7 @@
9#include "core/core_timing.h" 9#include "core/core_timing.h"
10#include "core/hle/kernel/k_page_table.h" 10#include "core/hle/kernel/k_page_table.h"
11#include "core/hle/kernel/k_process.h" 11#include "core/hle/kernel/k_process.h"
12#include "core/hle/kernel/k_process_page_table.h"
12#include "core/hle/service/hid/hid_server.h" 13#include "core/hle/service/hid/hid_server.h"
13#include "core/hle/service/sm/sm.h" 14#include "core/hle/service/sm/sm.h"
14#include "core/memory.h" 15#include "core/memory.h"
@@ -46,12 +47,23 @@ StandardVmCallbacks::StandardVmCallbacks(System& system_, const CheatProcessMeta
46 47
47StandardVmCallbacks::~StandardVmCallbacks() = default; 48StandardVmCallbacks::~StandardVmCallbacks() = default;
48 49
49void StandardVmCallbacks::MemoryRead(VAddr address, void* data, u64 size) { 50void StandardVmCallbacks::MemoryReadUnsafe(VAddr address, void* data, u64 size) {
50 system.ApplicationMemory().ReadBlock(SanitizeAddress(address), data, size); 51 // Return zero on invalid address
52 if (!IsAddressInRange(address) || !system.ApplicationMemory().IsValidVirtualAddress(address)) {
53 std::memset(data, 0, size);
54 return;
55 }
56
57 system.ApplicationMemory().ReadBlock(address, data, size);
51} 58}
52 59
53void StandardVmCallbacks::MemoryWrite(VAddr address, const void* data, u64 size) { 60void StandardVmCallbacks::MemoryWriteUnsafe(VAddr address, const void* data, u64 size) {
54 system.ApplicationMemory().WriteBlock(SanitizeAddress(address), data, size); 61 // Skip invalid memory write address
62 if (!IsAddressInRange(address) || !system.ApplicationMemory().IsValidVirtualAddress(address)) {
63 return;
64 }
65
66 system.ApplicationMemory().WriteBlock(address, data, size);
55} 67}
56 68
57u64 StandardVmCallbacks::HidKeysDown() { 69u64 StandardVmCallbacks::HidKeysDown() {
@@ -81,21 +93,25 @@ void StandardVmCallbacks::CommandLog(std::string_view data) {
81 data.back() == '\n' ? data.substr(0, data.size() - 1) : data); 93 data.back() == '\n' ? data.substr(0, data.size() - 1) : data);
82} 94}
83 95
84VAddr StandardVmCallbacks::SanitizeAddress(VAddr in) const { 96bool StandardVmCallbacks::IsAddressInRange(VAddr in) const {
85 if ((in < metadata.main_nso_extents.base || 97 if ((in < metadata.main_nso_extents.base ||
86 in >= metadata.main_nso_extents.base + metadata.main_nso_extents.size) && 98 in >= metadata.main_nso_extents.base + metadata.main_nso_extents.size) &&
87 (in < metadata.heap_extents.base || 99 (in < metadata.heap_extents.base ||
88 in >= metadata.heap_extents.base + metadata.heap_extents.size)) { 100 in >= metadata.heap_extents.base + metadata.heap_extents.size) &&
89 LOG_ERROR(CheatEngine, 101 (in < metadata.alias_extents.base ||
102 in >= metadata.heap_extents.base + metadata.alias_extents.size) &&
103 (in < metadata.aslr_extents.base ||
104 in >= metadata.heap_extents.base + metadata.aslr_extents.size)) {
105 LOG_DEBUG(CheatEngine,
90 "Cheat attempting to access memory at invalid address={:016X}, if this " 106 "Cheat attempting to access memory at invalid address={:016X}, if this "
91 "persists, " 107 "persists, "
92 "the cheat may be incorrect. However, this may be normal early in execution if " 108 "the cheat may be incorrect. However, this may be normal early in execution if "
93 "the game has not properly set up yet.", 109 "the game has not properly set up yet.",
94 in); 110 in);
95 return 0; ///< Invalid addresses will hard crash 111 return false; ///< Invalid addresses will hard crash
96 } 112 }
97 113
98 return in; 114 return true;
99} 115}
100 116
101CheatParser::~CheatParser() = default; 117CheatParser::~CheatParser() = default;
@@ -211,16 +227,14 @@ void CheatEngine::Initialize() {
211 .base = GetInteger(page_table.GetHeapRegionStart()), 227 .base = GetInteger(page_table.GetHeapRegionStart()),
212 .size = page_table.GetHeapRegionSize(), 228 .size = page_table.GetHeapRegionSize(),
213 }; 229 };
214 230 metadata.aslr_extents = {
215 metadata.address_space_extents = {
216 .base = GetInteger(page_table.GetAddressSpaceStart()),
217 .size = page_table.GetAddressSpaceSize(),
218 };
219
220 metadata.alias_extents = {
221 .base = GetInteger(page_table.GetAliasCodeRegionStart()), 231 .base = GetInteger(page_table.GetAliasCodeRegionStart()),
222 .size = page_table.GetAliasCodeRegionSize(), 232 .size = page_table.GetAliasCodeRegionSize(),
223 }; 233 };
234 metadata.alias_extents = {
235 .base = GetInteger(page_table.GetAliasRegionStart()),
236 .size = page_table.GetAliasRegionSize(),
237 };
224 238
225 is_pending_reload.exchange(true); 239 is_pending_reload.exchange(true);
226} 240}
diff --git a/src/core/memory/cheat_engine.h b/src/core/memory/cheat_engine.h
index ced2168d1..619cabaa2 100644
--- a/src/core/memory/cheat_engine.h
+++ b/src/core/memory/cheat_engine.h
@@ -27,17 +27,17 @@ public:
27 StandardVmCallbacks(System& system_, const CheatProcessMetadata& metadata_); 27 StandardVmCallbacks(System& system_, const CheatProcessMetadata& metadata_);
28 ~StandardVmCallbacks() override; 28 ~StandardVmCallbacks() override;
29 29
30 void MemoryRead(VAddr address, void* data, u64 size) override; 30 void MemoryReadUnsafe(VAddr address, void* data, u64 size) override;
31 void MemoryWrite(VAddr address, const void* data, u64 size) override; 31 void MemoryWriteUnsafe(VAddr address, const void* data, u64 size) override;
32 u64 HidKeysDown() override; 32 u64 HidKeysDown() override;
33 void DebugLog(u8 id, u64 value) override; 33 void DebugLog(u8 id, u64 value) override;
34 void CommandLog(std::string_view data) override; 34 void CommandLog(std::string_view data) override;
35 35
36private: 36private:
37 VAddr SanitizeAddress(VAddr address) const; 37 bool IsAddressInRange(VAddr address) const;
38 38
39 const CheatProcessMetadata& metadata; 39 const CheatProcessMetadata& metadata;
40 System& system; 40 Core::System& system;
41}; 41};
42 42
43// Intermediary class that parses a text file or other disk format for storing cheats into a 43// Intermediary class that parses a text file or other disk format for storing cheats into a
diff --git a/src/core/memory/dmnt_cheat_types.h b/src/core/memory/dmnt_cheat_types.h
index c6b40e505..64c072d3d 100644
--- a/src/core/memory/dmnt_cheat_types.h
+++ b/src/core/memory/dmnt_cheat_types.h
@@ -18,7 +18,7 @@ struct CheatProcessMetadata {
18 MemoryRegionExtents main_nso_extents{}; 18 MemoryRegionExtents main_nso_extents{};
19 MemoryRegionExtents heap_extents{}; 19 MemoryRegionExtents heap_extents{};
20 MemoryRegionExtents alias_extents{}; 20 MemoryRegionExtents alias_extents{};
21 MemoryRegionExtents address_space_extents{}; 21 MemoryRegionExtents aslr_extents{};
22 std::array<u8, 0x20> main_nso_build_id{}; 22 std::array<u8, 0x20> main_nso_build_id{};
23}; 23};
24 24
diff --git a/src/core/memory/dmnt_cheat_vm.cpp b/src/core/memory/dmnt_cheat_vm.cpp
index 31ffc4fbb..8bc81e72d 100644
--- a/src/core/memory/dmnt_cheat_vm.cpp
+++ b/src/core/memory/dmnt_cheat_vm.cpp
@@ -322,8 +322,9 @@ bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode& out) {
322 } break; 322 } break;
323 case CheatVmOpcodeType::EndConditionalBlock: { 323 case CheatVmOpcodeType::EndConditionalBlock: {
324 // 20000000 324 // 20000000
325 // There's actually nothing left to process here! 325 opcode.opcode = EndConditionalOpcode{
326 opcode.opcode = EndConditionalOpcode{}; 326 .is_else = ((first_dword >> 24) & 0xf) == 1,
327 };
327 } break; 328 } break;
328 case CheatVmOpcodeType::ControlLoop: { 329 case CheatVmOpcodeType::ControlLoop: {
329 // 300R0000 VVVVVVVV 330 // 300R0000 VVVVVVVV
@@ -555,6 +556,18 @@ bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode& out) {
555 .idx = first_dword & 0xF, 556 .idx = first_dword & 0xF,
556 }; 557 };
557 } break; 558 } break;
559 case CheatVmOpcodeType::PauseProcess: {
560 /* FF0????? */
561 /* FF0 = opcode 0xFF0 */
562 /* Pauses the current process. */
563 opcode.opcode = PauseProcessOpcode{};
564 } break;
565 case CheatVmOpcodeType::ResumeProcess: {
566 /* FF0????? */
567 /* FF0 = opcode 0xFF0 */
568 /* Pauses the current process. */
569 opcode.opcode = ResumeProcessOpcode{};
570 } break;
558 case CheatVmOpcodeType::DebugLog: { 571 case CheatVmOpcodeType::DebugLog: {
559 // FFFTIX## 572 // FFFTIX##
560 // FFFTI0Ma aaaaaaaa 573 // FFFTI0Ma aaaaaaaa
@@ -621,7 +634,7 @@ bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode& out) {
621 return valid; 634 return valid;
622} 635}
623 636
624void DmntCheatVm::SkipConditionalBlock() { 637void DmntCheatVm::SkipConditionalBlock(bool is_if) {
625 if (condition_depth > 0) { 638 if (condition_depth > 0) {
626 // We want to continue until we're out of the current block. 639 // We want to continue until we're out of the current block.
627 const std::size_t desired_depth = condition_depth - 1; 640 const std::size_t desired_depth = condition_depth - 1;
@@ -637,8 +650,12 @@ void DmntCheatVm::SkipConditionalBlock() {
637 // We also support nesting of conditional blocks, and Gateway does not. 650 // We also support nesting of conditional blocks, and Gateway does not.
638 if (skip_opcode.begin_conditional_block) { 651 if (skip_opcode.begin_conditional_block) {
639 condition_depth++; 652 condition_depth++;
640 } else if (std::holds_alternative<EndConditionalOpcode>(skip_opcode.opcode)) { 653 } else if (auto end_cond = std::get_if<EndConditionalOpcode>(&skip_opcode.opcode)) {
641 condition_depth--; 654 if (!end_cond->is_else) {
655 condition_depth--;
656 } else if (is_if && condition_depth - 1 == desired_depth) {
657 break;
658 }
642 } 659 }
643 } 660 }
644 } else { 661 } else {
@@ -675,6 +692,10 @@ u64 DmntCheatVm::GetCheatProcessAddress(const CheatProcessMetadata& metadata,
675 return metadata.main_nso_extents.base + rel_address; 692 return metadata.main_nso_extents.base + rel_address;
676 case MemoryAccessType::Heap: 693 case MemoryAccessType::Heap:
677 return metadata.heap_extents.base + rel_address; 694 return metadata.heap_extents.base + rel_address;
695 case MemoryAccessType::Alias:
696 return metadata.alias_extents.base + rel_address;
697 case MemoryAccessType::Aslr:
698 return metadata.aslr_extents.base + rel_address;
678 } 699 }
679} 700}
680 701
@@ -682,7 +703,6 @@ void DmntCheatVm::ResetState() {
682 registers.fill(0); 703 registers.fill(0);
683 saved_values.fill(0); 704 saved_values.fill(0);
684 loop_tops.fill(0); 705 loop_tops.fill(0);
685 static_registers.fill(0);
686 instruction_ptr = 0; 706 instruction_ptr = 0;
687 condition_depth = 0; 707 condition_depth = 0;
688 decode_success = true; 708 decode_success = true;
@@ -753,7 +773,7 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
753 case 2: 773 case 2:
754 case 4: 774 case 4:
755 case 8: 775 case 8:
756 callbacks->MemoryWrite(dst_address, &dst_value, store_static->bit_width); 776 callbacks->MemoryWriteUnsafe(dst_address, &dst_value, store_static->bit_width);
757 break; 777 break;
758 } 778 }
759 } else if (auto begin_cond = std::get_if<BeginConditionalOpcode>(&cur_opcode.opcode)) { 779 } else if (auto begin_cond = std::get_if<BeginConditionalOpcode>(&cur_opcode.opcode)) {
@@ -766,7 +786,7 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
766 case 2: 786 case 2:
767 case 4: 787 case 4:
768 case 8: 788 case 8:
769 callbacks->MemoryRead(src_address, &src_value, begin_cond->bit_width); 789 callbacks->MemoryReadUnsafe(src_address, &src_value, begin_cond->bit_width);
770 break; 790 break;
771 } 791 }
772 // Check against condition. 792 // Check against condition.
@@ -794,13 +814,18 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
794 } 814 }
795 // Skip conditional block if condition not met. 815 // Skip conditional block if condition not met.
796 if (!cond_met) { 816 if (!cond_met) {
797 SkipConditionalBlock(); 817 SkipConditionalBlock(true);
798 } 818 }
799 } else if (std::holds_alternative<EndConditionalOpcode>(cur_opcode.opcode)) { 819 } else if (auto end_cond = std::get_if<EndConditionalOpcode>(&cur_opcode.opcode)) {
800 // Decrement the condition depth. 820 if (end_cond->is_else) {
801 // We will assume, graciously, that mismatched conditional block ends are a nop. 821 /* Skip to the end of the conditional block. */
802 if (condition_depth > 0) { 822 this->SkipConditionalBlock(false);
803 condition_depth--; 823 } else {
824 /* Decrement the condition depth. */
825 /* We will assume, graciously, that mismatched conditional block ends are a nop. */
826 if (condition_depth > 0) {
827 condition_depth--;
828 }
804 } 829 }
805 } else if (auto ctrl_loop = std::get_if<ControlLoopOpcode>(&cur_opcode.opcode)) { 830 } else if (auto ctrl_loop = std::get_if<ControlLoopOpcode>(&cur_opcode.opcode)) {
806 if (ctrl_loop->start_loop) { 831 if (ctrl_loop->start_loop) {
@@ -832,8 +857,8 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
832 case 2: 857 case 2:
833 case 4: 858 case 4:
834 case 8: 859 case 8:
835 callbacks->MemoryRead(src_address, &registers[ldr_memory->reg_index], 860 callbacks->MemoryReadUnsafe(src_address, &registers[ldr_memory->reg_index],
836 ldr_memory->bit_width); 861 ldr_memory->bit_width);
837 break; 862 break;
838 } 863 }
839 } else if (auto str_static = std::get_if<StoreStaticToAddressOpcode>(&cur_opcode.opcode)) { 864 } else if (auto str_static = std::get_if<StoreStaticToAddressOpcode>(&cur_opcode.opcode)) {
@@ -849,7 +874,7 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
849 case 2: 874 case 2:
850 case 4: 875 case 4:
851 case 8: 876 case 8:
852 callbacks->MemoryWrite(dst_address, &dst_value, str_static->bit_width); 877 callbacks->MemoryWriteUnsafe(dst_address, &dst_value, str_static->bit_width);
853 break; 878 break;
854 } 879 }
855 // Increment register if relevant. 880 // Increment register if relevant.
@@ -908,7 +933,7 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
908 // Check for keypress. 933 // Check for keypress.
909 if ((begin_keypress_cond->key_mask & kDown) != begin_keypress_cond->key_mask) { 934 if ((begin_keypress_cond->key_mask & kDown) != begin_keypress_cond->key_mask) {
910 // Keys not pressed. Skip conditional block. 935 // Keys not pressed. Skip conditional block.
911 SkipConditionalBlock(); 936 SkipConditionalBlock(true);
912 } 937 }
913 } else if (auto perform_math_reg = 938 } else if (auto perform_math_reg =
914 std::get_if<PerformArithmeticRegisterOpcode>(&cur_opcode.opcode)) { 939 std::get_if<PerformArithmeticRegisterOpcode>(&cur_opcode.opcode)) {
@@ -1007,7 +1032,7 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
1007 case 2: 1032 case 2:
1008 case 4: 1033 case 4:
1009 case 8: 1034 case 8:
1010 callbacks->MemoryWrite(dst_address, &dst_value, str_register->bit_width); 1035 callbacks->MemoryWriteUnsafe(dst_address, &dst_value, str_register->bit_width);
1011 break; 1036 break;
1012 } 1037 }
1013 1038
@@ -1086,7 +1111,8 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
1086 case 2: 1111 case 2:
1087 case 4: 1112 case 4:
1088 case 8: 1113 case 8:
1089 callbacks->MemoryRead(cond_address, &cond_value, begin_reg_cond->bit_width); 1114 callbacks->MemoryReadUnsafe(cond_address, &cond_value,
1115 begin_reg_cond->bit_width);
1090 break; 1116 break;
1091 } 1117 }
1092 } 1118 }
@@ -1116,7 +1142,7 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
1116 1142
1117 // Skip conditional block if condition not met. 1143 // Skip conditional block if condition not met.
1118 if (!cond_met) { 1144 if (!cond_met) {
1119 SkipConditionalBlock(); 1145 SkipConditionalBlock(true);
1120 } 1146 }
1121 } else if (auto save_restore_reg = 1147 } else if (auto save_restore_reg =
1122 std::get_if<SaveRestoreRegisterOpcode>(&cur_opcode.opcode)) { 1148 std::get_if<SaveRestoreRegisterOpcode>(&cur_opcode.opcode)) {
@@ -1178,6 +1204,10 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
1178 // Store a register to a static register. 1204 // Store a register to a static register.
1179 static_registers[rw_static_reg->static_idx] = registers[rw_static_reg->idx]; 1205 static_registers[rw_static_reg->static_idx] = registers[rw_static_reg->idx];
1180 } 1206 }
1207 } else if (std::holds_alternative<PauseProcessOpcode>(cur_opcode.opcode)) {
1208 // TODO: Pause cheat process
1209 } else if (std::holds_alternative<ResumeProcessOpcode>(cur_opcode.opcode)) {
1210 // TODO: Resume cheat process
1181 } else if (auto debug_log = std::get_if<DebugLogOpcode>(&cur_opcode.opcode)) { 1211 } else if (auto debug_log = std::get_if<DebugLogOpcode>(&cur_opcode.opcode)) {
1182 // Read value from memory. 1212 // Read value from memory.
1183 u64 log_value = 0; 1213 u64 log_value = 0;
@@ -1224,7 +1254,7 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
1224 case 2: 1254 case 2:
1225 case 4: 1255 case 4:
1226 case 8: 1256 case 8:
1227 callbacks->MemoryRead(val_address, &log_value, debug_log->bit_width); 1257 callbacks->MemoryReadUnsafe(val_address, &log_value, debug_log->bit_width);
1228 break; 1258 break;
1229 } 1259 }
1230 } 1260 }
diff --git a/src/core/memory/dmnt_cheat_vm.h b/src/core/memory/dmnt_cheat_vm.h
index 641cb09c4..fed6a24ad 100644
--- a/src/core/memory/dmnt_cheat_vm.h
+++ b/src/core/memory/dmnt_cheat_vm.h
@@ -42,12 +42,16 @@ enum class CheatVmOpcodeType : u32 {
42 DoubleExtendedWidth = 0xF0, 42 DoubleExtendedWidth = 0xF0,
43 43
44 // Double-extended width opcodes. 44 // Double-extended width opcodes.
45 PauseProcess = 0xFF0,
46 ResumeProcess = 0xFF1,
45 DebugLog = 0xFFF, 47 DebugLog = 0xFFF,
46}; 48};
47 49
48enum class MemoryAccessType : u32 { 50enum class MemoryAccessType : u32 {
49 MainNso = 0, 51 MainNso = 0,
50 Heap = 1, 52 Heap = 1,
53 Alias = 2,
54 Aslr = 3,
51}; 55};
52 56
53enum class ConditionalComparisonType : u32 { 57enum class ConditionalComparisonType : u32 {
@@ -131,7 +135,9 @@ struct BeginConditionalOpcode {
131 VmInt value{}; 135 VmInt value{};
132}; 136};
133 137
134struct EndConditionalOpcode {}; 138struct EndConditionalOpcode {
139 bool is_else;
140};
135 141
136struct ControlLoopOpcode { 142struct ControlLoopOpcode {
137 bool start_loop{}; 143 bool start_loop{};
@@ -222,6 +228,10 @@ struct ReadWriteStaticRegisterOpcode {
222 u32 idx{}; 228 u32 idx{};
223}; 229};
224 230
231struct PauseProcessOpcode {};
232
233struct ResumeProcessOpcode {};
234
225struct DebugLogOpcode { 235struct DebugLogOpcode {
226 u32 bit_width{}; 236 u32 bit_width{};
227 u32 log_id{}; 237 u32 log_id{};
@@ -244,8 +254,8 @@ struct CheatVmOpcode {
244 PerformArithmeticStaticOpcode, BeginKeypressConditionalOpcode, 254 PerformArithmeticStaticOpcode, BeginKeypressConditionalOpcode,
245 PerformArithmeticRegisterOpcode, StoreRegisterToAddressOpcode, 255 PerformArithmeticRegisterOpcode, StoreRegisterToAddressOpcode,
246 BeginRegisterConditionalOpcode, SaveRestoreRegisterOpcode, 256 BeginRegisterConditionalOpcode, SaveRestoreRegisterOpcode,
247 SaveRestoreRegisterMaskOpcode, ReadWriteStaticRegisterOpcode, DebugLogOpcode, 257 SaveRestoreRegisterMaskOpcode, ReadWriteStaticRegisterOpcode, PauseProcessOpcode,
248 UnrecognizedInstruction> 258 ResumeProcessOpcode, DebugLogOpcode, UnrecognizedInstruction>
249 opcode{}; 259 opcode{};
250}; 260};
251 261
@@ -256,8 +266,8 @@ public:
256 public: 266 public:
257 virtual ~Callbacks(); 267 virtual ~Callbacks();
258 268
259 virtual void MemoryRead(VAddr address, void* data, u64 size) = 0; 269 virtual void MemoryReadUnsafe(VAddr address, void* data, u64 size) = 0;
260 virtual void MemoryWrite(VAddr address, const void* data, u64 size) = 0; 270 virtual void MemoryWriteUnsafe(VAddr address, const void* data, u64 size) = 0;
261 271
262 virtual u64 HidKeysDown() = 0; 272 virtual u64 HidKeysDown() = 0;
263 273
@@ -296,7 +306,7 @@ private:
296 std::array<std::size_t, NumRegisters> loop_tops{}; 306 std::array<std::size_t, NumRegisters> loop_tops{};
297 307
298 bool DecodeNextOpcode(CheatVmOpcode& out); 308 bool DecodeNextOpcode(CheatVmOpcode& out);
299 void SkipConditionalBlock(); 309 void SkipConditionalBlock(bool is_if);
300 void ResetState(); 310 void ResetState();
301 311
302 // For implementing the DebugLog opcode. 312 // For implementing the DebugLog opcode.
diff --git a/src/hid_core/irsensor/image_transfer_processor.cpp b/src/hid_core/irsensor/image_transfer_processor.cpp
index d6573f8dc..2b5a50ef6 100644
--- a/src/hid_core/irsensor/image_transfer_processor.cpp
+++ b/src/hid_core/irsensor/image_transfer_processor.cpp
@@ -145,9 +145,8 @@ void ImageTransferProcessor::SetTransferMemoryAddress(Common::ProcessAddress t_m
145} 145}
146 146
147Core::IrSensor::ImageTransferProcessorState ImageTransferProcessor::GetState( 147Core::IrSensor::ImageTransferProcessorState ImageTransferProcessor::GetState(
148 std::vector<u8>& data) const { 148 std::span<u8> data) const {
149 const auto size = GetDataSize(current_config.trimming_format); 149 const auto size = std::min(GetDataSize(current_config.trimming_format), data.size());
150 data.resize(size);
151 system.ApplicationMemory().ReadBlock(transfer_memory, data.data(), size); 150 system.ApplicationMemory().ReadBlock(transfer_memory, data.data(), size);
152 return processor_state; 151 return processor_state;
153} 152}
diff --git a/src/hid_core/irsensor/image_transfer_processor.h b/src/hid_core/irsensor/image_transfer_processor.h
index 4e0117084..df1c9d920 100644
--- a/src/hid_core/irsensor/image_transfer_processor.h
+++ b/src/hid_core/irsensor/image_transfer_processor.h
@@ -3,6 +3,8 @@
3 3
4#pragma once 4#pragma once
5 5
6#include <span>
7
6#include "common/typed_address.h" 8#include "common/typed_address.h"
7#include "hid_core/irsensor/irs_types.h" 9#include "hid_core/irsensor/irs_types.h"
8#include "hid_core/irsensor/processor_base.h" 10#include "hid_core/irsensor/processor_base.h"
@@ -39,7 +41,7 @@ public:
39 // Transfer memory where the image data will be stored 41 // Transfer memory where the image data will be stored
40 void SetTransferMemoryAddress(Common::ProcessAddress t_mem); 42 void SetTransferMemoryAddress(Common::ProcessAddress t_mem);
41 43
42 Core::IrSensor::ImageTransferProcessorState GetState(std::vector<u8>& data) const; 44 Core::IrSensor::ImageTransferProcessorState GetState(std::span<u8> data) const;
43 45
44private: 46private:
45 // This is nn::irsensor::ImageTransferProcessorConfig 47 // This is nn::irsensor::ImageTransferProcessorConfig
diff --git a/src/hid_core/resource_manager.cpp b/src/hid_core/resource_manager.cpp
index 68ce2c7ae..245da582e 100644
--- a/src/hid_core/resource_manager.cpp
+++ b/src/hid_core/resource_manager.cpp
@@ -52,9 +52,42 @@ ResourceManager::ResourceManager(Core::System& system_,
52 std::shared_ptr<HidFirmwareSettings> settings) 52 std::shared_ptr<HidFirmwareSettings> settings)
53 : firmware_settings{settings}, system{system_}, service_context{system_, "hid"} { 53 : firmware_settings{settings}, system{system_}, service_context{system_, "hid"} {
54 applet_resource = std::make_shared<AppletResource>(system); 54 applet_resource = std::make_shared<AppletResource>(system);
55
56 // Register update callbacks
57 npad_update_event = Core::Timing::CreateEvent("HID::UpdatePadCallback",
58 [this](s64 time, std::chrono::nanoseconds ns_late)
59 -> std::optional<std::chrono::nanoseconds> {
60 UpdateNpad(ns_late);
61 return std::nullopt;
62 });
63 default_update_event = Core::Timing::CreateEvent(
64 "HID::UpdateDefaultCallback",
65 [this](s64 time,
66 std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
67 UpdateControllers(ns_late);
68 return std::nullopt;
69 });
70 mouse_keyboard_update_event = Core::Timing::CreateEvent(
71 "HID::UpdateMouseKeyboardCallback",
72 [this](s64 time,
73 std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
74 UpdateMouseKeyboard(ns_late);
75 return std::nullopt;
76 });
77 motion_update_event = Core::Timing::CreateEvent(
78 "HID::UpdateMotionCallback",
79 [this](s64 time,
80 std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
81 UpdateMotion(ns_late);
82 return std::nullopt;
83 });
55} 84}
56 85
57ResourceManager::~ResourceManager() { 86ResourceManager::~ResourceManager() {
87 system.CoreTiming().UnscheduleEvent(npad_update_event);
88 system.CoreTiming().UnscheduleEvent(default_update_event);
89 system.CoreTiming().UnscheduleEvent(mouse_keyboard_update_event);
90 system.CoreTiming().UnscheduleEvent(motion_update_event);
58 system.CoreTiming().UnscheduleEvent(touch_update_event); 91 system.CoreTiming().UnscheduleEvent(touch_update_event);
59 input_event->Finalize(); 92 input_event->Finalize();
60}; 93};
@@ -201,6 +234,7 @@ void ResourceManager::InitializeHidCommonSampler() {
201 234
202 debug_pad->SetAppletResource(applet_resource, &shared_mutex); 235 debug_pad->SetAppletResource(applet_resource, &shared_mutex);
203 digitizer->SetAppletResource(applet_resource, &shared_mutex); 236 digitizer->SetAppletResource(applet_resource, &shared_mutex);
237 unique_pad->SetAppletResource(applet_resource, &shared_mutex);
204 keyboard->SetAppletResource(applet_resource, &shared_mutex); 238 keyboard->SetAppletResource(applet_resource, &shared_mutex);
205 239
206 const auto settings = 240 const auto settings =
@@ -214,6 +248,14 @@ void ResourceManager::InitializeHidCommonSampler() {
214 home_button->SetAppletResource(applet_resource, &shared_mutex); 248 home_button->SetAppletResource(applet_resource, &shared_mutex);
215 sleep_button->SetAppletResource(applet_resource, &shared_mutex); 249 sleep_button->SetAppletResource(applet_resource, &shared_mutex);
216 capture_button->SetAppletResource(applet_resource, &shared_mutex); 250 capture_button->SetAppletResource(applet_resource, &shared_mutex);
251
252 system.CoreTiming().ScheduleLoopingEvent(npad_update_ns, npad_update_ns, npad_update_event);
253 system.CoreTiming().ScheduleLoopingEvent(default_update_ns, default_update_ns,
254 default_update_event);
255 system.CoreTiming().ScheduleLoopingEvent(mouse_keyboard_update_ns, mouse_keyboard_update_ns,
256 mouse_keyboard_update_event);
257 system.CoreTiming().ScheduleLoopingEvent(motion_update_ns, motion_update_ns,
258 motion_update_event);
217} 259}
218 260
219void ResourceManager::InitializeTouchScreenSampler() { 261void ResourceManager::InitializeTouchScreenSampler() {
@@ -465,55 +507,9 @@ IAppletResource::IAppletResource(Core::System& system_, std::shared_ptr<Resource
465 {0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"}, 507 {0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"},
466 }; 508 };
467 RegisterHandlers(functions); 509 RegisterHandlers(functions);
468
469 // Register update callbacks
470 npad_update_event = Core::Timing::CreateEvent(
471 "HID::UpdatePadCallback",
472 [this, resource](
473 s64 time, std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
474 const auto guard = LockService();
475 resource->UpdateNpad(ns_late);
476 return std::nullopt;
477 });
478 default_update_event = Core::Timing::CreateEvent(
479 "HID::UpdateDefaultCallback",
480 [this, resource](
481 s64 time, std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
482 const auto guard = LockService();
483 resource->UpdateControllers(ns_late);
484 return std::nullopt;
485 });
486 mouse_keyboard_update_event = Core::Timing::CreateEvent(
487 "HID::UpdateMouseKeyboardCallback",
488 [this, resource](
489 s64 time, std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
490 const auto guard = LockService();
491 resource->UpdateMouseKeyboard(ns_late);
492 return std::nullopt;
493 });
494 motion_update_event = Core::Timing::CreateEvent(
495 "HID::UpdateMotionCallback",
496 [this, resource](
497 s64 time, std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
498 const auto guard = LockService();
499 resource->UpdateMotion(ns_late);
500 return std::nullopt;
501 });
502
503 system.CoreTiming().ScheduleLoopingEvent(npad_update_ns, npad_update_ns, npad_update_event);
504 system.CoreTiming().ScheduleLoopingEvent(default_update_ns, default_update_ns,
505 default_update_event);
506 system.CoreTiming().ScheduleLoopingEvent(mouse_keyboard_update_ns, mouse_keyboard_update_ns,
507 mouse_keyboard_update_event);
508 system.CoreTiming().ScheduleLoopingEvent(motion_update_ns, motion_update_ns,
509 motion_update_event);
510} 510}
511 511
512IAppletResource::~IAppletResource() { 512IAppletResource::~IAppletResource() {
513 system.CoreTiming().UnscheduleEvent(npad_update_event);
514 system.CoreTiming().UnscheduleEvent(default_update_event);
515 system.CoreTiming().UnscheduleEvent(mouse_keyboard_update_event);
516 system.CoreTiming().UnscheduleEvent(motion_update_event);
517 resource_manager->FreeAppletResourceId(aruid); 513 resource_manager->FreeAppletResourceId(aruid);
518} 514}
519 515
diff --git a/src/hid_core/resource_manager.h b/src/hid_core/resource_manager.h
index 0bfe09511..dc3ff01f8 100644
--- a/src/hid_core/resource_manager.h
+++ b/src/hid_core/resource_manager.h
@@ -147,6 +147,10 @@ private:
147 std::shared_ptr<SixAxis> six_axis{nullptr}; 147 std::shared_ptr<SixAxis> six_axis{nullptr};
148 std::shared_ptr<SleepButton> sleep_button{nullptr}; 148 std::shared_ptr<SleepButton> sleep_button{nullptr};
149 std::shared_ptr<UniquePad> unique_pad{nullptr}; 149 std::shared_ptr<UniquePad> unique_pad{nullptr};
150 std::shared_ptr<Core::Timing::EventType> npad_update_event;
151 std::shared_ptr<Core::Timing::EventType> default_update_event;
152 std::shared_ptr<Core::Timing::EventType> mouse_keyboard_update_event;
153 std::shared_ptr<Core::Timing::EventType> motion_update_event;
150 154
151 // TODO: Create these resources 155 // TODO: Create these resources
152 // std::shared_ptr<AudioControl> audio_control{nullptr}; 156 // std::shared_ptr<AudioControl> audio_control{nullptr};
@@ -179,11 +183,6 @@ public:
179private: 183private:
180 void GetSharedMemoryHandle(HLERequestContext& ctx); 184 void GetSharedMemoryHandle(HLERequestContext& ctx);
181 185
182 std::shared_ptr<Core::Timing::EventType> npad_update_event{nullptr};
183 std::shared_ptr<Core::Timing::EventType> default_update_event{nullptr};
184 std::shared_ptr<Core::Timing::EventType> mouse_keyboard_update_event{nullptr};
185 std::shared_ptr<Core::Timing::EventType> motion_update_event{nullptr};
186
187 u64 aruid{}; 186 u64 aruid{};
188 std::shared_ptr<ResourceManager> resource_manager; 187 std::shared_ptr<ResourceManager> resource_manager;
189}; 188};
diff --git a/src/hid_core/resources/abstracted_pad/abstract_sixaxis_handler.cpp b/src/hid_core/resources/abstracted_pad/abstract_sixaxis_handler.cpp
index 6d759298e..0dde244ef 100644
--- a/src/hid_core/resources/abstracted_pad/abstract_sixaxis_handler.cpp
+++ b/src/hid_core/resources/abstracted_pad/abstract_sixaxis_handler.cpp
@@ -57,7 +57,7 @@ Result NpadAbstractSixAxisHandler::UpdateSixAxisState() {
57 Core::HID::NpadIdType npad_id = properties_handler->GetNpadId(); 57 Core::HID::NpadIdType npad_id = properties_handler->GetNpadId();
58 for (std::size_t i = 0; i < AruidIndexMax; i++) { 58 for (std::size_t i = 0; i < AruidIndexMax; i++) {
59 auto* data = applet_resource_holder->applet_resource->GetAruidDataByIndex(i); 59 auto* data = applet_resource_holder->applet_resource->GetAruidDataByIndex(i);
60 if (data->flag.is_assigned) { 60 if (data == nullptr || !data->flag.is_assigned) {
61 continue; 61 continue;
62 } 62 }
63 auto& npad_entry = data->shared_memory_format->npad.npad_entry[NpadIdTypeToIndex(npad_id)]; 63 auto& npad_entry = data->shared_memory_format->npad.npad_entry[NpadIdTypeToIndex(npad_id)];
diff --git a/src/hid_core/resources/digitizer/digitizer.cpp b/src/hid_core/resources/digitizer/digitizer.cpp
index cd72fd6e5..5d7dcadfe 100644
--- a/src/hid_core/resources/digitizer/digitizer.cpp
+++ b/src/hid_core/resources/digitizer/digitizer.cpp
@@ -17,10 +17,6 @@ void Digitizer::OnInit() {}
17void Digitizer::OnRelease() {} 17void Digitizer::OnRelease() {}
18 18
19void Digitizer::OnUpdate(const Core::Timing::CoreTiming& core_timing) { 19void Digitizer::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
20 if (!smart_update) {
21 return;
22 }
23
24 std::scoped_lock shared_lock{*shared_mutex}; 20 std::scoped_lock shared_lock{*shared_mutex};
25 const u64 aruid = applet_resource->GetActiveAruid(); 21 const u64 aruid = applet_resource->GetActiveAruid();
26 auto* data = applet_resource->GetAruidData(aruid); 22 auto* data = applet_resource->GetAruidData(aruid);
diff --git a/src/hid_core/resources/digitizer/digitizer.h b/src/hid_core/resources/digitizer/digitizer.h
index e031a16b0..68b03111c 100644
--- a/src/hid_core/resources/digitizer/digitizer.h
+++ b/src/hid_core/resources/digitizer/digitizer.h
@@ -20,8 +20,5 @@ public:
20 20
21 // When the controller is requesting an update for the shared memory 21 // When the controller is requesting an update for the shared memory
22 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; 22 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
23
24private:
25 bool smart_update{};
26}; 23};
27} // namespace Service::HID 24} // namespace Service::HID
diff --git a/src/hid_core/resources/npad/npad.cpp b/src/hid_core/resources/npad/npad.cpp
index 1a58eff4a..053625b55 100644
--- a/src/hid_core/resources/npad/npad.cpp
+++ b/src/hid_core/resources/npad/npad.cpp
@@ -102,6 +102,8 @@ Result NPad::Activate(u64 aruid) {
102 for (std::size_t i = 0; i < 19; ++i) { 102 for (std::size_t i = 0; i < 19; ++i) {
103 WriteEmptyEntry(npad); 103 WriteEmptyEntry(npad);
104 } 104 }
105
106 controller.is_active = true;
105 } 107 }
106 108
107 return ResultSuccess; 109 return ResultSuccess;
@@ -129,7 +131,7 @@ void NPad::ControllerUpdate(Core::HID::ControllerTriggerType type, std::size_t c
129 131
130 auto* data = applet_resource_holder.applet_resource->GetAruidDataByIndex(aruid_index); 132 auto* data = applet_resource_holder.applet_resource->GetAruidDataByIndex(aruid_index);
131 133
132 if (!data->flag.is_assigned) { 134 if (data == nullptr || !data->flag.is_assigned) {
133 continue; 135 continue;
134 } 136 }
135 137
@@ -461,9 +463,16 @@ void NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
461 std::scoped_lock lock{*applet_resource_holder.shared_mutex}; 463 std::scoped_lock lock{*applet_resource_holder.shared_mutex};
462 for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; ++aruid_index) { 464 for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; ++aruid_index) {
463 const auto* data = applet_resource_holder.applet_resource->GetAruidDataByIndex(aruid_index); 465 const auto* data = applet_resource_holder.applet_resource->GetAruidDataByIndex(aruid_index);
464 const auto aruid = data->aruid;
465 466
466 if (!data->flag.is_assigned) { 467 if (data == nullptr || !data->flag.is_assigned) {
468 continue;
469 }
470
471 bool is_set{};
472 const auto aruid = data->aruid;
473 npad_resource.IsSupportedNpadStyleSet(is_set, aruid);
474 // Wait until style is defined
475 if (!is_set) {
467 continue; 476 continue;
468 } 477 }
469 478
@@ -484,6 +493,10 @@ void NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
484 continue; 493 continue;
485 } 494 }
486 495
496 if (!controller.is_active) {
497 continue;
498 }
499
487 RequestPadStateUpdate(aruid, controller.device->GetNpadIdType()); 500 RequestPadStateUpdate(aruid, controller.device->GetNpadIdType());
488 auto& pad_state = controller.npad_pad_state; 501 auto& pad_state = controller.npad_pad_state;
489 auto& libnx_state = controller.npad_libnx_state; 502 auto& libnx_state = controller.npad_libnx_state;
@@ -592,7 +605,9 @@ void NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
592 libnx_state.npad_buttons.raw = pad_state.npad_buttons.raw; 605 libnx_state.npad_buttons.raw = pad_state.npad_buttons.raw;
593 libnx_state.l_stick = pad_state.l_stick; 606 libnx_state.l_stick = pad_state.l_stick;
594 libnx_state.r_stick = pad_state.r_stick; 607 libnx_state.r_stick = pad_state.r_stick;
595 npad->system_ext_lifo.WriteNextEntry(pad_state); 608 libnx_state.sampling_number =
609 npad->system_ext_lifo.ReadCurrentEntry().state.sampling_number + 1;
610 npad->system_ext_lifo.WriteNextEntry(libnx_state);
596 611
597 press_state |= static_cast<u64>(pad_state.npad_buttons.raw); 612 press_state |= static_cast<u64>(pad_state.npad_buttons.raw);
598 } 613 }
@@ -1060,6 +1075,7 @@ void NPad::UnregisterAppletResourceUserId(u64 aruid) {
1060 // TODO: Remove this once abstract pad is emulated properly 1075 // TODO: Remove this once abstract pad is emulated properly
1061 const auto aruid_index = npad_resource.GetIndexFromAruid(aruid); 1076 const auto aruid_index = npad_resource.GetIndexFromAruid(aruid);
1062 for (auto& controller : controller_data[aruid_index]) { 1077 for (auto& controller : controller_data[aruid_index]) {
1078 controller.is_active = false;
1063 controller.is_connected = false; 1079 controller.is_connected = false;
1064 controller.shared_memory = nullptr; 1080 controller.shared_memory = nullptr;
1065 } 1081 }
diff --git a/src/hid_core/resources/npad/npad.h b/src/hid_core/resources/npad/npad.h
index 4e26ed2e8..c63488346 100644
--- a/src/hid_core/resources/npad/npad.h
+++ b/src/hid_core/resources/npad/npad.h
@@ -164,6 +164,7 @@ private:
164 NpadInternalState* shared_memory = nullptr; 164 NpadInternalState* shared_memory = nullptr;
165 Core::HID::EmulatedController* device = nullptr; 165 Core::HID::EmulatedController* device = nullptr;
166 166
167 bool is_active{};
167 bool is_connected{}; 168 bool is_connected{};
168 169
169 // Dual joycons can have only one side connected 170 // Dual joycons can have only one side connected
diff --git a/src/hid_core/resources/six_axis/six_axis.cpp b/src/hid_core/resources/six_axis/six_axis.cpp
index abb6fd152..b407a5c76 100644
--- a/src/hid_core/resources/six_axis/six_axis.cpp
+++ b/src/hid_core/resources/six_axis/six_axis.cpp
@@ -28,142 +28,148 @@ void SixAxis::OnRelease() {}
28 28
29void SixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) { 29void SixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
30 std::scoped_lock shared_lock{*shared_mutex}; 30 std::scoped_lock shared_lock{*shared_mutex};
31 const u64 aruid = applet_resource->GetActiveAruid();
32 auto* data = applet_resource->GetAruidData(aruid);
33 31
34 if (data == nullptr || !data->flag.is_assigned) { 32 for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; ++aruid_index) {
35 return; 33 const auto* data = applet_resource->GetAruidDataByIndex(aruid_index);
36 }
37
38 if (!IsControllerActivated()) {
39 return;
40 }
41 34
42 for (std::size_t i = 0; i < controller_data.size(); ++i) { 35 if (data == nullptr || !data->flag.is_assigned) {
43 NpadSharedMemoryEntry& shared_memory = data->shared_memory_format->npad.npad_entry[i];
44 auto& controller = controller_data[i];
45 const auto& controller_type = controller.device->GetNpadStyleIndex();
46
47 if (controller_type == Core::HID::NpadStyleIndex::None ||
48 !controller.device->IsConnected()) {
49 continue; 36 continue;
50 } 37 }
51 38
52 const auto& motion_state = controller.device->GetMotions(); 39 if (!IsControllerActivated()) {
53 auto& sixaxis_fullkey_state = controller.sixaxis_fullkey_state; 40 return;
54 auto& sixaxis_handheld_state = controller.sixaxis_handheld_state;
55 auto& sixaxis_dual_left_state = controller.sixaxis_dual_left_state;
56 auto& sixaxis_dual_right_state = controller.sixaxis_dual_right_state;
57 auto& sixaxis_left_lifo_state = controller.sixaxis_left_lifo_state;
58 auto& sixaxis_right_lifo_state = controller.sixaxis_right_lifo_state;
59
60 auto& sixaxis_fullkey_lifo = shared_memory.internal_state.sixaxis_fullkey_lifo;
61 auto& sixaxis_handheld_lifo = shared_memory.internal_state.sixaxis_handheld_lifo;
62 auto& sixaxis_dual_left_lifo = shared_memory.internal_state.sixaxis_dual_left_lifo;
63 auto& sixaxis_dual_right_lifo = shared_memory.internal_state.sixaxis_dual_right_lifo;
64 auto& sixaxis_left_lifo = shared_memory.internal_state.sixaxis_left_lifo;
65 auto& sixaxis_right_lifo = shared_memory.internal_state.sixaxis_right_lifo;
66
67 // Clear previous state
68 sixaxis_fullkey_state = {};
69 sixaxis_handheld_state = {};
70 sixaxis_dual_left_state = {};
71 sixaxis_dual_right_state = {};
72 sixaxis_left_lifo_state = {};
73 sixaxis_right_lifo_state = {};
74
75 if (controller.sixaxis_sensor_enabled && Settings::values.motion_enabled.GetValue()) {
76 controller.sixaxis_at_rest = true;
77 for (std::size_t e = 0; e < motion_state.size(); ++e) {
78 controller.sixaxis_at_rest =
79 controller.sixaxis_at_rest && motion_state[e].is_at_rest;
80 }
81 } 41 }
82 42
83 const auto set_motion_state = [&](Core::HID::SixAxisSensorState& state, 43 for (std::size_t i = 0; i < controller_data.size(); ++i) {
84 const Core::HID::ControllerMotion& hid_state) { 44 NpadSharedMemoryEntry& shared_memory = data->shared_memory_format->npad.npad_entry[i];
85 using namespace std::literals::chrono_literals; 45 auto& controller = controller_data[i];
86 static constexpr Core::HID::SixAxisSensorState default_motion_state = { 46 const auto& controller_type = controller.device->GetNpadStyleIndex();
87 .delta_time = std::chrono::nanoseconds(5ms).count(), 47
88 .accel = {0, 0, -1.0f}, 48 if (!data->flag.enable_six_axis_sensor) {
89 .orientation = 49 continue;
90 { 50 }
91 Common::Vec3f{1.0f, 0, 0}, 51
92 Common::Vec3f{0, 1.0f, 0}, 52 if (controller_type == Core::HID::NpadStyleIndex::None ||
93 Common::Vec3f{0, 0, 1.0f}, 53 !controller.device->IsConnected()) {
94 }, 54 continue;
95 .attribute = {1}, 55 }
56
57 const auto& motion_state = controller.device->GetMotions();
58 auto& sixaxis_fullkey_state = controller.sixaxis_fullkey_state;
59 auto& sixaxis_handheld_state = controller.sixaxis_handheld_state;
60 auto& sixaxis_dual_left_state = controller.sixaxis_dual_left_state;
61 auto& sixaxis_dual_right_state = controller.sixaxis_dual_right_state;
62 auto& sixaxis_left_lifo_state = controller.sixaxis_left_lifo_state;
63 auto& sixaxis_right_lifo_state = controller.sixaxis_right_lifo_state;
64
65 auto& sixaxis_fullkey_lifo = shared_memory.internal_state.sixaxis_fullkey_lifo;
66 auto& sixaxis_handheld_lifo = shared_memory.internal_state.sixaxis_handheld_lifo;
67 auto& sixaxis_dual_left_lifo = shared_memory.internal_state.sixaxis_dual_left_lifo;
68 auto& sixaxis_dual_right_lifo = shared_memory.internal_state.sixaxis_dual_right_lifo;
69 auto& sixaxis_left_lifo = shared_memory.internal_state.sixaxis_left_lifo;
70 auto& sixaxis_right_lifo = shared_memory.internal_state.sixaxis_right_lifo;
71
72 // Clear previous state
73 sixaxis_fullkey_state = {};
74 sixaxis_handheld_state = {};
75 sixaxis_dual_left_state = {};
76 sixaxis_dual_right_state = {};
77 sixaxis_left_lifo_state = {};
78 sixaxis_right_lifo_state = {};
79
80 if (controller.sixaxis_sensor_enabled && Settings::values.motion_enabled.GetValue()) {
81 controller.sixaxis_at_rest = true;
82 for (std::size_t e = 0; e < motion_state.size(); ++e) {
83 controller.sixaxis_at_rest =
84 controller.sixaxis_at_rest && motion_state[e].is_at_rest;
85 }
86 }
87
88 const auto set_motion_state = [&](Core::HID::SixAxisSensorState& state,
89 const Core::HID::ControllerMotion& hid_state) {
90 using namespace std::literals::chrono_literals;
91 static constexpr Core::HID::SixAxisSensorState default_motion_state = {
92 .delta_time = std::chrono::nanoseconds(5ms).count(),
93 .accel = {0, 0, -1.0f},
94 .orientation =
95 {
96 Common::Vec3f{1.0f, 0, 0},
97 Common::Vec3f{0, 1.0f, 0},
98 Common::Vec3f{0, 0, 1.0f},
99 },
100 .attribute = {1},
101 };
102 if (!controller.sixaxis_sensor_enabled) {
103 state = default_motion_state;
104 return;
105 }
106 if (!Settings::values.motion_enabled.GetValue()) {
107 state = default_motion_state;
108 return;
109 }
110 state.attribute.is_connected.Assign(1);
111 state.delta_time = std::chrono::nanoseconds(5ms).count();
112 state.accel = hid_state.accel;
113 state.gyro = hid_state.gyro;
114 state.rotation = hid_state.rotation;
115 state.orientation = hid_state.orientation;
96 }; 116 };
97 if (!controller.sixaxis_sensor_enabled) { 117
98 state = default_motion_state; 118 switch (controller_type) {
99 return; 119 case Core::HID::NpadStyleIndex::None:
120 ASSERT(false);
121 break;
122 case Core::HID::NpadStyleIndex::Fullkey:
123 set_motion_state(sixaxis_fullkey_state, motion_state[0]);
124 break;
125 case Core::HID::NpadStyleIndex::Handheld:
126 set_motion_state(sixaxis_handheld_state, motion_state[0]);
127 break;
128 case Core::HID::NpadStyleIndex::JoyconDual:
129 set_motion_state(sixaxis_dual_left_state, motion_state[0]);
130 set_motion_state(sixaxis_dual_right_state, motion_state[1]);
131 break;
132 case Core::HID::NpadStyleIndex::JoyconLeft:
133 set_motion_state(sixaxis_left_lifo_state, motion_state[0]);
134 break;
135 case Core::HID::NpadStyleIndex::JoyconRight:
136 set_motion_state(sixaxis_right_lifo_state, motion_state[1]);
137 break;
138 case Core::HID::NpadStyleIndex::Pokeball:
139 using namespace std::literals::chrono_literals;
140 set_motion_state(sixaxis_fullkey_state, motion_state[0]);
141 sixaxis_fullkey_state.delta_time = std::chrono::nanoseconds(15ms).count();
142 break;
143 default:
144 break;
100 } 145 }
101 if (!Settings::values.motion_enabled.GetValue()) { 146
102 state = default_motion_state; 147 sixaxis_fullkey_state.sampling_number =
103 return; 148 sixaxis_fullkey_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
149 sixaxis_handheld_state.sampling_number =
150 sixaxis_handheld_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
151 sixaxis_dual_left_state.sampling_number =
152 sixaxis_dual_left_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
153 sixaxis_dual_right_state.sampling_number =
154 sixaxis_dual_right_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
155 sixaxis_left_lifo_state.sampling_number =
156 sixaxis_left_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
157 sixaxis_right_lifo_state.sampling_number =
158 sixaxis_right_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
159
160 if (IndexToNpadIdType(i) == Core::HID::NpadIdType::Handheld) {
161 // This buffer only is updated on handheld on HW
162 sixaxis_handheld_lifo.lifo.WriteNextEntry(sixaxis_handheld_state);
163 } else {
164 // Handheld doesn't update this buffer on HW
165 sixaxis_fullkey_lifo.lifo.WriteNextEntry(sixaxis_fullkey_state);
104 } 166 }
105 state.attribute.is_connected.Assign(1);
106 state.delta_time = std::chrono::nanoseconds(5ms).count();
107 state.accel = hid_state.accel;
108 state.gyro = hid_state.gyro;
109 state.rotation = hid_state.rotation;
110 state.orientation = hid_state.orientation;
111 };
112
113 switch (controller_type) {
114 case Core::HID::NpadStyleIndex::None:
115 ASSERT(false);
116 break;
117 case Core::HID::NpadStyleIndex::Fullkey:
118 set_motion_state(sixaxis_fullkey_state, motion_state[0]);
119 break;
120 case Core::HID::NpadStyleIndex::Handheld:
121 set_motion_state(sixaxis_handheld_state, motion_state[0]);
122 break;
123 case Core::HID::NpadStyleIndex::JoyconDual:
124 set_motion_state(sixaxis_dual_left_state, motion_state[0]);
125 set_motion_state(sixaxis_dual_right_state, motion_state[1]);
126 break;
127 case Core::HID::NpadStyleIndex::JoyconLeft:
128 set_motion_state(sixaxis_left_lifo_state, motion_state[0]);
129 break;
130 case Core::HID::NpadStyleIndex::JoyconRight:
131 set_motion_state(sixaxis_right_lifo_state, motion_state[1]);
132 break;
133 case Core::HID::NpadStyleIndex::Pokeball:
134 using namespace std::literals::chrono_literals;
135 set_motion_state(sixaxis_fullkey_state, motion_state[0]);
136 sixaxis_fullkey_state.delta_time = std::chrono::nanoseconds(15ms).count();
137 break;
138 default:
139 break;
140 }
141 167
142 sixaxis_fullkey_state.sampling_number = 168 sixaxis_dual_left_lifo.lifo.WriteNextEntry(sixaxis_dual_left_state);
143 sixaxis_fullkey_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1; 169 sixaxis_dual_right_lifo.lifo.WriteNextEntry(sixaxis_dual_right_state);
144 sixaxis_handheld_state.sampling_number = 170 sixaxis_left_lifo.lifo.WriteNextEntry(sixaxis_left_lifo_state);
145 sixaxis_handheld_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1; 171 sixaxis_right_lifo.lifo.WriteNextEntry(sixaxis_right_lifo_state);
146 sixaxis_dual_left_state.sampling_number =
147 sixaxis_dual_left_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
148 sixaxis_dual_right_state.sampling_number =
149 sixaxis_dual_right_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
150 sixaxis_left_lifo_state.sampling_number =
151 sixaxis_left_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
152 sixaxis_right_lifo_state.sampling_number =
153 sixaxis_right_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
154
155 if (IndexToNpadIdType(i) == Core::HID::NpadIdType::Handheld) {
156 // This buffer only is updated on handheld on HW
157 sixaxis_handheld_lifo.lifo.WriteNextEntry(sixaxis_handheld_state);
158 } else {
159 // Handheld doesn't update this buffer on HW
160 sixaxis_fullkey_lifo.lifo.WriteNextEntry(sixaxis_fullkey_state);
161 } 172 }
162
163 sixaxis_dual_left_lifo.lifo.WriteNextEntry(sixaxis_dual_left_state);
164 sixaxis_dual_right_lifo.lifo.WriteNextEntry(sixaxis_dual_right_state);
165 sixaxis_left_lifo.lifo.WriteNextEntry(sixaxis_left_lifo_state);
166 sixaxis_right_lifo.lifo.WriteNextEntry(sixaxis_right_lifo_state);
167 } 173 }
168} 174}
169 175
diff --git a/src/hid_core/resources/touch_screen/touch_screen_resource.cpp b/src/hid_core/resources/touch_screen/touch_screen_resource.cpp
index 56e8e8e51..c39321915 100644
--- a/src/hid_core/resources/touch_screen/touch_screen_resource.cpp
+++ b/src/hid_core/resources/touch_screen/touch_screen_resource.cpp
@@ -63,7 +63,7 @@ Result TouchResource::ActivateTouch(u64 aruid) {
63 auto* applet_data = applet_resource->GetAruidDataByIndex(aruid_index); 63 auto* applet_data = applet_resource->GetAruidDataByIndex(aruid_index);
64 TouchAruidData& touch_data = aruid_data[aruid_index]; 64 TouchAruidData& touch_data = aruid_data[aruid_index];
65 65
66 if (!applet_data->flag.is_assigned) { 66 if (applet_data == nullptr || !applet_data->flag.is_assigned) {
67 touch_data = {}; 67 touch_data = {};
68 continue; 68 continue;
69 } 69 }
@@ -124,7 +124,7 @@ Result TouchResource::ActivateGesture(u64 aruid, u32 basic_gesture_id) {
124 auto* applet_data = applet_resource->GetAruidDataByIndex(aruid_index); 124 auto* applet_data = applet_resource->GetAruidDataByIndex(aruid_index);
125 TouchAruidData& touch_data = aruid_data[aruid_index]; 125 TouchAruidData& touch_data = aruid_data[aruid_index];
126 126
127 if (!applet_data->flag.is_assigned) { 127 if (applet_data == nullptr || !applet_data->flag.is_assigned) {
128 touch_data = {}; 128 touch_data = {};
129 continue; 129 continue;
130 } 130 }
@@ -324,7 +324,7 @@ Result TouchResource::SetTouchScreenConfiguration(
324 const auto* applet_data = applet_resource->GetAruidDataByIndex(aruid_index); 324 const auto* applet_data = applet_resource->GetAruidDataByIndex(aruid_index);
325 TouchAruidData& data = aruid_data[aruid_index]; 325 TouchAruidData& data = aruid_data[aruid_index];
326 326
327 if (!applet_data->flag.is_assigned) { 327 if (applet_data == nullptr || !applet_data->flag.is_assigned) {
328 continue; 328 continue;
329 } 329 }
330 if (aruid != data.aruid) { 330 if (aruid != data.aruid) {
@@ -344,7 +344,7 @@ Result TouchResource::GetTouchScreenConfiguration(
344 const auto* applet_data = applet_resource->GetAruidDataByIndex(aruid_index); 344 const auto* applet_data = applet_resource->GetAruidDataByIndex(aruid_index);
345 const TouchAruidData& data = aruid_data[aruid_index]; 345 const TouchAruidData& data = aruid_data[aruid_index];
346 346
347 if (!applet_data->flag.is_assigned) { 347 if (applet_data == nullptr || !applet_data->flag.is_assigned) {
348 continue; 348 continue;
349 } 349 }
350 if (aruid != data.aruid) { 350 if (aruid != data.aruid) {
diff --git a/src/hid_core/resources/unique_pad/unique_pad.cpp b/src/hid_core/resources/unique_pad/unique_pad.cpp
index 89fc57269..b2db55c5a 100644
--- a/src/hid_core/resources/unique_pad/unique_pad.cpp
+++ b/src/hid_core/resources/unique_pad/unique_pad.cpp
@@ -17,10 +17,6 @@ void UniquePad::OnInit() {}
17void UniquePad::OnRelease() {} 17void UniquePad::OnRelease() {}
18 18
19void UniquePad::OnUpdate(const Core::Timing::CoreTiming& core_timing) { 19void UniquePad::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
20 if (!smart_update) {
21 return;
22 }
23
24 const u64 aruid = applet_resource->GetActiveAruid(); 20 const u64 aruid = applet_resource->GetActiveAruid();
25 auto* data = applet_resource->GetAruidData(aruid); 21 auto* data = applet_resource->GetAruidData(aruid);
26 22
diff --git a/src/hid_core/resources/unique_pad/unique_pad.h b/src/hid_core/resources/unique_pad/unique_pad.h
index 674ad1691..4873b7f7e 100644
--- a/src/hid_core/resources/unique_pad/unique_pad.h
+++ b/src/hid_core/resources/unique_pad/unique_pad.h
@@ -20,8 +20,5 @@ public:
20 20
21 // When the controller is requesting an update for the shared memory 21 // When the controller is requesting an update for the shared memory
22 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; 22 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
23
24private:
25 bool smart_update{};
26}; 23};
27} // namespace Service::HID 24} // namespace Service::HID
diff --git a/src/video_core/host1x/host1x.cpp b/src/video_core/host1x/host1x.cpp
index c4c7a5883..e923bfa22 100644
--- a/src/video_core/host1x/host1x.cpp
+++ b/src/video_core/host1x/host1x.cpp
@@ -10,7 +10,7 @@ namespace Host1x {
10 10
11Host1x::Host1x(Core::System& system_) 11Host1x::Host1x(Core::System& system_)
12 : system{system_}, syncpoint_manager{}, 12 : system{system_}, syncpoint_manager{},
13 memory_manager(system.DeviceMemory()), gmmu_manager{system, memory_manager, 32, 12}, 13 memory_manager(system.DeviceMemory()), gmmu_manager{system, memory_manager, 32, 0, 12},
14 allocator{std::make_unique<Common::FlatAllocator<u32, 0, 32>>(1 << 12)} {} 14 allocator{std::make_unique<Common::FlatAllocator<u32, 0, 32>>(1 << 12)} {}
15 15
16Host1x::~Host1x() = default; 16Host1x::~Host1x() = default;
diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp
index a52f8e486..ffafc48ef 100644
--- a/src/video_core/memory_manager.cpp
+++ b/src/video_core/memory_manager.cpp
@@ -22,11 +22,12 @@ using Tegra::Memory::GuestMemoryFlags;
22std::atomic<size_t> MemoryManager::unique_identifier_generator{}; 22std::atomic<size_t> MemoryManager::unique_identifier_generator{};
23 23
24MemoryManager::MemoryManager(Core::System& system_, MaxwellDeviceMemoryManager& memory_, 24MemoryManager::MemoryManager(Core::System& system_, MaxwellDeviceMemoryManager& memory_,
25 u64 address_space_bits_, u64 big_page_bits_, u64 page_bits_) 25 u64 address_space_bits_, GPUVAddr split_address_, u64 big_page_bits_,
26 u64 page_bits_)
26 : system{system_}, memory{memory_}, address_space_bits{address_space_bits_}, 27 : system{system_}, memory{memory_}, address_space_bits{address_space_bits_},
27 page_bits{page_bits_}, big_page_bits{big_page_bits_}, entries{}, big_entries{}, 28 split_address{split_address_}, page_bits{page_bits_}, big_page_bits{big_page_bits_},
28 page_table{address_space_bits, address_space_bits + page_bits - 38, 29 entries{}, big_entries{}, page_table{address_space_bits, address_space_bits + page_bits - 38,
29 page_bits != big_page_bits ? page_bits : 0}, 30 page_bits != big_page_bits ? page_bits : 0},
30 kind_map{PTEKind::INVALID}, unique_identifier{unique_identifier_generator.fetch_add( 31 kind_map{PTEKind::INVALID}, unique_identifier{unique_identifier_generator.fetch_add(
31 1, std::memory_order_acq_rel)}, 32 1, std::memory_order_acq_rel)},
32 accumulator{std::make_unique<VideoCommon::InvalidationAccumulator>()} { 33 accumulator{std::make_unique<VideoCommon::InvalidationAccumulator>()} {
@@ -48,10 +49,10 @@ MemoryManager::MemoryManager(Core::System& system_, MaxwellDeviceMemoryManager&
48 entries.resize(page_table_size / 32, 0); 49 entries.resize(page_table_size / 32, 0);
49} 50}
50 51
51MemoryManager::MemoryManager(Core::System& system_, u64 address_space_bits_, u64 big_page_bits_, 52MemoryManager::MemoryManager(Core::System& system_, u64 address_space_bits_,
52 u64 page_bits_) 53 GPUVAddr split_address_, u64 big_page_bits_, u64 page_bits_)
53 : MemoryManager(system_, system_.Host1x().MemoryManager(), address_space_bits_, big_page_bits_, 54 : MemoryManager(system_, system_.Host1x().MemoryManager(), address_space_bits_, split_address_,
54 page_bits_) {} 55 big_page_bits_, page_bits_) {}
55 56
56MemoryManager::~MemoryManager() = default; 57MemoryManager::~MemoryManager() = default;
57 58
diff --git a/src/video_core/memory_manager.h b/src/video_core/memory_manager.h
index c5255f36c..ac7c1472a 100644
--- a/src/video_core/memory_manager.h
+++ b/src/video_core/memory_manager.h
@@ -36,10 +36,11 @@ namespace Tegra {
36class MemoryManager final { 36class MemoryManager final {
37public: 37public:
38 explicit MemoryManager(Core::System& system_, u64 address_space_bits_ = 40, 38 explicit MemoryManager(Core::System& system_, u64 address_space_bits_ = 40,
39 u64 big_page_bits_ = 16, u64 page_bits_ = 12); 39 GPUVAddr split_address = 1ULL << 34, u64 big_page_bits_ = 16,
40 explicit MemoryManager(Core::System& system_, MaxwellDeviceMemoryManager& memory_,
41 u64 address_space_bits_ = 40, u64 big_page_bits_ = 16,
42 u64 page_bits_ = 12); 40 u64 page_bits_ = 12);
41 explicit MemoryManager(Core::System& system_, MaxwellDeviceMemoryManager& memory_,
42 u64 address_space_bits_ = 40, GPUVAddr split_address = 1ULL << 34,
43 u64 big_page_bits_ = 16, u64 page_bits_ = 12);
43 ~MemoryManager(); 44 ~MemoryManager();
44 45
45 size_t GetID() const { 46 size_t GetID() const {
@@ -192,6 +193,7 @@ private:
192 MaxwellDeviceMemoryManager& memory; 193 MaxwellDeviceMemoryManager& memory;
193 194
194 const u64 address_space_bits; 195 const u64 address_space_bits;
196 GPUVAddr split_address;
195 const u64 page_bits; 197 const u64 page_bits;
196 u64 address_space_size; 198 u64 address_space_size;
197 u64 page_size; 199 u64 page_size;
diff --git a/src/yuzu/configuration/configure_per_game.cpp b/src/yuzu/configuration/configure_per_game.cpp
index 9d38ab812..4dbe801a9 100644
--- a/src/yuzu/configuration/configure_per_game.cpp
+++ b/src/yuzu/configuration/configure_per_game.cpp
@@ -73,8 +73,11 @@ ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id_, const std::st
73 ui->tabWidget->addTab(graphics_advanced_tab.get(), tr("Adv. Graphics")); 73 ui->tabWidget->addTab(graphics_advanced_tab.get(), tr("Adv. Graphics"));
74 ui->tabWidget->addTab(audio_tab.get(), tr("Audio")); 74 ui->tabWidget->addTab(audio_tab.get(), tr("Audio"));
75 ui->tabWidget->addTab(input_tab.get(), tr("Input Profiles")); 75 ui->tabWidget->addTab(input_tab.get(), tr("Input Profiles"));
76
76 // Only show Linux tab on Unix 77 // Only show Linux tab on Unix
78 linux_tab->setVisible(false);
77#ifdef __unix__ 79#ifdef __unix__
80 linux_tab->setVisible(true);
78 ui->tabWidget->addTab(linux_tab.get(), tr("Linux")); 81 ui->tabWidget->addTab(linux_tab.get(), tr("Linux"));
79#endif 82#endif
80 83
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 303d84a1f..13381fea8 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -1353,6 +1353,13 @@ void GMainWindow::InitializeHotkeys() {
1353 LinkActionShortcut(ui->action_TAS_Start, QStringLiteral("TAS Start/Stop"), true); 1353 LinkActionShortcut(ui->action_TAS_Start, QStringLiteral("TAS Start/Stop"), true);
1354 LinkActionShortcut(ui->action_TAS_Record, QStringLiteral("TAS Record"), true); 1354 LinkActionShortcut(ui->action_TAS_Record, QStringLiteral("TAS Record"), true);
1355 LinkActionShortcut(ui->action_TAS_Reset, QStringLiteral("TAS Reset"), true); 1355 LinkActionShortcut(ui->action_TAS_Reset, QStringLiteral("TAS Reset"), true);
1356 LinkActionShortcut(ui->action_View_Lobby,
1357 QStringLiteral("Multiplayer Browse Public Game Lobby"));
1358 LinkActionShortcut(ui->action_Start_Room, QStringLiteral("Multiplayer Create Room"));
1359 LinkActionShortcut(ui->action_Connect_To_Room,
1360 QStringLiteral("Multiplayer Direct Connect to Room"));
1361 LinkActionShortcut(ui->action_Show_Room, QStringLiteral("Multiplayer Show Current Room"));
1362 LinkActionShortcut(ui->action_Leave_Room, QStringLiteral("Multiplayer Leave Room"));
1356 1363
1357 static const QString main_window = QStringLiteral("Main Window"); 1364 static const QString main_window = QStringLiteral("Main Window");
1358 const auto connect_shortcut = [&]<typename Fn>(const QString& action_name, const Fn& function) { 1365 const auto connect_shortcut = [&]<typename Fn>(const QString& action_name, const Fn& function) {
diff --git a/src/yuzu/multiplayer/lobby.cpp b/src/yuzu/multiplayer/lobby.cpp
index 41692c05b..77ac84295 100644
--- a/src/yuzu/multiplayer/lobby.cpp
+++ b/src/yuzu/multiplayer/lobby.cpp
@@ -77,16 +77,23 @@ Lobby::Lobby(QWidget* parent, QStandardItemModel* list,
77 77
78 // UI Buttons 78 // UI Buttons
79 connect(ui->refresh_list, &QPushButton::clicked, this, &Lobby::RefreshLobby); 79 connect(ui->refresh_list, &QPushButton::clicked, this, &Lobby::RefreshLobby);
80 connect(ui->search, &QLineEdit::textChanged, proxy, &LobbyFilterProxyModel::SetFilterSearch);
80 connect(ui->games_owned, &QCheckBox::toggled, proxy, &LobbyFilterProxyModel::SetFilterOwned); 81 connect(ui->games_owned, &QCheckBox::toggled, proxy, &LobbyFilterProxyModel::SetFilterOwned);
81 connect(ui->hide_empty, &QCheckBox::toggled, proxy, &LobbyFilterProxyModel::SetFilterEmpty); 82 connect(ui->hide_empty, &QCheckBox::toggled, proxy, &LobbyFilterProxyModel::SetFilterEmpty);
82 connect(ui->hide_full, &QCheckBox::toggled, proxy, &LobbyFilterProxyModel::SetFilterFull); 83 connect(ui->hide_full, &QCheckBox::toggled, proxy, &LobbyFilterProxyModel::SetFilterFull);
83 connect(ui->search, &QLineEdit::textChanged, proxy, &LobbyFilterProxyModel::SetFilterSearch);
84 connect(ui->room_list, &QTreeView::doubleClicked, this, &Lobby::OnJoinRoom); 84 connect(ui->room_list, &QTreeView::doubleClicked, this, &Lobby::OnJoinRoom);
85 connect(ui->room_list, &QTreeView::clicked, this, &Lobby::OnExpandRoom); 85 connect(ui->room_list, &QTreeView::clicked, this, &Lobby::OnExpandRoom);
86 86
87 // Actions 87 // Actions
88 connect(&room_list_watcher, &QFutureWatcher<AnnounceMultiplayerRoom::RoomList>::finished, this, 88 connect(&room_list_watcher, &QFutureWatcher<AnnounceMultiplayerRoom::RoomList>::finished, this,
89 &Lobby::OnRefreshLobby); 89 &Lobby::OnRefreshLobby);
90
91 // Load persistent filters after events are connected to make sure they apply
92 ui->search->setText(
93 QString::fromStdString(UISettings::values.multiplayer_filter_text.GetValue()));
94 ui->games_owned->setChecked(UISettings::values.multiplayer_filter_games_owned.GetValue());
95 ui->hide_empty->setChecked(UISettings::values.multiplayer_filter_hide_empty.GetValue());
96 ui->hide_full->setChecked(UISettings::values.multiplayer_filter_hide_full.GetValue());
90} 97}
91 98
92Lobby::~Lobby() = default; 99Lobby::~Lobby() = default;
@@ -204,6 +211,10 @@ void Lobby::OnJoinRoom(const QModelIndex& source) {
204 211
205 // Save settings 212 // Save settings
206 UISettings::values.multiplayer_nickname = ui->nickname->text().toStdString(); 213 UISettings::values.multiplayer_nickname = ui->nickname->text().toStdString();
214 UISettings::values.multiplayer_filter_text = ui->search->text().toStdString();
215 UISettings::values.multiplayer_filter_games_owned = ui->games_owned->isChecked();
216 UISettings::values.multiplayer_filter_hide_empty = ui->hide_empty->isChecked();
217 UISettings::values.multiplayer_filter_hide_full = ui->hide_full->isChecked();
207 UISettings::values.multiplayer_ip = 218 UISettings::values.multiplayer_ip =
208 proxy->data(connection_index, LobbyItemHost::HostIPRole).value<QString>().toStdString(); 219 proxy->data(connection_index, LobbyItemHost::HostIPRole).value<QString>().toStdString();
209 UISettings::values.multiplayer_port = 220 UISettings::values.multiplayer_port =
diff --git a/src/yuzu/multiplayer/lobby_p.h b/src/yuzu/multiplayer/lobby_p.h
index 068c95aca..398833e7a 100644
--- a/src/yuzu/multiplayer/lobby_p.h
+++ b/src/yuzu/multiplayer/lobby_p.h
@@ -193,12 +193,29 @@ public:
193 } 193 }
194 194
195 QVariant data(int role) const override { 195 QVariant data(int role) const override {
196 if (role != Qt::DisplayRole) { 196 switch (role) {
197 case Qt::DisplayRole: {
198 auto members = data(MemberListRole).toList();
199 return QStringLiteral("%1 / %2 ")
200 .arg(QString::number(members.size()), data(MaxPlayerRole).toString());
201 }
202 case Qt::ForegroundRole: {
203 auto members = data(MemberListRole).toList();
204 auto max_players = data(MaxPlayerRole).toInt();
205 if (members.size() >= max_players) {
206 return QBrush(QColor(255, 48, 32));
207 } else if (members.size() == (max_players - 1)) {
208 return QBrush(QColor(255, 140, 32));
209 } else if (members.size() == 0) {
210 return QBrush(QColor(128, 128, 128));
211 }
212 // FIXME: How to return a value that tells Qt not to modify the
213 // text color from the default (as if Qt::ForegroundRole wasn't overridden)?
214 return QBrush(nullptr);
215 }
216 default:
197 return LobbyItem::data(role); 217 return LobbyItem::data(role);
198 } 218 }
199 auto members = data(MemberListRole).toList();
200 return QStringLiteral("%1 / %2 ")
201 .arg(QString::number(members.size()), data(MaxPlayerRole).toString());
202 } 219 }
203 220
204 bool operator<(const QStandardItem& other) const override { 221 bool operator<(const QStandardItem& other) const override {
diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h
index f9906be33..03e42b930 100644
--- a/src/yuzu/uisettings.h
+++ b/src/yuzu/uisettings.h
@@ -169,6 +169,13 @@ struct Values {
169 169
170 // multiplayer settings 170 // multiplayer settings
171 Setting<std::string> multiplayer_nickname{linkage, {}, "nickname", Category::Multiplayer}; 171 Setting<std::string> multiplayer_nickname{linkage, {}, "nickname", Category::Multiplayer};
172 Setting<std::string> multiplayer_filter_text{linkage, {}, "filter_text", Category::Multiplayer};
173 Setting<bool> multiplayer_filter_games_owned{linkage, false, "filter_games_owned",
174 Category::Multiplayer};
175 Setting<bool> multiplayer_filter_hide_empty{linkage, false, "filter_games_hide_empty",
176 Category::Multiplayer};
177 Setting<bool> multiplayer_filter_hide_full{linkage, false, "filter_games_hide_full",
178 Category::Multiplayer};
172 Setting<std::string> multiplayer_ip{linkage, {}, "ip", Category::Multiplayer}; 179 Setting<std::string> multiplayer_ip{linkage, {}, "ip", Category::Multiplayer};
173 Setting<u16, true> multiplayer_port{linkage, 24872, 0, 180 Setting<u16, true> multiplayer_port{linkage, 24872, 0,
174 UINT16_MAX, "port", Category::Multiplayer}; 181 UINT16_MAX, "port", Category::Multiplayer};
@@ -222,7 +229,7 @@ void RestoreWindowState(std::unique_ptr<QtConfig>& qtConfig);
222// This must be in alphabetical order according to action name as it must have the same order as 229// This must be in alphabetical order according to action name as it must have the same order as
223// UISetting::values.shortcuts, which is alphabetically ordered. 230// UISetting::values.shortcuts, which is alphabetically ordered.
224// clang-format off 231// clang-format off
225const std::array<Shortcut, 23> default_hotkeys{{ 232const std::array<Shortcut, 28> default_hotkeys{{
226 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Mute/Unmute")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+M"), std::string("Home+Dpad_Right"), Qt::WindowShortcut, false}}, 233 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Mute/Unmute")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+M"), std::string("Home+Dpad_Right"), Qt::WindowShortcut, false}},
227 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Down")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("-"), std::string("Home+Dpad_Down"), Qt::ApplicationShortcut, true}}, 234 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Down")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("-"), std::string("Home+Dpad_Down"), Qt::ApplicationShortcut, true}},
228 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Up")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("="), std::string("Home+Dpad_Up"), Qt::ApplicationShortcut, true}}, 235 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Up")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("="), std::string("Home+Dpad_Up"), Qt::ApplicationShortcut, true}},
@@ -236,6 +243,11 @@ const std::array<Shortcut, 23> default_hotkeys{{
236 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Fullscreen")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F11"), std::string("Home+B"), Qt::WindowShortcut, false}}, 243 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Fullscreen")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F11"), std::string("Home+B"), Qt::WindowShortcut, false}},
237 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load File")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+O"), std::string(""), Qt::WidgetWithChildrenShortcut, false}}, 244 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load File")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+O"), std::string(""), Qt::WidgetWithChildrenShortcut, false}},
238 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load/Remove Amiibo")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F2"), std::string("Home+A"), Qt::WidgetWithChildrenShortcut, false}}, 245 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load/Remove Amiibo")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F2"), std::string("Home+A"), Qt::WidgetWithChildrenShortcut, false}},
246 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Multiplayer Browse Public Game Lobby")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+B"), std::string(""), Qt::ApplicationShortcut, false}},
247 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Multiplayer Create Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+N"), std::string(""), Qt::ApplicationShortcut, false}},
248 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Multiplayer Direct Connect to Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+C"), std::string(""), Qt::ApplicationShortcut, false}},
249 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Multiplayer Leave Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+L"), std::string(""), Qt::ApplicationShortcut, false}},
250 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Multiplayer Show Current Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+R"), std::string(""), Qt::ApplicationShortcut, false}},
239 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Restart Emulation")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F6"), std::string("R+Plus+Minus"), Qt::WindowShortcut, false}}, 251 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Restart Emulation")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F6"), std::string("R+Plus+Minus"), Qt::WindowShortcut, false}},
240 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Stop Emulation")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F5"), std::string("L+Plus+Minus"), Qt::WindowShortcut, false}}, 252 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Stop Emulation")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F5"), std::string("L+Plus+Minus"), Qt::WindowShortcut, false}},
241 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Record")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F7"), std::string(""), Qt::ApplicationShortcut, false}}, 253 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Record")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F7"), std::string(""), Qt::ApplicationShortcut, false}},