summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/android/app/build.gradle.kts4
-rw-r--r--src/android/app/src/main/AndroidManifest.xml5
-rw-r--r--src/common/input.h2
-rw-r--r--src/input_common/drivers/joycon.cpp35
-rw-r--r--src/input_common/drivers/joycon.h3
-rw-r--r--src/input_common/helpers/joycon_driver.cpp129
-rw-r--r--src/input_common/helpers/joycon_driver.h48
-rw-r--r--src/input_common/helpers/joycon_protocol/calibration.cpp53
-rw-r--r--src/input_common/helpers/joycon_protocol/calibration.h15
-rw-r--r--src/input_common/helpers/joycon_protocol/common_protocol.cpp104
-rw-r--r--src/input_common/helpers/joycon_protocol/common_protocol.h44
-rw-r--r--src/input_common/helpers/joycon_protocol/generic_functions.cpp52
-rw-r--r--src/input_common/helpers/joycon_protocol/generic_functions.h41
-rw-r--r--src/input_common/helpers/joycon_protocol/irs.cpp70
-rw-r--r--src/input_common/helpers/joycon_protocol/irs.h22
-rw-r--r--src/input_common/helpers/joycon_protocol/joycon_types.h17
-rw-r--r--src/input_common/helpers/joycon_protocol/nfc.cpp231
-rw-r--r--src/input_common/helpers/joycon_protocol/nfc.h66
-rw-r--r--src/input_common/helpers/joycon_protocol/ringcon.cpp45
-rw-r--r--src/input_common/helpers/joycon_protocol/ringcon.h14
-rw-r--r--src/input_common/helpers/joycon_protocol/rumble.cpp5
-rw-r--r--src/input_common/helpers/joycon_protocol/rumble.h8
-rw-r--r--src/video_core/CMakeLists.txt6
-rw-r--r--src/video_core/renderer_vulkan/blit_image.cpp3
-rw-r--r--src/video_core/renderer_vulkan/maxwell_to_vk.cpp20
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.cpp18
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.h5
-rw-r--r--src/video_core/renderer_vulkan/vk_buffer_cache.cpp3
-rw-r--r--src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp5
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.cpp7
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp23
-rw-r--r--src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp16
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.cpp4
-rw-r--r--src/video_core/surface.cpp22
-rw-r--r--src/video_core/surface.h2
-rw-r--r--src/video_core/texture_cache/decode_bc.cpp129
-rw-r--r--src/video_core/texture_cache/decode_bc.h (renamed from src/video_core/texture_cache/decode_bc4.h)6
-rw-r--r--src/video_core/texture_cache/decode_bc4.cpp96
-rw-r--r--src/video_core/texture_cache/util.cpp24
-rw-r--r--src/video_core/textures/bcn.cpp1
-rw-r--r--src/video_core/textures/bcn.h9
-rw-r--r--src/video_core/vulkan_common/vulkan_debug_callback.cpp40
-rw-r--r--src/video_core/vulkan_common/vulkan_debug_callback.h4
-rw-r--r--src/video_core/vulkan_common/vulkan_device.cpp14
-rw-r--r--src/video_core/vulkan_common/vulkan_device.h35
-rw-r--r--src/video_core/vulkan_common/vulkan_instance.cpp58
-rw-r--r--src/video_core/vulkan_common/vulkan_wrapper.cpp14
-rw-r--r--src/video_core/vulkan_common/vulkan_wrapper.h9
-rw-r--r--src/yuzu/configuration/configure_ringcon.cpp3
49 files changed, 932 insertions, 657 deletions
diff --git a/src/android/app/build.gradle.kts b/src/android/app/build.gradle.kts
index bab4f4d0f..9a47e2bd8 100644
--- a/src/android/app/build.gradle.kts
+++ b/src/android/app/build.gradle.kts
@@ -26,7 +26,7 @@ val autoVersion = (((System.currentTimeMillis() / 1000) - 1451606400) / 10).toIn
26android { 26android {
27 namespace = "org.yuzu.yuzu_emu" 27 namespace = "org.yuzu.yuzu_emu"
28 28
29 compileSdkVersion = "android-33" 29 compileSdkVersion = "android-34"
30 ndkVersion = "25.2.9519653" 30 ndkVersion = "25.2.9519653"
31 31
32 buildFeatures { 32 buildFeatures {
@@ -51,7 +51,7 @@ android {
51 // TODO If this is ever modified, change application_id in strings.xml 51 // TODO If this is ever modified, change application_id in strings.xml
52 applicationId = "org.yuzu.yuzu_emu" 52 applicationId = "org.yuzu.yuzu_emu"
53 minSdk = 30 53 minSdk = 30
54 targetSdk = 33 54 targetSdk = 34
55 versionName = getGitVersion() 55 versionName = getGitVersion()
56 56
57 // If you want to use autoVersion for the versionCode, create a property in local.properties 57 // If you want to use autoVersion for the versionCode, create a property in local.properties
diff --git a/src/android/app/src/main/AndroidManifest.xml b/src/android/app/src/main/AndroidManifest.xml
index e31ad69e2..51d949d65 100644
--- a/src/android/app/src/main/AndroidManifest.xml
+++ b/src/android/app/src/main/AndroidManifest.xml
@@ -13,6 +13,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
13 13
14 <uses-permission android:name="android.permission.INTERNET" /> 14 <uses-permission android:name="android.permission.INTERNET" />
15 <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> 15 <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
16 <uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
16 <uses-permission android:name="android.permission.NFC" /> 17 <uses-permission android:name="android.permission.NFC" />
17 <uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> 18 <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
18 19
@@ -69,7 +70,9 @@ SPDX-License-Identifier: GPL-3.0-or-later
69 android:resource="@xml/nfc_tech_filter" /> 70 android:resource="@xml/nfc_tech_filter" />
70 </activity> 71 </activity>
71 72
72 <service android:name="org.yuzu.yuzu_emu.utils.ForegroundService"/> 73 <service android:name="org.yuzu.yuzu_emu.utils.ForegroundService" android:foregroundServiceType="specialUse">
74 <property android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE" android:value="Keep emulation running in background"/>
75 </service>
73 76
74 <provider 77 <provider
75 android:name=".features.DocumentProvider" 78 android:name=".features.DocumentProvider"
diff --git a/src/common/input.h b/src/common/input.h
index ea30770ae..2c4ccea22 100644
--- a/src/common/input.h
+++ b/src/common/input.h
@@ -75,8 +75,10 @@ enum class DriverResult {
75 ErrorWritingData, 75 ErrorWritingData,
76 NoDeviceDetected, 76 NoDeviceDetected,
77 InvalidHandle, 77 InvalidHandle,
78 InvalidParameters,
78 NotSupported, 79 NotSupported,
79 Disabled, 80 Disabled,
81 Delayed,
80 Unknown, 82 Unknown,
81}; 83};
82 84
diff --git a/src/input_common/drivers/joycon.cpp b/src/input_common/drivers/joycon.cpp
index 52494e0d9..0aca5a3a3 100644
--- a/src/input_common/drivers/joycon.cpp
+++ b/src/input_common/drivers/joycon.cpp
@@ -102,12 +102,12 @@ bool Joycons::IsDeviceNew(SDL_hid_device_info* device_info) const {
102 Joycon::SerialNumber serial_number{}; 102 Joycon::SerialNumber serial_number{};
103 103
104 const auto result = Joycon::JoyconDriver::GetDeviceType(device_info, type); 104 const auto result = Joycon::JoyconDriver::GetDeviceType(device_info, type);
105 if (result != Joycon::DriverResult::Success) { 105 if (result != Common::Input::DriverResult::Success) {
106 return false; 106 return false;
107 } 107 }
108 108
109 const auto result2 = Joycon::JoyconDriver::GetSerialNumber(device_info, serial_number); 109 const auto result2 = Joycon::JoyconDriver::GetSerialNumber(device_info, serial_number);
110 if (result2 != Joycon::DriverResult::Success) { 110 if (result2 != Common::Input::DriverResult::Success) {
111 return false; 111 return false;
112 } 112 }
113 113
@@ -171,10 +171,10 @@ void Joycons::RegisterNewDevice(SDL_hid_device_info* device_info) {
171 LOG_WARNING(Input, "No free handles available"); 171 LOG_WARNING(Input, "No free handles available");
172 return; 172 return;
173 } 173 }
174 if (result == Joycon::DriverResult::Success) { 174 if (result == Common::Input::DriverResult::Success) {
175 result = handle->RequestDeviceAccess(device_info); 175 result = handle->RequestDeviceAccess(device_info);
176 } 176 }
177 if (result == Joycon::DriverResult::Success) { 177 if (result == Common::Input::DriverResult::Success) {
178 LOG_WARNING(Input, "Initialize device"); 178 LOG_WARNING(Input, "Initialize device");
179 179
180 const std::size_t port = handle->GetDevicePort(); 180 const std::size_t port = handle->GetDevicePort();
@@ -273,8 +273,7 @@ Common::Input::DriverResult Joycons::SetLeds(const PadIdentifier& identifier,
273 led_config += led_status.led_3 ? 4 : 0; 273 led_config += led_status.led_3 ? 4 : 0;
274 led_config += led_status.led_4 ? 8 : 0; 274 led_config += led_status.led_4 ? 8 : 0;
275 275
276 return static_cast<Common::Input::DriverResult>( 276 return handle->SetLedConfig(static_cast<u8>(led_config));
277 handle->SetLedConfig(static_cast<u8>(led_config)));
278} 277}
279 278
280Common::Input::DriverResult Joycons::SetCameraFormat(const PadIdentifier& identifier, 279Common::Input::DriverResult Joycons::SetCameraFormat(const PadIdentifier& identifier,
@@ -283,8 +282,8 @@ Common::Input::DriverResult Joycons::SetCameraFormat(const PadIdentifier& identi
283 if (handle == nullptr) { 282 if (handle == nullptr) {
284 return Common::Input::DriverResult::InvalidHandle; 283 return Common::Input::DriverResult::InvalidHandle;
285 } 284 }
286 return static_cast<Common::Input::DriverResult>(handle->SetIrsConfig( 285 return handle->SetIrsConfig(Joycon::IrsMode::ImageTransfer,
287 Joycon::IrsMode::ImageTransfer, static_cast<Joycon::IrsResolution>(camera_format))); 286 static_cast<Joycon::IrsResolution>(camera_format));
288}; 287};
289 288
290Common::Input::NfcState Joycons::SupportsNfc(const PadIdentifier& identifier_) const { 289Common::Input::NfcState Joycons::SupportsNfc(const PadIdentifier& identifier_) const {
@@ -351,7 +350,7 @@ Common::Input::NfcState Joycons::ReadMifareData(const PadIdentifier& identifier,
351 350
352 std::vector<Joycon::MifareReadData> read_data(read_request.size()); 351 std::vector<Joycon::MifareReadData> read_data(read_request.size());
353 const auto result = handle->ReadMifareData(read_request, read_data); 352 const auto result = handle->ReadMifareData(read_request, read_data);
354 if (result == Joycon::DriverResult::Success) { 353 if (result == Common::Input::DriverResult::Success) {
355 for (std::size_t i = 0; i < read_request.size(); i++) { 354 for (std::size_t i = 0; i < read_request.size(); i++) {
356 data.data[i] = { 355 data.data[i] = {
357 .command = static_cast<u8>(command), 356 .command = static_cast<u8>(command),
@@ -402,15 +401,15 @@ Common::Input::DriverResult Joycons::SetPollingMode(const PadIdentifier& identif
402 401
403 switch (polling_mode) { 402 switch (polling_mode) {
404 case Common::Input::PollingMode::Active: 403 case Common::Input::PollingMode::Active:
405 return static_cast<Common::Input::DriverResult>(handle->SetActiveMode()); 404 return handle->SetActiveMode();
406 case Common::Input::PollingMode::Passive: 405 case Common::Input::PollingMode::Passive:
407 return static_cast<Common::Input::DriverResult>(handle->SetPassiveMode()); 406 return handle->SetPassiveMode();
408 case Common::Input::PollingMode::IR: 407 case Common::Input::PollingMode::IR:
409 return static_cast<Common::Input::DriverResult>(handle->SetIrMode()); 408 return handle->SetIrMode();
410 case Common::Input::PollingMode::NFC: 409 case Common::Input::PollingMode::NFC:
411 return static_cast<Common::Input::DriverResult>(handle->SetNfcMode()); 410 return handle->SetNfcMode();
412 case Common::Input::PollingMode::Ring: 411 case Common::Input::PollingMode::Ring:
413 return static_cast<Common::Input::DriverResult>(handle->SetRingConMode()); 412 return handle->SetRingConMode();
414 default: 413 default:
415 return Common::Input::DriverResult::NotSupported; 414 return Common::Input::DriverResult::NotSupported;
416 } 415 }
@@ -828,13 +827,13 @@ std::string Joycons::JoyconName(Joycon::ControllerType type) const {
828 } 827 }
829} 828}
830 829
831Common::Input::NfcState Joycons::TranslateDriverResult(Joycon::DriverResult result) const { 830Common::Input::NfcState Joycons::TranslateDriverResult(Common::Input::DriverResult result) const {
832 switch (result) { 831 switch (result) {
833 case Joycon::DriverResult::Success: 832 case Common::Input::DriverResult::Success:
834 return Common::Input::NfcState::Success; 833 return Common::Input::NfcState::Success;
835 case Joycon::DriverResult::Disabled: 834 case Common::Input::DriverResult::Disabled:
836 return Common::Input::NfcState::WrongDeviceState; 835 return Common::Input::NfcState::WrongDeviceState;
837 case Joycon::DriverResult::NotSupported: 836 case Common::Input::DriverResult::NotSupported:
838 return Common::Input::NfcState::NotSupported; 837 return Common::Input::NfcState::NotSupported;
839 default: 838 default:
840 return Common::Input::NfcState::Unknown; 839 return Common::Input::NfcState::Unknown;
diff --git a/src/input_common/drivers/joycon.h b/src/input_common/drivers/joycon.h
index 4c323d7d6..112e970e1 100644
--- a/src/input_common/drivers/joycon.h
+++ b/src/input_common/drivers/joycon.h
@@ -17,7 +17,6 @@ struct Color;
17struct MotionData; 17struct MotionData;
18struct TagInfo; 18struct TagInfo;
19enum class ControllerType : u8; 19enum class ControllerType : u8;
20enum class DriverResult;
21enum class IrsResolution; 20enum class IrsResolution;
22class JoyconDriver; 21class JoyconDriver;
23} // namespace InputCommon::Joycon 22} // namespace InputCommon::Joycon
@@ -112,7 +111,7 @@ private:
112 /// Returns the name of the device in text format 111 /// Returns the name of the device in text format
113 std::string JoyconName(Joycon::ControllerType type) const; 112 std::string JoyconName(Joycon::ControllerType type) const;
114 113
115 Common::Input::NfcState TranslateDriverResult(Joycon::DriverResult result) const; 114 Common::Input::NfcState TranslateDriverResult(Common::Input::DriverResult result) const;
116 115
117 std::jthread scan_thread; 116 std::jthread scan_thread;
118 117
diff --git a/src/input_common/helpers/joycon_driver.cpp b/src/input_common/helpers/joycon_driver.cpp
index ec984a647..cf51f3481 100644
--- a/src/input_common/helpers/joycon_driver.cpp
+++ b/src/input_common/helpers/joycon_driver.cpp
@@ -1,6 +1,7 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "common/input.h"
4#include "common/logging/log.h" 5#include "common/logging/log.h"
5#include "common/scope_exit.h" 6#include "common/scope_exit.h"
6#include "common/swap.h" 7#include "common/swap.h"
@@ -28,13 +29,13 @@ void JoyconDriver::Stop() {
28 input_thread = {}; 29 input_thread = {};
29} 30}
30 31
31DriverResult JoyconDriver::RequestDeviceAccess(SDL_hid_device_info* device_info) { 32Common::Input::DriverResult JoyconDriver::RequestDeviceAccess(SDL_hid_device_info* device_info) {
32 std::scoped_lock lock{mutex}; 33 std::scoped_lock lock{mutex};
33 34
34 handle_device_type = ControllerType::None; 35 handle_device_type = ControllerType::None;
35 GetDeviceType(device_info, handle_device_type); 36 GetDeviceType(device_info, handle_device_type);
36 if (handle_device_type == ControllerType::None) { 37 if (handle_device_type == ControllerType::None) {
37 return DriverResult::UnsupportedControllerType; 38 return Common::Input::DriverResult::UnsupportedControllerType;
38 } 39 }
39 40
40 hidapi_handle->handle = 41 hidapi_handle->handle =
@@ -43,15 +44,15 @@ DriverResult JoyconDriver::RequestDeviceAccess(SDL_hid_device_info* device_info)
43 if (!hidapi_handle->handle) { 44 if (!hidapi_handle->handle) {
44 LOG_ERROR(Input, "Yuzu can't gain access to this device: ID {:04X}:{:04X}.", 45 LOG_ERROR(Input, "Yuzu can't gain access to this device: ID {:04X}:{:04X}.",
45 device_info->vendor_id, device_info->product_id); 46 device_info->vendor_id, device_info->product_id);
46 return DriverResult::HandleInUse; 47 return Common::Input::DriverResult::HandleInUse;
47 } 48 }
48 SDL_hid_set_nonblocking(hidapi_handle->handle, 1); 49 SDL_hid_set_nonblocking(hidapi_handle->handle, 1);
49 return DriverResult::Success; 50 return Common::Input::DriverResult::Success;
50} 51}
51 52
52DriverResult JoyconDriver::InitializeDevice() { 53Common::Input::DriverResult JoyconDriver::InitializeDevice() {
53 if (!hidapi_handle->handle) { 54 if (!hidapi_handle->handle) {
54 return DriverResult::InvalidHandle; 55 return Common::Input::DriverResult::InvalidHandle;
55 } 56 }
56 std::scoped_lock lock{mutex}; 57 std::scoped_lock lock{mutex};
57 disable_input_thread = true; 58 disable_input_thread = true;
@@ -87,7 +88,7 @@ DriverResult JoyconDriver::InitializeDevice() {
87 rumble_protocol = std::make_unique<RumbleProtocol>(hidapi_handle); 88 rumble_protocol = std::make_unique<RumbleProtocol>(hidapi_handle);
88 89
89 // Get fixed joycon info 90 // Get fixed joycon info
90 if (generic_protocol->GetVersionNumber(version) != DriverResult::Success) { 91 if (generic_protocol->GetVersionNumber(version) != Common::Input::DriverResult::Success) {
91 // If this command fails the device doesn't accept configuration commands 92 // If this command fails the device doesn't accept configuration commands
92 input_only_device = true; 93 input_only_device = true;
93 } 94 }
@@ -129,7 +130,7 @@ DriverResult JoyconDriver::InitializeDevice() {
129 } 130 }
130 131
131 disable_input_thread = false; 132 disable_input_thread = false;
132 return DriverResult::Success; 133 return Common::Input::DriverResult::Success;
133} 134}
134 135
135void JoyconDriver::InputThread(std::stop_token stop_token) { 136void JoyconDriver::InputThread(std::stop_token stop_token) {
@@ -229,7 +230,7 @@ void JoyconDriver::OnNewData(std::span<u8> buffer) {
229 if (!amiibo_detected) { 230 if (!amiibo_detected) {
230 Joycon::TagInfo tag_info; 231 Joycon::TagInfo tag_info;
231 const auto result = nfc_protocol->GetTagInfo(tag_info); 232 const auto result = nfc_protocol->GetTagInfo(tag_info);
232 if (result == DriverResult::Success) { 233 if (result == Common::Input::DriverResult::Success) {
233 joycon_poller->UpdateAmiibo(tag_info); 234 joycon_poller->UpdateAmiibo(tag_info);
234 amiibo_detected = true; 235 amiibo_detected = true;
235 } 236 }
@@ -255,7 +256,7 @@ void JoyconDriver::OnNewData(std::span<u8> buffer) {
255 } 256 }
256} 257}
257 258
258DriverResult JoyconDriver::SetPollingMode() { 259Common::Input::DriverResult JoyconDriver::SetPollingMode() {
259 SCOPE_EXIT({ disable_input_thread = false; }); 260 SCOPE_EXIT({ disable_input_thread = false; });
260 disable_input_thread = true; 261 disable_input_thread = true;
261 262
@@ -270,7 +271,7 @@ DriverResult JoyconDriver::SetPollingMode() {
270 } 271 }
271 272
272 if (input_only_device) { 273 if (input_only_device) {
273 return DriverResult::NotSupported; 274 return Common::Input::DriverResult::NotSupported;
274 } 275 }
275 276
276 if (irs_protocol->IsEnabled()) { 277 if (irs_protocol->IsEnabled()) {
@@ -289,7 +290,7 @@ DriverResult JoyconDriver::SetPollingMode() {
289 290
290 if (irs_enabled && supported_features.irs) { 291 if (irs_enabled && supported_features.irs) {
291 auto result = irs_protocol->EnableIrs(); 292 auto result = irs_protocol->EnableIrs();
292 if (result == DriverResult::Success) { 293 if (result == Common::Input::DriverResult::Success) {
293 return result; 294 return result;
294 } 295 }
295 irs_protocol->DisableIrs(); 296 irs_protocol->DisableIrs();
@@ -299,7 +300,7 @@ DriverResult JoyconDriver::SetPollingMode() {
299 300
300 if (nfc_enabled && supported_features.nfc) { 301 if (nfc_enabled && supported_features.nfc) {
301 auto result = nfc_protocol->EnableNfc(); 302 auto result = nfc_protocol->EnableNfc();
302 if (result == DriverResult::Success) { 303 if (result == Common::Input::DriverResult::Success) {
303 return result; 304 return result;
304 } 305 }
305 nfc_protocol->DisableNfc(); 306 nfc_protocol->DisableNfc();
@@ -309,10 +310,10 @@ DriverResult JoyconDriver::SetPollingMode() {
309 310
310 if (hidbus_enabled && supported_features.hidbus) { 311 if (hidbus_enabled && supported_features.hidbus) {
311 auto result = ring_protocol->EnableRingCon(); 312 auto result = ring_protocol->EnableRingCon();
312 if (result == DriverResult::Success) { 313 if (result == Common::Input::DriverResult::Success) {
313 result = ring_protocol->StartRingconPolling(); 314 result = ring_protocol->StartRingconPolling();
314 } 315 }
315 if (result == DriverResult::Success) { 316 if (result == Common::Input::DriverResult::Success) {
316 ring_connected = true; 317 ring_connected = true;
317 return result; 318 return result;
318 } 319 }
@@ -324,7 +325,7 @@ DriverResult JoyconDriver::SetPollingMode() {
324 325
325 if (passive_enabled && supported_features.passive) { 326 if (passive_enabled && supported_features.passive) {
326 const auto result = generic_protocol->EnablePassiveMode(); 327 const auto result = generic_protocol->EnablePassiveMode();
327 if (result == DriverResult::Success) { 328 if (result == Common::Input::DriverResult::Success) {
328 return result; 329 return result;
329 } 330 }
330 LOG_ERROR(Input, "Error enabling passive mode"); 331 LOG_ERROR(Input, "Error enabling passive mode");
@@ -332,7 +333,7 @@ DriverResult JoyconDriver::SetPollingMode() {
332 333
333 // Default Mode 334 // Default Mode
334 const auto result = generic_protocol->EnableActiveMode(); 335 const auto result = generic_protocol->EnableActiveMode();
335 if (result != DriverResult::Success) { 336 if (result != Common::Input::DriverResult::Success) {
336 LOG_ERROR(Input, "Error enabling active mode"); 337 LOG_ERROR(Input, "Error enabling active mode");
337 } 338 }
338 // Switch calls this function after enabling active mode 339 // Switch calls this function after enabling active mode
@@ -396,26 +397,26 @@ bool JoyconDriver::IsPayloadCorrect(int status, std::span<const u8> buffer) {
396 return true; 397 return true;
397} 398}
398 399
399DriverResult JoyconDriver::SetVibration(const VibrationValue& vibration) { 400Common::Input::DriverResult JoyconDriver::SetVibration(const VibrationValue& vibration) {
400 std::scoped_lock lock{mutex}; 401 std::scoped_lock lock{mutex};
401 if (disable_input_thread) { 402 if (disable_input_thread) {
402 return DriverResult::HandleInUse; 403 return Common::Input::DriverResult::HandleInUse;
403 } 404 }
404 return rumble_protocol->SendVibration(vibration); 405 return rumble_protocol->SendVibration(vibration);
405} 406}
406 407
407DriverResult JoyconDriver::SetLedConfig(u8 led_pattern) { 408Common::Input::DriverResult JoyconDriver::SetLedConfig(u8 led_pattern) {
408 std::scoped_lock lock{mutex}; 409 std::scoped_lock lock{mutex};
409 if (disable_input_thread) { 410 if (disable_input_thread) {
410 return DriverResult::HandleInUse; 411 return Common::Input::DriverResult::HandleInUse;
411 } 412 }
412 return generic_protocol->SetLedPattern(led_pattern); 413 return generic_protocol->SetLedPattern(led_pattern);
413} 414}
414 415
415DriverResult JoyconDriver::SetIrsConfig(IrsMode mode_, IrsResolution format_) { 416Common::Input::DriverResult JoyconDriver::SetIrsConfig(IrsMode mode_, IrsResolution format_) {
416 std::scoped_lock lock{mutex}; 417 std::scoped_lock lock{mutex};
417 if (disable_input_thread) { 418 if (disable_input_thread) {
418 return DriverResult::HandleInUse; 419 return Common::Input::DriverResult::HandleInUse;
419 } 420 }
420 disable_input_thread = true; 421 disable_input_thread = true;
421 const auto result = irs_protocol->SetIrsConfig(mode_, format_); 422 const auto result = irs_protocol->SetIrsConfig(mode_, format_);
@@ -423,7 +424,7 @@ DriverResult JoyconDriver::SetIrsConfig(IrsMode mode_, IrsResolution format_) {
423 return result; 424 return result;
424} 425}
425 426
426DriverResult JoyconDriver::SetPassiveMode() { 427Common::Input::DriverResult JoyconDriver::SetPassiveMode() {
427 std::scoped_lock lock{mutex}; 428 std::scoped_lock lock{mutex};
428 motion_enabled = false; 429 motion_enabled = false;
429 hidbus_enabled = false; 430 hidbus_enabled = false;
@@ -433,7 +434,7 @@ DriverResult JoyconDriver::SetPassiveMode() {
433 return SetPollingMode(); 434 return SetPollingMode();
434} 435}
435 436
436DriverResult JoyconDriver::SetActiveMode() { 437Common::Input::DriverResult JoyconDriver::SetActiveMode() {
437 if (is_ring_disabled_by_irs) { 438 if (is_ring_disabled_by_irs) {
438 is_ring_disabled_by_irs = false; 439 is_ring_disabled_by_irs = false;
439 SetActiveMode(); 440 SetActiveMode();
@@ -449,11 +450,11 @@ DriverResult JoyconDriver::SetActiveMode() {
449 return SetPollingMode(); 450 return SetPollingMode();
450} 451}
451 452
452DriverResult JoyconDriver::SetIrMode() { 453Common::Input::DriverResult JoyconDriver::SetIrMode() {
453 std::scoped_lock lock{mutex}; 454 std::scoped_lock lock{mutex};
454 455
455 if (!supported_features.irs) { 456 if (!supported_features.irs) {
456 return DriverResult::NotSupported; 457 return Common::Input::DriverResult::NotSupported;
457 } 458 }
458 459
459 if (ring_connected) { 460 if (ring_connected) {
@@ -468,11 +469,11 @@ DriverResult JoyconDriver::SetIrMode() {
468 return SetPollingMode(); 469 return SetPollingMode();
469} 470}
470 471
471DriverResult JoyconDriver::SetNfcMode() { 472Common::Input::DriverResult JoyconDriver::SetNfcMode() {
472 std::scoped_lock lock{mutex}; 473 std::scoped_lock lock{mutex};
473 474
474 if (!supported_features.nfc) { 475 if (!supported_features.nfc) {
475 return DriverResult::NotSupported; 476 return Common::Input::DriverResult::NotSupported;
476 } 477 }
477 478
478 motion_enabled = true; 479 motion_enabled = true;
@@ -483,11 +484,11 @@ DriverResult JoyconDriver::SetNfcMode() {
483 return SetPollingMode(); 484 return SetPollingMode();
484} 485}
485 486
486DriverResult JoyconDriver::SetRingConMode() { 487Common::Input::DriverResult JoyconDriver::SetRingConMode() {
487 std::scoped_lock lock{mutex}; 488 std::scoped_lock lock{mutex};
488 489
489 if (!supported_features.hidbus) { 490 if (!supported_features.hidbus) {
490 return DriverResult::NotSupported; 491 return Common::Input::DriverResult::NotSupported;
491 } 492 }
492 493
493 motion_enabled = true; 494 motion_enabled = true;
@@ -499,20 +500,20 @@ DriverResult JoyconDriver::SetRingConMode() {
499 const auto result = SetPollingMode(); 500 const auto result = SetPollingMode();
500 501
501 if (!ring_connected) { 502 if (!ring_connected) {
502 return DriverResult::NoDeviceDetected; 503 return Common::Input::DriverResult::NoDeviceDetected;
503 } 504 }
504 505
505 return result; 506 return result;
506} 507}
507 508
508DriverResult JoyconDriver::StartNfcPolling() { 509Common::Input::DriverResult JoyconDriver::StartNfcPolling() {
509 std::scoped_lock lock{mutex}; 510 std::scoped_lock lock{mutex};
510 511
511 if (!supported_features.nfc) { 512 if (!supported_features.nfc) {
512 return DriverResult::NotSupported; 513 return Common::Input::DriverResult::NotSupported;
513 } 514 }
514 if (!nfc_protocol->IsEnabled()) { 515 if (!nfc_protocol->IsEnabled()) {
515 return DriverResult::Disabled; 516 return Common::Input::DriverResult::Disabled;
516 } 517 }
517 518
518 disable_input_thread = true; 519 disable_input_thread = true;
@@ -522,14 +523,14 @@ DriverResult JoyconDriver::StartNfcPolling() {
522 return result; 523 return result;
523} 524}
524 525
525DriverResult JoyconDriver::StopNfcPolling() { 526Common::Input::DriverResult JoyconDriver::StopNfcPolling() {
526 std::scoped_lock lock{mutex}; 527 std::scoped_lock lock{mutex};
527 528
528 if (!supported_features.nfc) { 529 if (!supported_features.nfc) {
529 return DriverResult::NotSupported; 530 return Common::Input::DriverResult::NotSupported;
530 } 531 }
531 if (!nfc_protocol->IsEnabled()) { 532 if (!nfc_protocol->IsEnabled()) {
532 return DriverResult::Disabled; 533 return Common::Input::DriverResult::Disabled;
533 } 534 }
534 535
535 disable_input_thread = true; 536 disable_input_thread = true;
@@ -544,17 +545,17 @@ DriverResult JoyconDriver::StopNfcPolling() {
544 return result; 545 return result;
545} 546}
546 547
547DriverResult JoyconDriver::ReadAmiiboData(std::vector<u8>& out_data) { 548Common::Input::DriverResult JoyconDriver::ReadAmiiboData(std::vector<u8>& out_data) {
548 std::scoped_lock lock{mutex}; 549 std::scoped_lock lock{mutex};
549 550
550 if (!supported_features.nfc) { 551 if (!supported_features.nfc) {
551 return DriverResult::NotSupported; 552 return Common::Input::DriverResult::NotSupported;
552 } 553 }
553 if (!nfc_protocol->IsEnabled()) { 554 if (!nfc_protocol->IsEnabled()) {
554 return DriverResult::Disabled; 555 return Common::Input::DriverResult::Disabled;
555 } 556 }
556 if (!amiibo_detected) { 557 if (!amiibo_detected) {
557 return DriverResult::ErrorWritingData; 558 return Common::Input::DriverResult::ErrorWritingData;
558 } 559 }
559 560
560 out_data.resize(0x21C); 561 out_data.resize(0x21C);
@@ -565,17 +566,17 @@ DriverResult JoyconDriver::ReadAmiiboData(std::vector<u8>& out_data) {
565 return result; 566 return result;
566} 567}
567 568
568DriverResult JoyconDriver::WriteNfcData(std::span<const u8> data) { 569Common::Input::DriverResult JoyconDriver::WriteNfcData(std::span<const u8> data) {
569 std::scoped_lock lock{mutex}; 570 std::scoped_lock lock{mutex};
570 571
571 if (!supported_features.nfc) { 572 if (!supported_features.nfc) {
572 return DriverResult::NotSupported; 573 return Common::Input::DriverResult::NotSupported;
573 } 574 }
574 if (!nfc_protocol->IsEnabled()) { 575 if (!nfc_protocol->IsEnabled()) {
575 return DriverResult::Disabled; 576 return Common::Input::DriverResult::Disabled;
576 } 577 }
577 if (!amiibo_detected) { 578 if (!amiibo_detected) {
578 return DriverResult::ErrorWritingData; 579 return Common::Input::DriverResult::ErrorWritingData;
579 } 580 }
580 581
581 disable_input_thread = true; 582 disable_input_thread = true;
@@ -585,18 +586,18 @@ DriverResult JoyconDriver::WriteNfcData(std::span<const u8> data) {
585 return result; 586 return result;
586} 587}
587 588
588DriverResult JoyconDriver::ReadMifareData(std::span<const MifareReadChunk> data, 589Common::Input::DriverResult JoyconDriver::ReadMifareData(std::span<const MifareReadChunk> data,
589 std::span<MifareReadData> out_data) { 590 std::span<MifareReadData> out_data) {
590 std::scoped_lock lock{mutex}; 591 std::scoped_lock lock{mutex};
591 592
592 if (!supported_features.nfc) { 593 if (!supported_features.nfc) {
593 return DriverResult::NotSupported; 594 return Common::Input::DriverResult::NotSupported;
594 } 595 }
595 if (!nfc_protocol->IsEnabled()) { 596 if (!nfc_protocol->IsEnabled()) {
596 return DriverResult::Disabled; 597 return Common::Input::DriverResult::Disabled;
597 } 598 }
598 if (!amiibo_detected) { 599 if (!amiibo_detected) {
599 return DriverResult::ErrorWritingData; 600 return Common::Input::DriverResult::ErrorWritingData;
600 } 601 }
601 602
602 disable_input_thread = true; 603 disable_input_thread = true;
@@ -606,17 +607,17 @@ DriverResult JoyconDriver::ReadMifareData(std::span<const MifareReadChunk> data,
606 return result; 607 return result;
607} 608}
608 609
609DriverResult JoyconDriver::WriteMifareData(std::span<const MifareWriteChunk> data) { 610Common::Input::DriverResult JoyconDriver::WriteMifareData(std::span<const MifareWriteChunk> data) {
610 std::scoped_lock lock{mutex}; 611 std::scoped_lock lock{mutex};
611 612
612 if (!supported_features.nfc) { 613 if (!supported_features.nfc) {
613 return DriverResult::NotSupported; 614 return Common::Input::DriverResult::NotSupported;
614 } 615 }
615 if (!nfc_protocol->IsEnabled()) { 616 if (!nfc_protocol->IsEnabled()) {
616 return DriverResult::Disabled; 617 return Common::Input::DriverResult::Disabled;
617 } 618 }
618 if (!amiibo_detected) { 619 if (!amiibo_detected) {
619 return DriverResult::ErrorWritingData; 620 return Common::Input::DriverResult::ErrorWritingData;
620 } 621 }
621 622
622 disable_input_thread = true; 623 disable_input_thread = true;
@@ -675,8 +676,8 @@ void JoyconDriver::SetCallbacks(const JoyconCallbacks& callbacks) {
675 joycon_poller->SetCallbacks(callbacks); 676 joycon_poller->SetCallbacks(callbacks);
676} 677}
677 678
678DriverResult JoyconDriver::GetDeviceType(SDL_hid_device_info* device_info, 679Common::Input::DriverResult JoyconDriver::GetDeviceType(SDL_hid_device_info* device_info,
679 ControllerType& controller_type) { 680 ControllerType& controller_type) {
680 static constexpr std::array<std::pair<u32, ControllerType>, 6> supported_devices{ 681 static constexpr std::array<std::pair<u32, ControllerType>, 6> supported_devices{
681 std::pair<u32, ControllerType>{0x2006, ControllerType::Left}, 682 std::pair<u32, ControllerType>{0x2006, ControllerType::Left},
682 {0x2007, ControllerType::Right}, 683 {0x2007, ControllerType::Right},
@@ -686,25 +687,25 @@ DriverResult JoyconDriver::GetDeviceType(SDL_hid_device_info* device_info,
686 687
687 controller_type = ControllerType::None; 688 controller_type = ControllerType::None;
688 if (device_info->vendor_id != nintendo_vendor_id) { 689 if (device_info->vendor_id != nintendo_vendor_id) {
689 return DriverResult::UnsupportedControllerType; 690 return Common::Input::DriverResult::UnsupportedControllerType;
690 } 691 }
691 692
692 for (const auto& [product_id, type] : supported_devices) { 693 for (const auto& [product_id, type] : supported_devices) {
693 if (device_info->product_id == static_cast<u16>(product_id)) { 694 if (device_info->product_id == static_cast<u16>(product_id)) {
694 controller_type = type; 695 controller_type = type;
695 return Joycon::DriverResult::Success; 696 return Common::Input::DriverResult::Success;
696 } 697 }
697 } 698 }
698 return Joycon::DriverResult::UnsupportedControllerType; 699 return Common::Input::DriverResult::UnsupportedControllerType;
699} 700}
700 701
701DriverResult JoyconDriver::GetSerialNumber(SDL_hid_device_info* device_info, 702Common::Input::DriverResult JoyconDriver::GetSerialNumber(SDL_hid_device_info* device_info,
702 SerialNumber& serial_number) { 703 SerialNumber& serial_number) {
703 if (device_info->serial_number == nullptr) { 704 if (device_info->serial_number == nullptr) {
704 return DriverResult::Unknown; 705 return Common::Input::DriverResult::Unknown;
705 } 706 }
706 std::memcpy(&serial_number, device_info->serial_number, 15); 707 std::memcpy(&serial_number, device_info->serial_number, 15);
707 return Joycon::DriverResult::Success; 708 return Common::Input::DriverResult::Success;
708} 709}
709 710
710} // namespace InputCommon::Joycon 711} // namespace InputCommon::Joycon
diff --git a/src/input_common/helpers/joycon_driver.h b/src/input_common/helpers/joycon_driver.h
index 45b32d2f8..335e12cc3 100644
--- a/src/input_common/helpers/joycon_driver.h
+++ b/src/input_common/helpers/joycon_driver.h
@@ -11,6 +11,10 @@
11 11
12#include "input_common/helpers/joycon_protocol/joycon_types.h" 12#include "input_common/helpers/joycon_protocol/joycon_types.h"
13 13
14namespace Common::Input {
15enum class DriverResult;
16}
17
14namespace InputCommon::Joycon { 18namespace InputCommon::Joycon {
15class CalibrationProtocol; 19class CalibrationProtocol;
16class GenericProtocol; 20class GenericProtocol;
@@ -26,8 +30,8 @@ public:
26 30
27 ~JoyconDriver(); 31 ~JoyconDriver();
28 32
29 DriverResult RequestDeviceAccess(SDL_hid_device_info* device_info); 33 Common::Input::DriverResult RequestDeviceAccess(SDL_hid_device_info* device_info);
30 DriverResult InitializeDevice(); 34 Common::Input::DriverResult InitializeDevice();
31 void Stop(); 35 void Stop();
32 36
33 bool IsConnected() const; 37 bool IsConnected() const;
@@ -41,31 +45,31 @@ public:
41 SerialNumber GetSerialNumber() const; 45 SerialNumber GetSerialNumber() const;
42 SerialNumber GetHandleSerialNumber() const; 46 SerialNumber GetHandleSerialNumber() const;
43 47
44 DriverResult SetVibration(const VibrationValue& vibration); 48 Common::Input::DriverResult SetVibration(const VibrationValue& vibration);
45 DriverResult SetLedConfig(u8 led_pattern); 49 Common::Input::DriverResult SetLedConfig(u8 led_pattern);
46 DriverResult SetIrsConfig(IrsMode mode_, IrsResolution format_); 50 Common::Input::DriverResult SetIrsConfig(IrsMode mode_, IrsResolution format_);
47 DriverResult SetPassiveMode(); 51 Common::Input::DriverResult SetPassiveMode();
48 DriverResult SetActiveMode(); 52 Common::Input::DriverResult SetActiveMode();
49 DriverResult SetIrMode(); 53 Common::Input::DriverResult SetIrMode();
50 DriverResult SetNfcMode(); 54 Common::Input::DriverResult SetNfcMode();
51 DriverResult SetRingConMode(); 55 Common::Input::DriverResult SetRingConMode();
52 DriverResult StartNfcPolling(); 56 Common::Input::DriverResult StartNfcPolling();
53 DriverResult StopNfcPolling(); 57 Common::Input::DriverResult StopNfcPolling();
54 DriverResult ReadAmiiboData(std::vector<u8>& out_data); 58 Common::Input::DriverResult ReadAmiiboData(std::vector<u8>& out_data);
55 DriverResult WriteNfcData(std::span<const u8> data); 59 Common::Input::DriverResult WriteNfcData(std::span<const u8> data);
56 DriverResult ReadMifareData(std::span<const MifareReadChunk> request, 60 Common::Input::DriverResult ReadMifareData(std::span<const MifareReadChunk> request,
57 std::span<MifareReadData> out_data); 61 std::span<MifareReadData> out_data);
58 DriverResult WriteMifareData(std::span<const MifareWriteChunk> request); 62 Common::Input::DriverResult WriteMifareData(std::span<const MifareWriteChunk> request);
59 63
60 void SetCallbacks(const JoyconCallbacks& callbacks); 64 void SetCallbacks(const JoyconCallbacks& callbacks);
61 65
62 // Returns device type from hidapi handle 66 // Returns device type from hidapi handle
63 static DriverResult GetDeviceType(SDL_hid_device_info* device_info, 67 static Common::Input::DriverResult GetDeviceType(SDL_hid_device_info* device_info,
64 ControllerType& controller_type); 68 ControllerType& controller_type);
65 69
66 // Returns serial number from hidapi handle 70 // Returns serial number from hidapi handle
67 static DriverResult GetSerialNumber(SDL_hid_device_info* device_info, 71 static Common::Input::DriverResult GetSerialNumber(SDL_hid_device_info* device_info,
68 SerialNumber& serial_number); 72 SerialNumber& serial_number);
69 73
70private: 74private:
71 struct SupportedFeatures { 75 struct SupportedFeatures {
@@ -84,7 +88,7 @@ private:
84 void OnNewData(std::span<u8> buffer); 88 void OnNewData(std::span<u8> buffer);
85 89
86 /// Updates device configuration to enable or disable features 90 /// Updates device configuration to enable or disable features
87 DriverResult SetPollingMode(); 91 Common::Input::DriverResult SetPollingMode();
88 92
89 /// Returns true if input thread is valid and doesn't need to be stopped 93 /// Returns true if input thread is valid and doesn't need to be stopped
90 bool IsInputThreadValid() const; 94 bool IsInputThreadValid() const;
diff --git a/src/input_common/helpers/joycon_protocol/calibration.cpp b/src/input_common/helpers/joycon_protocol/calibration.cpp
index d8f040f75..1300ecaf5 100644
--- a/src/input_common/helpers/joycon_protocol/calibration.cpp
+++ b/src/input_common/helpers/joycon_protocol/calibration.cpp
@@ -3,6 +3,7 @@
3 3
4#include <cstring> 4#include <cstring>
5 5
6#include "common/input.h"
6#include "input_common/helpers/joycon_protocol/calibration.h" 7#include "input_common/helpers/joycon_protocol/calibration.h"
7#include "input_common/helpers/joycon_protocol/joycon_types.h" 8#include "input_common/helpers/joycon_protocol/joycon_types.h"
8 9
@@ -11,28 +12,29 @@ namespace InputCommon::Joycon {
11CalibrationProtocol::CalibrationProtocol(std::shared_ptr<JoyconHandle> handle) 12CalibrationProtocol::CalibrationProtocol(std::shared_ptr<JoyconHandle> handle)
12 : JoyconCommonProtocol(std::move(handle)) {} 13 : JoyconCommonProtocol(std::move(handle)) {}
13 14
14DriverResult CalibrationProtocol::GetLeftJoyStickCalibration(JoyStickCalibration& calibration) { 15Common::Input::DriverResult CalibrationProtocol::GetLeftJoyStickCalibration(
16 JoyStickCalibration& calibration) {
15 ScopedSetBlocking sb(this); 17 ScopedSetBlocking sb(this);
16 DriverResult result{DriverResult::Success}; 18 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
17 JoystickLeftSpiCalibration spi_calibration{}; 19 JoystickLeftSpiCalibration spi_calibration{};
18 bool has_user_calibration = false; 20 bool has_user_calibration = false;
19 calibration = {}; 21 calibration = {};
20 22
21 if (result == DriverResult::Success) { 23 if (result == Common::Input::DriverResult::Success) {
22 result = HasUserCalibration(SpiAddress::USER_LEFT_MAGIC, has_user_calibration); 24 result = HasUserCalibration(SpiAddress::USER_LEFT_MAGIC, has_user_calibration);
23 } 25 }
24 26
25 // Read User defined calibration 27 // Read User defined calibration
26 if (result == DriverResult::Success && has_user_calibration) { 28 if (result == Common::Input::DriverResult::Success && has_user_calibration) {
27 result = ReadSPI(SpiAddress::USER_LEFT_DATA, spi_calibration); 29 result = ReadSPI(SpiAddress::USER_LEFT_DATA, spi_calibration);
28 } 30 }
29 31
30 // Read Factory calibration 32 // Read Factory calibration
31 if (result == DriverResult::Success && !has_user_calibration) { 33 if (result == Common::Input::DriverResult::Success && !has_user_calibration) {
32 result = ReadSPI(SpiAddress::FACT_LEFT_DATA, spi_calibration); 34 result = ReadSPI(SpiAddress::FACT_LEFT_DATA, spi_calibration);
33 } 35 }
34 36
35 if (result == DriverResult::Success) { 37 if (result == Common::Input::DriverResult::Success) {
36 calibration.x.center = GetXAxisCalibrationValue(spi_calibration.center); 38 calibration.x.center = GetXAxisCalibrationValue(spi_calibration.center);
37 calibration.y.center = GetYAxisCalibrationValue(spi_calibration.center); 39 calibration.y.center = GetYAxisCalibrationValue(spi_calibration.center);
38 calibration.x.min = GetXAxisCalibrationValue(spi_calibration.min); 40 calibration.x.min = GetXAxisCalibrationValue(spi_calibration.min);
@@ -47,28 +49,29 @@ DriverResult CalibrationProtocol::GetLeftJoyStickCalibration(JoyStickCalibration
47 return result; 49 return result;
48} 50}
49 51
50DriverResult CalibrationProtocol::GetRightJoyStickCalibration(JoyStickCalibration& calibration) { 52Common::Input::DriverResult CalibrationProtocol::GetRightJoyStickCalibration(
53 JoyStickCalibration& calibration) {
51 ScopedSetBlocking sb(this); 54 ScopedSetBlocking sb(this);
52 DriverResult result{DriverResult::Success}; 55 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
53 JoystickRightSpiCalibration spi_calibration{}; 56 JoystickRightSpiCalibration spi_calibration{};
54 bool has_user_calibration = false; 57 bool has_user_calibration = false;
55 calibration = {}; 58 calibration = {};
56 59
57 if (result == DriverResult::Success) { 60 if (result == Common::Input::DriverResult::Success) {
58 result = HasUserCalibration(SpiAddress::USER_RIGHT_MAGIC, has_user_calibration); 61 result = HasUserCalibration(SpiAddress::USER_RIGHT_MAGIC, has_user_calibration);
59 } 62 }
60 63
61 // Read User defined calibration 64 // Read User defined calibration
62 if (result == DriverResult::Success && has_user_calibration) { 65 if (result == Common::Input::DriverResult::Success && has_user_calibration) {
63 result = ReadSPI(SpiAddress::USER_RIGHT_DATA, spi_calibration); 66 result = ReadSPI(SpiAddress::USER_RIGHT_DATA, spi_calibration);
64 } 67 }
65 68
66 // Read Factory calibration 69 // Read Factory calibration
67 if (result == DriverResult::Success && !has_user_calibration) { 70 if (result == Common::Input::DriverResult::Success && !has_user_calibration) {
68 result = ReadSPI(SpiAddress::FACT_RIGHT_DATA, spi_calibration); 71 result = ReadSPI(SpiAddress::FACT_RIGHT_DATA, spi_calibration);
69 } 72 }
70 73
71 if (result == DriverResult::Success) { 74 if (result == Common::Input::DriverResult::Success) {
72 calibration.x.center = GetXAxisCalibrationValue(spi_calibration.center); 75 calibration.x.center = GetXAxisCalibrationValue(spi_calibration.center);
73 calibration.y.center = GetYAxisCalibrationValue(spi_calibration.center); 76 calibration.y.center = GetYAxisCalibrationValue(spi_calibration.center);
74 calibration.x.min = GetXAxisCalibrationValue(spi_calibration.min); 77 calibration.x.min = GetXAxisCalibrationValue(spi_calibration.min);
@@ -83,28 +86,28 @@ DriverResult CalibrationProtocol::GetRightJoyStickCalibration(JoyStickCalibratio
83 return result; 86 return result;
84} 87}
85 88
86DriverResult CalibrationProtocol::GetImuCalibration(MotionCalibration& calibration) { 89Common::Input::DriverResult CalibrationProtocol::GetImuCalibration(MotionCalibration& calibration) {
87 ScopedSetBlocking sb(this); 90 ScopedSetBlocking sb(this);
88 DriverResult result{DriverResult::Success}; 91 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
89 ImuSpiCalibration spi_calibration{}; 92 ImuSpiCalibration spi_calibration{};
90 bool has_user_calibration = false; 93 bool has_user_calibration = false;
91 calibration = {}; 94 calibration = {};
92 95
93 if (result == DriverResult::Success) { 96 if (result == Common::Input::DriverResult::Success) {
94 result = HasUserCalibration(SpiAddress::USER_IMU_MAGIC, has_user_calibration); 97 result = HasUserCalibration(SpiAddress::USER_IMU_MAGIC, has_user_calibration);
95 } 98 }
96 99
97 // Read User defined calibration 100 // Read User defined calibration
98 if (result == DriverResult::Success && has_user_calibration) { 101 if (result == Common::Input::DriverResult::Success && has_user_calibration) {
99 result = ReadSPI(SpiAddress::USER_IMU_DATA, spi_calibration); 102 result = ReadSPI(SpiAddress::USER_IMU_DATA, spi_calibration);
100 } 103 }
101 104
102 // Read Factory calibration 105 // Read Factory calibration
103 if (result == DriverResult::Success && !has_user_calibration) { 106 if (result == Common::Input::DriverResult::Success && !has_user_calibration) {
104 result = ReadSPI(SpiAddress::FACT_IMU_DATA, spi_calibration); 107 result = ReadSPI(SpiAddress::FACT_IMU_DATA, spi_calibration);
105 } 108 }
106 109
107 if (result == DriverResult::Success) { 110 if (result == Common::Input::DriverResult::Success) {
108 calibration.accelerometer[0].offset = spi_calibration.accelerometer_offset[0]; 111 calibration.accelerometer[0].offset = spi_calibration.accelerometer_offset[0];
109 calibration.accelerometer[1].offset = spi_calibration.accelerometer_offset[1]; 112 calibration.accelerometer[1].offset = spi_calibration.accelerometer_offset[1];
110 calibration.accelerometer[2].offset = spi_calibration.accelerometer_offset[2]; 113 calibration.accelerometer[2].offset = spi_calibration.accelerometer_offset[2];
@@ -127,8 +130,8 @@ DriverResult CalibrationProtocol::GetImuCalibration(MotionCalibration& calibrati
127 return result; 130 return result;
128} 131}
129 132
130DriverResult CalibrationProtocol::GetRingCalibration(RingCalibration& calibration, 133Common::Input::DriverResult CalibrationProtocol::GetRingCalibration(RingCalibration& calibration,
131 s16 current_value) { 134 s16 current_value) {
132 constexpr s16 DefaultRingRange{800}; 135 constexpr s16 DefaultRingRange{800};
133 136
134 // TODO: Get default calibration form ring itself 137 // TODO: Get default calibration form ring itself
@@ -144,15 +147,15 @@ DriverResult CalibrationProtocol::GetRingCalibration(RingCalibration& calibratio
144 .max_value = ring_data_max, 147 .max_value = ring_data_max,
145 .min_value = ring_data_min, 148 .min_value = ring_data_min,
146 }; 149 };
147 return DriverResult::Success; 150 return Common::Input::DriverResult::Success;
148} 151}
149 152
150DriverResult CalibrationProtocol::HasUserCalibration(SpiAddress address, 153Common::Input::DriverResult CalibrationProtocol::HasUserCalibration(SpiAddress address,
151 bool& has_user_calibration) { 154 bool& has_user_calibration) {
152 MagicSpiCalibration spi_magic{}; 155 MagicSpiCalibration spi_magic{};
153 const DriverResult result{ReadSPI(address, spi_magic)}; 156 const Common::Input::DriverResult result{ReadSPI(address, spi_magic)};
154 has_user_calibration = false; 157 has_user_calibration = false;
155 if (result == DriverResult::Success) { 158 if (result == Common::Input::DriverResult::Success) {
156 has_user_calibration = spi_magic.first == CalibrationMagic::USR_MAGIC_0 && 159 has_user_calibration = spi_magic.first == CalibrationMagic::USR_MAGIC_0 &&
157 spi_magic.second == CalibrationMagic::USR_MAGIC_1; 160 spi_magic.second == CalibrationMagic::USR_MAGIC_1;
158 } 161 }
diff --git a/src/input_common/helpers/joycon_protocol/calibration.h b/src/input_common/helpers/joycon_protocol/calibration.h
index c6fd0f729..82d94b366 100644
--- a/src/input_common/helpers/joycon_protocol/calibration.h
+++ b/src/input_common/helpers/joycon_protocol/calibration.h
@@ -12,8 +12,11 @@
12 12
13#include "input_common/helpers/joycon_protocol/common_protocol.h" 13#include "input_common/helpers/joycon_protocol/common_protocol.h"
14 14
15namespace InputCommon::Joycon { 15namespace Common::Input {
16enum class DriverResult; 16enum class DriverResult;
17}
18
19namespace InputCommon::Joycon {
17struct JoyStickCalibration; 20struct JoyStickCalibration;
18struct IMUCalibration; 21struct IMUCalibration;
19struct JoyconHandle; 22struct JoyconHandle;
@@ -31,30 +34,30 @@ public:
31 * @param is_factory_calibration if true factory values will be returned 34 * @param is_factory_calibration if true factory values will be returned
32 * @returns JoyStickCalibration of the left joystick 35 * @returns JoyStickCalibration of the left joystick
33 */ 36 */
34 DriverResult GetLeftJoyStickCalibration(JoyStickCalibration& calibration); 37 Common::Input::DriverResult GetLeftJoyStickCalibration(JoyStickCalibration& calibration);
35 38
36 /** 39 /**
37 * Sends a request to obtain the right stick calibration from memory 40 * Sends a request to obtain the right stick calibration from memory
38 * @param is_factory_calibration if true factory values will be returned 41 * @param is_factory_calibration if true factory values will be returned
39 * @returns JoyStickCalibration of the right joystick 42 * @returns JoyStickCalibration of the right joystick
40 */ 43 */
41 DriverResult GetRightJoyStickCalibration(JoyStickCalibration& calibration); 44 Common::Input::DriverResult GetRightJoyStickCalibration(JoyStickCalibration& calibration);
42 45
43 /** 46 /**
44 * Sends a request to obtain the motion calibration from memory 47 * Sends a request to obtain the motion calibration from memory
45 * @returns ImuCalibration of the motion sensor 48 * @returns ImuCalibration of the motion sensor
46 */ 49 */
47 DriverResult GetImuCalibration(MotionCalibration& calibration); 50 Common::Input::DriverResult GetImuCalibration(MotionCalibration& calibration);
48 51
49 /** 52 /**
50 * Calculates on run time the proper calibration of the ring controller 53 * Calculates on run time the proper calibration of the ring controller
51 * @returns RingCalibration of the ring sensor 54 * @returns RingCalibration of the ring sensor
52 */ 55 */
53 DriverResult GetRingCalibration(RingCalibration& calibration, s16 current_value); 56 Common::Input::DriverResult GetRingCalibration(RingCalibration& calibration, s16 current_value);
54 57
55private: 58private:
56 /// Returns true if the specified address corresponds to the magic value of user calibration 59 /// Returns true if the specified address corresponds to the magic value of user calibration
57 DriverResult HasUserCalibration(SpiAddress address, bool& has_user_calibration); 60 Common::Input::DriverResult HasUserCalibration(SpiAddress address, bool& has_user_calibration);
58 61
59 /// Converts a raw calibration block to an u16 value containing the x axis value 62 /// Converts a raw calibration block to an u16 value containing the x axis value
60 u16 GetXAxisCalibrationValue(std::span<u8> block) const; 63 u16 GetXAxisCalibrationValue(std::span<u8> block) const;
diff --git a/src/input_common/helpers/joycon_protocol/common_protocol.cpp b/src/input_common/helpers/joycon_protocol/common_protocol.cpp
index 88f4cec1c..a6eecf980 100644
--- a/src/input_common/helpers/joycon_protocol/common_protocol.cpp
+++ b/src/input_common/helpers/joycon_protocol/common_protocol.cpp
@@ -1,6 +1,7 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "common/input.h"
4#include "common/logging/log.h" 5#include "common/logging/log.h"
5#include "input_common/helpers/joycon_protocol/common_protocol.h" 6#include "input_common/helpers/joycon_protocol/common_protocol.h"
6 7
@@ -21,10 +22,10 @@ void JoyconCommonProtocol::SetNonBlocking() {
21 SDL_hid_set_nonblocking(hidapi_handle->handle, 1); 22 SDL_hid_set_nonblocking(hidapi_handle->handle, 1);
22} 23}
23 24
24DriverResult JoyconCommonProtocol::GetDeviceType(ControllerType& controller_type) { 25Common::Input::DriverResult JoyconCommonProtocol::GetDeviceType(ControllerType& controller_type) {
25 const auto result = ReadSPI(SpiAddress::DEVICE_TYPE, controller_type); 26 const auto result = ReadSPI(SpiAddress::DEVICE_TYPE, controller_type);
26 27
27 if (result == DriverResult::Success) { 28 if (result == Common::Input::DriverResult::Success) {
28 // Fallback to 3rd party pro controllers 29 // Fallback to 3rd party pro controllers
29 if (controller_type == ControllerType::None) { 30 if (controller_type == ControllerType::None) {
30 controller_type = ControllerType::Pro; 31 controller_type = ControllerType::Pro;
@@ -34,12 +35,13 @@ DriverResult JoyconCommonProtocol::GetDeviceType(ControllerType& controller_type
34 return result; 35 return result;
35} 36}
36 37
37DriverResult JoyconCommonProtocol::CheckDeviceAccess(SDL_hid_device_info* device_info) { 38Common::Input::DriverResult JoyconCommonProtocol::CheckDeviceAccess(
39 SDL_hid_device_info* device_info) {
38 ControllerType controller_type{ControllerType::None}; 40 ControllerType controller_type{ControllerType::None};
39 const auto result = GetDeviceType(controller_type); 41 const auto result = GetDeviceType(controller_type);
40 42
41 if (result != DriverResult::Success || controller_type == ControllerType::None) { 43 if (result != Common::Input::DriverResult::Success || controller_type == ControllerType::None) {
42 return DriverResult::UnsupportedControllerType; 44 return Common::Input::DriverResult::UnsupportedControllerType;
43 } 45 }
44 46
45 hidapi_handle->handle = 47 hidapi_handle->handle =
@@ -48,32 +50,32 @@ DriverResult JoyconCommonProtocol::CheckDeviceAccess(SDL_hid_device_info* device
48 if (!hidapi_handle->handle) { 50 if (!hidapi_handle->handle) {
49 LOG_ERROR(Input, "Yuzu can't gain access to this device: ID {:04X}:{:04X}.", 51 LOG_ERROR(Input, "Yuzu can't gain access to this device: ID {:04X}:{:04X}.",
50 device_info->vendor_id, device_info->product_id); 52 device_info->vendor_id, device_info->product_id);
51 return DriverResult::HandleInUse; 53 return Common::Input::DriverResult::HandleInUse;
52 } 54 }
53 55
54 SetNonBlocking(); 56 SetNonBlocking();
55 return DriverResult::Success; 57 return Common::Input::DriverResult::Success;
56} 58}
57 59
58DriverResult JoyconCommonProtocol::SetReportMode(ReportMode report_mode) { 60Common::Input::DriverResult JoyconCommonProtocol::SetReportMode(ReportMode report_mode) {
59 const std::array<u8, 1> buffer{static_cast<u8>(report_mode)}; 61 const std::array<u8, 1> buffer{static_cast<u8>(report_mode)};
60 return SendSubCommand(SubCommand::SET_REPORT_MODE, buffer); 62 return SendSubCommand(SubCommand::SET_REPORT_MODE, buffer);
61} 63}
62 64
63DriverResult JoyconCommonProtocol::SendRawData(std::span<const u8> buffer) { 65Common::Input::DriverResult JoyconCommonProtocol::SendRawData(std::span<const u8> buffer) {
64 const auto result = SDL_hid_write(hidapi_handle->handle, buffer.data(), buffer.size()); 66 const auto result = SDL_hid_write(hidapi_handle->handle, buffer.data(), buffer.size());
65 67
66 if (result == -1) { 68 if (result == -1) {
67 return DriverResult::ErrorWritingData; 69 return Common::Input::DriverResult::ErrorWritingData;
68 } 70 }
69 71
70 return DriverResult::Success; 72 return Common::Input::DriverResult::Success;
71} 73}
72 74
73DriverResult JoyconCommonProtocol::GetSubCommandResponse(SubCommand sc, 75Common::Input::DriverResult JoyconCommonProtocol::GetSubCommandResponse(
74 SubCommandResponse& output) { 76 SubCommand sc, SubCommandResponse& output) {
75 constexpr int timeout_mili = 66; 77 constexpr int timeout_mili = 66;
76 constexpr int MaxTries = 3; 78 constexpr int MaxTries = 10;
77 int tries = 0; 79 int tries = 0;
78 80
79 do { 81 do {
@@ -84,16 +86,17 @@ DriverResult JoyconCommonProtocol::GetSubCommandResponse(SubCommand sc,
84 LOG_ERROR(Input, "No response from joycon"); 86 LOG_ERROR(Input, "No response from joycon");
85 } 87 }
86 if (tries++ > MaxTries) { 88 if (tries++ > MaxTries) {
87 return DriverResult::Timeout; 89 return Common::Input::DriverResult::Timeout;
88 } 90 }
89 } while (output.input_report.report_mode != ReportMode::SUBCMD_REPLY && 91 } while (output.input_report.report_mode != ReportMode::SUBCMD_REPLY &&
90 output.sub_command != sc); 92 output.sub_command != sc);
91 93
92 return DriverResult::Success; 94 return Common::Input::DriverResult::Success;
93} 95}
94 96
95DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const u8> buffer, 97Common::Input::DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc,
96 SubCommandResponse& output) { 98 std::span<const u8> buffer,
99 SubCommandResponse& output) {
97 SubCommandPacket packet{ 100 SubCommandPacket packet{
98 .output_report = OutputReport::RUMBLE_AND_SUBCMD, 101 .output_report = OutputReport::RUMBLE_AND_SUBCMD,
99 .packet_counter = GetCounter(), 102 .packet_counter = GetCounter(),
@@ -102,26 +105,28 @@ DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const
102 }; 105 };
103 106
104 if (buffer.size() > packet.command_data.size()) { 107 if (buffer.size() > packet.command_data.size()) {
105 return DriverResult::InvalidParameters; 108 return Common::Input::DriverResult::InvalidParameters;
106 } 109 }
107 110
108 memcpy(packet.command_data.data(), buffer.data(), buffer.size()); 111 memcpy(packet.command_data.data(), buffer.data(), buffer.size());
109 112
110 auto result = SendData(packet); 113 auto result = SendData(packet);
111 114
112 if (result != DriverResult::Success) { 115 if (result != Common::Input::DriverResult::Success) {
113 return result; 116 return result;
114 } 117 }
115 118
116 return GetSubCommandResponse(sc, output); 119 return GetSubCommandResponse(sc, output);
117} 120}
118 121
119DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const u8> buffer) { 122Common::Input::DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc,
123 std::span<const u8> buffer) {
120 SubCommandResponse output{}; 124 SubCommandResponse output{};
121 return SendSubCommand(sc, buffer, output); 125 return SendSubCommand(sc, buffer, output);
122} 126}
123 127
124DriverResult JoyconCommonProtocol::SendMCUCommand(SubCommand sc, std::span<const u8> buffer) { 128Common::Input::DriverResult JoyconCommonProtocol::SendMCUCommand(SubCommand sc,
129 std::span<const u8> buffer) {
125 SubCommandPacket packet{ 130 SubCommandPacket packet{
126 .output_report = OutputReport::MCU_DATA, 131 .output_report = OutputReport::MCU_DATA,
127 .packet_counter = GetCounter(), 132 .packet_counter = GetCounter(),
@@ -130,7 +135,7 @@ DriverResult JoyconCommonProtocol::SendMCUCommand(SubCommand sc, std::span<const
130 }; 135 };
131 136
132 if (buffer.size() > packet.command_data.size()) { 137 if (buffer.size() > packet.command_data.size()) {
133 return DriverResult::InvalidParameters; 138 return Common::Input::DriverResult::InvalidParameters;
134 } 139 }
135 140
136 memcpy(packet.command_data.data(), buffer.data(), buffer.size()); 141 memcpy(packet.command_data.data(), buffer.data(), buffer.size());
@@ -138,7 +143,7 @@ DriverResult JoyconCommonProtocol::SendMCUCommand(SubCommand sc, std::span<const
138 return SendData(packet); 143 return SendData(packet);
139} 144}
140 145
141DriverResult JoyconCommonProtocol::SendVibrationReport(std::span<const u8> buffer) { 146Common::Input::DriverResult JoyconCommonProtocol::SendVibrationReport(std::span<const u8> buffer) {
142 VibrationPacket packet{ 147 VibrationPacket packet{
143 .output_report = OutputReport::RUMBLE_ONLY, 148 .output_report = OutputReport::RUMBLE_ONLY,
144 .packet_counter = GetCounter(), 149 .packet_counter = GetCounter(),
@@ -146,7 +151,7 @@ DriverResult JoyconCommonProtocol::SendVibrationReport(std::span<const u8> buffe
146 }; 151 };
147 152
148 if (buffer.size() > packet.vibration_data.size()) { 153 if (buffer.size() > packet.vibration_data.size()) {
149 return DriverResult::InvalidParameters; 154 return Common::Input::DriverResult::InvalidParameters;
150 } 155 }
151 156
152 memcpy(packet.vibration_data.data(), buffer.data(), buffer.size()); 157 memcpy(packet.vibration_data.data(), buffer.data(), buffer.size());
@@ -154,7 +159,8 @@ DriverResult JoyconCommonProtocol::SendVibrationReport(std::span<const u8> buffe
154 return SendData(packet); 159 return SendData(packet);
155} 160}
156 161
157DriverResult JoyconCommonProtocol::ReadRawSPI(SpiAddress addr, std::span<u8> output) { 162Common::Input::DriverResult JoyconCommonProtocol::ReadRawSPI(SpiAddress addr,
163 std::span<u8> output) {
158 constexpr std::size_t HeaderSize = 5; 164 constexpr std::size_t HeaderSize = 5;
159 constexpr std::size_t MaxTries = 5; 165 constexpr std::size_t MaxTries = 5;
160 std::size_t tries = 0; 166 std::size_t tries = 0;
@@ -168,36 +174,36 @@ DriverResult JoyconCommonProtocol::ReadRawSPI(SpiAddress addr, std::span<u8> out
168 memcpy(buffer.data(), &packet_data, sizeof(ReadSpiPacket)); 174 memcpy(buffer.data(), &packet_data, sizeof(ReadSpiPacket));
169 do { 175 do {
170 const auto result = SendSubCommand(SubCommand::SPI_FLASH_READ, buffer, response); 176 const auto result = SendSubCommand(SubCommand::SPI_FLASH_READ, buffer, response);
171 if (result != DriverResult::Success) { 177 if (result != Common::Input::DriverResult::Success) {
172 return result; 178 return result;
173 } 179 }
174 180
175 if (tries++ > MaxTries) { 181 if (tries++ > MaxTries) {
176 return DriverResult::Timeout; 182 return Common::Input::DriverResult::Timeout;
177 } 183 }
178 } while (response.spi_address != addr); 184 } while (response.spi_address != addr);
179 185
180 if (response.command_data.size() < packet_data.size + HeaderSize) { 186 if (response.command_data.size() < packet_data.size + HeaderSize) {
181 return DriverResult::WrongReply; 187 return Common::Input::DriverResult::WrongReply;
182 } 188 }
183 189
184 // Remove header from output 190 // Remove header from output
185 memcpy(output.data(), response.command_data.data() + HeaderSize, packet_data.size); 191 memcpy(output.data(), response.command_data.data() + HeaderSize, packet_data.size);
186 return DriverResult::Success; 192 return Common::Input::DriverResult::Success;
187} 193}
188 194
189DriverResult JoyconCommonProtocol::EnableMCU(bool enable) { 195Common::Input::DriverResult JoyconCommonProtocol::EnableMCU(bool enable) {
190 const std::array<u8, 1> mcu_state{static_cast<u8>(enable ? 1 : 0)}; 196 const std::array<u8, 1> mcu_state{static_cast<u8>(enable ? 1 : 0)};
191 const auto result = SendSubCommand(SubCommand::SET_MCU_STATE, mcu_state); 197 const auto result = SendSubCommand(SubCommand::SET_MCU_STATE, mcu_state);
192 198
193 if (result != DriverResult::Success) { 199 if (result != Common::Input::DriverResult::Success) {
194 LOG_ERROR(Input, "Failed with error {}", result); 200 LOG_ERROR(Input, "Failed with error {}", result);
195 } 201 }
196 202
197 return result; 203 return result;
198} 204}
199 205
200DriverResult JoyconCommonProtocol::ConfigureMCU(const MCUConfig& config) { 206Common::Input::DriverResult JoyconCommonProtocol::ConfigureMCU(const MCUConfig& config) {
201 LOG_DEBUG(Input, "ConfigureMCU"); 207 LOG_DEBUG(Input, "ConfigureMCU");
202 std::array<u8, sizeof(MCUConfig)> config_buffer; 208 std::array<u8, sizeof(MCUConfig)> config_buffer;
203 memcpy(config_buffer.data(), &config, sizeof(MCUConfig)); 209 memcpy(config_buffer.data(), &config, sizeof(MCUConfig));
@@ -205,15 +211,15 @@ DriverResult JoyconCommonProtocol::ConfigureMCU(const MCUConfig& config) {
205 211
206 const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, config_buffer); 212 const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, config_buffer);
207 213
208 if (result != DriverResult::Success) { 214 if (result != Common::Input::DriverResult::Success) {
209 LOG_ERROR(Input, "Failed with error {}", result); 215 LOG_ERROR(Input, "Failed with error {}", result);
210 } 216 }
211 217
212 return result; 218 return result;
213} 219}
214 220
215DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode, 221Common::Input::DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode,
216 MCUCommandResponse& output) { 222 MCUCommandResponse& output) {
217 constexpr int TimeoutMili = 200; 223 constexpr int TimeoutMili = 200;
218 constexpr int MaxTries = 9; 224 constexpr int MaxTries = 9;
219 int tries = 0; 225 int tries = 0;
@@ -226,17 +232,18 @@ DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode,
226 LOG_ERROR(Input, "No response from joycon attempt {}", tries); 232 LOG_ERROR(Input, "No response from joycon attempt {}", tries);
227 } 233 }
228 if (tries++ > MaxTries) { 234 if (tries++ > MaxTries) {
229 return DriverResult::Timeout; 235 return Common::Input::DriverResult::Timeout;
230 } 236 }
231 } while (output.input_report.report_mode != report_mode || 237 } while (output.input_report.report_mode != report_mode ||
232 output.mcu_report == MCUReport::EmptyAwaitingCmd); 238 output.mcu_report == MCUReport::EmptyAwaitingCmd);
233 239
234 return DriverResult::Success; 240 return Common::Input::DriverResult::Success;
235} 241}
236 242
237DriverResult JoyconCommonProtocol::SendMCUData(ReportMode report_mode, MCUSubCommand sc, 243Common::Input::DriverResult JoyconCommonProtocol::SendMCUData(ReportMode report_mode,
238 std::span<const u8> buffer, 244 MCUSubCommand sc,
239 MCUCommandResponse& output) { 245 std::span<const u8> buffer,
246 MCUCommandResponse& output) {
240 SubCommandPacket packet{ 247 SubCommandPacket packet{
241 .output_report = OutputReport::MCU_DATA, 248 .output_report = OutputReport::MCU_DATA,
242 .packet_counter = GetCounter(), 249 .packet_counter = GetCounter(),
@@ -245,23 +252,24 @@ DriverResult JoyconCommonProtocol::SendMCUData(ReportMode report_mode, MCUSubCom
245 }; 252 };
246 253
247 if (buffer.size() > packet.command_data.size()) { 254 if (buffer.size() > packet.command_data.size()) {
248 return DriverResult::InvalidParameters; 255 return Common::Input::DriverResult::InvalidParameters;
249 } 256 }
250 257
251 memcpy(packet.command_data.data(), buffer.data(), buffer.size()); 258 memcpy(packet.command_data.data(), buffer.data(), buffer.size());
252 259
253 auto result = SendData(packet); 260 auto result = SendData(packet);
254 261
255 if (result != DriverResult::Success) { 262 if (result != Common::Input::DriverResult::Success) {
256 return result; 263 return result;
257 } 264 }
258 265
259 result = GetMCUDataResponse(report_mode, output); 266 result = GetMCUDataResponse(report_mode, output);
260 267
261 return DriverResult::Success; 268 return Common::Input::DriverResult::Success;
262} 269}
263 270
264DriverResult JoyconCommonProtocol::WaitSetMCUMode(ReportMode report_mode, MCUMode mode) { 271Common::Input::DriverResult JoyconCommonProtocol::WaitSetMCUMode(ReportMode report_mode,
272 MCUMode mode) {
265 MCUCommandResponse output{}; 273 MCUCommandResponse output{};
266 constexpr std::size_t MaxTries{16}; 274 constexpr std::size_t MaxTries{16};
267 std::size_t tries{}; 275 std::size_t tries{};
@@ -269,17 +277,17 @@ DriverResult JoyconCommonProtocol::WaitSetMCUMode(ReportMode report_mode, MCUMod
269 do { 277 do {
270 const auto result = SendMCUData(report_mode, MCUSubCommand::SetDeviceMode, {}, output); 278 const auto result = SendMCUData(report_mode, MCUSubCommand::SetDeviceMode, {}, output);
271 279
272 if (result != DriverResult::Success) { 280 if (result != Common::Input::DriverResult::Success) {
273 return result; 281 return result;
274 } 282 }
275 283
276 if (tries++ > MaxTries) { 284 if (tries++ > MaxTries) {
277 return DriverResult::WrongReply; 285 return Common::Input::DriverResult::WrongReply;
278 } 286 }
279 } while (output.mcu_report != MCUReport::StateReport || 287 } while (output.mcu_report != MCUReport::StateReport ||
280 output.mcu_data[6] != static_cast<u8>(mode)); 288 output.mcu_data[6] != static_cast<u8>(mode));
281 289
282 return DriverResult::Success; 290 return Common::Input::DriverResult::Success;
283} 291}
284 292
285// crc-8-ccitt / polynomial 0x07 look up table 293// crc-8-ccitt / polynomial 0x07 look up table
diff --git a/src/input_common/helpers/joycon_protocol/common_protocol.h b/src/input_common/helpers/joycon_protocol/common_protocol.h
index 411ec018a..dd667ca2b 100644
--- a/src/input_common/helpers/joycon_protocol/common_protocol.h
+++ b/src/input_common/helpers/joycon_protocol/common_protocol.h
@@ -38,30 +38,30 @@ public:
38 * Sends a request to obtain the joycon type from device 38 * Sends a request to obtain the joycon type from device
39 * @returns controller type of the joycon 39 * @returns controller type of the joycon
40 */ 40 */
41 DriverResult GetDeviceType(ControllerType& controller_type); 41 Common::Input::DriverResult GetDeviceType(ControllerType& controller_type);
42 42
43 /** 43 /**
44 * Verifies and sets the joycon_handle if device is valid 44 * Verifies and sets the joycon_handle if device is valid
45 * @param device info from the driver 45 * @param device info from the driver
46 * @returns success if the device is valid 46 * @returns success if the device is valid
47 */ 47 */
48 DriverResult CheckDeviceAccess(SDL_hid_device_info* device); 48 Common::Input::DriverResult CheckDeviceAccess(SDL_hid_device_info* device);
49 49
50 /** 50 /**
51 * Sends a request to set the polling mode of the joycon 51 * Sends a request to set the polling mode of the joycon
52 * @param report_mode polling mode to be set 52 * @param report_mode polling mode to be set
53 */ 53 */
54 DriverResult SetReportMode(Joycon::ReportMode report_mode); 54 Common::Input::DriverResult SetReportMode(Joycon::ReportMode report_mode);
55 55
56 /** 56 /**
57 * Sends data to the joycon device 57 * Sends data to the joycon device
58 * @param buffer data to be send 58 * @param buffer data to be send
59 */ 59 */
60 DriverResult SendRawData(std::span<const u8> buffer); 60 Common::Input::DriverResult SendRawData(std::span<const u8> buffer);
61 61
62 template <typename Output> 62 template <typename Output>
63 requires std::is_trivially_copyable_v<Output> 63 requires std::is_trivially_copyable_v<Output>
64 DriverResult SendData(const Output& output) { 64 Common::Input::DriverResult SendData(const Output& output) {
65 std::array<u8, sizeof(Output)> buffer; 65 std::array<u8, sizeof(Output)> buffer;
66 std::memcpy(buffer.data(), &output, sizeof(Output)); 66 std::memcpy(buffer.data(), &output, sizeof(Output));
67 return SendRawData(buffer); 67 return SendRawData(buffer);
@@ -72,7 +72,8 @@ public:
72 * @param sub_command type of data to be returned 72 * @param sub_command type of data to be returned
73 * @returns a buffer containing the response 73 * @returns a buffer containing the response
74 */ 74 */
75 DriverResult GetSubCommandResponse(SubCommand sub_command, SubCommandResponse& output); 75 Common::Input::DriverResult GetSubCommandResponse(SubCommand sub_command,
76 SubCommandResponse& output);
76 77
77 /** 78 /**
78 * Sends a sub command to the device and waits for it's reply 79 * Sends a sub command to the device and waits for it's reply
@@ -80,35 +81,35 @@ public:
80 * @param buffer data to be send 81 * @param buffer data to be send
81 * @returns output buffer containing the response 82 * @returns output buffer containing the response
82 */ 83 */
83 DriverResult SendSubCommand(SubCommand sc, std::span<const u8> buffer, 84 Common::Input::DriverResult SendSubCommand(SubCommand sc, std::span<const u8> buffer,
84 SubCommandResponse& output); 85 SubCommandResponse& output);
85 86
86 /** 87 /**
87 * Sends a sub command to the device and waits for it's reply and ignores the output 88 * Sends a sub command to the device and waits for it's reply and ignores the output
88 * @param sc sub command to be send 89 * @param sc sub command to be send
89 * @param buffer data to be send 90 * @param buffer data to be send
90 */ 91 */
91 DriverResult SendSubCommand(SubCommand sc, std::span<const u8> buffer); 92 Common::Input::DriverResult SendSubCommand(SubCommand sc, std::span<const u8> buffer);
92 93
93 /** 94 /**
94 * Sends a mcu command to the device 95 * Sends a mcu command to the device
95 * @param sc sub command to be send 96 * @param sc sub command to be send
96 * @param buffer data to be send 97 * @param buffer data to be send
97 */ 98 */
98 DriverResult SendMCUCommand(SubCommand sc, std::span<const u8> buffer); 99 Common::Input::DriverResult SendMCUCommand(SubCommand sc, std::span<const u8> buffer);
99 100
100 /** 101 /**
101 * Sends vibration data to the joycon 102 * Sends vibration data to the joycon
102 * @param buffer data to be send 103 * @param buffer data to be send
103 */ 104 */
104 DriverResult SendVibrationReport(std::span<const u8> buffer); 105 Common::Input::DriverResult SendVibrationReport(std::span<const u8> buffer);
105 106
106 /** 107 /**
107 * Reads the SPI memory stored on the joycon 108 * Reads the SPI memory stored on the joycon
108 * @param Initial address location 109 * @param Initial address location
109 * @returns output buffer containing the response 110 * @returns output buffer containing the response
110 */ 111 */
111 DriverResult ReadRawSPI(SpiAddress addr, std::span<u8> output); 112 Common::Input::DriverResult ReadRawSPI(SpiAddress addr, std::span<u8> output);
112 113
113 /** 114 /**
114 * Reads the SPI memory stored on the joycon 115 * Reads the SPI memory stored on the joycon
@@ -117,37 +118,38 @@ public:
117 */ 118 */
118 template <typename Output> 119 template <typename Output>
119 requires std::is_trivially_copyable_v<Output> 120 requires std::is_trivially_copyable_v<Output>
120 DriverResult ReadSPI(SpiAddress addr, Output& output) { 121 Common::Input::DriverResult ReadSPI(SpiAddress addr, Output& output) {
121 std::array<u8, sizeof(Output)> buffer; 122 std::array<u8, sizeof(Output)> buffer;
122 output = {}; 123 output = {};
123 124
124 const auto result = ReadRawSPI(addr, buffer); 125 const auto result = ReadRawSPI(addr, buffer);
125 if (result != DriverResult::Success) { 126 if (result != Common::Input::DriverResult::Success) {
126 return result; 127 return result;
127 } 128 }
128 129
129 std::memcpy(&output, buffer.data(), sizeof(Output)); 130 std::memcpy(&output, buffer.data(), sizeof(Output));
130 return DriverResult::Success; 131 return Common::Input::DriverResult::Success;
131 } 132 }
132 133
133 /** 134 /**
134 * Enables MCU chip on the joycon 135 * Enables MCU chip on the joycon
135 * @param enable if true the chip will be enabled 136 * @param enable if true the chip will be enabled
136 */ 137 */
137 DriverResult EnableMCU(bool enable); 138 Common::Input::DriverResult EnableMCU(bool enable);
138 139
139 /** 140 /**
140 * Configures the MCU to the corresponding mode 141 * Configures the MCU to the corresponding mode
141 * @param MCUConfig configuration 142 * @param MCUConfig configuration
142 */ 143 */
143 DriverResult ConfigureMCU(const MCUConfig& config); 144 Common::Input::DriverResult ConfigureMCU(const MCUConfig& config);
144 145
145 /** 146 /**
146 * Waits until there's MCU data available. On timeout returns error 147 * Waits until there's MCU data available. On timeout returns error
147 * @param report mode of the expected reply 148 * @param report mode of the expected reply
148 * @returns a buffer containing the response 149 * @returns a buffer containing the response
149 */ 150 */
150 DriverResult GetMCUDataResponse(ReportMode report_mode_, MCUCommandResponse& output); 151 Common::Input::DriverResult GetMCUDataResponse(ReportMode report_mode_,
152 MCUCommandResponse& output);
151 153
152 /** 154 /**
153 * Sends data to the MCU chip and waits for it's reply 155 * Sends data to the MCU chip and waits for it's reply
@@ -156,15 +158,15 @@ public:
156 * @param buffer data to be send 158 * @param buffer data to be send
157 * @returns output buffer containing the response 159 * @returns output buffer containing the response
158 */ 160 */
159 DriverResult SendMCUData(ReportMode report_mode, MCUSubCommand sc, std::span<const u8> buffer, 161 Common::Input::DriverResult SendMCUData(ReportMode report_mode, MCUSubCommand sc,
160 MCUCommandResponse& output); 162 std::span<const u8> buffer, MCUCommandResponse& output);
161 163
162 /** 164 /**
163 * Wait's until the MCU chip is on the specified mode 165 * Wait's until the MCU chip is on the specified mode
164 * @param report mode of the expected reply 166 * @param report mode of the expected reply
165 * @param MCUMode configuration 167 * @param MCUMode configuration
166 */ 168 */
167 DriverResult WaitSetMCUMode(ReportMode report_mode, MCUMode mode); 169 Common::Input::DriverResult WaitSetMCUMode(ReportMode report_mode, MCUMode mode);
168 170
169 /** 171 /**
170 * Calculates the checksum from the MCU data 172 * Calculates the checksum from the MCU data
diff --git a/src/input_common/helpers/joycon_protocol/generic_functions.cpp b/src/input_common/helpers/joycon_protocol/generic_functions.cpp
index 548a4b9e3..e9a056448 100644
--- a/src/input_common/helpers/joycon_protocol/generic_functions.cpp
+++ b/src/input_common/helpers/joycon_protocol/generic_functions.cpp
@@ -1,6 +1,7 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "common/input.h"
4#include "common/logging/log.h" 5#include "common/logging/log.h"
5#include "input_common/helpers/joycon_protocol/generic_functions.h" 6#include "input_common/helpers/joycon_protocol/generic_functions.h"
6 7
@@ -9,73 +10,74 @@ namespace InputCommon::Joycon {
9GenericProtocol::GenericProtocol(std::shared_ptr<JoyconHandle> handle) 10GenericProtocol::GenericProtocol(std::shared_ptr<JoyconHandle> handle)
10 : JoyconCommonProtocol(std::move(handle)) {} 11 : JoyconCommonProtocol(std::move(handle)) {}
11 12
12DriverResult GenericProtocol::EnablePassiveMode() { 13Common::Input::DriverResult GenericProtocol::EnablePassiveMode() {
13 ScopedSetBlocking sb(this); 14 ScopedSetBlocking sb(this);
14 return SetReportMode(ReportMode::SIMPLE_HID_MODE); 15 return SetReportMode(ReportMode::SIMPLE_HID_MODE);
15} 16}
16 17
17DriverResult GenericProtocol::EnableActiveMode() { 18Common::Input::DriverResult GenericProtocol::EnableActiveMode() {
18 ScopedSetBlocking sb(this); 19 ScopedSetBlocking sb(this);
19 return SetReportMode(ReportMode::STANDARD_FULL_60HZ); 20 return SetReportMode(ReportMode::STANDARD_FULL_60HZ);
20} 21}
21 22
22DriverResult GenericProtocol::SetLowPowerMode(bool enable) { 23Common::Input::DriverResult GenericProtocol::SetLowPowerMode(bool enable) {
23 ScopedSetBlocking sb(this); 24 ScopedSetBlocking sb(this);
24 const std::array<u8, 1> buffer{static_cast<u8>(enable ? 1 : 0)}; 25 const std::array<u8, 1> buffer{static_cast<u8>(enable ? 1 : 0)};
25 return SendSubCommand(SubCommand::LOW_POWER_MODE, buffer); 26 return SendSubCommand(SubCommand::LOW_POWER_MODE, buffer);
26} 27}
27 28
28DriverResult GenericProtocol::TriggersElapsed() { 29Common::Input::DriverResult GenericProtocol::TriggersElapsed() {
29 ScopedSetBlocking sb(this); 30 ScopedSetBlocking sb(this);
30 return SendSubCommand(SubCommand::TRIGGERS_ELAPSED, {}); 31 return SendSubCommand(SubCommand::TRIGGERS_ELAPSED, {});
31} 32}
32 33
33DriverResult GenericProtocol::GetDeviceInfo(DeviceInfo& device_info) { 34Common::Input::DriverResult GenericProtocol::GetDeviceInfo(DeviceInfo& device_info) {
34 ScopedSetBlocking sb(this); 35 ScopedSetBlocking sb(this);
35 SubCommandResponse output{}; 36 SubCommandResponse output{};
36 37
37 const auto result = SendSubCommand(SubCommand::REQ_DEV_INFO, {}, output); 38 const auto result = SendSubCommand(SubCommand::REQ_DEV_INFO, {}, output);
38 39
39 device_info = {}; 40 device_info = {};
40 if (result == DriverResult::Success) { 41 if (result == Common::Input::DriverResult::Success) {
41 device_info = output.device_info; 42 device_info = output.device_info;
42 } 43 }
43 44
44 return result; 45 return result;
45} 46}
46 47
47DriverResult GenericProtocol::GetControllerType(ControllerType& controller_type) { 48Common::Input::DriverResult GenericProtocol::GetControllerType(ControllerType& controller_type) {
48 return GetDeviceType(controller_type); 49 return GetDeviceType(controller_type);
49} 50}
50 51
51DriverResult GenericProtocol::EnableImu(bool enable) { 52Common::Input::DriverResult GenericProtocol::EnableImu(bool enable) {
52 ScopedSetBlocking sb(this); 53 ScopedSetBlocking sb(this);
53 const std::array<u8, 1> buffer{static_cast<u8>(enable ? 1 : 0)}; 54 const std::array<u8, 1> buffer{static_cast<u8>(enable ? 1 : 0)};
54 return SendSubCommand(SubCommand::ENABLE_IMU, buffer); 55 return SendSubCommand(SubCommand::ENABLE_IMU, buffer);
55} 56}
56 57
57DriverResult GenericProtocol::SetImuConfig(GyroSensitivity gsen, GyroPerformance gfrec, 58Common::Input::DriverResult GenericProtocol::SetImuConfig(GyroSensitivity gsen,
58 AccelerometerSensitivity asen, 59 GyroPerformance gfrec,
59 AccelerometerPerformance afrec) { 60 AccelerometerSensitivity asen,
61 AccelerometerPerformance afrec) {
60 ScopedSetBlocking sb(this); 62 ScopedSetBlocking sb(this);
61 const std::array<u8, 4> buffer{static_cast<u8>(gsen), static_cast<u8>(asen), 63 const std::array<u8, 4> buffer{static_cast<u8>(gsen), static_cast<u8>(asen),
62 static_cast<u8>(gfrec), static_cast<u8>(afrec)}; 64 static_cast<u8>(gfrec), static_cast<u8>(afrec)};
63 return SendSubCommand(SubCommand::SET_IMU_SENSITIVITY, buffer); 65 return SendSubCommand(SubCommand::SET_IMU_SENSITIVITY, buffer);
64} 66}
65 67
66DriverResult GenericProtocol::GetBattery(u32& battery_level) { 68Common::Input::DriverResult GenericProtocol::GetBattery(u32& battery_level) {
67 // This function is meant to request the high resolution battery status 69 // This function is meant to request the high resolution battery status
68 battery_level = 0; 70 battery_level = 0;
69 return DriverResult::NotSupported; 71 return Common::Input::DriverResult::NotSupported;
70} 72}
71 73
72DriverResult GenericProtocol::GetColor(Color& color) { 74Common::Input::DriverResult GenericProtocol::GetColor(Color& color) {
73 ScopedSetBlocking sb(this); 75 ScopedSetBlocking sb(this);
74 std::array<u8, 12> buffer{}; 76 std::array<u8, 12> buffer{};
75 const auto result = ReadRawSPI(SpiAddress::COLOR_DATA, buffer); 77 const auto result = ReadRawSPI(SpiAddress::COLOR_DATA, buffer);
76 78
77 color = {}; 79 color = {};
78 if (result == DriverResult::Success) { 80 if (result == Common::Input::DriverResult::Success) {
79 color.body = static_cast<u32>((buffer[0] << 16) | (buffer[1] << 8) | buffer[2]); 81 color.body = static_cast<u32>((buffer[0] << 16) | (buffer[1] << 8) | buffer[2]);
80 color.buttons = static_cast<u32>((buffer[3] << 16) | (buffer[4] << 8) | buffer[5]); 82 color.buttons = static_cast<u32>((buffer[3] << 16) | (buffer[4] << 8) | buffer[5]);
81 color.left_grip = static_cast<u32>((buffer[6] << 16) | (buffer[7] << 8) | buffer[8]); 83 color.left_grip = static_cast<u32>((buffer[6] << 16) | (buffer[7] << 8) | buffer[8]);
@@ -85,26 +87,26 @@ DriverResult GenericProtocol::GetColor(Color& color) {
85 return result; 87 return result;
86} 88}
87 89
88DriverResult GenericProtocol::GetSerialNumber(SerialNumber& serial_number) { 90Common::Input::DriverResult GenericProtocol::GetSerialNumber(SerialNumber& serial_number) {
89 ScopedSetBlocking sb(this); 91 ScopedSetBlocking sb(this);
90 std::array<u8, 16> buffer{}; 92 std::array<u8, 16> buffer{};
91 const auto result = ReadRawSPI(SpiAddress::SERIAL_NUMBER, buffer); 93 const auto result = ReadRawSPI(SpiAddress::SERIAL_NUMBER, buffer);
92 94
93 serial_number = {}; 95 serial_number = {};
94 if (result == DriverResult::Success) { 96 if (result == Common::Input::DriverResult::Success) {
95 memcpy(serial_number.data(), buffer.data() + 1, sizeof(SerialNumber)); 97 memcpy(serial_number.data(), buffer.data() + 1, sizeof(SerialNumber));
96 } 98 }
97 99
98 return result; 100 return result;
99} 101}
100 102
101DriverResult GenericProtocol::GetTemperature(u32& temperature) { 103Common::Input::DriverResult GenericProtocol::GetTemperature(u32& temperature) {
102 // Not all devices have temperature sensor 104 // Not all devices have temperature sensor
103 temperature = 25; 105 temperature = 25;
104 return DriverResult::NotSupported; 106 return Common::Input::DriverResult::NotSupported;
105} 107}
106 108
107DriverResult GenericProtocol::GetVersionNumber(FirmwareVersion& version) { 109Common::Input::DriverResult GenericProtocol::GetVersionNumber(FirmwareVersion& version) {
108 DeviceInfo device_info{}; 110 DeviceInfo device_info{};
109 111
110 const auto result = GetDeviceInfo(device_info); 112 const auto result = GetDeviceInfo(device_info);
@@ -113,23 +115,23 @@ DriverResult GenericProtocol::GetVersionNumber(FirmwareVersion& version) {
113 return result; 115 return result;
114} 116}
115 117
116DriverResult GenericProtocol::SetHomeLight() { 118Common::Input::DriverResult GenericProtocol::SetHomeLight() {
117 ScopedSetBlocking sb(this); 119 ScopedSetBlocking sb(this);
118 static constexpr std::array<u8, 3> buffer{0x0f, 0xf0, 0x00}; 120 static constexpr std::array<u8, 3> buffer{0x0f, 0xf0, 0x00};
119 return SendSubCommand(SubCommand::SET_HOME_LIGHT, buffer); 121 return SendSubCommand(SubCommand::SET_HOME_LIGHT, buffer);
120} 122}
121 123
122DriverResult GenericProtocol::SetLedBusy() { 124Common::Input::DriverResult GenericProtocol::SetLedBusy() {
123 return DriverResult::NotSupported; 125 return Common::Input::DriverResult::NotSupported;
124} 126}
125 127
126DriverResult GenericProtocol::SetLedPattern(u8 leds) { 128Common::Input::DriverResult GenericProtocol::SetLedPattern(u8 leds) {
127 ScopedSetBlocking sb(this); 129 ScopedSetBlocking sb(this);
128 const std::array<u8, 1> buffer{leds}; 130 const std::array<u8, 1> buffer{leds};
129 return SendSubCommand(SubCommand::SET_PLAYER_LIGHTS, buffer); 131 return SendSubCommand(SubCommand::SET_PLAYER_LIGHTS, buffer);
130} 132}
131 133
132DriverResult GenericProtocol::SetLedBlinkPattern(u8 leds) { 134Common::Input::DriverResult GenericProtocol::SetLedBlinkPattern(u8 leds) {
133 return SetLedPattern(static_cast<u8>(leds << 4)); 135 return SetLedPattern(static_cast<u8>(leds << 4));
134} 136}
135 137
diff --git a/src/input_common/helpers/joycon_protocol/generic_functions.h b/src/input_common/helpers/joycon_protocol/generic_functions.h
index 424831e81..90fcd17f6 100644
--- a/src/input_common/helpers/joycon_protocol/generic_functions.h
+++ b/src/input_common/helpers/joycon_protocol/generic_functions.h
@@ -11,6 +11,10 @@
11#include "input_common/helpers/joycon_protocol/common_protocol.h" 11#include "input_common/helpers/joycon_protocol/common_protocol.h"
12#include "input_common/helpers/joycon_protocol/joycon_types.h" 12#include "input_common/helpers/joycon_protocol/joycon_types.h"
13 13
14namespace Common::Input {
15enum class DriverResult;
16}
17
14namespace InputCommon::Joycon { 18namespace InputCommon::Joycon {
15 19
16/// Joycon driver functions that easily implemented 20/// Joycon driver functions that easily implemented
@@ -20,34 +24,34 @@ public:
20 24
21 /// Enables passive mode. This mode only sends button data on change. Sticks will return digital 25 /// Enables passive mode. This mode only sends button data on change. Sticks will return digital
22 /// data instead of analog. Motion will be disabled 26 /// data instead of analog. Motion will be disabled
23 DriverResult EnablePassiveMode(); 27 Common::Input::DriverResult EnablePassiveMode();
24 28
25 /// Enables active mode. This mode will return the current status every 5-15ms 29 /// Enables active mode. This mode will return the current status every 5-15ms
26 DriverResult EnableActiveMode(); 30 Common::Input::DriverResult EnableActiveMode();
27 31
28 /// Enables or disables the low power mode 32 /// Enables or disables the low power mode
29 DriverResult SetLowPowerMode(bool enable); 33 Common::Input::DriverResult SetLowPowerMode(bool enable);
30 34
31 /// Unknown function used by the switch 35 /// Unknown function used by the switch
32 DriverResult TriggersElapsed(); 36 Common::Input::DriverResult TriggersElapsed();
33 37
34 /** 38 /**
35 * Sends a request to obtain the joycon firmware and mac from handle 39 * Sends a request to obtain the joycon firmware and mac from handle
36 * @returns controller device info 40 * @returns controller device info
37 */ 41 */
38 DriverResult GetDeviceInfo(DeviceInfo& controller_type); 42 Common::Input::DriverResult GetDeviceInfo(DeviceInfo& controller_type);
39 43
40 /** 44 /**
41 * Sends a request to obtain the joycon type from handle 45 * Sends a request to obtain the joycon type from handle
42 * @returns controller type of the joycon 46 * @returns controller type of the joycon
43 */ 47 */
44 DriverResult GetControllerType(ControllerType& controller_type); 48 Common::Input::DriverResult GetControllerType(ControllerType& controller_type);
45 49
46 /** 50 /**
47 * Enables motion input 51 * Enables motion input
48 * @param enable if true motion data will be enabled 52 * @param enable if true motion data will be enabled
49 */ 53 */
50 DriverResult EnableImu(bool enable); 54 Common::Input::DriverResult EnableImu(bool enable);
51 55
52 /** 56 /**
53 * Configures the motion sensor with the specified parameters 57 * Configures the motion sensor with the specified parameters
@@ -56,59 +60,60 @@ public:
56 * @param asen accelerometer sensitivity in G force 60 * @param asen accelerometer sensitivity in G force
57 * @param afrec accelerometer frequency in hertz 61 * @param afrec accelerometer frequency in hertz
58 */ 62 */
59 DriverResult SetImuConfig(GyroSensitivity gsen, GyroPerformance gfrec, 63 Common::Input::DriverResult SetImuConfig(GyroSensitivity gsen, GyroPerformance gfrec,
60 AccelerometerSensitivity asen, AccelerometerPerformance afrec); 64 AccelerometerSensitivity asen,
65 AccelerometerPerformance afrec);
61 66
62 /** 67 /**
63 * Request battery level from the device 68 * Request battery level from the device
64 * @returns battery level 69 * @returns battery level
65 */ 70 */
66 DriverResult GetBattery(u32& battery_level); 71 Common::Input::DriverResult GetBattery(u32& battery_level);
67 72
68 /** 73 /**
69 * Request joycon colors from the device 74 * Request joycon colors from the device
70 * @returns colors of the body and buttons 75 * @returns colors of the body and buttons
71 */ 76 */
72 DriverResult GetColor(Color& color); 77 Common::Input::DriverResult GetColor(Color& color);
73 78
74 /** 79 /**
75 * Request joycon serial number from the device 80 * Request joycon serial number from the device
76 * @returns 16 byte serial number 81 * @returns 16 byte serial number
77 */ 82 */
78 DriverResult GetSerialNumber(SerialNumber& serial_number); 83 Common::Input::DriverResult GetSerialNumber(SerialNumber& serial_number);
79 84
80 /** 85 /**
81 * Request joycon serial number from the device 86 * Request joycon serial number from the device
82 * @returns 16 byte serial number 87 * @returns 16 byte serial number
83 */ 88 */
84 DriverResult GetTemperature(u32& temperature); 89 Common::Input::DriverResult GetTemperature(u32& temperature);
85 90
86 /** 91 /**
87 * Request joycon serial number from the device 92 * Request joycon serial number from the device
88 * @returns 16 byte serial number 93 * @returns 16 byte serial number
89 */ 94 */
90 DriverResult GetVersionNumber(FirmwareVersion& version); 95 Common::Input::DriverResult GetVersionNumber(FirmwareVersion& version);
91 96
92 /** 97 /**
93 * Sets home led behaviour 98 * Sets home led behaviour
94 */ 99 */
95 DriverResult SetHomeLight(); 100 Common::Input::DriverResult SetHomeLight();
96 101
97 /** 102 /**
98 * Sets home led into a slow breathing state 103 * Sets home led into a slow breathing state
99 */ 104 */
100 DriverResult SetLedBusy(); 105 Common::Input::DriverResult SetLedBusy();
101 106
102 /** 107 /**
103 * Sets the 4 player leds on the joycon on a solid state 108 * Sets the 4 player leds on the joycon on a solid state
104 * @params bit flag containing the led state 109 * @params bit flag containing the led state
105 */ 110 */
106 DriverResult SetLedPattern(u8 leds); 111 Common::Input::DriverResult SetLedPattern(u8 leds);
107 112
108 /** 113 /**
109 * Sets the 4 player leds on the joycon on a blinking state 114 * Sets the 4 player leds on the joycon on a blinking state
110 * @returns bit flag containing the led state 115 * @returns bit flag containing the led state
111 */ 116 */
112 DriverResult SetLedBlinkPattern(u8 leds); 117 Common::Input::DriverResult SetLedBlinkPattern(u8 leds);
113}; 118};
114} // namespace InputCommon::Joycon 119} // namespace InputCommon::Joycon
diff --git a/src/input_common/helpers/joycon_protocol/irs.cpp b/src/input_common/helpers/joycon_protocol/irs.cpp
index 731fd5981..68b0589e3 100644
--- a/src/input_common/helpers/joycon_protocol/irs.cpp
+++ b/src/input_common/helpers/joycon_protocol/irs.cpp
@@ -1,7 +1,7 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include <thread> 4#include "common/input.h"
5#include "common/logging/log.h" 5#include "common/logging/log.h"
6#include "input_common/helpers/joycon_protocol/irs.h" 6#include "input_common/helpers/joycon_protocol/irs.h"
7 7
@@ -10,21 +10,21 @@ namespace InputCommon::Joycon {
10IrsProtocol::IrsProtocol(std::shared_ptr<JoyconHandle> handle) 10IrsProtocol::IrsProtocol(std::shared_ptr<JoyconHandle> handle)
11 : JoyconCommonProtocol(std::move(handle)) {} 11 : JoyconCommonProtocol(std::move(handle)) {}
12 12
13DriverResult IrsProtocol::EnableIrs() { 13Common::Input::DriverResult IrsProtocol::EnableIrs() {
14 LOG_INFO(Input, "Enable IRS"); 14 LOG_INFO(Input, "Enable IRS");
15 ScopedSetBlocking sb(this); 15 ScopedSetBlocking sb(this);
16 DriverResult result{DriverResult::Success}; 16 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
17 17
18 if (result == DriverResult::Success) { 18 if (result == Common::Input::DriverResult::Success) {
19 result = SetReportMode(ReportMode::NFC_IR_MODE_60HZ); 19 result = SetReportMode(ReportMode::NFC_IR_MODE_60HZ);
20 } 20 }
21 if (result == DriverResult::Success) { 21 if (result == Common::Input::DriverResult::Success) {
22 result = EnableMCU(true); 22 result = EnableMCU(true);
23 } 23 }
24 if (result == DriverResult::Success) { 24 if (result == Common::Input::DriverResult::Success) {
25 result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::Standby); 25 result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::Standby);
26 } 26 }
27 if (result == DriverResult::Success) { 27 if (result == Common::Input::DriverResult::Success) {
28 const MCUConfig config{ 28 const MCUConfig config{
29 .command = MCUCommand::ConfigureMCU, 29 .command = MCUCommand::ConfigureMCU,
30 .sub_command = MCUSubCommand::SetMCUMode, 30 .sub_command = MCUSubCommand::SetMCUMode,
@@ -34,16 +34,16 @@ DriverResult IrsProtocol::EnableIrs() {
34 34
35 result = ConfigureMCU(config); 35 result = ConfigureMCU(config);
36 } 36 }
37 if (result == DriverResult::Success) { 37 if (result == Common::Input::DriverResult::Success) {
38 result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::IR); 38 result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::IR);
39 } 39 }
40 if (result == DriverResult::Success) { 40 if (result == Common::Input::DriverResult::Success) {
41 result = ConfigureIrs(); 41 result = ConfigureIrs();
42 } 42 }
43 if (result == DriverResult::Success) { 43 if (result == Common::Input::DriverResult::Success) {
44 result = WriteRegistersStep1(); 44 result = WriteRegistersStep1();
45 } 45 }
46 if (result == DriverResult::Success) { 46 if (result == Common::Input::DriverResult::Success) {
47 result = WriteRegistersStep2(); 47 result = WriteRegistersStep2();
48 } 48 }
49 49
@@ -52,12 +52,12 @@ DriverResult IrsProtocol::EnableIrs() {
52 return result; 52 return result;
53} 53}
54 54
55DriverResult IrsProtocol::DisableIrs() { 55Common::Input::DriverResult IrsProtocol::DisableIrs() {
56 LOG_DEBUG(Input, "Disable IRS"); 56 LOG_DEBUG(Input, "Disable IRS");
57 ScopedSetBlocking sb(this); 57 ScopedSetBlocking sb(this);
58 DriverResult result{DriverResult::Success}; 58 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
59 59
60 if (result == DriverResult::Success) { 60 if (result == Common::Input::DriverResult::Success) {
61 result = EnableMCU(false); 61 result = EnableMCU(false);
62 } 62 }
63 63
@@ -66,7 +66,7 @@ DriverResult IrsProtocol::DisableIrs() {
66 return result; 66 return result;
67} 67}
68 68
69DriverResult IrsProtocol::SetIrsConfig(IrsMode mode, IrsResolution format) { 69Common::Input::DriverResult IrsProtocol::SetIrsConfig(IrsMode mode, IrsResolution format) {
70 irs_mode = mode; 70 irs_mode = mode;
71 switch (format) { 71 switch (format) {
72 case IrsResolution::Size320x240: 72 case IrsResolution::Size320x240:
@@ -103,10 +103,10 @@ DriverResult IrsProtocol::SetIrsConfig(IrsMode mode, IrsResolution format) {
103 return EnableIrs(); 103 return EnableIrs();
104 } 104 }
105 105
106 return DriverResult::Success; 106 return Common::Input::DriverResult::Success;
107} 107}
108 108
109DriverResult IrsProtocol::RequestImage(std::span<u8> buffer) { 109Common::Input::DriverResult IrsProtocol::RequestImage(std::span<u8> buffer) {
110 const u8 next_packet_fragment = 110 const u8 next_packet_fragment =
111 static_cast<u8>((packet_fragment + 1) % (static_cast<u8>(fragments) + 1)); 111 static_cast<u8>((packet_fragment + 1) % (static_cast<u8>(fragments) + 1));
112 112
@@ -129,7 +129,7 @@ DriverResult IrsProtocol::RequestImage(std::span<u8> buffer) {
129 return RequestFrame(packet_fragment); 129 return RequestFrame(packet_fragment);
130} 130}
131 131
132DriverResult IrsProtocol::ConfigureIrs() { 132Common::Input::DriverResult IrsProtocol::ConfigureIrs() {
133 LOG_DEBUG(Input, "Configure IRS"); 133 LOG_DEBUG(Input, "Configure IRS");
134 constexpr std::size_t max_tries = 28; 134 constexpr std::size_t max_tries = 28;
135 SubCommandResponse output{}; 135 SubCommandResponse output{};
@@ -152,20 +152,20 @@ DriverResult IrsProtocol::ConfigureIrs() {
152 do { 152 do {
153 const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, request_data, output); 153 const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, request_data, output);
154 154
155 if (result != DriverResult::Success) { 155 if (result != Common::Input::DriverResult::Success) {
156 return result; 156 return result;
157 } 157 }
158 if (tries++ >= max_tries) { 158 if (tries++ >= max_tries) {
159 return DriverResult::WrongReply; 159 return Common::Input::DriverResult::WrongReply;
160 } 160 }
161 } while (output.command_data[0] != 0x0b); 161 } while (output.command_data[0] != 0x0b);
162 162
163 return DriverResult::Success; 163 return Common::Input::DriverResult::Success;
164} 164}
165 165
166DriverResult IrsProtocol::WriteRegistersStep1() { 166Common::Input::DriverResult IrsProtocol::WriteRegistersStep1() {
167 LOG_DEBUG(Input, "WriteRegistersStep1"); 167 LOG_DEBUG(Input, "WriteRegistersStep1");
168 DriverResult result{DriverResult::Success}; 168 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
169 constexpr std::size_t max_tries = 28; 169 constexpr std::size_t max_tries = 28;
170 SubCommandResponse output{}; 170 SubCommandResponse output{};
171 std::size_t tries = 0; 171 std::size_t tries = 0;
@@ -197,7 +197,7 @@ DriverResult IrsProtocol::WriteRegistersStep1() {
197 mcu_request[36] = CalculateMCU_CRC8(mcu_request.data(), 36); 197 mcu_request[36] = CalculateMCU_CRC8(mcu_request.data(), 36);
198 mcu_request[37] = 0xFF; 198 mcu_request[37] = 0xFF;
199 199
200 if (result != DriverResult::Success) { 200 if (result != Common::Input::DriverResult::Success) {
201 return result; 201 return result;
202 } 202 }
203 203
@@ -205,26 +205,26 @@ DriverResult IrsProtocol::WriteRegistersStep1() {
205 result = SendSubCommand(SubCommand::SET_MCU_CONFIG, request_data, output); 205 result = SendSubCommand(SubCommand::SET_MCU_CONFIG, request_data, output);
206 206
207 // First time we need to set the report mode 207 // First time we need to set the report mode
208 if (result == DriverResult::Success && tries == 0) { 208 if (result == Common::Input::DriverResult::Success && tries == 0) {
209 result = SendMCUCommand(SubCommand::SET_REPORT_MODE, mcu_request); 209 result = SendMCUCommand(SubCommand::SET_REPORT_MODE, mcu_request);
210 } 210 }
211 if (result == DriverResult::Success && tries == 0) { 211 if (result == Common::Input::DriverResult::Success && tries == 0) {
212 GetSubCommandResponse(SubCommand::SET_MCU_CONFIG, output); 212 GetSubCommandResponse(SubCommand::SET_MCU_CONFIG, output);
213 } 213 }
214 214
215 if (result != DriverResult::Success) { 215 if (result != Common::Input::DriverResult::Success) {
216 return result; 216 return result;
217 } 217 }
218 if (tries++ >= max_tries) { 218 if (tries++ >= max_tries) {
219 return DriverResult::WrongReply; 219 return Common::Input::DriverResult::WrongReply;
220 } 220 }
221 } while (!(output.command_data[0] == 0x13 && output.command_data[2] == 0x07) && 221 } while (!(output.command_data[0] == 0x13 && output.command_data[2] == 0x07) &&
222 output.command_data[0] != 0x23); 222 output.command_data[0] != 0x23);
223 223
224 return DriverResult::Success; 224 return Common::Input::DriverResult::Success;
225} 225}
226 226
227DriverResult IrsProtocol::WriteRegistersStep2() { 227Common::Input::DriverResult IrsProtocol::WriteRegistersStep2() {
228 LOG_DEBUG(Input, "WriteRegistersStep2"); 228 LOG_DEBUG(Input, "WriteRegistersStep2");
229 constexpr std::size_t max_tries = 28; 229 constexpr std::size_t max_tries = 28;
230 SubCommandResponse output{}; 230 SubCommandResponse output{};
@@ -255,18 +255,18 @@ DriverResult IrsProtocol::WriteRegistersStep2() {
255 do { 255 do {
256 const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, request_data, output); 256 const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, request_data, output);
257 257
258 if (result != DriverResult::Success) { 258 if (result != Common::Input::DriverResult::Success) {
259 return result; 259 return result;
260 } 260 }
261 if (tries++ >= max_tries) { 261 if (tries++ >= max_tries) {
262 return DriverResult::WrongReply; 262 return Common::Input::DriverResult::WrongReply;
263 } 263 }
264 } while (output.command_data[0] != 0x13 && output.command_data[0] != 0x23); 264 } while (output.command_data[0] != 0x13 && output.command_data[0] != 0x23);
265 265
266 return DriverResult::Success; 266 return Common::Input::DriverResult::Success;
267} 267}
268 268
269DriverResult IrsProtocol::RequestFrame(u8 frame) { 269Common::Input::DriverResult IrsProtocol::RequestFrame(u8 frame) {
270 std::array<u8, 38> mcu_request{}; 270 std::array<u8, 38> mcu_request{};
271 mcu_request[3] = frame; 271 mcu_request[3] = frame;
272 mcu_request[36] = CalculateMCU_CRC8(mcu_request.data(), 36); 272 mcu_request[36] = CalculateMCU_CRC8(mcu_request.data(), 36);
@@ -274,7 +274,7 @@ DriverResult IrsProtocol::RequestFrame(u8 frame) {
274 return SendMCUCommand(SubCommand::SET_REPORT_MODE, mcu_request); 274 return SendMCUCommand(SubCommand::SET_REPORT_MODE, mcu_request);
275} 275}
276 276
277DriverResult IrsProtocol::ResendFrame(u8 frame) { 277Common::Input::DriverResult IrsProtocol::ResendFrame(u8 frame) {
278 std::array<u8, 38> mcu_request{}; 278 std::array<u8, 38> mcu_request{};
279 mcu_request[1] = 0x1; 279 mcu_request[1] = 0x1;
280 mcu_request[2] = frame; 280 mcu_request[2] = frame;
diff --git a/src/input_common/helpers/joycon_protocol/irs.h b/src/input_common/helpers/joycon_protocol/irs.h
index 76dfa02ea..714cbb6b2 100644
--- a/src/input_common/helpers/joycon_protocol/irs.h
+++ b/src/input_common/helpers/joycon_protocol/irs.h
@@ -13,19 +13,23 @@
13#include "input_common/helpers/joycon_protocol/common_protocol.h" 13#include "input_common/helpers/joycon_protocol/common_protocol.h"
14#include "input_common/helpers/joycon_protocol/joycon_types.h" 14#include "input_common/helpers/joycon_protocol/joycon_types.h"
15 15
16namespace Common::Input {
17enum class DriverResult;
18}
19
16namespace InputCommon::Joycon { 20namespace InputCommon::Joycon {
17 21
18class IrsProtocol final : private JoyconCommonProtocol { 22class IrsProtocol final : private JoyconCommonProtocol {
19public: 23public:
20 explicit IrsProtocol(std::shared_ptr<JoyconHandle> handle); 24 explicit IrsProtocol(std::shared_ptr<JoyconHandle> handle);
21 25
22 DriverResult EnableIrs(); 26 Common::Input::DriverResult EnableIrs();
23 27
24 DriverResult DisableIrs(); 28 Common::Input::DriverResult DisableIrs();
25 29
26 DriverResult SetIrsConfig(IrsMode mode, IrsResolution format); 30 Common::Input::DriverResult SetIrsConfig(IrsMode mode, IrsResolution format);
27 31
28 DriverResult RequestImage(std::span<u8> buffer); 32 Common::Input::DriverResult RequestImage(std::span<u8> buffer);
29 33
30 std::vector<u8> GetImage() const; 34 std::vector<u8> GetImage() const;
31 35
@@ -34,13 +38,13 @@ public:
34 bool IsEnabled() const; 38 bool IsEnabled() const;
35 39
36private: 40private:
37 DriverResult ConfigureIrs(); 41 Common::Input::DriverResult ConfigureIrs();
38 42
39 DriverResult WriteRegistersStep1(); 43 Common::Input::DriverResult WriteRegistersStep1();
40 DriverResult WriteRegistersStep2(); 44 Common::Input::DriverResult WriteRegistersStep2();
41 45
42 DriverResult RequestFrame(u8 frame); 46 Common::Input::DriverResult RequestFrame(u8 frame);
43 DriverResult ResendFrame(u8 frame); 47 Common::Input::DriverResult ResendFrame(u8 frame);
44 48
45 IrsMode irs_mode{IrsMode::ImageTransfer}; 49 IrsMode irs_mode{IrsMode::ImageTransfer};
46 IrsResolution resolution{IrsResolution::Size40x30}; 50 IrsResolution resolution{IrsResolution::Size40x30};
diff --git a/src/input_common/helpers/joycon_protocol/joycon_types.h b/src/input_common/helpers/joycon_protocol/joycon_types.h
index e0e431156..77a43c67a 100644
--- a/src/input_common/helpers/joycon_protocol/joycon_types.h
+++ b/src/input_common/helpers/joycon_protocol/joycon_types.h
@@ -402,23 +402,6 @@ enum class ExternalDeviceId : u16 {
402 Starlink = 0x2800, 402 Starlink = 0x2800,
403}; 403};
404 404
405enum class DriverResult {
406 Success,
407 WrongReply,
408 Timeout,
409 InvalidParameters,
410 UnsupportedControllerType,
411 HandleInUse,
412 ErrorReadingData,
413 ErrorWritingData,
414 NoDeviceDetected,
415 InvalidHandle,
416 NotSupported,
417 Disabled,
418 Delayed,
419 Unknown,
420};
421
422struct MotionSensorCalibration { 405struct MotionSensorCalibration {
423 s16 offset; 406 s16 offset;
424 s16 scale; 407 s16 scale;
diff --git a/src/input_common/helpers/joycon_protocol/nfc.cpp b/src/input_common/helpers/joycon_protocol/nfc.cpp
index 261f46255..09953394b 100644
--- a/src/input_common/helpers/joycon_protocol/nfc.cpp
+++ b/src/input_common/helpers/joycon_protocol/nfc.cpp
@@ -1,7 +1,7 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include <thread> 4#include "common/input.h"
5#include "common/logging/log.h" 5#include "common/logging/log.h"
6#include "input_common/helpers/joycon_protocol/nfc.h" 6#include "input_common/helpers/joycon_protocol/nfc.h"
7 7
@@ -10,21 +10,21 @@ namespace InputCommon::Joycon {
10NfcProtocol::NfcProtocol(std::shared_ptr<JoyconHandle> handle) 10NfcProtocol::NfcProtocol(std::shared_ptr<JoyconHandle> handle)
11 : JoyconCommonProtocol(std::move(handle)) {} 11 : JoyconCommonProtocol(std::move(handle)) {}
12 12
13DriverResult NfcProtocol::EnableNfc() { 13Common::Input::DriverResult NfcProtocol::EnableNfc() {
14 LOG_INFO(Input, "Enable NFC"); 14 LOG_INFO(Input, "Enable NFC");
15 ScopedSetBlocking sb(this); 15 ScopedSetBlocking sb(this);
16 DriverResult result{DriverResult::Success}; 16 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
17 17
18 if (result == DriverResult::Success) { 18 if (result == Common::Input::DriverResult::Success) {
19 result = SetReportMode(ReportMode::NFC_IR_MODE_60HZ); 19 result = SetReportMode(ReportMode::NFC_IR_MODE_60HZ);
20 } 20 }
21 if (result == DriverResult::Success) { 21 if (result == Common::Input::DriverResult::Success) {
22 result = EnableMCU(true); 22 result = EnableMCU(true);
23 } 23 }
24 if (result == DriverResult::Success) { 24 if (result == Common::Input::DriverResult::Success) {
25 result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::Standby); 25 result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::Standby);
26 } 26 }
27 if (result == DriverResult::Success) { 27 if (result == Common::Input::DriverResult::Success) {
28 const MCUConfig config{ 28 const MCUConfig config{
29 .command = MCUCommand::ConfigureMCU, 29 .command = MCUCommand::ConfigureMCU,
30 .sub_command = MCUSubCommand::SetMCUMode, 30 .sub_command = MCUSubCommand::SetMCUMode,
@@ -34,32 +34,32 @@ DriverResult NfcProtocol::EnableNfc() {
34 34
35 result = ConfigureMCU(config); 35 result = ConfigureMCU(config);
36 } 36 }
37 if (result == DriverResult::Success) { 37 if (result == Common::Input::DriverResult::Success) {
38 result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::NFC); 38 result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::NFC);
39 } 39 }
40 if (result == DriverResult::Success) { 40 if (result == Common::Input::DriverResult::Success) {
41 result = WaitUntilNfcIs(NFCStatus::Ready); 41 result = WaitUntilNfcIs(NFCStatus::Ready);
42 } 42 }
43 if (result == DriverResult::Success) { 43 if (result == Common::Input::DriverResult::Success) {
44 MCUCommandResponse output{}; 44 MCUCommandResponse output{};
45 result = SendStopPollingRequest(output); 45 result = SendStopPollingRequest(output);
46 } 46 }
47 if (result == DriverResult::Success) { 47 if (result == Common::Input::DriverResult::Success) {
48 result = WaitUntilNfcIs(NFCStatus::Ready); 48 result = WaitUntilNfcIs(NFCStatus::Ready);
49 } 49 }
50 if (result == DriverResult::Success) { 50 if (result == Common::Input::DriverResult::Success) {
51 is_enabled = true; 51 is_enabled = true;
52 } 52 }
53 53
54 return result; 54 return result;
55} 55}
56 56
57DriverResult NfcProtocol::DisableNfc() { 57Common::Input::DriverResult NfcProtocol::DisableNfc() {
58 LOG_DEBUG(Input, "Disable NFC"); 58 LOG_DEBUG(Input, "Disable NFC");
59 ScopedSetBlocking sb(this); 59 ScopedSetBlocking sb(this);
60 DriverResult result{DriverResult::Success}; 60 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
61 61
62 if (result == DriverResult::Success) { 62 if (result == Common::Input::DriverResult::Success) {
63 result = EnableMCU(false); 63 result = EnableMCU(false);
64 } 64 }
65 65
@@ -69,60 +69,60 @@ DriverResult NfcProtocol::DisableNfc() {
69 return result; 69 return result;
70} 70}
71 71
72DriverResult NfcProtocol::StartNFCPollingMode() { 72Common::Input::DriverResult NfcProtocol::StartNFCPollingMode() {
73 LOG_DEBUG(Input, "Start NFC polling Mode"); 73 LOG_DEBUG(Input, "Start NFC polling Mode");
74 ScopedSetBlocking sb(this); 74 ScopedSetBlocking sb(this);
75 DriverResult result{DriverResult::Success}; 75 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
76 76
77 if (result == DriverResult::Success) { 77 if (result == Common::Input::DriverResult::Success) {
78 MCUCommandResponse output{}; 78 MCUCommandResponse output{};
79 result = SendStartPollingRequest(output); 79 result = SendStartPollingRequest(output);
80 } 80 }
81 if (result == DriverResult::Success) { 81 if (result == Common::Input::DriverResult::Success) {
82 result = WaitUntilNfcIs(NFCStatus::Polling); 82 result = WaitUntilNfcIs(NFCStatus::Polling);
83 } 83 }
84 if (result == DriverResult::Success) { 84 if (result == Common::Input::DriverResult::Success) {
85 is_polling = true; 85 is_polling = true;
86 } 86 }
87 87
88 return result; 88 return result;
89} 89}
90 90
91DriverResult NfcProtocol::StopNFCPollingMode() { 91Common::Input::DriverResult NfcProtocol::StopNFCPollingMode() {
92 LOG_DEBUG(Input, "Stop NFC polling Mode"); 92 LOG_DEBUG(Input, "Stop NFC polling Mode");
93 ScopedSetBlocking sb(this); 93 ScopedSetBlocking sb(this);
94 DriverResult result{DriverResult::Success}; 94 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
95 95
96 if (result == DriverResult::Success) { 96 if (result == Common::Input::DriverResult::Success) {
97 MCUCommandResponse output{}; 97 MCUCommandResponse output{};
98 result = SendStopPollingRequest(output); 98 result = SendStopPollingRequest(output);
99 } 99 }
100 if (result == DriverResult::Success) { 100 if (result == Common::Input::DriverResult::Success) {
101 result = WaitUntilNfcIs(NFCStatus::WriteReady); 101 result = WaitUntilNfcIs(NFCStatus::WriteReady);
102 } 102 }
103 if (result == DriverResult::Success) { 103 if (result == Common::Input::DriverResult::Success) {
104 is_polling = false; 104 is_polling = false;
105 } 105 }
106 106
107 return result; 107 return result;
108} 108}
109 109
110DriverResult NfcProtocol::GetTagInfo(Joycon::TagInfo& tag_info) { 110Common::Input::DriverResult NfcProtocol::GetTagInfo(Joycon::TagInfo& tag_info) {
111 if (update_counter++ < AMIIBO_UPDATE_DELAY) { 111 if (update_counter++ < AMIIBO_UPDATE_DELAY) {
112 return DriverResult::Delayed; 112 return Common::Input::DriverResult::Delayed;
113 } 113 }
114 update_counter = 0; 114 update_counter = 0;
115 115
116 LOG_DEBUG(Input, "Scan for amiibos"); 116 LOG_DEBUG(Input, "Scan for amiibos");
117 ScopedSetBlocking sb(this); 117 ScopedSetBlocking sb(this);
118 DriverResult result{DriverResult::Success}; 118 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
119 TagFoundData tag_data{}; 119 TagFoundData tag_data{};
120 120
121 if (result == DriverResult::Success) { 121 if (result == Common::Input::DriverResult::Success) {
122 result = IsTagInRange(tag_data); 122 result = IsTagInRange(tag_data);
123 } 123 }
124 124
125 if (result == DriverResult::Success) { 125 if (result == Common::Input::DriverResult::Success) {
126 tag_info = { 126 tag_info = {
127 .uuid_length = tag_data.uuid_size, 127 .uuid_length = tag_data.uuid_size,
128 .protocol = 1, 128 .protocol = 1,
@@ -147,59 +147,59 @@ DriverResult NfcProtocol::GetTagInfo(Joycon::TagInfo& tag_info) {
147 return result; 147 return result;
148} 148}
149 149
150DriverResult NfcProtocol::ReadAmiibo(std::vector<u8>& data) { 150Common::Input::DriverResult NfcProtocol::ReadAmiibo(std::vector<u8>& data) {
151 LOG_DEBUG(Input, "Scan for amiibos"); 151 LOG_DEBUG(Input, "Scan for amiibos");
152 ScopedSetBlocking sb(this); 152 ScopedSetBlocking sb(this);
153 DriverResult result{DriverResult::Success}; 153 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
154 TagFoundData tag_data{}; 154 TagFoundData tag_data{};
155 155
156 if (result == DriverResult::Success) { 156 if (result == Common::Input::DriverResult::Success) {
157 result = IsTagInRange(tag_data, 7); 157 result = IsTagInRange(tag_data, 7);
158 } 158 }
159 159
160 if (result == DriverResult::Success) { 160 if (result == Common::Input::DriverResult::Success) {
161 result = GetAmiiboData(data); 161 result = GetAmiiboData(data);
162 } 162 }
163 163
164 return result; 164 return result;
165} 165}
166 166
167DriverResult NfcProtocol::WriteAmiibo(std::span<const u8> data) { 167Common::Input::DriverResult NfcProtocol::WriteAmiibo(std::span<const u8> data) {
168 LOG_DEBUG(Input, "Write amiibo"); 168 LOG_DEBUG(Input, "Write amiibo");
169 ScopedSetBlocking sb(this); 169 ScopedSetBlocking sb(this);
170 DriverResult result{DriverResult::Success}; 170 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
171 TagUUID tag_uuid = GetTagUUID(data); 171 TagUUID tag_uuid = GetTagUUID(data);
172 TagFoundData tag_data{}; 172 TagFoundData tag_data{};
173 173
174 if (result == DriverResult::Success) { 174 if (result == Common::Input::DriverResult::Success) {
175 result = IsTagInRange(tag_data, 7); 175 result = IsTagInRange(tag_data, 7);
176 } 176 }
177 if (result == DriverResult::Success) { 177 if (result == Common::Input::DriverResult::Success) {
178 if (tag_data.uuid != tag_uuid) { 178 if (tag_data.uuid != tag_uuid) {
179 result = DriverResult::InvalidParameters; 179 result = Common::Input::DriverResult::InvalidParameters;
180 } 180 }
181 } 181 }
182 if (result == DriverResult::Success) { 182 if (result == Common::Input::DriverResult::Success) {
183 MCUCommandResponse output{}; 183 MCUCommandResponse output{};
184 result = SendStopPollingRequest(output); 184 result = SendStopPollingRequest(output);
185 } 185 }
186 if (result == DriverResult::Success) { 186 if (result == Common::Input::DriverResult::Success) {
187 result = WaitUntilNfcIs(NFCStatus::Ready); 187 result = WaitUntilNfcIs(NFCStatus::Ready);
188 } 188 }
189 if (result == DriverResult::Success) { 189 if (result == Common::Input::DriverResult::Success) {
190 MCUCommandResponse output{}; 190 MCUCommandResponse output{};
191 result = SendStartPollingRequest(output, true); 191 result = SendStartPollingRequest(output, true);
192 } 192 }
193 if (result == DriverResult::Success) { 193 if (result == Common::Input::DriverResult::Success) {
194 result = WaitUntilNfcIs(NFCStatus::WriteReady); 194 result = WaitUntilNfcIs(NFCStatus::WriteReady);
195 } 195 }
196 if (result == DriverResult::Success) { 196 if (result == Common::Input::DriverResult::Success) {
197 result = WriteAmiiboData(tag_uuid, data); 197 result = WriteAmiiboData(tag_uuid, data);
198 } 198 }
199 if (result == DriverResult::Success) { 199 if (result == Common::Input::DriverResult::Success) {
200 result = WaitUntilNfcIs(NFCStatus::WriteDone); 200 result = WaitUntilNfcIs(NFCStatus::WriteDone);
201 } 201 }
202 if (result == DriverResult::Success) { 202 if (result == Common::Input::DriverResult::Success) {
203 MCUCommandResponse output{}; 203 MCUCommandResponse output{};
204 result = SendStopPollingRequest(output); 204 result = SendStopPollingRequest(output);
205 } 205 }
@@ -207,64 +207,65 @@ DriverResult NfcProtocol::WriteAmiibo(std::span<const u8> data) {
207 return result; 207 return result;
208} 208}
209 209
210DriverResult NfcProtocol::ReadMifare(std::span<const MifareReadChunk> read_request, 210Common::Input::DriverResult NfcProtocol::ReadMifare(std::span<const MifareReadChunk> read_request,
211 std::span<MifareReadData> out_data) { 211 std::span<MifareReadData> out_data) {
212 LOG_DEBUG(Input, "Read mifare"); 212 LOG_DEBUG(Input, "Read mifare");
213 ScopedSetBlocking sb(this); 213 ScopedSetBlocking sb(this);
214 DriverResult result{DriverResult::Success}; 214 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
215 TagFoundData tag_data{}; 215 TagFoundData tag_data{};
216 MifareUUID tag_uuid{}; 216 MifareUUID tag_uuid{};
217 217
218 if (result == DriverResult::Success) { 218 if (result == Common::Input::DriverResult::Success) {
219 result = IsTagInRange(tag_data, 7); 219 result = IsTagInRange(tag_data, 7);
220 } 220 }
221 if (result == DriverResult::Success) { 221 if (result == Common::Input::DriverResult::Success) {
222 memcpy(tag_uuid.data(), tag_data.uuid.data(), sizeof(MifareUUID)); 222 memcpy(tag_uuid.data(), tag_data.uuid.data(), sizeof(MifareUUID));
223 result = GetMifareData(tag_uuid, read_request, out_data); 223 result = GetMifareData(tag_uuid, read_request, out_data);
224 } 224 }
225 if (result == DriverResult::Success) { 225 if (result == Common::Input::DriverResult::Success) {
226 MCUCommandResponse output{}; 226 MCUCommandResponse output{};
227 result = SendStopPollingRequest(output); 227 result = SendStopPollingRequest(output);
228 } 228 }
229 if (result == DriverResult::Success) { 229 if (result == Common::Input::DriverResult::Success) {
230 result = WaitUntilNfcIs(NFCStatus::Ready); 230 result = WaitUntilNfcIs(NFCStatus::Ready);
231 } 231 }
232 if (result == DriverResult::Success) { 232 if (result == Common::Input::DriverResult::Success) {
233 MCUCommandResponse output{}; 233 MCUCommandResponse output{};
234 result = SendStartPollingRequest(output, true); 234 result = SendStartPollingRequest(output, true);
235 } 235 }
236 if (result == DriverResult::Success) { 236 if (result == Common::Input::DriverResult::Success) {
237 result = WaitUntilNfcIs(NFCStatus::WriteReady); 237 result = WaitUntilNfcIs(NFCStatus::WriteReady);
238 } 238 }
239 return result; 239 return result;
240} 240}
241 241
242DriverResult NfcProtocol::WriteMifare(std::span<const MifareWriteChunk> write_request) { 242Common::Input::DriverResult NfcProtocol::WriteMifare(
243 std::span<const MifareWriteChunk> write_request) {
243 LOG_DEBUG(Input, "Write mifare"); 244 LOG_DEBUG(Input, "Write mifare");
244 ScopedSetBlocking sb(this); 245 ScopedSetBlocking sb(this);
245 DriverResult result{DriverResult::Success}; 246 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
246 TagFoundData tag_data{}; 247 TagFoundData tag_data{};
247 MifareUUID tag_uuid{}; 248 MifareUUID tag_uuid{};
248 249
249 if (result == DriverResult::Success) { 250 if (result == Common::Input::DriverResult::Success) {
250 result = IsTagInRange(tag_data, 7); 251 result = IsTagInRange(tag_data, 7);
251 } 252 }
252 if (result == DriverResult::Success) { 253 if (result == Common::Input::DriverResult::Success) {
253 memcpy(tag_uuid.data(), tag_data.uuid.data(), sizeof(MifareUUID)); 254 memcpy(tag_uuid.data(), tag_data.uuid.data(), sizeof(MifareUUID));
254 result = WriteMifareData(tag_uuid, write_request); 255 result = WriteMifareData(tag_uuid, write_request);
255 } 256 }
256 if (result == DriverResult::Success) { 257 if (result == Common::Input::DriverResult::Success) {
257 MCUCommandResponse output{}; 258 MCUCommandResponse output{};
258 result = SendStopPollingRequest(output); 259 result = SendStopPollingRequest(output);
259 } 260 }
260 if (result == DriverResult::Success) { 261 if (result == Common::Input::DriverResult::Success) {
261 result = WaitUntilNfcIs(NFCStatus::Ready); 262 result = WaitUntilNfcIs(NFCStatus::Ready);
262 } 263 }
263 if (result == DriverResult::Success) { 264 if (result == Common::Input::DriverResult::Success) {
264 MCUCommandResponse output{}; 265 MCUCommandResponse output{};
265 result = SendStartPollingRequest(output, true); 266 result = SendStartPollingRequest(output, true);
266 } 267 }
267 if (result == DriverResult::Success) { 268 if (result == Common::Input::DriverResult::Success) {
268 result = WaitUntilNfcIs(NFCStatus::WriteReady); 269 result = WaitUntilNfcIs(NFCStatus::WriteReady);
269 } 270 }
270 return result; 271 return result;
@@ -277,17 +278,17 @@ bool NfcProtocol::HasAmiibo() {
277 update_counter = 0; 278 update_counter = 0;
278 279
279 ScopedSetBlocking sb(this); 280 ScopedSetBlocking sb(this);
280 DriverResult result{DriverResult::Success}; 281 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
281 TagFoundData tag_data{}; 282 TagFoundData tag_data{};
282 283
283 if (result == DriverResult::Success) { 284 if (result == Common::Input::DriverResult::Success) {
284 result = IsTagInRange(tag_data, 7); 285 result = IsTagInRange(tag_data, 7);
285 } 286 }
286 287
287 return result == DriverResult::Success; 288 return result == Common::Input::DriverResult::Success;
288} 289}
289 290
290DriverResult NfcProtocol::WaitUntilNfcIs(NFCStatus status) { 291Common::Input::DriverResult NfcProtocol::WaitUntilNfcIs(NFCStatus status) {
291 constexpr std::size_t timeout_limit = 10; 292 constexpr std::size_t timeout_limit = 10;
292 MCUCommandResponse output{}; 293 MCUCommandResponse output{};
293 std::size_t tries = 0; 294 std::size_t tries = 0;
@@ -295,30 +296,31 @@ DriverResult NfcProtocol::WaitUntilNfcIs(NFCStatus status) {
295 do { 296 do {
296 auto result = SendNextPackageRequest(output, {}); 297 auto result = SendNextPackageRequest(output, {});
297 298
298 if (result != DriverResult::Success) { 299 if (result != Common::Input::DriverResult::Success) {
299 return result; 300 return result;
300 } 301 }
301 if (tries++ > timeout_limit) { 302 if (tries++ > timeout_limit) {
302 return DriverResult::Timeout; 303 return Common::Input::DriverResult::Timeout;
303 } 304 }
304 } while (output.mcu_report != MCUReport::NFCState || 305 } while (output.mcu_report != MCUReport::NFCState ||
305 (output.mcu_data[1] << 8) + output.mcu_data[0] != 0x0500 || 306 (output.mcu_data[1] << 8) + output.mcu_data[0] != 0x0500 ||
306 output.mcu_data[5] != 0x31 || output.mcu_data[6] != static_cast<u8>(status)); 307 output.mcu_data[5] != 0x31 || output.mcu_data[6] != static_cast<u8>(status));
307 308
308 return DriverResult::Success; 309 return Common::Input::DriverResult::Success;
309} 310}
310 311
311DriverResult NfcProtocol::IsTagInRange(TagFoundData& data, std::size_t timeout_limit) { 312Common::Input::DriverResult NfcProtocol::IsTagInRange(TagFoundData& data,
313 std::size_t timeout_limit) {
312 MCUCommandResponse output{}; 314 MCUCommandResponse output{};
313 std::size_t tries = 0; 315 std::size_t tries = 0;
314 316
315 do { 317 do {
316 const auto result = SendNextPackageRequest(output, {}); 318 const auto result = SendNextPackageRequest(output, {});
317 if (result != DriverResult::Success) { 319 if (result != Common::Input::DriverResult::Success) {
318 return result; 320 return result;
319 } 321 }
320 if (tries++ > timeout_limit) { 322 if (tries++ > timeout_limit) {
321 return DriverResult::Timeout; 323 return Common::Input::DriverResult::Timeout;
322 } 324 }
323 } while (output.mcu_report != MCUReport::NFCState || 325 } while (output.mcu_report != MCUReport::NFCState ||
324 (output.mcu_data[1] << 8) + output.mcu_data[0] != 0x0500 || 326 (output.mcu_data[1] << 8) + output.mcu_data[0] != 0x0500 ||
@@ -328,10 +330,10 @@ DriverResult NfcProtocol::IsTagInRange(TagFoundData& data, std::size_t timeout_l
328 data.uuid_size = std::min(output.mcu_data[14], static_cast<u8>(sizeof(TagUUID))); 330 data.uuid_size = std::min(output.mcu_data[14], static_cast<u8>(sizeof(TagUUID)));
329 memcpy(data.uuid.data(), output.mcu_data.data() + 15, data.uuid.size()); 331 memcpy(data.uuid.data(), output.mcu_data.data() + 15, data.uuid.size());
330 332
331 return DriverResult::Success; 333 return Common::Input::DriverResult::Success;
332} 334}
333 335
334DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) { 336Common::Input::DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) {
335 constexpr std::size_t timeout_limit = 60; 337 constexpr std::size_t timeout_limit = 60;
336 MCUCommandResponse output{}; 338 MCUCommandResponse output{};
337 std::size_t tries = 0; 339 std::size_t tries = 0;
@@ -340,7 +342,7 @@ DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) {
340 std::size_t ntag_buffer_pos = 0; 342 std::size_t ntag_buffer_pos = 0;
341 auto result = SendReadAmiiboRequest(output, NFCPages::Block135); 343 auto result = SendReadAmiiboRequest(output, NFCPages::Block135);
342 344
343 if (result != DriverResult::Success) { 345 if (result != Common::Input::DriverResult::Success) {
344 return result; 346 return result;
345 } 347 }
346 348
@@ -349,14 +351,14 @@ DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) {
349 result = SendNextPackageRequest(output, package_index); 351 result = SendNextPackageRequest(output, package_index);
350 const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]); 352 const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]);
351 353
352 if (result != DriverResult::Success) { 354 if (result != Common::Input::DriverResult::Success) {
353 return result; 355 return result;
354 } 356 }
355 357
356 if ((output.mcu_report == MCUReport::NFCReadData || 358 if ((output.mcu_report == MCUReport::NFCReadData ||
357 output.mcu_report == MCUReport::NFCState) && 359 output.mcu_report == MCUReport::NFCState) &&
358 nfc_status == NFCStatus::TagLost) { 360 nfc_status == NFCStatus::TagLost) {
359 return DriverResult::ErrorReadingData; 361 return Common::Input::DriverResult::ErrorReadingData;
360 } 362 }
361 363
362 if (output.mcu_report == MCUReport::NFCReadData && output.mcu_data[1] == 0x07) { 364 if (output.mcu_report == MCUReport::NFCReadData && output.mcu_data[1] == 0x07) {
@@ -375,14 +377,15 @@ DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) {
375 377
376 if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::LastPackage) { 378 if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::LastPackage) {
377 LOG_INFO(Input, "Finished reading amiibo"); 379 LOG_INFO(Input, "Finished reading amiibo");
378 return DriverResult::Success; 380 return Common::Input::DriverResult::Success;
379 } 381 }
380 } 382 }
381 383
382 return DriverResult::Timeout; 384 return Common::Input::DriverResult::Timeout;
383} 385}
384 386
385DriverResult NfcProtocol::WriteAmiiboData(const TagUUID& tag_uuid, std::span<const u8> data) { 387Common::Input::DriverResult NfcProtocol::WriteAmiiboData(const TagUUID& tag_uuid,
388 std::span<const u8> data) {
386 constexpr std::size_t timeout_limit = 60; 389 constexpr std::size_t timeout_limit = 60;
387 const auto nfc_data = MakeAmiiboWritePackage(tag_uuid, data); 390 const auto nfc_data = MakeAmiiboWritePackage(tag_uuid, data);
388 const std::vector<u8> nfc_buffer_data = SerializeWritePackage(nfc_data); 391 const std::vector<u8> nfc_buffer_data = SerializeWritePackage(nfc_data);
@@ -397,7 +400,7 @@ DriverResult NfcProtocol::WriteAmiiboData(const TagUUID& tag_uuid, std::span<con
397 400
398 auto result = SendWriteAmiiboRequest(output, tag_uuid); 401 auto result = SendWriteAmiiboRequest(output, tag_uuid);
399 402
400 if (result != DriverResult::Success) { 403 if (result != Common::Input::DriverResult::Success) {
401 return result; 404 return result;
402 } 405 }
403 406
@@ -406,14 +409,14 @@ DriverResult NfcProtocol::WriteAmiiboData(const TagUUID& tag_uuid, std::span<con
406 result = SendNextPackageRequest(output, package_index); 409 result = SendNextPackageRequest(output, package_index);
407 const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]); 410 const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]);
408 411
409 if (result != DriverResult::Success) { 412 if (result != Common::Input::DriverResult::Success) {
410 return result; 413 return result;
411 } 414 }
412 415
413 if ((output.mcu_report == MCUReport::NFCReadData || 416 if ((output.mcu_report == MCUReport::NFCReadData ||
414 output.mcu_report == MCUReport::NFCState) && 417 output.mcu_report == MCUReport::NFCState) &&
415 nfc_status == NFCStatus::TagLost) { 418 nfc_status == NFCStatus::TagLost) {
416 return DriverResult::ErrorReadingData; 419 return Common::Input::DriverResult::ErrorReadingData;
417 } 420 }
418 421
419 if (output.mcu_report == MCUReport::NFCReadData && output.mcu_data[1] == 0x07) { 422 if (output.mcu_report == MCUReport::NFCReadData && output.mcu_data[1] == 0x07) {
@@ -442,7 +445,7 @@ DriverResult NfcProtocol::WriteAmiiboData(const TagUUID& tag_uuid, std::span<con
442 if ((output.mcu_report == MCUReport::NFCReadData || 445 if ((output.mcu_report == MCUReport::NFCReadData ||
443 output.mcu_report == MCUReport::NFCState) && 446 output.mcu_report == MCUReport::NFCState) &&
444 nfc_status == NFCStatus::TagLost) { 447 nfc_status == NFCStatus::TagLost) {
445 return DriverResult::ErrorReadingData; 448 return Common::Input::DriverResult::ErrorReadingData;
446 } 449 }
447 450
448 // Increase position when data is confirmed by the joycon 451 // Increase position when data is confirmed by the joycon
@@ -457,14 +460,14 @@ DriverResult NfcProtocol::WriteAmiiboData(const TagUUID& tag_uuid, std::span<con
457 return result; 460 return result;
458} 461}
459 462
460DriverResult NfcProtocol::GetMifareData(const MifareUUID& tag_uuid, 463Common::Input::DriverResult NfcProtocol::GetMifareData(
461 std::span<const MifareReadChunk> read_request, 464 const MifareUUID& tag_uuid, std::span<const MifareReadChunk> read_request,
462 std::span<MifareReadData> out_data) { 465 std::span<MifareReadData> out_data) {
463 constexpr std::size_t timeout_limit = 60; 466 constexpr std::size_t timeout_limit = 60;
464 const auto nfc_data = MakeMifareReadPackage(tag_uuid, read_request); 467 const auto nfc_data = MakeMifareReadPackage(tag_uuid, read_request);
465 const std::vector<u8> nfc_buffer_data = SerializeMifareReadPackage(nfc_data); 468 const std::vector<u8> nfc_buffer_data = SerializeMifareReadPackage(nfc_data);
466 std::span<const u8> buffer(nfc_buffer_data); 469 std::span<const u8> buffer(nfc_buffer_data);
467 DriverResult result = DriverResult::Success; 470 Common::Input::DriverResult result = Common::Input::DriverResult::Success;
468 MCUCommandResponse output{}; 471 MCUCommandResponse output{};
469 u8 block_id = 1; 472 u8 block_id = 1;
470 u8 package_index = 0; 473 u8 package_index = 0;
@@ -486,7 +489,7 @@ DriverResult NfcProtocol::GetMifareData(const MifareUUID& tag_uuid,
486 const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]); 489 const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]);
487 490
488 if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) { 491 if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) {
489 return DriverResult::ErrorReadingData; 492 return Common::Input::DriverResult::ErrorReadingData;
490 } 493 }
491 494
492 // Increase position when data is confirmed by the joycon 495 // Increase position when data is confirmed by the joycon
@@ -498,7 +501,7 @@ DriverResult NfcProtocol::GetMifareData(const MifareUUID& tag_uuid,
498 } 501 }
499 } 502 }
500 503
501 if (result != DriverResult::Success) { 504 if (result != Common::Input::DriverResult::Success) {
502 return result; 505 return result;
503 } 506 }
504 507
@@ -507,12 +510,12 @@ DriverResult NfcProtocol::GetMifareData(const MifareUUID& tag_uuid,
507 result = SendNextPackageRequest(output, package_index); 510 result = SendNextPackageRequest(output, package_index);
508 const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]); 511 const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]);
509 512
510 if (result != DriverResult::Success) { 513 if (result != Common::Input::DriverResult::Success) {
511 return result; 514 return result;
512 } 515 }
513 516
514 if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) { 517 if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) {
515 return DriverResult::ErrorReadingData; 518 return Common::Input::DriverResult::ErrorReadingData;
516 } 519 }
517 520
518 if (output.mcu_report == MCUReport::NFCState && output.mcu_data[1] == 0x10) { 521 if (output.mcu_report == MCUReport::NFCState && output.mcu_data[1] == 0x10) {
@@ -538,13 +541,13 @@ DriverResult NfcProtocol::GetMifareData(const MifareUUID& tag_uuid,
538 return result; 541 return result;
539} 542}
540 543
541DriverResult NfcProtocol::WriteMifareData(const MifareUUID& tag_uuid, 544Common::Input::DriverResult NfcProtocol::WriteMifareData(
542 std::span<const MifareWriteChunk> write_request) { 545 const MifareUUID& tag_uuid, std::span<const MifareWriteChunk> write_request) {
543 constexpr std::size_t timeout_limit = 60; 546 constexpr std::size_t timeout_limit = 60;
544 const auto nfc_data = MakeMifareWritePackage(tag_uuid, write_request); 547 const auto nfc_data = MakeMifareWritePackage(tag_uuid, write_request);
545 const std::vector<u8> nfc_buffer_data = SerializeMifareWritePackage(nfc_data); 548 const std::vector<u8> nfc_buffer_data = SerializeMifareWritePackage(nfc_data);
546 std::span<const u8> buffer(nfc_buffer_data); 549 std::span<const u8> buffer(nfc_buffer_data);
547 DriverResult result = DriverResult::Success; 550 Common::Input::DriverResult result = Common::Input::DriverResult::Success;
548 MCUCommandResponse output{}; 551 MCUCommandResponse output{};
549 u8 block_id = 1; 552 u8 block_id = 1;
550 u8 package_index = 0; 553 u8 package_index = 0;
@@ -566,7 +569,7 @@ DriverResult NfcProtocol::WriteMifareData(const MifareUUID& tag_uuid,
566 const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]); 569 const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]);
567 570
568 if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) { 571 if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) {
569 return DriverResult::ErrorReadingData; 572 return Common::Input::DriverResult::ErrorReadingData;
570 } 573 }
571 574
572 // Increase position when data is confirmed by the joycon 575 // Increase position when data is confirmed by the joycon
@@ -578,7 +581,7 @@ DriverResult NfcProtocol::WriteMifareData(const MifareUUID& tag_uuid,
578 } 581 }
579 } 582 }
580 583
581 if (result != DriverResult::Success) { 584 if (result != Common::Input::DriverResult::Success) {
582 return result; 585 return result;
583 } 586 }
584 587
@@ -587,12 +590,12 @@ DriverResult NfcProtocol::WriteMifareData(const MifareUUID& tag_uuid,
587 result = SendNextPackageRequest(output, package_index); 590 result = SendNextPackageRequest(output, package_index);
588 const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]); 591 const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]);
589 592
590 if (result != DriverResult::Success) { 593 if (result != Common::Input::DriverResult::Success) {
591 return result; 594 return result;
592 } 595 }
593 596
594 if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) { 597 if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) {
595 return DriverResult::ErrorReadingData; 598 return Common::Input::DriverResult::ErrorReadingData;
596 } 599 }
597 600
598 if (output.mcu_report == MCUReport::NFCState && output.mcu_data[1] == 0x10) { 601 if (output.mcu_report == MCUReport::NFCState && output.mcu_data[1] == 0x10) {
@@ -609,8 +612,8 @@ DriverResult NfcProtocol::WriteMifareData(const MifareUUID& tag_uuid,
609 return result; 612 return result;
610} 613}
611 614
612DriverResult NfcProtocol::SendStartPollingRequest(MCUCommandResponse& output, 615Common::Input::DriverResult NfcProtocol::SendStartPollingRequest(MCUCommandResponse& output,
613 bool is_second_attempt) { 616 bool is_second_attempt) {
614 NFCRequestState request{ 617 NFCRequestState request{
615 .command_argument = NFCCommand::StartPolling, 618 .command_argument = NFCCommand::StartPolling,
616 .block_id = {}, 619 .block_id = {},
@@ -635,7 +638,7 @@ DriverResult NfcProtocol::SendStartPollingRequest(MCUCommandResponse& output,
635 output); 638 output);
636} 639}
637 640
638DriverResult NfcProtocol::SendStopPollingRequest(MCUCommandResponse& output) { 641Common::Input::DriverResult NfcProtocol::SendStopPollingRequest(MCUCommandResponse& output) {
639 NFCRequestState request{ 642 NFCRequestState request{
640 .command_argument = NFCCommand::StopPolling, 643 .command_argument = NFCCommand::StopPolling,
641 .block_id = {}, 644 .block_id = {},
@@ -653,7 +656,8 @@ DriverResult NfcProtocol::SendStopPollingRequest(MCUCommandResponse& output) {
653 output); 656 output);
654} 657}
655 658
656DriverResult NfcProtocol::SendNextPackageRequest(MCUCommandResponse& output, u8 packet_id) { 659Common::Input::DriverResult NfcProtocol::SendNextPackageRequest(MCUCommandResponse& output,
660 u8 packet_id) {
657 NFCRequestState request{ 661 NFCRequestState request{
658 .command_argument = NFCCommand::StartWaitingRecieve, 662 .command_argument = NFCCommand::StartWaitingRecieve,
659 .block_id = {}, 663 .block_id = {},
@@ -671,7 +675,8 @@ DriverResult NfcProtocol::SendNextPackageRequest(MCUCommandResponse& output, u8
671 output); 675 output);
672} 676}
673 677
674DriverResult NfcProtocol::SendReadAmiiboRequest(MCUCommandResponse& output, NFCPages ntag_pages) { 678Common::Input::DriverResult NfcProtocol::SendReadAmiiboRequest(MCUCommandResponse& output,
679 NFCPages ntag_pages) {
675 NFCRequestState request{ 680 NFCRequestState request{
676 .command_argument = NFCCommand::ReadNtag, 681 .command_argument = NFCCommand::ReadNtag,
677 .block_id = {}, 682 .block_id = {},
@@ -696,8 +701,8 @@ DriverResult NfcProtocol::SendReadAmiiboRequest(MCUCommandResponse& output, NFCP
696 output); 701 output);
697} 702}
698 703
699DriverResult NfcProtocol::SendWriteAmiiboRequest(MCUCommandResponse& output, 704Common::Input::DriverResult NfcProtocol::SendWriteAmiiboRequest(MCUCommandResponse& output,
700 const TagUUID& tag_uuid) { 705 const TagUUID& tag_uuid) {
701 NFCRequestState request{ 706 NFCRequestState request{
702 .command_argument = NFCCommand::ReadNtag, 707 .command_argument = NFCCommand::ReadNtag,
703 .block_id = {}, 708 .block_id = {},
@@ -722,9 +727,10 @@ DriverResult NfcProtocol::SendWriteAmiiboRequest(MCUCommandResponse& output,
722 output); 727 output);
723} 728}
724 729
725DriverResult NfcProtocol::SendWriteDataAmiiboRequest(MCUCommandResponse& output, u8 block_id, 730Common::Input::DriverResult NfcProtocol::SendWriteDataAmiiboRequest(MCUCommandResponse& output,
726 bool is_last_packet, 731 u8 block_id,
727 std::span<const u8> data) { 732 bool is_last_packet,
733 std::span<const u8> data) {
728 const auto data_size = std::min(data.size(), sizeof(NFCRequestState::raw_data)); 734 const auto data_size = std::min(data.size(), sizeof(NFCRequestState::raw_data));
729 NFCRequestState request{ 735 NFCRequestState request{
730 .command_argument = NFCCommand::WriteNtag, 736 .command_argument = NFCCommand::WriteNtag,
@@ -745,8 +751,9 @@ DriverResult NfcProtocol::SendWriteDataAmiiboRequest(MCUCommandResponse& output,
745 output); 751 output);
746} 752}
747 753
748DriverResult NfcProtocol::SendReadDataMifareRequest(MCUCommandResponse& output, u8 block_id, 754Common::Input::DriverResult NfcProtocol::SendReadDataMifareRequest(MCUCommandResponse& output,
749 bool is_last_packet, std::span<const u8> data) { 755 u8 block_id, bool is_last_packet,
756 std::span<const u8> data) {
750 const auto data_size = std::min(data.size(), sizeof(NFCRequestState::raw_data)); 757 const auto data_size = std::min(data.size(), sizeof(NFCRequestState::raw_data));
751 NFCRequestState request{ 758 NFCRequestState request{
752 .command_argument = NFCCommand::Mifare, 759 .command_argument = NFCCommand::Mifare,
diff --git a/src/input_common/helpers/joycon_protocol/nfc.h b/src/input_common/helpers/joycon_protocol/nfc.h
index 0be95e40e..22db95170 100644
--- a/src/input_common/helpers/joycon_protocol/nfc.h
+++ b/src/input_common/helpers/joycon_protocol/nfc.h
@@ -13,30 +13,34 @@
13#include "input_common/helpers/joycon_protocol/common_protocol.h" 13#include "input_common/helpers/joycon_protocol/common_protocol.h"
14#include "input_common/helpers/joycon_protocol/joycon_types.h" 14#include "input_common/helpers/joycon_protocol/joycon_types.h"
15 15
16namespace Common::Input {
17enum class DriverResult;
18}
19
16namespace InputCommon::Joycon { 20namespace InputCommon::Joycon {
17 21
18class NfcProtocol final : private JoyconCommonProtocol { 22class NfcProtocol final : private JoyconCommonProtocol {
19public: 23public:
20 explicit NfcProtocol(std::shared_ptr<JoyconHandle> handle); 24 explicit NfcProtocol(std::shared_ptr<JoyconHandle> handle);
21 25
22 DriverResult EnableNfc(); 26 Common::Input::DriverResult EnableNfc();
23 27
24 DriverResult DisableNfc(); 28 Common::Input::DriverResult DisableNfc();
25 29
26 DriverResult StartNFCPollingMode(); 30 Common::Input::DriverResult StartNFCPollingMode();
27 31
28 DriverResult StopNFCPollingMode(); 32 Common::Input::DriverResult StopNFCPollingMode();
29 33
30 DriverResult GetTagInfo(Joycon::TagInfo& tag_info); 34 Common::Input::DriverResult GetTagInfo(Joycon::TagInfo& tag_info);
31 35
32 DriverResult ReadAmiibo(std::vector<u8>& data); 36 Common::Input::DriverResult ReadAmiibo(std::vector<u8>& data);
33 37
34 DriverResult WriteAmiibo(std::span<const u8> data); 38 Common::Input::DriverResult WriteAmiibo(std::span<const u8> data);
35 39
36 DriverResult ReadMifare(std::span<const MifareReadChunk> read_request, 40 Common::Input::DriverResult ReadMifare(std::span<const MifareReadChunk> read_request,
37 std::span<MifareReadData> out_data); 41 std::span<MifareReadData> out_data);
38 42
39 DriverResult WriteMifare(std::span<const MifareWriteChunk> write_request); 43 Common::Input::DriverResult WriteMifare(std::span<const MifareWriteChunk> write_request);
40 44
41 bool HasAmiibo(); 45 bool HasAmiibo();
42 46
@@ -54,37 +58,41 @@ private:
54 TagUUID uuid; 58 TagUUID uuid;
55 }; 59 };
56 60
57 DriverResult WaitUntilNfcIs(NFCStatus status); 61 Common::Input::DriverResult WaitUntilNfcIs(NFCStatus status);
58 62
59 DriverResult IsTagInRange(TagFoundData& data, std::size_t timeout_limit = 1); 63 Common::Input::DriverResult IsTagInRange(TagFoundData& data, std::size_t timeout_limit = 1);
60 64
61 DriverResult GetAmiiboData(std::vector<u8>& data); 65 Common::Input::DriverResult GetAmiiboData(std::vector<u8>& data);
62 66
63 DriverResult WriteAmiiboData(const TagUUID& tag_uuid, std::span<const u8> data); 67 Common::Input::DriverResult WriteAmiiboData(const TagUUID& tag_uuid, std::span<const u8> data);
64 68
65 DriverResult GetMifareData(const MifareUUID& tag_uuid, 69 Common::Input::DriverResult GetMifareData(const MifareUUID& tag_uuid,
66 std::span<const MifareReadChunk> read_request, 70 std::span<const MifareReadChunk> read_request,
67 std::span<MifareReadData> out_data); 71 std::span<MifareReadData> out_data);
68 72
69 DriverResult WriteMifareData(const MifareUUID& tag_uuid, 73 Common::Input::DriverResult WriteMifareData(const MifareUUID& tag_uuid,
70 std::span<const MifareWriteChunk> write_request); 74 std::span<const MifareWriteChunk> write_request);
71 75
72 DriverResult SendStartPollingRequest(MCUCommandResponse& output, 76 Common::Input::DriverResult SendStartPollingRequest(MCUCommandResponse& output,
73 bool is_second_attempt = false); 77 bool is_second_attempt = false);
74 78
75 DriverResult SendStopPollingRequest(MCUCommandResponse& output); 79 Common::Input::DriverResult SendStopPollingRequest(MCUCommandResponse& output);
76 80
77 DriverResult SendNextPackageRequest(MCUCommandResponse& output, u8 packet_id); 81 Common::Input::DriverResult SendNextPackageRequest(MCUCommandResponse& output, u8 packet_id);
78 82
79 DriverResult SendReadAmiiboRequest(MCUCommandResponse& output, NFCPages ntag_pages); 83 Common::Input::DriverResult SendReadAmiiboRequest(MCUCommandResponse& output,
84 NFCPages ntag_pages);
80 85
81 DriverResult SendWriteAmiiboRequest(MCUCommandResponse& output, const TagUUID& tag_uuid); 86 Common::Input::DriverResult SendWriteAmiiboRequest(MCUCommandResponse& output,
87 const TagUUID& tag_uuid);
82 88
83 DriverResult SendWriteDataAmiiboRequest(MCUCommandResponse& output, u8 block_id, 89 Common::Input::DriverResult SendWriteDataAmiiboRequest(MCUCommandResponse& output, u8 block_id,
84 bool is_last_packet, std::span<const u8> data); 90 bool is_last_packet,
91 std::span<const u8> data);
85 92
86 DriverResult SendReadDataMifareRequest(MCUCommandResponse& output, u8 block_id, 93 Common::Input::DriverResult SendReadDataMifareRequest(MCUCommandResponse& output, u8 block_id,
87 bool is_last_packet, std::span<const u8> data); 94 bool is_last_packet,
95 std::span<const u8> data);
88 96
89 std::vector<u8> SerializeWritePackage(const NFCWritePackage& package) const; 97 std::vector<u8> SerializeWritePackage(const NFCWritePackage& package) const;
90 98
diff --git a/src/input_common/helpers/joycon_protocol/ringcon.cpp b/src/input_common/helpers/joycon_protocol/ringcon.cpp
index 190cef812..96414fb67 100644
--- a/src/input_common/helpers/joycon_protocol/ringcon.cpp
+++ b/src/input_common/helpers/joycon_protocol/ringcon.cpp
@@ -1,6 +1,7 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "common/input.h"
4#include "common/logging/log.h" 5#include "common/logging/log.h"
5#include "input_common/helpers/joycon_protocol/ringcon.h" 6#include "input_common/helpers/joycon_protocol/ringcon.h"
6 7
@@ -9,18 +10,18 @@ namespace InputCommon::Joycon {
9RingConProtocol::RingConProtocol(std::shared_ptr<JoyconHandle> handle) 10RingConProtocol::RingConProtocol(std::shared_ptr<JoyconHandle> handle)
10 : JoyconCommonProtocol(std::move(handle)) {} 11 : JoyconCommonProtocol(std::move(handle)) {}
11 12
12DriverResult RingConProtocol::EnableRingCon() { 13Common::Input::DriverResult RingConProtocol::EnableRingCon() {
13 LOG_DEBUG(Input, "Enable Ringcon"); 14 LOG_DEBUG(Input, "Enable Ringcon");
14 ScopedSetBlocking sb(this); 15 ScopedSetBlocking sb(this);
15 DriverResult result{DriverResult::Success}; 16 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
16 17
17 if (result == DriverResult::Success) { 18 if (result == Common::Input::DriverResult::Success) {
18 result = SetReportMode(ReportMode::STANDARD_FULL_60HZ); 19 result = SetReportMode(ReportMode::STANDARD_FULL_60HZ);
19 } 20 }
20 if (result == DriverResult::Success) { 21 if (result == Common::Input::DriverResult::Success) {
21 result = EnableMCU(true); 22 result = EnableMCU(true);
22 } 23 }
23 if (result == DriverResult::Success) { 24 if (result == Common::Input::DriverResult::Success) {
24 const MCUConfig config{ 25 const MCUConfig config{
25 .command = MCUCommand::ConfigureMCU, 26 .command = MCUCommand::ConfigureMCU,
26 .sub_command = MCUSubCommand::SetDeviceMode, 27 .sub_command = MCUSubCommand::SetDeviceMode,
@@ -33,12 +34,12 @@ DriverResult RingConProtocol::EnableRingCon() {
33 return result; 34 return result;
34} 35}
35 36
36DriverResult RingConProtocol::DisableRingCon() { 37Common::Input::DriverResult RingConProtocol::DisableRingCon() {
37 LOG_DEBUG(Input, "Disable RingCon"); 38 LOG_DEBUG(Input, "Disable RingCon");
38 ScopedSetBlocking sb(this); 39 ScopedSetBlocking sb(this);
39 DriverResult result{DriverResult::Success}; 40 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
40 41
41 if (result == DriverResult::Success) { 42 if (result == Common::Input::DriverResult::Success) {
42 result = EnableMCU(false); 43 result = EnableMCU(false);
43 } 44 }
44 45
@@ -47,29 +48,29 @@ DriverResult RingConProtocol::DisableRingCon() {
47 return result; 48 return result;
48} 49}
49 50
50DriverResult RingConProtocol::StartRingconPolling() { 51Common::Input::DriverResult RingConProtocol::StartRingconPolling() {
51 LOG_DEBUG(Input, "Enable Ringcon"); 52 LOG_DEBUG(Input, "Enable Ringcon");
52 ScopedSetBlocking sb(this); 53 ScopedSetBlocking sb(this);
53 DriverResult result{DriverResult::Success}; 54 Common::Input::DriverResult result{Common::Input::DriverResult::Success};
54 bool is_connected = false; 55 bool is_connected = false;
55 56
56 if (result == DriverResult::Success) { 57 if (result == Common::Input::DriverResult::Success) {
57 result = IsRingConnected(is_connected); 58 result = IsRingConnected(is_connected);
58 } 59 }
59 if (result == DriverResult::Success && is_connected) { 60 if (result == Common::Input::DriverResult::Success && is_connected) {
60 LOG_INFO(Input, "Ringcon detected"); 61 LOG_INFO(Input, "Ringcon detected");
61 result = ConfigureRing(); 62 result = ConfigureRing();
62 } 63 }
63 if (result == DriverResult::Success) { 64 if (result == Common::Input::DriverResult::Success) {
64 is_enabled = true; 65 is_enabled = true;
65 } 66 }
66 67
67 return result; 68 return result;
68} 69}
69 70
70DriverResult RingConProtocol::IsRingConnected(bool& is_connected) { 71Common::Input::DriverResult RingConProtocol::IsRingConnected(bool& is_connected) {
71 LOG_DEBUG(Input, "IsRingConnected"); 72 LOG_DEBUG(Input, "IsRingConnected");
72 constexpr std::size_t max_tries = 28; 73 constexpr std::size_t max_tries = 42;
73 SubCommandResponse output{}; 74 SubCommandResponse output{};
74 std::size_t tries = 0; 75 std::size_t tries = 0;
75 is_connected = false; 76 is_connected = false;
@@ -77,20 +78,21 @@ DriverResult RingConProtocol::IsRingConnected(bool& is_connected) {
77 do { 78 do {
78 const auto result = SendSubCommand(SubCommand::GET_EXTERNAL_DEVICE_INFO, {}, output); 79 const auto result = SendSubCommand(SubCommand::GET_EXTERNAL_DEVICE_INFO, {}, output);
79 80
80 if (result != DriverResult::Success) { 81 if (result != Common::Input::DriverResult::Success &&
82 result != Common::Input::DriverResult::Timeout) {
81 return result; 83 return result;
82 } 84 }
83 85
84 if (tries++ >= max_tries) { 86 if (tries++ >= max_tries) {
85 return DriverResult::NoDeviceDetected; 87 return Common::Input::DriverResult::NoDeviceDetected;
86 } 88 }
87 } while (output.external_device_id != ExternalDeviceId::RingController); 89 } while (output.external_device_id != ExternalDeviceId::RingController);
88 90
89 is_connected = true; 91 is_connected = true;
90 return DriverResult::Success; 92 return Common::Input::DriverResult::Success;
91} 93}
92 94
93DriverResult RingConProtocol::ConfigureRing() { 95Common::Input::DriverResult RingConProtocol::ConfigureRing() {
94 LOG_DEBUG(Input, "ConfigureRing"); 96 LOG_DEBUG(Input, "ConfigureRing");
95 97
96 static constexpr std::array<u8, 37> ring_config{ 98 static constexpr std::array<u8, 37> ring_config{
@@ -98,9 +100,10 @@ DriverResult RingConProtocol::ConfigureRing() {
98 0x00, 0x00, 0x00, 0x0A, 0x64, 0x0B, 0xE6, 0xA9, 0x22, 0x00, 0x00, 0x04, 0x00, 100 0x00, 0x00, 0x00, 0x0A, 0x64, 0x0B, 0xE6, 0xA9, 0x22, 0x00, 0x00, 0x04, 0x00,
99 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0xA8, 0xE1, 0x34, 0x36}; 101 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0xA8, 0xE1, 0x34, 0x36};
100 102
101 const DriverResult result = SendSubCommand(SubCommand::SET_EXTERNAL_FORMAT_CONFIG, ring_config); 103 const Common::Input::DriverResult result =
104 SendSubCommand(SubCommand::SET_EXTERNAL_FORMAT_CONFIG, ring_config);
102 105
103 if (result != DriverResult::Success) { 106 if (result != Common::Input::DriverResult::Success) {
104 return result; 107 return result;
105 } 108 }
106 109
diff --git a/src/input_common/helpers/joycon_protocol/ringcon.h b/src/input_common/helpers/joycon_protocol/ringcon.h
index 6e858f3fc..9f0888de3 100644
--- a/src/input_common/helpers/joycon_protocol/ringcon.h
+++ b/src/input_common/helpers/joycon_protocol/ringcon.h
@@ -13,24 +13,28 @@
13#include "input_common/helpers/joycon_protocol/common_protocol.h" 13#include "input_common/helpers/joycon_protocol/common_protocol.h"
14#include "input_common/helpers/joycon_protocol/joycon_types.h" 14#include "input_common/helpers/joycon_protocol/joycon_types.h"
15 15
16namespace Common::Input {
17enum class DriverResult;
18}
19
16namespace InputCommon::Joycon { 20namespace InputCommon::Joycon {
17 21
18class RingConProtocol final : private JoyconCommonProtocol { 22class RingConProtocol final : private JoyconCommonProtocol {
19public: 23public:
20 explicit RingConProtocol(std::shared_ptr<JoyconHandle> handle); 24 explicit RingConProtocol(std::shared_ptr<JoyconHandle> handle);
21 25
22 DriverResult EnableRingCon(); 26 Common::Input::DriverResult EnableRingCon();
23 27
24 DriverResult DisableRingCon(); 28 Common::Input::DriverResult DisableRingCon();
25 29
26 DriverResult StartRingconPolling(); 30 Common::Input::DriverResult StartRingconPolling();
27 31
28 bool IsEnabled() const; 32 bool IsEnabled() const;
29 33
30private: 34private:
31 DriverResult IsRingConnected(bool& is_connected); 35 Common::Input::DriverResult IsRingConnected(bool& is_connected);
32 36
33 DriverResult ConfigureRing(); 37 Common::Input::DriverResult ConfigureRing();
34 38
35 bool is_enabled{}; 39 bool is_enabled{};
36}; 40};
diff --git a/src/input_common/helpers/joycon_protocol/rumble.cpp b/src/input_common/helpers/joycon_protocol/rumble.cpp
index 63b60c946..7647f505e 100644
--- a/src/input_common/helpers/joycon_protocol/rumble.cpp
+++ b/src/input_common/helpers/joycon_protocol/rumble.cpp
@@ -4,6 +4,7 @@
4#include <algorithm> 4#include <algorithm>
5#include <cmath> 5#include <cmath>
6 6
7#include "common/input.h"
7#include "common/logging/log.h" 8#include "common/logging/log.h"
8#include "input_common/helpers/joycon_protocol/rumble.h" 9#include "input_common/helpers/joycon_protocol/rumble.h"
9 10
@@ -12,14 +13,14 @@ namespace InputCommon::Joycon {
12RumbleProtocol::RumbleProtocol(std::shared_ptr<JoyconHandle> handle) 13RumbleProtocol::RumbleProtocol(std::shared_ptr<JoyconHandle> handle)
13 : JoyconCommonProtocol(std::move(handle)) {} 14 : JoyconCommonProtocol(std::move(handle)) {}
14 15
15DriverResult RumbleProtocol::EnableRumble(bool is_enabled) { 16Common::Input::DriverResult RumbleProtocol::EnableRumble(bool is_enabled) {
16 LOG_DEBUG(Input, "Enable Rumble"); 17 LOG_DEBUG(Input, "Enable Rumble");
17 ScopedSetBlocking sb(this); 18 ScopedSetBlocking sb(this);
18 const std::array<u8, 1> buffer{static_cast<u8>(is_enabled ? 1 : 0)}; 19 const std::array<u8, 1> buffer{static_cast<u8>(is_enabled ? 1 : 0)};
19 return SendSubCommand(SubCommand::ENABLE_VIBRATION, buffer); 20 return SendSubCommand(SubCommand::ENABLE_VIBRATION, buffer);
20} 21}
21 22
22DriverResult RumbleProtocol::SendVibration(const VibrationValue& vibration) { 23Common::Input::DriverResult RumbleProtocol::SendVibration(const VibrationValue& vibration) {
23 std::array<u8, sizeof(DefaultVibrationBuffer)> buffer{}; 24 std::array<u8, sizeof(DefaultVibrationBuffer)> buffer{};
24 25
25 if (vibration.high_amplitude <= 0.0f && vibration.low_amplitude <= 0.0f) { 26 if (vibration.high_amplitude <= 0.0f && vibration.low_amplitude <= 0.0f) {
diff --git a/src/input_common/helpers/joycon_protocol/rumble.h b/src/input_common/helpers/joycon_protocol/rumble.h
index 6c12b7925..5e50e531a 100644
--- a/src/input_common/helpers/joycon_protocol/rumble.h
+++ b/src/input_common/helpers/joycon_protocol/rumble.h
@@ -13,15 +13,19 @@
13#include "input_common/helpers/joycon_protocol/common_protocol.h" 13#include "input_common/helpers/joycon_protocol/common_protocol.h"
14#include "input_common/helpers/joycon_protocol/joycon_types.h" 14#include "input_common/helpers/joycon_protocol/joycon_types.h"
15 15
16namespace Common::Input {
17enum class DriverResult;
18}
19
16namespace InputCommon::Joycon { 20namespace InputCommon::Joycon {
17 21
18class RumbleProtocol final : private JoyconCommonProtocol { 22class RumbleProtocol final : private JoyconCommonProtocol {
19public: 23public:
20 explicit RumbleProtocol(std::shared_ptr<JoyconHandle> handle); 24 explicit RumbleProtocol(std::shared_ptr<JoyconHandle> handle);
21 25
22 DriverResult EnableRumble(bool is_enabled); 26 Common::Input::DriverResult EnableRumble(bool is_enabled);
23 27
24 DriverResult SendVibration(const VibrationValue& vibration); 28 Common::Input::DriverResult SendVibration(const VibrationValue& vibration);
25 29
26private: 30private:
27 u16 EncodeHighFrequency(f32 frequency) const; 31 u16 EncodeHighFrequency(f32 frequency) const;
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index e9e6f278d..3b2fe01da 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -220,8 +220,8 @@ add_library(video_core STATIC
220 surface.h 220 surface.h
221 texture_cache/accelerated_swizzle.cpp 221 texture_cache/accelerated_swizzle.cpp
222 texture_cache/accelerated_swizzle.h 222 texture_cache/accelerated_swizzle.h
223 texture_cache/decode_bc4.cpp 223 texture_cache/decode_bc.cpp
224 texture_cache/decode_bc4.h 224 texture_cache/decode_bc.h
225 texture_cache/descriptor_table.h 225 texture_cache/descriptor_table.h
226 texture_cache/formatter.cpp 226 texture_cache/formatter.cpp
227 texture_cache/formatter.h 227 texture_cache/formatter.h
@@ -279,7 +279,7 @@ add_library(video_core STATIC
279create_target_directory_groups(video_core) 279create_target_directory_groups(video_core)
280 280
281target_link_libraries(video_core PUBLIC common core) 281target_link_libraries(video_core PUBLIC common core)
282target_link_libraries(video_core PUBLIC glad shader_recompiler stb) 282target_link_libraries(video_core PUBLIC glad shader_recompiler stb bc_decoder)
283 283
284if (YUZU_USE_BUNDLED_FFMPEG AND NOT (WIN32 OR ANDROID)) 284if (YUZU_USE_BUNDLED_FFMPEG AND NOT (WIN32 OR ANDROID))
285 add_dependencies(video_core ffmpeg-build) 285 add_dependencies(video_core ffmpeg-build)
diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp
index cf2964a3f..28d4b15a0 100644
--- a/src/video_core/renderer_vulkan/blit_image.cpp
+++ b/src/video_core/renderer_vulkan/blit_image.cpp
@@ -495,6 +495,9 @@ void BlitImageHelper::BlitDepthStencil(const Framebuffer* dst_framebuffer,
495 const Region2D& dst_region, const Region2D& src_region, 495 const Region2D& dst_region, const Region2D& src_region,
496 Tegra::Engines::Fermi2D::Filter filter, 496 Tegra::Engines::Fermi2D::Filter filter,
497 Tegra::Engines::Fermi2D::Operation operation) { 497 Tegra::Engines::Fermi2D::Operation operation) {
498 if (!device.IsExtShaderStencilExportSupported()) {
499 return;
500 }
498 ASSERT(filter == Tegra::Engines::Fermi2D::Filter::Point); 501 ASSERT(filter == Tegra::Engines::Fermi2D::Filter::Point);
499 ASSERT(operation == Tegra::Engines::Fermi2D::Operation::SrcCopy); 502 ASSERT(operation == Tegra::Engines::Fermi2D::Operation::SrcCopy);
500 const BlitImagePipelineKey key{ 503 const BlitImagePipelineKey key{
diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
index 9a0b10568..a8540339d 100644
--- a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
+++ b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
@@ -259,6 +259,26 @@ FormatInfo SurfaceFormat(const Device& device, FormatType format_type, bool with
259 break; 259 break;
260 } 260 }
261 } 261 }
262 // Transcode on hardware that doesn't support BCn natively
263 if (!device.IsOptimalBcnSupported() && VideoCore::Surface::IsPixelFormatBCn(pixel_format)) {
264 const bool is_srgb = with_srgb && VideoCore::Surface::IsPixelFormatSRGB(pixel_format);
265 if (pixel_format == PixelFormat::BC4_SNORM) {
266 tuple.format = VK_FORMAT_R8_SNORM;
267 } else if (pixel_format == PixelFormat::BC4_UNORM) {
268 tuple.format = VK_FORMAT_R8_UNORM;
269 } else if (pixel_format == PixelFormat::BC5_SNORM) {
270 tuple.format = VK_FORMAT_R8G8_SNORM;
271 } else if (pixel_format == PixelFormat::BC5_UNORM) {
272 tuple.format = VK_FORMAT_R8G8_UNORM;
273 } else if (pixel_format == PixelFormat::BC6H_SFLOAT ||
274 pixel_format == PixelFormat::BC6H_UFLOAT) {
275 tuple.format = VK_FORMAT_R16G16B16A16_SFLOAT;
276 } else if (is_srgb) {
277 tuple.format = VK_FORMAT_A8B8G8R8_SRGB_PACK32;
278 } else {
279 tuple.format = VK_FORMAT_A8B8G8R8_UNORM_PACK32;
280 }
281 }
262 const bool attachable = (tuple.usage & Attachable) != 0; 282 const bool attachable = (tuple.usage & Attachable) != 0;
263 const bool storage = (tuple.usage & Storage) != 0; 283 const bool storage = (tuple.usage & Storage) != 0;
264 284
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
index ddf28ca28..454bb66a4 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
@@ -12,6 +12,7 @@
12#include <fmt/format.h> 12#include <fmt/format.h>
13 13
14#include "common/logging/log.h" 14#include "common/logging/log.h"
15#include "common/polyfill_ranges.h"
15#include "common/scope_exit.h" 16#include "common/scope_exit.h"
16#include "common/settings.h" 17#include "common/settings.h"
17#include "common/telemetry.h" 18#include "common/telemetry.h"
@@ -65,6 +66,21 @@ std::string BuildCommaSeparatedExtensions(
65 return fmt::format("{}", fmt::join(available_extensions, ",")); 66 return fmt::format("{}", fmt::join(available_extensions, ","));
66} 67}
67 68
69DebugCallback MakeDebugCallback(const vk::Instance& instance, const vk::InstanceDispatch& dld) {
70 if (!Settings::values.renderer_debug) {
71 return DebugCallback{};
72 }
73 const std::optional properties = vk::EnumerateInstanceExtensionProperties(dld);
74 const auto it = std::ranges::find_if(*properties, [](const auto& prop) {
75 return std::strcmp(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, prop.extensionName) == 0;
76 });
77 if (it != properties->end()) {
78 return CreateDebugUtilsCallback(instance);
79 } else {
80 return CreateDebugReportCallback(instance);
81 }
82}
83
68} // Anonymous namespace 84} // Anonymous namespace
69 85
70Device CreateDevice(const vk::Instance& instance, const vk::InstanceDispatch& dld, 86Device CreateDevice(const vk::Instance& instance, const vk::InstanceDispatch& dld,
@@ -87,7 +103,7 @@ RendererVulkan::RendererVulkan(Core::TelemetrySession& telemetry_session_,
87 cpu_memory(cpu_memory_), gpu(gpu_), library(OpenLibrary(context.get())), 103 cpu_memory(cpu_memory_), gpu(gpu_), library(OpenLibrary(context.get())),
88 instance(CreateInstance(*library, dld, VK_API_VERSION_1_1, render_window.GetWindowInfo().type, 104 instance(CreateInstance(*library, dld, VK_API_VERSION_1_1, render_window.GetWindowInfo().type,
89 Settings::values.renderer_debug.GetValue())), 105 Settings::values.renderer_debug.GetValue())),
90 debug_callback(Settings::values.renderer_debug ? CreateDebugCallback(instance) : nullptr), 106 debug_callback(MakeDebugCallback(instance, dld)),
91 surface(CreateSurface(instance, render_window.GetWindowInfo())), 107 surface(CreateSurface(instance, render_window.GetWindowInfo())),
92 device(CreateDevice(instance, dld, *surface)), memory_allocator(device), state_tracker(), 108 device(CreateDevice(instance, dld, *surface)), memory_allocator(device), state_tracker(),
93 scheduler(device, state_tracker), 109 scheduler(device, state_tracker),
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h
index b2e8cbd1b..ca22c0baa 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.h
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.h
@@ -5,6 +5,7 @@
5 5
6#include <memory> 6#include <memory>
7#include <string> 7#include <string>
8#include <variant>
8 9
9#include "common/dynamic_library.h" 10#include "common/dynamic_library.h"
10#include "video_core/renderer_base.h" 11#include "video_core/renderer_base.h"
@@ -33,6 +34,8 @@ class GPU;
33 34
34namespace Vulkan { 35namespace Vulkan {
35 36
37using DebugCallback = std::variant<vk::DebugUtilsMessenger, vk::DebugReportCallback>;
38
36Device CreateDevice(const vk::Instance& instance, const vk::InstanceDispatch& dld, 39Device CreateDevice(const vk::Instance& instance, const vk::InstanceDispatch& dld,
37 VkSurfaceKHR surface); 40 VkSurfaceKHR surface);
38 41
@@ -71,7 +74,7 @@ private:
71 vk::InstanceDispatch dld; 74 vk::InstanceDispatch dld;
72 75
73 vk::Instance instance; 76 vk::Instance instance;
74 vk::DebugUtilsMessenger debug_callback; 77 DebugCallback debug_callback;
75 vk::SurfaceKHR surface; 78 vk::SurfaceKHR surface;
76 79
77 ScreenInfo screen_info; 80 ScreenInfo screen_info;
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
index 660f7c9ff..b72f95235 100644
--- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
@@ -590,7 +590,8 @@ void BufferCacheRuntime::ReserveNullBuffer() {
590 .pNext = nullptr, 590 .pNext = nullptr,
591 .flags = 0, 591 .flags = 0,
592 .size = 4, 592 .size = 4,
593 .usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, 593 .usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT |
594 VK_BUFFER_USAGE_TRANSFER_DST_BIT,
594 .sharingMode = VK_SHARING_MODE_EXCLUSIVE, 595 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
595 .queueFamilyIndexCount = 0, 596 .queueFamilyIndexCount = 0,
596 .pQueueFamilyIndices = nullptr, 597 .pQueueFamilyIndices = nullptr,
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
index c1595642e..ad35cacac 100644
--- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
+++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
@@ -652,13 +652,14 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
652 .pNext = nullptr, 652 .pNext = nullptr,
653 .negativeOneToOne = key.state.ndc_minus_one_to_one.Value() != 0 ? VK_TRUE : VK_FALSE, 653 .negativeOneToOne = key.state.ndc_minus_one_to_one.Value() != 0 ? VK_TRUE : VK_FALSE,
654 }; 654 };
655 const u32 num_viewports = std::min<u32>(device.GetMaxViewports(), Maxwell::NumViewports);
655 VkPipelineViewportStateCreateInfo viewport_ci{ 656 VkPipelineViewportStateCreateInfo viewport_ci{
656 .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, 657 .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
657 .pNext = nullptr, 658 .pNext = nullptr,
658 .flags = 0, 659 .flags = 0,
659 .viewportCount = Maxwell::NumViewports, 660 .viewportCount = num_viewports,
660 .pViewports = nullptr, 661 .pViewports = nullptr,
661 .scissorCount = Maxwell::NumViewports, 662 .scissorCount = num_viewports,
662 .pScissors = nullptr, 663 .pScissors = nullptr,
663 }; 664 };
664 if (device.IsNvViewportSwizzleSupported()) { 665 if (device.IsNvViewportSwizzleSupported()) {
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
index 9f316113c..d600c4e61 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
@@ -309,7 +309,7 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device
309 .support_int16 = device.IsShaderInt16Supported(), 309 .support_int16 = device.IsShaderInt16Supported(),
310 .support_int64 = device.IsShaderInt64Supported(), 310 .support_int64 = device.IsShaderInt64Supported(),
311 .support_vertex_instance_id = false, 311 .support_vertex_instance_id = false,
312 .support_float_controls = true, 312 .support_float_controls = device.IsKhrShaderFloatControlsSupported(),
313 .support_separate_denorm_behavior = 313 .support_separate_denorm_behavior =
314 float_control.denormBehaviorIndependence == VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL, 314 float_control.denormBehaviorIndependence == VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL,
315 .support_separate_rounding_mode = 315 .support_separate_rounding_mode =
@@ -325,12 +325,13 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device
325 .support_fp64_signed_zero_nan_preserve = 325 .support_fp64_signed_zero_nan_preserve =
326 float_control.shaderSignedZeroInfNanPreserveFloat64 != VK_FALSE, 326 float_control.shaderSignedZeroInfNanPreserveFloat64 != VK_FALSE,
327 .support_explicit_workgroup_layout = device.IsKhrWorkgroupMemoryExplicitLayoutSupported(), 327 .support_explicit_workgroup_layout = device.IsKhrWorkgroupMemoryExplicitLayoutSupported(),
328 .support_vote = true, 328 .support_vote = device.IsSubgroupFeatureSupported(VK_SUBGROUP_FEATURE_VOTE_BIT),
329 .support_viewport_index_layer_non_geometry = 329 .support_viewport_index_layer_non_geometry =
330 device.IsExtShaderViewportIndexLayerSupported(), 330 device.IsExtShaderViewportIndexLayerSupported(),
331 .support_viewport_mask = device.IsNvViewportArray2Supported(), 331 .support_viewport_mask = device.IsNvViewportArray2Supported(),
332 .support_typeless_image_loads = device.IsFormatlessImageLoadSupported(), 332 .support_typeless_image_loads = device.IsFormatlessImageLoadSupported(),
333 .support_demote_to_helper_invocation = true, 333 .support_demote_to_helper_invocation =
334 device.IsExtShaderDemoteToHelperInvocationSupported(),
334 .support_int64_atomics = device.IsExtShaderAtomicInt64Supported(), 335 .support_int64_atomics = device.IsExtShaderAtomicInt64Supported(),
335 .support_derivative_control = true, 336 .support_derivative_control = true,
336 .support_geometry_shader_passthrough = device.IsNvGeometryShaderPassthroughSupported(), 337 .support_geometry_shader_passthrough = device.IsNvGeometryShaderPassthroughSupported(),
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index 84e3a30cc..f7c0d939a 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -315,7 +315,14 @@ void RasterizerVulkan::Clear(u32 layer_count) {
315 FlushWork(); 315 FlushWork();
316 gpu_memory->FlushCaching(); 316 gpu_memory->FlushCaching();
317 317
318#if ANDROID
319 if (Settings::IsGPULevelHigh()) {
320 // This is problematic on Android, disable on GPU Normal.
321 query_cache.UpdateCounters();
322 }
323#else
318 query_cache.UpdateCounters(); 324 query_cache.UpdateCounters();
325#endif
319 326
320 auto& regs = maxwell3d->regs; 327 auto& regs = maxwell3d->regs;
321 const bool use_color = regs.clear_surface.R || regs.clear_surface.G || regs.clear_surface.B || 328 const bool use_color = regs.clear_surface.R || regs.clear_surface.G || regs.clear_surface.B ||
@@ -925,7 +932,7 @@ void RasterizerVulkan::UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& reg
925 } 932 }
926 const bool is_rescaling{texture_cache.IsRescaling()}; 933 const bool is_rescaling{texture_cache.IsRescaling()};
927 const float scale = is_rescaling ? Settings::values.resolution_info.up_factor : 1.0f; 934 const float scale = is_rescaling ? Settings::values.resolution_info.up_factor : 1.0f;
928 const std::array viewports{ 935 const std::array viewport_list{
929 GetViewportState(device, regs, 0, scale), GetViewportState(device, regs, 1, scale), 936 GetViewportState(device, regs, 0, scale), GetViewportState(device, regs, 1, scale),
930 GetViewportState(device, regs, 2, scale), GetViewportState(device, regs, 3, scale), 937 GetViewportState(device, regs, 2, scale), GetViewportState(device, regs, 3, scale),
931 GetViewportState(device, regs, 4, scale), GetViewportState(device, regs, 5, scale), 938 GetViewportState(device, regs, 4, scale), GetViewportState(device, regs, 5, scale),
@@ -935,7 +942,11 @@ void RasterizerVulkan::UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& reg
935 GetViewportState(device, regs, 12, scale), GetViewportState(device, regs, 13, scale), 942 GetViewportState(device, regs, 12, scale), GetViewportState(device, regs, 13, scale),
936 GetViewportState(device, regs, 14, scale), GetViewportState(device, regs, 15, scale), 943 GetViewportState(device, regs, 14, scale), GetViewportState(device, regs, 15, scale),
937 }; 944 };
938 scheduler.Record([viewports](vk::CommandBuffer cmdbuf) { cmdbuf.SetViewport(0, viewports); }); 945 scheduler.Record([this, viewport_list](vk::CommandBuffer cmdbuf) {
946 const u32 num_viewports = std::min<u32>(device.GetMaxViewports(), Maxwell::NumViewports);
947 const vk::Span<VkViewport> viewports(viewport_list.data(), num_viewports);
948 cmdbuf.SetViewport(0, viewports);
949 });
939} 950}
940 951
941void RasterizerVulkan::UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs) { 952void RasterizerVulkan::UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs) {
@@ -948,7 +959,7 @@ void RasterizerVulkan::UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs
948 up_scale = Settings::values.resolution_info.up_scale; 959 up_scale = Settings::values.resolution_info.up_scale;
949 down_shift = Settings::values.resolution_info.down_shift; 960 down_shift = Settings::values.resolution_info.down_shift;
950 } 961 }
951 const std::array scissors{ 962 const std::array scissor_list{
952 GetScissorState(regs, 0, up_scale, down_shift), 963 GetScissorState(regs, 0, up_scale, down_shift),
953 GetScissorState(regs, 1, up_scale, down_shift), 964 GetScissorState(regs, 1, up_scale, down_shift),
954 GetScissorState(regs, 2, up_scale, down_shift), 965 GetScissorState(regs, 2, up_scale, down_shift),
@@ -966,7 +977,11 @@ void RasterizerVulkan::UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs
966 GetScissorState(regs, 14, up_scale, down_shift), 977 GetScissorState(regs, 14, up_scale, down_shift),
967 GetScissorState(regs, 15, up_scale, down_shift), 978 GetScissorState(regs, 15, up_scale, down_shift),
968 }; 979 };
969 scheduler.Record([scissors](vk::CommandBuffer cmdbuf) { cmdbuf.SetScissor(0, scissors); }); 980 scheduler.Record([this, scissor_list](vk::CommandBuffer cmdbuf) {
981 const u32 num_scissors = std::min<u32>(device.GetMaxViewports(), Maxwell::NumViewports);
982 const vk::Span<VkRect2D> scissors(scissor_list.data(), num_scissors);
983 cmdbuf.SetScissor(0, scissors);
984 });
970} 985}
971 986
972void RasterizerVulkan::UpdateDepthBias(Tegra::Engines::Maxwell3D::Regs& regs) { 987void RasterizerVulkan::UpdateDepthBias(Tegra::Engines::Maxwell3D::Regs& regs) {
diff --git a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp
index 62b251a9b..ce92f66ab 100644
--- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp
+++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp
@@ -38,18 +38,20 @@ size_t Region(size_t iterator) noexcept {
38StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& memory_allocator_, 38StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& memory_allocator_,
39 Scheduler& scheduler_) 39 Scheduler& scheduler_)
40 : device{device_}, memory_allocator{memory_allocator_}, scheduler{scheduler_} { 40 : device{device_}, memory_allocator{memory_allocator_}, scheduler{scheduler_} {
41 const VkBufferCreateInfo stream_ci = { 41 VkBufferCreateInfo stream_ci = {
42 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, 42 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
43 .pNext = nullptr, 43 .pNext = nullptr,
44 .flags = 0, 44 .flags = 0,
45 .size = STREAM_BUFFER_SIZE, 45 .size = STREAM_BUFFER_SIZE,
46 .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | 46 .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT |
47 VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | 47 VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
48 VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT,
49 .sharingMode = VK_SHARING_MODE_EXCLUSIVE, 48 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
50 .queueFamilyIndexCount = 0, 49 .queueFamilyIndexCount = 0,
51 .pQueueFamilyIndices = nullptr, 50 .pQueueFamilyIndices = nullptr,
52 }; 51 };
52 if (device.IsExtTransformFeedbackSupported()) {
53 stream_ci.usage |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT;
54 }
53 stream_buffer = memory_allocator.CreateBuffer(stream_ci, MemoryUsage::Stream); 55 stream_buffer = memory_allocator.CreateBuffer(stream_ci, MemoryUsage::Stream);
54 if (device.HasDebuggingToolAttached()) { 56 if (device.HasDebuggingToolAttached()) {
55 stream_buffer.SetObjectNameEXT("Stream Buffer"); 57 stream_buffer.SetObjectNameEXT("Stream Buffer");
@@ -164,19 +166,21 @@ std::optional<StagingBufferRef> StagingBufferPool::TryGetReservedBuffer(size_t s
164StagingBufferRef StagingBufferPool::CreateStagingBuffer(size_t size, MemoryUsage usage, 166StagingBufferRef StagingBufferPool::CreateStagingBuffer(size_t size, MemoryUsage usage,
165 bool deferred) { 167 bool deferred) {
166 const u32 log2 = Common::Log2Ceil64(size); 168 const u32 log2 = Common::Log2Ceil64(size);
167 const VkBufferCreateInfo buffer_ci = { 169 VkBufferCreateInfo buffer_ci = {
168 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, 170 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
169 .pNext = nullptr, 171 .pNext = nullptr,
170 .flags = 0, 172 .flags = 0,
171 .size = 1ULL << log2, 173 .size = 1ULL << log2,
172 .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | 174 .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
173 VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | 175 VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
174 VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | 176 VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
175 VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT,
176 .sharingMode = VK_SHARING_MODE_EXCLUSIVE, 177 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
177 .queueFamilyIndexCount = 0, 178 .queueFamilyIndexCount = 0,
178 .pQueueFamilyIndices = nullptr, 179 .pQueueFamilyIndices = nullptr,
179 }; 180 };
181 if (device.IsExtTransformFeedbackSupported()) {
182 buffer_ci.usage |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT;
183 }
180 vk::Buffer buffer = memory_allocator.CreateBuffer(buffer_ci, usage); 184 vk::Buffer buffer = memory_allocator.CreateBuffer(buffer_ci, usage);
181 if (device.HasDebuggingToolAttached()) { 185 if (device.HasDebuggingToolAttached()) {
182 ++buffer_index; 186 ++buffer_index;
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
index ce6acc30c..8385b5509 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -1279,6 +1279,10 @@ Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info_, GPUVAddr gpu
1279 flags |= VideoCommon::ImageFlagBits::Converted; 1279 flags |= VideoCommon::ImageFlagBits::Converted;
1280 flags |= VideoCommon::ImageFlagBits::CostlyLoad; 1280 flags |= VideoCommon::ImageFlagBits::CostlyLoad;
1281 } 1281 }
1282 if (IsPixelFormatBCn(info.format) && !runtime->device.IsOptimalBcnSupported()) {
1283 flags |= VideoCommon::ImageFlagBits::Converted;
1284 flags |= VideoCommon::ImageFlagBits::CostlyLoad;
1285 }
1282 if (runtime->device.HasDebuggingToolAttached()) { 1286 if (runtime->device.HasDebuggingToolAttached()) {
1283 original_image.SetObjectNameEXT(VideoCommon::Name(*this).c_str()); 1287 original_image.SetObjectNameEXT(VideoCommon::Name(*this).c_str());
1284 } 1288 }
diff --git a/src/video_core/surface.cpp b/src/video_core/surface.cpp
index cb51529e4..e16cd5e73 100644
--- a/src/video_core/surface.cpp
+++ b/src/video_core/surface.cpp
@@ -269,6 +269,28 @@ bool IsPixelFormatASTC(PixelFormat format) {
269 } 269 }
270} 270}
271 271
272bool IsPixelFormatBCn(PixelFormat format) {
273 switch (format) {
274 case PixelFormat::BC1_RGBA_UNORM:
275 case PixelFormat::BC2_UNORM:
276 case PixelFormat::BC3_UNORM:
277 case PixelFormat::BC4_UNORM:
278 case PixelFormat::BC4_SNORM:
279 case PixelFormat::BC5_UNORM:
280 case PixelFormat::BC5_SNORM:
281 case PixelFormat::BC1_RGBA_SRGB:
282 case PixelFormat::BC2_SRGB:
283 case PixelFormat::BC3_SRGB:
284 case PixelFormat::BC7_UNORM:
285 case PixelFormat::BC6H_UFLOAT:
286 case PixelFormat::BC6H_SFLOAT:
287 case PixelFormat::BC7_SRGB:
288 return true;
289 default:
290 return false;
291 }
292}
293
272bool IsPixelFormatSRGB(PixelFormat format) { 294bool IsPixelFormatSRGB(PixelFormat format) {
273 switch (format) { 295 switch (format) {
274 case PixelFormat::A8B8G8R8_SRGB: 296 case PixelFormat::A8B8G8R8_SRGB:
diff --git a/src/video_core/surface.h b/src/video_core/surface.h
index 0225d3287..9b9c4d9bc 100644
--- a/src/video_core/surface.h
+++ b/src/video_core/surface.h
@@ -501,6 +501,8 @@ SurfaceType GetFormatType(PixelFormat pixel_format);
501 501
502bool IsPixelFormatASTC(PixelFormat format); 502bool IsPixelFormatASTC(PixelFormat format);
503 503
504bool IsPixelFormatBCn(PixelFormat format);
505
504bool IsPixelFormatSRGB(PixelFormat format); 506bool IsPixelFormatSRGB(PixelFormat format);
505 507
506bool IsPixelFormatInteger(PixelFormat format); 508bool IsPixelFormatInteger(PixelFormat format);
diff --git a/src/video_core/texture_cache/decode_bc.cpp b/src/video_core/texture_cache/decode_bc.cpp
new file mode 100644
index 000000000..3e26474a3
--- /dev/null
+++ b/src/video_core/texture_cache/decode_bc.cpp
@@ -0,0 +1,129 @@
1// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <algorithm>
5#include <array>
6#include <span>
7#include <bc_decoder.h>
8
9#include "common/common_types.h"
10#include "video_core/texture_cache/decode_bc.h"
11
12namespace VideoCommon {
13
14namespace {
15constexpr u32 BLOCK_SIZE = 4;
16
17using VideoCore::Surface::PixelFormat;
18
19constexpr bool IsSigned(PixelFormat pixel_format) {
20 switch (pixel_format) {
21 case PixelFormat::BC4_SNORM:
22 case PixelFormat::BC4_UNORM:
23 case PixelFormat::BC5_SNORM:
24 case PixelFormat::BC5_UNORM:
25 case PixelFormat::BC6H_SFLOAT:
26 case PixelFormat::BC6H_UFLOAT:
27 return true;
28 default:
29 return false;
30 }
31}
32
33constexpr u32 BlockSize(PixelFormat pixel_format) {
34 switch (pixel_format) {
35 case PixelFormat::BC1_RGBA_SRGB:
36 case PixelFormat::BC1_RGBA_UNORM:
37 case PixelFormat::BC4_SNORM:
38 case PixelFormat::BC4_UNORM:
39 return 8;
40 default:
41 return 16;
42 }
43}
44} // Anonymous namespace
45
46u32 ConvertedBytesPerBlock(VideoCore::Surface::PixelFormat pixel_format) {
47 switch (pixel_format) {
48 case PixelFormat::BC4_SNORM:
49 case PixelFormat::BC4_UNORM:
50 return 1;
51 case PixelFormat::BC5_SNORM:
52 case PixelFormat::BC5_UNORM:
53 return 2;
54 case PixelFormat::BC6H_SFLOAT:
55 case PixelFormat::BC6H_UFLOAT:
56 return 8;
57 default:
58 return 4;
59 }
60}
61
62template <auto decompress, PixelFormat pixel_format>
63void DecompressBlocks(std::span<const u8> input, std::span<u8> output, Extent3D extent,
64 bool is_signed = false) {
65 const u32 out_bpp = ConvertedBytesPerBlock(pixel_format);
66 const u32 block_width = std::min(extent.width, BLOCK_SIZE);
67 const u32 block_height = std::min(extent.height, BLOCK_SIZE);
68 const u32 pitch = extent.width * out_bpp;
69 size_t input_offset = 0;
70 size_t output_offset = 0;
71 for (u32 slice = 0; slice < extent.depth; ++slice) {
72 for (u32 y = 0; y < extent.height; y += block_height) {
73 size_t row_offset = 0;
74 for (u32 x = 0; x < extent.width;
75 x += block_width, row_offset += block_width * out_bpp) {
76 const u8* src = input.data() + input_offset;
77 u8* const dst = output.data() + output_offset + row_offset;
78 if constexpr (IsSigned(pixel_format)) {
79 decompress(src, dst, x, y, extent.width, extent.height, is_signed);
80 } else {
81 decompress(src, dst, x, y, extent.width, extent.height);
82 }
83 input_offset += BlockSize(pixel_format);
84 }
85 output_offset += block_height * pitch;
86 }
87 }
88}
89
90void DecompressBCn(std::span<const u8> input, std::span<u8> output, Extent3D extent,
91 VideoCore::Surface::PixelFormat pixel_format) {
92 switch (pixel_format) {
93 case PixelFormat::BC1_RGBA_UNORM:
94 case PixelFormat::BC1_RGBA_SRGB:
95 DecompressBlocks<bcn::DecodeBc1, PixelFormat::BC1_RGBA_UNORM>(input, output, extent);
96 break;
97 case PixelFormat::BC2_UNORM:
98 case PixelFormat::BC2_SRGB:
99 DecompressBlocks<bcn::DecodeBc2, PixelFormat::BC2_UNORM>(input, output, extent);
100 break;
101 case PixelFormat::BC3_UNORM:
102 case PixelFormat::BC3_SRGB:
103 DecompressBlocks<bcn::DecodeBc3, PixelFormat::BC3_UNORM>(input, output, extent);
104 break;
105 case PixelFormat::BC4_SNORM:
106 case PixelFormat::BC4_UNORM:
107 DecompressBlocks<bcn::DecodeBc4, PixelFormat::BC4_UNORM>(
108 input, output, extent, pixel_format == PixelFormat::BC4_SNORM);
109 break;
110 case PixelFormat::BC5_SNORM:
111 case PixelFormat::BC5_UNORM:
112 DecompressBlocks<bcn::DecodeBc5, PixelFormat::BC5_UNORM>(
113 input, output, extent, pixel_format == PixelFormat::BC5_SNORM);
114 break;
115 case PixelFormat::BC6H_SFLOAT:
116 case PixelFormat::BC6H_UFLOAT:
117 DecompressBlocks<bcn::DecodeBc6, PixelFormat::BC6H_UFLOAT>(
118 input, output, extent, pixel_format == PixelFormat::BC6H_SFLOAT);
119 break;
120 case PixelFormat::BC7_SRGB:
121 case PixelFormat::BC7_UNORM:
122 DecompressBlocks<bcn::DecodeBc7, PixelFormat::BC7_UNORM>(input, output, extent);
123 break;
124 default:
125 LOG_WARNING(HW_GPU, "Unimplemented BCn decompression {}", pixel_format);
126 }
127}
128
129} // namespace VideoCommon
diff --git a/src/video_core/texture_cache/decode_bc4.h b/src/video_core/texture_cache/decode_bc.h
index ab2f735be..41d1ec0a3 100644
--- a/src/video_core/texture_cache/decode_bc4.h
+++ b/src/video_core/texture_cache/decode_bc.h
@@ -6,10 +6,14 @@
6#include <span> 6#include <span>
7 7
8#include "common/common_types.h" 8#include "common/common_types.h"
9#include "video_core/surface.h"
9#include "video_core/texture_cache/types.h" 10#include "video_core/texture_cache/types.h"
10 11
11namespace VideoCommon { 12namespace VideoCommon {
12 13
13void DecompressBC4(std::span<const u8> data, Extent3D extent, std::span<u8> output); 14[[nodiscard]] u32 ConvertedBytesPerBlock(VideoCore::Surface::PixelFormat pixel_format);
15
16void DecompressBCn(std::span<const u8> input, std::span<u8> output, Extent3D extent,
17 VideoCore::Surface::PixelFormat pixel_format);
14 18
15} // namespace VideoCommon 19} // namespace VideoCommon
diff --git a/src/video_core/texture_cache/decode_bc4.cpp b/src/video_core/texture_cache/decode_bc4.cpp
deleted file mode 100644
index ef98afdca..000000000
--- a/src/video_core/texture_cache/decode_bc4.cpp
+++ /dev/null
@@ -1,96 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <algorithm>
5#include <array>
6#include <span>
7
8#include "common/assert.h"
9#include "common/common_types.h"
10#include "video_core/texture_cache/decode_bc4.h"
11#include "video_core/texture_cache/types.h"
12
13namespace VideoCommon {
14
15// https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_texture_compression_rgtc.txt
16[[nodiscard]] constexpr u32 DecompressBlock(u64 bits, u32 x, u32 y) {
17 const u32 code_offset = 16 + 3 * (4 * y + x);
18 const u32 code = (bits >> code_offset) & 7;
19 const u32 red0 = (bits >> 0) & 0xff;
20 const u32 red1 = (bits >> 8) & 0xff;
21 if (red0 > red1) {
22 switch (code) {
23 case 0:
24 return red0;
25 case 1:
26 return red1;
27 case 2:
28 return (6 * red0 + 1 * red1) / 7;
29 case 3:
30 return (5 * red0 + 2 * red1) / 7;
31 case 4:
32 return (4 * red0 + 3 * red1) / 7;
33 case 5:
34 return (3 * red0 + 4 * red1) / 7;
35 case 6:
36 return (2 * red0 + 5 * red1) / 7;
37 case 7:
38 return (1 * red0 + 6 * red1) / 7;
39 }
40 } else {
41 switch (code) {
42 case 0:
43 return red0;
44 case 1:
45 return red1;
46 case 2:
47 return (4 * red0 + 1 * red1) / 5;
48 case 3:
49 return (3 * red0 + 2 * red1) / 5;
50 case 4:
51 return (2 * red0 + 3 * red1) / 5;
52 case 5:
53 return (1 * red0 + 4 * red1) / 5;
54 case 6:
55 return 0;
56 case 7:
57 return 0xff;
58 }
59 }
60 return 0;
61}
62
63void DecompressBC4(std::span<const u8> input, Extent3D extent, std::span<u8> output) {
64 UNIMPLEMENTED_IF_MSG(extent.width % 4 != 0, "Unaligned width={}", extent.width);
65 UNIMPLEMENTED_IF_MSG(extent.height % 4 != 0, "Unaligned height={}", extent.height);
66 static constexpr u32 BLOCK_SIZE = 4;
67 size_t input_offset = 0;
68 for (u32 slice = 0; slice < extent.depth; ++slice) {
69 for (u32 block_y = 0; block_y < extent.height / 4; ++block_y) {
70 for (u32 block_x = 0; block_x < extent.width / 4; ++block_x) {
71 u64 bits;
72 std::memcpy(&bits, &input[input_offset], sizeof(bits));
73 input_offset += sizeof(bits);
74
75 for (u32 y = 0; y < BLOCK_SIZE; ++y) {
76 for (u32 x = 0; x < BLOCK_SIZE; ++x) {
77 const u32 linear_z = slice;
78 const u32 linear_y = block_y * BLOCK_SIZE + y;
79 const u32 linear_x = block_x * BLOCK_SIZE + x;
80 const u32 offset_z = linear_z * extent.width * extent.height;
81 const u32 offset_y = linear_y * extent.width;
82 const u32 offset_x = linear_x;
83 const u32 output_offset = (offset_z + offset_y + offset_x) * 4ULL;
84 const u32 color = DecompressBlock(bits, x, y);
85 output[output_offset + 0] = static_cast<u8>(color);
86 output[output_offset + 1] = 0;
87 output[output_offset + 2] = 0;
88 output[output_offset + 3] = 0xff;
89 }
90 }
91 }
92 }
93 }
94}
95
96} // namespace VideoCommon
diff --git a/src/video_core/texture_cache/util.cpp b/src/video_core/texture_cache/util.cpp
index f781cb7a0..9a618a57a 100644
--- a/src/video_core/texture_cache/util.cpp
+++ b/src/video_core/texture_cache/util.cpp
@@ -24,7 +24,7 @@
24#include "video_core/engines/maxwell_3d.h" 24#include "video_core/engines/maxwell_3d.h"
25#include "video_core/memory_manager.h" 25#include "video_core/memory_manager.h"
26#include "video_core/surface.h" 26#include "video_core/surface.h"
27#include "video_core/texture_cache/decode_bc4.h" 27#include "video_core/texture_cache/decode_bc.h"
28#include "video_core/texture_cache/format_lookup_table.h" 28#include "video_core/texture_cache/format_lookup_table.h"
29#include "video_core/texture_cache/formatter.h" 29#include "video_core/texture_cache/formatter.h"
30#include "video_core/texture_cache/samples_helper.h" 30#include "video_core/texture_cache/samples_helper.h"
@@ -61,8 +61,6 @@ using VideoCore::Surface::PixelFormatFromDepthFormat;
61using VideoCore::Surface::PixelFormatFromRenderTargetFormat; 61using VideoCore::Surface::PixelFormatFromRenderTargetFormat;
62using VideoCore::Surface::SurfaceType; 62using VideoCore::Surface::SurfaceType;
63 63
64constexpr u32 CONVERTED_BYTES_PER_BLOCK = BytesPerBlock(PixelFormat::A8B8G8R8_UNORM);
65
66struct LevelInfo { 64struct LevelInfo {
67 Extent3D size; 65 Extent3D size;
68 Extent3D block; 66 Extent3D block;
@@ -612,7 +610,8 @@ u32 CalculateConvertedSizeBytes(const ImageInfo& info) noexcept {
612 } 610 }
613 return output_size; 611 return output_size;
614 } 612 }
615 return NumBlocksPerLayer(info, TILE_SIZE) * info.resources.layers * CONVERTED_BYTES_PER_BLOCK; 613 return NumBlocksPerLayer(info, TILE_SIZE) * info.resources.layers *
614 ConvertedBytesPerBlock(info.format);
616} 615}
617 616
618u32 CalculateLayerStride(const ImageInfo& info) noexcept { 617u32 CalculateLayerStride(const ImageInfo& info) noexcept {
@@ -945,7 +944,8 @@ void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8
945 tile_size.height, output.subspan(output_offset)); 944 tile_size.height, output.subspan(output_offset));
946 945
947 output_offset += copy.image_extent.width * copy.image_extent.height * 946 output_offset += copy.image_extent.width * copy.image_extent.height *
948 copy.image_subresource.num_layers * CONVERTED_BYTES_PER_BLOCK; 947 copy.image_subresource.num_layers *
948 BytesPerBlock(PixelFormat::A8B8G8R8_UNORM);
949 } else if (astc) { 949 } else if (astc) {
950 // BC1 uses 0.5 bytes per texel 950 // BC1 uses 0.5 bytes per texel
951 // BC3 uses 1 byte per texel 951 // BC3 uses 1 byte per texel
@@ -956,7 +956,8 @@ void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8
956 956
957 const u32 plane_dim = copy.image_extent.width * copy.image_extent.height; 957 const u32 plane_dim = copy.image_extent.width * copy.image_extent.height;
958 const u32 level_size = plane_dim * copy.image_extent.depth * 958 const u32 level_size = plane_dim * copy.image_extent.depth *
959 copy.image_subresource.num_layers * CONVERTED_BYTES_PER_BLOCK; 959 copy.image_subresource.num_layers *
960 BytesPerBlock(PixelFormat::A8B8G8R8_UNORM);
960 decode_scratch.resize_destructive(level_size); 961 decode_scratch.resize_destructive(level_size);
961 962
962 Tegra::Texture::ASTC::Decompress( 963 Tegra::Texture::ASTC::Decompress(
@@ -976,10 +977,15 @@ void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8
976 bpp_div; 977 bpp_div;
977 output_offset += static_cast<u32>(copy.buffer_size); 978 output_offset += static_cast<u32>(copy.buffer_size);
978 } else { 979 } else {
979 DecompressBC4(input_offset, copy.image_extent, output.subspan(output_offset)); 980 const Extent3D image_extent{
980 981 .width = copy.image_extent.width,
982 .height = copy.image_extent.height * copy.image_subresource.num_layers,
983 .depth = copy.image_extent.depth,
984 };
985 DecompressBCn(input_offset, output.subspan(output_offset), image_extent, info.format);
981 output_offset += copy.image_extent.width * copy.image_extent.height * 986 output_offset += copy.image_extent.width * copy.image_extent.height *
982 copy.image_subresource.num_layers * CONVERTED_BYTES_PER_BLOCK; 987 copy.image_subresource.num_layers *
988 ConvertedBytesPerBlock(info.format);
983 } 989 }
984 } 990 }
985} 991}
diff --git a/src/video_core/textures/bcn.cpp b/src/video_core/textures/bcn.cpp
index 671212a49..16ddbe320 100644
--- a/src/video_core/textures/bcn.cpp
+++ b/src/video_core/textures/bcn.cpp
@@ -3,7 +3,6 @@
3 3
4#include <stb_dxt.h> 4#include <stb_dxt.h>
5#include <string.h> 5#include <string.h>
6
7#include "common/alignment.h" 6#include "common/alignment.h"
8#include "video_core/textures/bcn.h" 7#include "video_core/textures/bcn.h"
9#include "video_core/textures/workers.h" 8#include "video_core/textures/workers.h"
diff --git a/src/video_core/textures/bcn.h b/src/video_core/textures/bcn.h
index 6464af885..d5d2a16c9 100644
--- a/src/video_core/textures/bcn.h
+++ b/src/video_core/textures/bcn.h
@@ -4,14 +4,13 @@
4#pragma once 4#pragma once
5 5
6#include <span> 6#include <span>
7#include <stdint.h> 7
8#include "common/common_types.h"
8 9
9namespace Tegra::Texture::BCN { 10namespace Tegra::Texture::BCN {
10 11
11void CompressBC1(std::span<const uint8_t> data, uint32_t width, uint32_t height, uint32_t depth, 12void CompressBC1(std::span<const u8> data, u32 width, u32 height, u32 depth, std::span<u8> output);
12 std::span<uint8_t> output);
13 13
14void CompressBC3(std::span<const uint8_t> data, uint32_t width, uint32_t height, uint32_t depth, 14void CompressBC3(std::span<const u8> data, u32 width, u32 height, u32 depth, std::span<u8> output);
15 std::span<uint8_t> output);
16 15
17} // namespace Tegra::Texture::BCN 16} // namespace Tegra::Texture::BCN
diff --git a/src/video_core/vulkan_common/vulkan_debug_callback.cpp b/src/video_core/vulkan_common/vulkan_debug_callback.cpp
index 9de484c29..67e8065a4 100644
--- a/src/video_core/vulkan_common/vulkan_debug_callback.cpp
+++ b/src/video_core/vulkan_common/vulkan_debug_callback.cpp
@@ -7,10 +7,10 @@
7 7
8namespace Vulkan { 8namespace Vulkan {
9namespace { 9namespace {
10VkBool32 Callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, 10VkBool32 DebugUtilCallback(VkDebugUtilsMessageSeverityFlagBitsEXT severity,
11 VkDebugUtilsMessageTypeFlagsEXT type, 11 VkDebugUtilsMessageTypeFlagsEXT type,
12 const VkDebugUtilsMessengerCallbackDataEXT* data, 12 const VkDebugUtilsMessengerCallbackDataEXT* data,
13 [[maybe_unused]] void* user_data) { 13 [[maybe_unused]] void* user_data) {
14 // Skip logging known false-positive validation errors 14 // Skip logging known false-positive validation errors
15 switch (static_cast<u32>(data->messageIdNumber)) { 15 switch (static_cast<u32>(data->messageIdNumber)) {
16#ifdef ANDROID 16#ifdef ANDROID
@@ -62,9 +62,26 @@ VkBool32 Callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity,
62 } 62 }
63 return VK_FALSE; 63 return VK_FALSE;
64} 64}
65
66VkBool32 DebugReportCallback(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType,
67 uint64_t object, size_t location, int32_t messageCode,
68 const char* pLayerPrefix, const char* pMessage, void* pUserData) {
69 const VkDebugReportFlagBitsEXT severity = static_cast<VkDebugReportFlagBitsEXT>(flags);
70 const std::string_view message{pMessage};
71 if (severity & VK_DEBUG_REPORT_ERROR_BIT_EXT) {
72 LOG_CRITICAL(Render_Vulkan, "{}", message);
73 } else if (severity & VK_DEBUG_REPORT_WARNING_BIT_EXT) {
74 LOG_WARNING(Render_Vulkan, "{}", message);
75 } else if (severity & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) {
76 LOG_INFO(Render_Vulkan, "{}", message);
77 } else if (severity & VK_DEBUG_REPORT_DEBUG_BIT_EXT) {
78 LOG_DEBUG(Render_Vulkan, "{}", message);
79 }
80 return VK_FALSE;
81}
65} // Anonymous namespace 82} // Anonymous namespace
66 83
67vk::DebugUtilsMessenger CreateDebugCallback(const vk::Instance& instance) { 84vk::DebugUtilsMessenger CreateDebugUtilsCallback(const vk::Instance& instance) {
68 return instance.CreateDebugUtilsMessenger(VkDebugUtilsMessengerCreateInfoEXT{ 85 return instance.CreateDebugUtilsMessenger(VkDebugUtilsMessengerCreateInfoEXT{
69 .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, 86 .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
70 .pNext = nullptr, 87 .pNext = nullptr,
@@ -76,7 +93,18 @@ vk::DebugUtilsMessenger CreateDebugCallback(const vk::Instance& instance) {
76 .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | 93 .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
77 VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | 94 VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
78 VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT, 95 VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT,
79 .pfnUserCallback = Callback, 96 .pfnUserCallback = DebugUtilCallback,
97 .pUserData = nullptr,
98 });
99}
100
101vk::DebugReportCallback CreateDebugReportCallback(const vk::Instance& instance) {
102 return instance.CreateDebugReportCallback({
103 .sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT,
104 .pNext = nullptr,
105 .flags = VK_DEBUG_REPORT_DEBUG_BIT_EXT | VK_DEBUG_REPORT_INFORMATION_BIT_EXT |
106 VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT,
107 .pfnCallback = DebugReportCallback,
80 .pUserData = nullptr, 108 .pUserData = nullptr,
81 }); 109 });
82} 110}
diff --git a/src/video_core/vulkan_common/vulkan_debug_callback.h b/src/video_core/vulkan_common/vulkan_debug_callback.h
index 71b1f69ec..a8af7b406 100644
--- a/src/video_core/vulkan_common/vulkan_debug_callback.h
+++ b/src/video_core/vulkan_common/vulkan_debug_callback.h
@@ -7,6 +7,8 @@
7 7
8namespace Vulkan { 8namespace Vulkan {
9 9
10vk::DebugUtilsMessenger CreateDebugCallback(const vk::Instance& instance); 10vk::DebugUtilsMessenger CreateDebugUtilsCallback(const vk::Instance& instance);
11
12vk::DebugReportCallback CreateDebugReportCallback(const vk::Instance& instance);
11 13
12} // namespace Vulkan 14} // namespace Vulkan
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp
index e4ca65b58..421e71e5a 100644
--- a/src/video_core/vulkan_common/vulkan_device.cpp
+++ b/src/video_core/vulkan_common/vulkan_device.cpp
@@ -349,7 +349,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
349 const bool is_s8gen2 = device_id == 0x43050a01; 349 const bool is_s8gen2 = device_id == 0x43050a01;
350 const bool is_arm = driver_id == VK_DRIVER_ID_ARM_PROPRIETARY; 350 const bool is_arm = driver_id == VK_DRIVER_ID_ARM_PROPRIETARY;
351 351
352 if ((is_mvk || is_qualcomm || is_turnip) && !is_suitable) { 352 if ((is_mvk || is_qualcomm || is_turnip || is_arm) && !is_suitable) {
353 LOG_WARNING(Render_Vulkan, "Unsuitable driver, continuing anyway"); 353 LOG_WARNING(Render_Vulkan, "Unsuitable driver, continuing anyway");
354 } else if (!is_suitable) { 354 } else if (!is_suitable) {
355 throw vk::Exception(VK_ERROR_INCOMPATIBLE_DRIVER); 355 throw vk::Exception(VK_ERROR_INCOMPATIBLE_DRIVER);
@@ -528,6 +528,14 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
528 } 528 }
529 529
530 sets_per_pool = 64; 530 sets_per_pool = 64;
531 if (extensions.extended_dynamic_state3 && is_amd_driver &&
532 properties.properties.driverVersion >= VK_MAKE_API_VERSION(0, 2, 0, 270)) {
533 LOG_WARNING(Render_Vulkan,
534 "AMD drivers after 23.5.2 have broken extendedDynamicState3ColorBlendEquation");
535 features.extended_dynamic_state3.extendedDynamicState3ColorBlendEnable = false;
536 features.extended_dynamic_state3.extendedDynamicState3ColorBlendEquation = false;
537 dynamic_state3_blending = false;
538 }
531 if (is_amd_driver) { 539 if (is_amd_driver) {
532 // AMD drivers need a higher amount of Sets per Pool in certain circumstances like in XC2. 540 // AMD drivers need a higher amount of Sets per Pool in certain circumstances like in XC2.
533 sets_per_pool = 96; 541 sets_per_pool = 96;
@@ -905,6 +913,10 @@ bool Device::GetSuitability(bool requires_swapchain) {
905 properties.driver.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES; 913 properties.driver.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES;
906 SetNext(next, properties.driver); 914 SetNext(next, properties.driver);
907 915
916 // Retrieve subgroup properties.
917 properties.subgroup_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES;
918 SetNext(next, properties.subgroup_properties);
919
908 // Retrieve relevant extension properties. 920 // Retrieve relevant extension properties.
909 if (extensions.shader_float_controls) { 921 if (extensions.shader_float_controls) {
910 properties.float_controls.sType = 922 properties.float_controls.sType =
diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h
index b84af3dfb..1f17265d5 100644
--- a/src/video_core/vulkan_common/vulkan_device.h
+++ b/src/video_core/vulkan_common/vulkan_device.h
@@ -293,6 +293,11 @@ public:
293 return features.features.textureCompressionASTC_LDR; 293 return features.features.textureCompressionASTC_LDR;
294 } 294 }
295 295
296 /// Returns true if BCn is natively supported.
297 bool IsOptimalBcnSupported() const {
298 return features.features.textureCompressionBC;
299 }
300
296 /// Returns true if descriptor aliasing is natively supported. 301 /// Returns true if descriptor aliasing is natively supported.
297 bool IsDescriptorAliasingSupported() const { 302 bool IsDescriptorAliasingSupported() const {
298 return GetDriverID() != VK_DRIVER_ID_QUALCOMM_PROPRIETARY; 303 return GetDriverID() != VK_DRIVER_ID_QUALCOMM_PROPRIETARY;
@@ -323,6 +328,11 @@ public:
323 return properties.subgroup_size_control.requiredSubgroupSizeStages & stage; 328 return properties.subgroup_size_control.requiredSubgroupSizeStages & stage;
324 } 329 }
325 330
331 /// Returns true if the device supports the provided subgroup feature.
332 bool IsSubgroupFeatureSupported(VkSubgroupFeatureFlagBits feature) const {
333 return properties.subgroup_properties.supportedOperations & feature;
334 }
335
326 /// Returns the maximum number of push descriptors. 336 /// Returns the maximum number of push descriptors.
327 u32 MaxPushDescriptors() const { 337 u32 MaxPushDescriptors() const {
328 return properties.push_descriptor.maxPushDescriptors; 338 return properties.push_descriptor.maxPushDescriptors;
@@ -388,6 +398,11 @@ public:
388 return extensions.swapchain_mutable_format; 398 return extensions.swapchain_mutable_format;
389 } 399 }
390 400
401 /// Returns true if VK_KHR_shader_float_controls is enabled.
402 bool IsKhrShaderFloatControlsSupported() const {
403 return extensions.shader_float_controls;
404 }
405
391 /// Returns true if the device supports VK_KHR_workgroup_memory_explicit_layout. 406 /// Returns true if the device supports VK_KHR_workgroup_memory_explicit_layout.
392 bool IsKhrWorkgroupMemoryExplicitLayoutSupported() const { 407 bool IsKhrWorkgroupMemoryExplicitLayoutSupported() const {
393 return extensions.workgroup_memory_explicit_layout; 408 return extensions.workgroup_memory_explicit_layout;
@@ -413,6 +428,11 @@ public:
413 return extensions.sampler_filter_minmax; 428 return extensions.sampler_filter_minmax;
414 } 429 }
415 430
431 /// Returns true if the device supports VK_EXT_shader_stencil_export.
432 bool IsExtShaderStencilExportSupported() const {
433 return extensions.shader_stencil_export;
434 }
435
416 /// Returns true if the device supports VK_EXT_depth_range_unrestricted. 436 /// Returns true if the device supports VK_EXT_depth_range_unrestricted.
417 bool IsExtDepthRangeUnrestrictedSupported() const { 437 bool IsExtDepthRangeUnrestrictedSupported() const {
418 return extensions.depth_range_unrestricted; 438 return extensions.depth_range_unrestricted;
@@ -482,9 +502,9 @@ public:
482 return extensions.vertex_input_dynamic_state; 502 return extensions.vertex_input_dynamic_state;
483 } 503 }
484 504
485 /// Returns true if the device supports VK_EXT_shader_stencil_export. 505 /// Returns true if the device supports VK_EXT_shader_demote_to_helper_invocation
486 bool IsExtShaderStencilExportSupported() const { 506 bool IsExtShaderDemoteToHelperInvocationSupported() const {
487 return extensions.shader_stencil_export; 507 return extensions.shader_demote_to_helper_invocation;
488 } 508 }
489 509
490 /// Returns true if the device supports VK_EXT_conservative_rasterization. 510 /// Returns true if the device supports VK_EXT_conservative_rasterization.
@@ -518,12 +538,12 @@ public:
518 if (extensions.spirv_1_4) { 538 if (extensions.spirv_1_4) {
519 return 0x00010400U; 539 return 0x00010400U;
520 } 540 }
521 return 0x00010000U; 541 return 0x00010300U;
522 } 542 }
523 543
524 /// Returns true when a known debugging tool is attached. 544 /// Returns true when a known debugging tool is attached.
525 bool HasDebuggingToolAttached() const { 545 bool HasDebuggingToolAttached() const {
526 return has_renderdoc || has_nsight_graphics || Settings::values.renderer_debug.GetValue(); 546 return has_renderdoc || has_nsight_graphics;
527 } 547 }
528 548
529 /// @returns True if compute pipelines can cause crashing. 549 /// @returns True if compute pipelines can cause crashing.
@@ -588,6 +608,10 @@ public:
588 return properties.properties.limits.maxVertexInputBindings; 608 return properties.properties.limits.maxVertexInputBindings;
589 } 609 }
590 610
611 u32 GetMaxViewports() const {
612 return properties.properties.limits.maxViewports;
613 }
614
591 bool SupportsConditionalBarriers() const { 615 bool SupportsConditionalBarriers() const {
592 return supports_conditional_barriers; 616 return supports_conditional_barriers;
593 } 617 }
@@ -680,6 +704,7 @@ private:
680 704
681 struct Properties { 705 struct Properties {
682 VkPhysicalDeviceDriverProperties driver{}; 706 VkPhysicalDeviceDriverProperties driver{};
707 VkPhysicalDeviceSubgroupProperties subgroup_properties{};
683 VkPhysicalDeviceFloatControlsProperties float_controls{}; 708 VkPhysicalDeviceFloatControlsProperties float_controls{};
684 VkPhysicalDevicePushDescriptorPropertiesKHR push_descriptor{}; 709 VkPhysicalDevicePushDescriptorPropertiesKHR push_descriptor{};
685 VkPhysicalDeviceSubgroupSizeControlProperties subgroup_size_control{}; 710 VkPhysicalDeviceSubgroupSizeControlProperties subgroup_size_control{};
diff --git a/src/video_core/vulkan_common/vulkan_instance.cpp b/src/video_core/vulkan_common/vulkan_instance.cpp
index b6d83e446..7624a9b32 100644
--- a/src/video_core/vulkan_common/vulkan_instance.cpp
+++ b/src/video_core/vulkan_common/vulkan_instance.cpp
@@ -31,10 +31,34 @@
31 31
32namespace Vulkan { 32namespace Vulkan {
33namespace { 33namespace {
34
35[[nodiscard]] bool AreExtensionsSupported(const vk::InstanceDispatch& dld,
36 std::span<const char* const> extensions) {
37 const std::optional properties = vk::EnumerateInstanceExtensionProperties(dld);
38 if (!properties) {
39 LOG_ERROR(Render_Vulkan, "Failed to query extension properties");
40 return false;
41 }
42 for (const char* extension : extensions) {
43 const auto it = std::ranges::find_if(*properties, [extension](const auto& prop) {
44 return std::strcmp(extension, prop.extensionName) == 0;
45 });
46 if (it == properties->end()) {
47 LOG_ERROR(Render_Vulkan, "Required instance extension {} is not available", extension);
48 return false;
49 }
50 }
51 return true;
52}
53
34[[nodiscard]] std::vector<const char*> RequiredExtensions( 54[[nodiscard]] std::vector<const char*> RequiredExtensions(
35 Core::Frontend::WindowSystemType window_type, bool enable_validation) { 55 const vk::InstanceDispatch& dld, Core::Frontend::WindowSystemType window_type,
56 bool enable_validation) {
36 std::vector<const char*> extensions; 57 std::vector<const char*> extensions;
37 extensions.reserve(6); 58 extensions.reserve(6);
59#ifdef __APPLE__
60 extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
61#endif
38 switch (window_type) { 62 switch (window_type) {
39 case Core::Frontend::WindowSystemType::Headless: 63 case Core::Frontend::WindowSystemType::Headless:
40 break; 64 break;
@@ -66,35 +90,14 @@ namespace {
66 extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME); 90 extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
67 } 91 }
68 if (enable_validation) { 92 if (enable_validation) {
69 extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); 93 const bool debug_utils =
94 AreExtensionsSupported(dld, std::array{VK_EXT_DEBUG_UTILS_EXTENSION_NAME});
95 extensions.push_back(debug_utils ? VK_EXT_DEBUG_UTILS_EXTENSION_NAME
96 : VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
70 } 97 }
71 extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
72
73#ifdef __APPLE__
74 extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
75#endif
76 return extensions; 98 return extensions;
77} 99}
78 100
79[[nodiscard]] bool AreExtensionsSupported(const vk::InstanceDispatch& dld,
80 std::span<const char* const> extensions) {
81 const std::optional properties = vk::EnumerateInstanceExtensionProperties(dld);
82 if (!properties) {
83 LOG_ERROR(Render_Vulkan, "Failed to query extension properties");
84 return false;
85 }
86 for (const char* extension : extensions) {
87 const auto it = std::ranges::find_if(*properties, [extension](const auto& prop) {
88 return std::strcmp(extension, prop.extensionName) == 0;
89 });
90 if (it == properties->end()) {
91 LOG_ERROR(Render_Vulkan, "Required instance extension {} is not available", extension);
92 return false;
93 }
94 }
95 return true;
96}
97
98[[nodiscard]] std::vector<const char*> Layers(bool enable_validation) { 101[[nodiscard]] std::vector<const char*> Layers(bool enable_validation) {
99 std::vector<const char*> layers; 102 std::vector<const char*> layers;
100 if (enable_validation) { 103 if (enable_validation) {
@@ -138,7 +141,8 @@ vk::Instance CreateInstance(const Common::DynamicLibrary& library, vk::InstanceD
138 LOG_ERROR(Render_Vulkan, "Failed to load Vulkan function pointers"); 141 LOG_ERROR(Render_Vulkan, "Failed to load Vulkan function pointers");
139 throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED); 142 throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
140 } 143 }
141 const std::vector<const char*> extensions = RequiredExtensions(window_type, enable_validation); 144 const std::vector<const char*> extensions =
145 RequiredExtensions(dld, window_type, enable_validation);
142 if (!AreExtensionsSupported(dld, extensions)) { 146 if (!AreExtensionsSupported(dld, extensions)) {
143 throw vk::Exception(VK_ERROR_EXTENSION_NOT_PRESENT); 147 throw vk::Exception(VK_ERROR_EXTENSION_NOT_PRESENT);
144 } 148 }
diff --git a/src/video_core/vulkan_common/vulkan_wrapper.cpp b/src/video_core/vulkan_common/vulkan_wrapper.cpp
index 28fcb21a0..2fa29793a 100644
--- a/src/video_core/vulkan_common/vulkan_wrapper.cpp
+++ b/src/video_core/vulkan_common/vulkan_wrapper.cpp
@@ -259,7 +259,9 @@ bool Load(VkInstance instance, InstanceDispatch& dld) noexcept {
259 // These functions may fail to load depending on the enabled extensions. 259 // These functions may fail to load depending on the enabled extensions.
260 // Don't return a failure on these. 260 // Don't return a failure on these.
261 X(vkCreateDebugUtilsMessengerEXT); 261 X(vkCreateDebugUtilsMessengerEXT);
262 X(vkCreateDebugReportCallbackEXT);
262 X(vkDestroyDebugUtilsMessengerEXT); 263 X(vkDestroyDebugUtilsMessengerEXT);
264 X(vkDestroyDebugReportCallbackEXT);
263 X(vkDestroySurfaceKHR); 265 X(vkDestroySurfaceKHR);
264 X(vkGetPhysicalDeviceFeatures2); 266 X(vkGetPhysicalDeviceFeatures2);
265 X(vkGetPhysicalDeviceProperties2); 267 X(vkGetPhysicalDeviceProperties2);
@@ -481,6 +483,11 @@ void Destroy(VkInstance instance, VkDebugUtilsMessengerEXT handle,
481 dld.vkDestroyDebugUtilsMessengerEXT(instance, handle, nullptr); 483 dld.vkDestroyDebugUtilsMessengerEXT(instance, handle, nullptr);
482} 484}
483 485
486void Destroy(VkInstance instance, VkDebugReportCallbackEXT handle,
487 const InstanceDispatch& dld) noexcept {
488 dld.vkDestroyDebugReportCallbackEXT(instance, handle, nullptr);
489}
490
484void Destroy(VkInstance instance, VkSurfaceKHR handle, const InstanceDispatch& dld) noexcept { 491void Destroy(VkInstance instance, VkSurfaceKHR handle, const InstanceDispatch& dld) noexcept {
485 dld.vkDestroySurfaceKHR(instance, handle, nullptr); 492 dld.vkDestroySurfaceKHR(instance, handle, nullptr);
486} 493}
@@ -549,6 +556,13 @@ DebugUtilsMessenger Instance::CreateDebugUtilsMessenger(
549 return DebugUtilsMessenger(object, handle, *dld); 556 return DebugUtilsMessenger(object, handle, *dld);
550} 557}
551 558
559DebugReportCallback Instance::CreateDebugReportCallback(
560 const VkDebugReportCallbackCreateInfoEXT& create_info) const {
561 VkDebugReportCallbackEXT object;
562 Check(dld->vkCreateDebugReportCallbackEXT(handle, &create_info, nullptr, &object));
563 return DebugReportCallback(object, handle, *dld);
564}
565
552void Image::SetObjectNameEXT(const char* name) const { 566void Image::SetObjectNameEXT(const char* name) const {
553 SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_IMAGE, name); 567 SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_IMAGE, name);
554} 568}
diff --git a/src/video_core/vulkan_common/vulkan_wrapper.h b/src/video_core/vulkan_common/vulkan_wrapper.h
index 44fce47a5..b5e70fcd4 100644
--- a/src/video_core/vulkan_common/vulkan_wrapper.h
+++ b/src/video_core/vulkan_common/vulkan_wrapper.h
@@ -164,8 +164,10 @@ struct InstanceDispatch {
164 PFN_vkEnumerateInstanceLayerProperties vkEnumerateInstanceLayerProperties{}; 164 PFN_vkEnumerateInstanceLayerProperties vkEnumerateInstanceLayerProperties{};
165 165
166 PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT{}; 166 PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT{};
167 PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallbackEXT{};
167 PFN_vkCreateDevice vkCreateDevice{}; 168 PFN_vkCreateDevice vkCreateDevice{};
168 PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT{}; 169 PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT{};
170 PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallbackEXT{};
169 PFN_vkDestroyDevice vkDestroyDevice{}; 171 PFN_vkDestroyDevice vkDestroyDevice{};
170 PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR{}; 172 PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR{};
171 PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties{}; 173 PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties{};
@@ -366,6 +368,7 @@ void Destroy(VkDevice, VkSwapchainKHR, const DeviceDispatch&) noexcept;
366void Destroy(VkDevice, VkSemaphore, const DeviceDispatch&) noexcept; 368void Destroy(VkDevice, VkSemaphore, const DeviceDispatch&) noexcept;
367void Destroy(VkDevice, VkShaderModule, const DeviceDispatch&) noexcept; 369void Destroy(VkDevice, VkShaderModule, const DeviceDispatch&) noexcept;
368void Destroy(VkInstance, VkDebugUtilsMessengerEXT, const InstanceDispatch&) noexcept; 370void Destroy(VkInstance, VkDebugUtilsMessengerEXT, const InstanceDispatch&) noexcept;
371void Destroy(VkInstance, VkDebugReportCallbackEXT, const InstanceDispatch&) noexcept;
369void Destroy(VkInstance, VkSurfaceKHR, const InstanceDispatch&) noexcept; 372void Destroy(VkInstance, VkSurfaceKHR, const InstanceDispatch&) noexcept;
370 373
371VkResult Free(VkDevice, VkDescriptorPool, Span<VkDescriptorSet>, const DeviceDispatch&) noexcept; 374VkResult Free(VkDevice, VkDescriptorPool, Span<VkDescriptorSet>, const DeviceDispatch&) noexcept;
@@ -581,6 +584,7 @@ private:
581}; 584};
582 585
583using DebugUtilsMessenger = Handle<VkDebugUtilsMessengerEXT, VkInstance, InstanceDispatch>; 586using DebugUtilsMessenger = Handle<VkDebugUtilsMessengerEXT, VkInstance, InstanceDispatch>;
587using DebugReportCallback = Handle<VkDebugReportCallbackEXT, VkInstance, InstanceDispatch>;
584using DescriptorSetLayout = Handle<VkDescriptorSetLayout, VkDevice, DeviceDispatch>; 588using DescriptorSetLayout = Handle<VkDescriptorSetLayout, VkDevice, DeviceDispatch>;
585using DescriptorUpdateTemplate = Handle<VkDescriptorUpdateTemplate, VkDevice, DeviceDispatch>; 589using DescriptorUpdateTemplate = Handle<VkDescriptorUpdateTemplate, VkDevice, DeviceDispatch>;
586using Pipeline = Handle<VkPipeline, VkDevice, DeviceDispatch>; 590using Pipeline = Handle<VkPipeline, VkDevice, DeviceDispatch>;
@@ -613,6 +617,11 @@ public:
613 DebugUtilsMessenger CreateDebugUtilsMessenger( 617 DebugUtilsMessenger CreateDebugUtilsMessenger(
614 const VkDebugUtilsMessengerCreateInfoEXT& create_info) const; 618 const VkDebugUtilsMessengerCreateInfoEXT& create_info) const;
615 619
620 /// Creates a debug report callback.
621 /// @throw Exception on creation failure.
622 DebugReportCallback CreateDebugReportCallback(
623 const VkDebugReportCallbackCreateInfoEXT& create_info) const;
624
616 /// Returns dispatch table. 625 /// Returns dispatch table.
617 const InstanceDispatch& Dispatch() const noexcept { 626 const InstanceDispatch& Dispatch() const noexcept {
618 return *dld; 627 return *dld;
diff --git a/src/yuzu/configuration/configure_ringcon.cpp b/src/yuzu/configuration/configure_ringcon.cpp
index 71afbc423..f83705544 100644
--- a/src/yuzu/configuration/configure_ringcon.cpp
+++ b/src/yuzu/configuration/configure_ringcon.cpp
@@ -305,6 +305,9 @@ void ConfigureRingController::EnableRingController() {
305 QMessageBox::warning(this, dialog_title, 305 QMessageBox::warning(this, dialog_title,
306 tr("The current mapped device doesn't have a ring attached")); 306 tr("The current mapped device doesn't have a ring attached"));
307 break; 307 break;
308 case Common::Input::DriverResult::InvalidHandle:
309 QMessageBox::warning(this, dialog_title, tr("The current mapped device is not connected"));
310 break;
308 default: 311 default:
309 QMessageBox::warning(this, dialog_title, 312 QMessageBox::warning(this, dialog_title,
310 tr("Unexpected driver result %1").arg(static_cast<int>(result))); 313 tr("Unexpected driver result %1").arg(static_cast<int>(result)));