diff options
| author | 2022-07-24 13:31:28 -0400 | |
|---|---|---|
| committer | 2022-07-24 13:31:28 -0400 | |
| commit | 5af06d14337a61d9ed1093079d13f68cbb1f5451 (patch) | |
| tree | 88df3fada076b04c2ab2da8972d1d785f492b520 | |
| parent | Merge pull request #8545 from Kelebek1/Audio (diff) | |
| parent | yuzu: Add webcam support and rebase to latest master (diff) | |
| download | yuzu-5af06d14337a61d9ed1093079d13f68cbb1f5451.tar.gz yuzu-5af06d14337a61d9ed1093079d13f68cbb1f5451.tar.xz yuzu-5af06d14337a61d9ed1093079d13f68cbb1f5451.zip | |
Merge pull request #8484 from german77/irs_release
service: irs: Add camera support, split processors and implement ImageTransferProcessor
50 files changed, 2342 insertions, 320 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 3f7dcc924..40ca8b149 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt | |||
| @@ -196,7 +196,7 @@ if(ENABLE_QT) | |||
| 196 | # Check for system Qt on Linux, fallback to bundled Qt | 196 | # Check for system Qt on Linux, fallback to bundled Qt |
| 197 | if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux") | 197 | if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux") |
| 198 | if (NOT YUZU_USE_BUNDLED_QT) | 198 | if (NOT YUZU_USE_BUNDLED_QT) |
| 199 | find_package(Qt5 ${QT_VERSION} COMPONENTS Widgets DBus) | 199 | find_package(Qt5 ${QT_VERSION} COMPONENTS Widgets DBus Multimedia) |
| 200 | endif() | 200 | endif() |
| 201 | if (NOT Qt5_FOUND OR YUZU_USE_BUNDLED_QT) | 201 | if (NOT Qt5_FOUND OR YUZU_USE_BUNDLED_QT) |
| 202 | # Check for dependencies, then enable bundled Qt download | 202 | # Check for dependencies, then enable bundled Qt download |
| @@ -300,9 +300,9 @@ if(ENABLE_QT) | |||
| 300 | set(YUZU_QT_NO_CMAKE_SYSTEM_PATH "NO_CMAKE_SYSTEM_PATH") | 300 | set(YUZU_QT_NO_CMAKE_SYSTEM_PATH "NO_CMAKE_SYSTEM_PATH") |
| 301 | endif() | 301 | endif() |
| 302 | if ((${CMAKE_SYSTEM_NAME} STREQUAL "Linux") AND YUZU_USE_BUNDLED_QT) | 302 | if ((${CMAKE_SYSTEM_NAME} STREQUAL "Linux") AND YUZU_USE_BUNDLED_QT) |
| 303 | find_package(Qt5 ${QT_VERSION} REQUIRED COMPONENTS Widgets Concurrent DBus ${QT_PREFIX_HINT} ${YUZU_QT_NO_CMAKE_SYSTEM_PATH}) | 303 | find_package(Qt5 ${QT_VERSION} REQUIRED COMPONENTS Widgets Concurrent Multimedia DBus ${QT_PREFIX_HINT} ${YUZU_QT_NO_CMAKE_SYSTEM_PATH}) |
| 304 | else() | 304 | else() |
| 305 | find_package(Qt5 ${QT_VERSION} REQUIRED COMPONENTS Widgets Concurrent ${QT_PREFIX_HINT} ${YUZU_QT_NO_CMAKE_SYSTEM_PATH}) | 305 | find_package(Qt5 ${QT_VERSION} REQUIRED COMPONENTS Widgets Concurrent Multimedia ${QT_PREFIX_HINT} ${YUZU_QT_NO_CMAKE_SYSTEM_PATH}) |
| 306 | endif() | 306 | endif() |
| 307 | if (YUZU_USE_QT_WEB_ENGINE) | 307 | if (YUZU_USE_QT_WEB_ENGINE) |
| 308 | find_package(Qt5 REQUIRED COMPONENTS WebEngineCore WebEngineWidgets) | 308 | find_package(Qt5 REQUIRED COMPONENTS WebEngineCore WebEngineWidgets) |
diff --git a/CMakeModules/CopyYuzuQt5Deps.cmake b/CMakeModules/CopyYuzuQt5Deps.cmake index 0c27d51a6..6c5044caa 100644 --- a/CMakeModules/CopyYuzuQt5Deps.cmake +++ b/CMakeModules/CopyYuzuQt5Deps.cmake | |||
| @@ -10,11 +10,13 @@ function(copy_yuzu_Qt5_deps target_dir) | |||
| 10 | set(Qt5_PLATFORMS_DIR "${Qt5_DIR}/../../../plugins/platforms/") | 10 | set(Qt5_PLATFORMS_DIR "${Qt5_DIR}/../../../plugins/platforms/") |
| 11 | set(Qt5_PLATFORMTHEMES_DIR "${Qt5_DIR}/../../../plugins/platformthemes/") | 11 | set(Qt5_PLATFORMTHEMES_DIR "${Qt5_DIR}/../../../plugins/platformthemes/") |
| 12 | set(Qt5_PLATFORMINPUTCONTEXTS_DIR "${Qt5_DIR}/../../../plugins/platforminputcontexts/") | 12 | set(Qt5_PLATFORMINPUTCONTEXTS_DIR "${Qt5_DIR}/../../../plugins/platforminputcontexts/") |
| 13 | set(Qt5_MEDIASERVICE_DIR "${Qt5_DIR}/../../../plugins/mediaservice/") | ||
| 13 | set(Qt5_XCBGLINTEGRATIONS_DIR "${Qt5_DIR}/../../../plugins/xcbglintegrations/") | 14 | set(Qt5_XCBGLINTEGRATIONS_DIR "${Qt5_DIR}/../../../plugins/xcbglintegrations/") |
| 14 | set(Qt5_STYLES_DIR "${Qt5_DIR}/../../../plugins/styles/") | 15 | set(Qt5_STYLES_DIR "${Qt5_DIR}/../../../plugins/styles/") |
| 15 | set(Qt5_IMAGEFORMATS_DIR "${Qt5_DIR}/../../../plugins/imageformats/") | 16 | set(Qt5_IMAGEFORMATS_DIR "${Qt5_DIR}/../../../plugins/imageformats/") |
| 16 | set(Qt5_RESOURCES_DIR "${Qt5_DIR}/../../../resources/") | 17 | set(Qt5_RESOURCES_DIR "${Qt5_DIR}/../../../resources/") |
| 17 | set(PLATFORMS ${DLL_DEST}plugins/platforms/) | 18 | set(PLATFORMS ${DLL_DEST}plugins/platforms/) |
| 19 | set(MEDIASERVICE ${DLL_DEST}mediaservice/) | ||
| 18 | set(STYLES ${DLL_DEST}plugins/styles/) | 20 | set(STYLES ${DLL_DEST}plugins/styles/) |
| 19 | set(IMAGEFORMATS ${DLL_DEST}plugins/imageformats/) | 21 | set(IMAGEFORMATS ${DLL_DEST}plugins/imageformats/) |
| 20 | if (MSVC) | 22 | if (MSVC) |
| @@ -22,6 +24,8 @@ function(copy_yuzu_Qt5_deps target_dir) | |||
| 22 | Qt5Core$<$<CONFIG:Debug>:d>.* | 24 | Qt5Core$<$<CONFIG:Debug>:d>.* |
| 23 | Qt5Gui$<$<CONFIG:Debug>:d>.* | 25 | Qt5Gui$<$<CONFIG:Debug>:d>.* |
| 24 | Qt5Widgets$<$<CONFIG:Debug>:d>.* | 26 | Qt5Widgets$<$<CONFIG:Debug>:d>.* |
| 27 | Qt5Multimedia$<$<CONFIG:Debug>:d>.* | ||
| 28 | Qt5Network$<$<CONFIG:Debug>:d>.* | ||
| 25 | ) | 29 | ) |
| 26 | 30 | ||
| 27 | if (YUZU_USE_QT_WEB_ENGINE) | 31 | if (YUZU_USE_QT_WEB_ENGINE) |
| @@ -53,6 +57,10 @@ function(copy_yuzu_Qt5_deps target_dir) | |||
| 53 | qjpeg$<$<CONFIG:Debug>:d>.* | 57 | qjpeg$<$<CONFIG:Debug>:d>.* |
| 54 | qgif$<$<CONFIG:Debug>:d>.* | 58 | qgif$<$<CONFIG:Debug>:d>.* |
| 55 | ) | 59 | ) |
| 60 | windows_copy_files(yuzu ${Qt5_MEDIASERVICE_DIR} ${MEDIASERVICE} | ||
| 61 | dsengine$<$<CONFIG:Debug>:d>.* | ||
| 62 | wmfengine$<$<CONFIG:Debug>:d>.* | ||
| 63 | ) | ||
| 56 | else() | 64 | else() |
| 57 | set(Qt5_DLLS | 65 | set(Qt5_DLLS |
| 58 | "${Qt5_DLL_DIR}libQt5Core.so.5" | 66 | "${Qt5_DLL_DIR}libQt5Core.so.5" |
diff --git a/src/common/input.h b/src/common/input.h index bb42aaacc..995c35d9d 100644 --- a/src/common/input.h +++ b/src/common/input.h | |||
| @@ -28,7 +28,7 @@ enum class InputType { | |||
| 28 | Color, | 28 | Color, |
| 29 | Vibration, | 29 | Vibration, |
| 30 | Nfc, | 30 | Nfc, |
| 31 | Ir, | 31 | IrSensor, |
| 32 | }; | 32 | }; |
| 33 | 33 | ||
| 34 | // Internal battery charge level | 34 | // Internal battery charge level |
| @@ -53,6 +53,15 @@ enum class PollingMode { | |||
| 53 | IR, | 53 | IR, |
| 54 | }; | 54 | }; |
| 55 | 55 | ||
| 56 | enum class CameraFormat { | ||
| 57 | Size320x240, | ||
| 58 | Size160x120, | ||
| 59 | Size80x60, | ||
| 60 | Size40x30, | ||
| 61 | Size20x15, | ||
| 62 | None, | ||
| 63 | }; | ||
| 64 | |||
| 56 | // Vibration reply from the controller | 65 | // Vibration reply from the controller |
| 57 | enum class VibrationError { | 66 | enum class VibrationError { |
| 58 | None, | 67 | None, |
| @@ -68,6 +77,13 @@ enum class PollingError { | |||
| 68 | Unknown, | 77 | Unknown, |
| 69 | }; | 78 | }; |
| 70 | 79 | ||
| 80 | // Ir camera reply from the controller | ||
| 81 | enum class CameraError { | ||
| 82 | None, | ||
| 83 | NotSupported, | ||
| 84 | Unknown, | ||
| 85 | }; | ||
| 86 | |||
| 71 | // Hint for amplification curve to be used | 87 | // Hint for amplification curve to be used |
| 72 | enum class VibrationAmplificationType { | 88 | enum class VibrationAmplificationType { |
| 73 | Linear, | 89 | Linear, |
| @@ -176,6 +192,12 @@ struct LedStatus { | |||
| 176 | bool led_4{}; | 192 | bool led_4{}; |
| 177 | }; | 193 | }; |
| 178 | 194 | ||
| 195 | // Raw data fom camera | ||
| 196 | struct CameraStatus { | ||
| 197 | CameraFormat format{CameraFormat::None}; | ||
| 198 | std::vector<u8> data{}; | ||
| 199 | }; | ||
| 200 | |||
| 179 | // List of buttons to be passed to Qt that can be translated | 201 | // List of buttons to be passed to Qt that can be translated |
| 180 | enum class ButtonNames { | 202 | enum class ButtonNames { |
| 181 | Undefined, | 203 | Undefined, |
| @@ -233,6 +255,7 @@ struct CallbackStatus { | |||
| 233 | BodyColorStatus color_status{}; | 255 | BodyColorStatus color_status{}; |
| 234 | BatteryStatus battery_status{}; | 256 | BatteryStatus battery_status{}; |
| 235 | VibrationStatus vibration_status{}; | 257 | VibrationStatus vibration_status{}; |
| 258 | CameraStatus camera_status{}; | ||
| 236 | }; | 259 | }; |
| 237 | 260 | ||
| 238 | // Triggered once every input change | 261 | // Triggered once every input change |
| @@ -281,6 +304,10 @@ public: | |||
| 281 | virtual PollingError SetPollingMode([[maybe_unused]] PollingMode polling_mode) { | 304 | virtual PollingError SetPollingMode([[maybe_unused]] PollingMode polling_mode) { |
| 282 | return PollingError::NotSupported; | 305 | return PollingError::NotSupported; |
| 283 | } | 306 | } |
| 307 | |||
| 308 | virtual CameraError SetCameraFormat([[maybe_unused]] CameraFormat camera_format) { | ||
| 309 | return CameraError::NotSupported; | ||
| 310 | } | ||
| 284 | }; | 311 | }; |
| 285 | 312 | ||
| 286 | /// An abstract class template for a factory that can create input devices. | 313 | /// An abstract class template for a factory that can create input devices. |
diff --git a/src/common/settings.h b/src/common/settings.h index 06d72c8bf..1079cf8cb 100644 --- a/src/common/settings.h +++ b/src/common/settings.h | |||
| @@ -503,6 +503,9 @@ struct Values { | |||
| 503 | Setting<bool> enable_ring_controller{true, "enable_ring_controller"}; | 503 | Setting<bool> enable_ring_controller{true, "enable_ring_controller"}; |
| 504 | RingconRaw ringcon_analogs; | 504 | RingconRaw ringcon_analogs; |
| 505 | 505 | ||
| 506 | Setting<bool> enable_ir_sensor{false, "enable_ir_sensor"}; | ||
| 507 | Setting<std::string> ir_sensor_device{"auto", "ir_sensor_device"}; | ||
| 508 | |||
| 506 | // Data Storage | 509 | // Data Storage |
| 507 | Setting<bool> use_virtual_sd{true, "use_virtual_sd"}; | 510 | Setting<bool> use_virtual_sd{true, "use_virtual_sd"}; |
| 508 | Setting<bool> gamecard_inserted{false, "gamecard_inserted"}; | 511 | Setting<bool> gamecard_inserted{false, "gamecard_inserted"}; |
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 11d554bad..32cc2f392 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -158,6 +158,7 @@ add_library(core STATIC | |||
| 158 | hid/input_converter.h | 158 | hid/input_converter.h |
| 159 | hid/input_interpreter.cpp | 159 | hid/input_interpreter.cpp |
| 160 | hid/input_interpreter.h | 160 | hid/input_interpreter.h |
| 161 | hid/irs_types.h | ||
| 161 | hid/motion_input.cpp | 162 | hid/motion_input.cpp |
| 162 | hid/motion_input.h | 163 | hid/motion_input.h |
| 163 | hle/api_version.h | 164 | hle/api_version.h |
| @@ -477,6 +478,20 @@ add_library(core STATIC | |||
| 477 | hle/service/hid/hidbus/starlink.h | 478 | hle/service/hid/hidbus/starlink.h |
| 478 | hle/service/hid/hidbus/stubbed.cpp | 479 | hle/service/hid/hidbus/stubbed.cpp |
| 479 | hle/service/hid/hidbus/stubbed.h | 480 | hle/service/hid/hidbus/stubbed.h |
| 481 | hle/service/hid/irsensor/clustering_processor.cpp | ||
| 482 | hle/service/hid/irsensor/clustering_processor.h | ||
| 483 | hle/service/hid/irsensor/image_transfer_processor.cpp | ||
| 484 | hle/service/hid/irsensor/image_transfer_processor.h | ||
| 485 | hle/service/hid/irsensor/ir_led_processor.cpp | ||
| 486 | hle/service/hid/irsensor/ir_led_processor.h | ||
| 487 | hle/service/hid/irsensor/moment_processor.cpp | ||
| 488 | hle/service/hid/irsensor/moment_processor.h | ||
| 489 | hle/service/hid/irsensor/pointing_processor.cpp | ||
| 490 | hle/service/hid/irsensor/pointing_processor.h | ||
| 491 | hle/service/hid/irsensor/processor_base.cpp | ||
| 492 | hle/service/hid/irsensor/processor_base.h | ||
| 493 | hle/service/hid/irsensor/tera_plugin_processor.cpp | ||
| 494 | hle/service/hid/irsensor/tera_plugin_processor.h | ||
| 480 | hle/service/jit/jit_context.cpp | 495 | hle/service/jit/jit_context.cpp |
| 481 | hle/service/jit/jit_context.h | 496 | hle/service/jit/jit_context.h |
| 482 | hle/service/jit/jit.cpp | 497 | hle/service/jit/jit.cpp |
diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index bd2384515..8c3895937 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp | |||
| @@ -126,10 +126,14 @@ void EmulatedController::LoadDevices() { | |||
| 126 | battery_params[LeftIndex].Set("battery", true); | 126 | battery_params[LeftIndex].Set("battery", true); |
| 127 | battery_params[RightIndex].Set("battery", true); | 127 | battery_params[RightIndex].Set("battery", true); |
| 128 | 128 | ||
| 129 | camera_params = Common::ParamPackage{"engine:camera,camera:1"}; | ||
| 130 | |||
| 129 | output_params[LeftIndex] = left_joycon; | 131 | output_params[LeftIndex] = left_joycon; |
| 130 | output_params[RightIndex] = right_joycon; | 132 | output_params[RightIndex] = right_joycon; |
| 133 | output_params[2] = camera_params; | ||
| 131 | output_params[LeftIndex].Set("output", true); | 134 | output_params[LeftIndex].Set("output", true); |
| 132 | output_params[RightIndex].Set("output", true); | 135 | output_params[RightIndex].Set("output", true); |
| 136 | output_params[2].Set("output", true); | ||
| 133 | 137 | ||
| 134 | LoadTASParams(); | 138 | LoadTASParams(); |
| 135 | 139 | ||
| @@ -146,6 +150,7 @@ void EmulatedController::LoadDevices() { | |||
| 146 | Common::Input::CreateDevice<Common::Input::InputDevice>); | 150 | Common::Input::CreateDevice<Common::Input::InputDevice>); |
| 147 | std::transform(battery_params.begin(), battery_params.end(), battery_devices.begin(), | 151 | std::transform(battery_params.begin(), battery_params.end(), battery_devices.begin(), |
| 148 | Common::Input::CreateDevice<Common::Input::InputDevice>); | 152 | Common::Input::CreateDevice<Common::Input::InputDevice>); |
| 153 | camera_devices = Common::Input::CreateDevice<Common::Input::InputDevice>(camera_params); | ||
| 149 | std::transform(output_params.begin(), output_params.end(), output_devices.begin(), | 154 | std::transform(output_params.begin(), output_params.end(), output_devices.begin(), |
| 150 | Common::Input::CreateDevice<Common::Input::OutputDevice>); | 155 | Common::Input::CreateDevice<Common::Input::OutputDevice>); |
| 151 | 156 | ||
| @@ -267,6 +272,14 @@ void EmulatedController::ReloadInput() { | |||
| 267 | motion_devices[index]->ForceUpdate(); | 272 | motion_devices[index]->ForceUpdate(); |
| 268 | } | 273 | } |
| 269 | 274 | ||
| 275 | if (camera_devices) { | ||
| 276 | camera_devices->SetCallback({ | ||
| 277 | .on_change = | ||
| 278 | [this](const Common::Input::CallbackStatus& callback) { SetCamera(callback); }, | ||
| 279 | }); | ||
| 280 | camera_devices->ForceUpdate(); | ||
| 281 | } | ||
| 282 | |||
| 270 | // Use a common UUID for TAS | 283 | // Use a common UUID for TAS |
| 271 | static constexpr Common::UUID TAS_UUID = Common::UUID{ | 284 | static constexpr Common::UUID TAS_UUID = Common::UUID{ |
| 272 | {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xA5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}; | 285 | {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xA5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}; |
| @@ -851,6 +864,25 @@ void EmulatedController::SetBattery(const Common::Input::CallbackStatus& callbac | |||
| 851 | TriggerOnChange(ControllerTriggerType::Battery, true); | 864 | TriggerOnChange(ControllerTriggerType::Battery, true); |
| 852 | } | 865 | } |
| 853 | 866 | ||
| 867 | void EmulatedController::SetCamera(const Common::Input::CallbackStatus& callback) { | ||
| 868 | std::unique_lock lock{mutex}; | ||
| 869 | controller.camera_values = TransformToCamera(callback); | ||
| 870 | |||
| 871 | if (is_configuring) { | ||
| 872 | lock.unlock(); | ||
| 873 | TriggerOnChange(ControllerTriggerType::IrSensor, false); | ||
| 874 | return; | ||
| 875 | } | ||
| 876 | |||
| 877 | controller.camera_state.sample++; | ||
| 878 | controller.camera_state.format = | ||
| 879 | static_cast<Core::IrSensor::ImageTransferProcessorFormat>(controller.camera_values.format); | ||
| 880 | controller.camera_state.data = controller.camera_values.data; | ||
| 881 | |||
| 882 | lock.unlock(); | ||
| 883 | TriggerOnChange(ControllerTriggerType::IrSensor, true); | ||
| 884 | } | ||
| 885 | |||
| 854 | bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue vibration) { | 886 | bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue vibration) { |
| 855 | if (device_index >= output_devices.size()) { | 887 | if (device_index >= output_devices.size()) { |
| 856 | return false; | 888 | return false; |
| @@ -928,6 +960,23 @@ bool EmulatedController::SetPollingMode(Common::Input::PollingMode polling_mode) | |||
| 928 | return output_device->SetPollingMode(polling_mode) == Common::Input::PollingError::None; | 960 | return output_device->SetPollingMode(polling_mode) == Common::Input::PollingError::None; |
| 929 | } | 961 | } |
| 930 | 962 | ||
| 963 | bool EmulatedController::SetCameraFormat( | ||
| 964 | Core::IrSensor::ImageTransferProcessorFormat camera_format) { | ||
| 965 | LOG_INFO(Service_HID, "Set camera format {}", camera_format); | ||
| 966 | |||
| 967 | auto& right_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)]; | ||
| 968 | auto& camera_output_device = output_devices[2]; | ||
| 969 | |||
| 970 | if (right_output_device->SetCameraFormat(static_cast<Common::Input::CameraFormat>( | ||
| 971 | camera_format)) == Common::Input::CameraError::None) { | ||
| 972 | return true; | ||
| 973 | } | ||
| 974 | |||
| 975 | // Fallback to Qt camera if native device doesn't have support | ||
| 976 | return camera_output_device->SetCameraFormat(static_cast<Common::Input::CameraFormat>( | ||
| 977 | camera_format)) == Common::Input::CameraError::None; | ||
| 978 | } | ||
| 979 | |||
| 931 | void EmulatedController::SetLedPattern() { | 980 | void EmulatedController::SetLedPattern() { |
| 932 | for (auto& device : output_devices) { | 981 | for (auto& device : output_devices) { |
| 933 | if (!device) { | 982 | if (!device) { |
| @@ -1163,6 +1212,11 @@ BatteryValues EmulatedController::GetBatteryValues() const { | |||
| 1163 | return controller.battery_values; | 1212 | return controller.battery_values; |
| 1164 | } | 1213 | } |
| 1165 | 1214 | ||
| 1215 | CameraValues EmulatedController::GetCameraValues() const { | ||
| 1216 | std::scoped_lock lock{mutex}; | ||
| 1217 | return controller.camera_values; | ||
| 1218 | } | ||
| 1219 | |||
| 1166 | HomeButtonState EmulatedController::GetHomeButtons() const { | 1220 | HomeButtonState EmulatedController::GetHomeButtons() const { |
| 1167 | std::scoped_lock lock{mutex}; | 1221 | std::scoped_lock lock{mutex}; |
| 1168 | if (is_configuring) { | 1222 | if (is_configuring) { |
| @@ -1251,6 +1305,11 @@ BatteryLevelState EmulatedController::GetBattery() const { | |||
| 1251 | return controller.battery_state; | 1305 | return controller.battery_state; |
| 1252 | } | 1306 | } |
| 1253 | 1307 | ||
| 1308 | const CameraState& EmulatedController::GetCamera() const { | ||
| 1309 | std::scoped_lock lock{mutex}; | ||
| 1310 | return controller.camera_state; | ||
| 1311 | } | ||
| 1312 | |||
| 1254 | void EmulatedController::TriggerOnChange(ControllerTriggerType type, bool is_npad_service_update) { | 1313 | void EmulatedController::TriggerOnChange(ControllerTriggerType type, bool is_npad_service_update) { |
| 1255 | std::scoped_lock lock{callback_mutex}; | 1314 | std::scoped_lock lock{callback_mutex}; |
| 1256 | for (const auto& poller_pair : callback_list) { | 1315 | for (const auto& poller_pair : callback_list) { |
diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index 3f02ed3c0..823c1700c 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h | |||
| @@ -15,10 +15,12 @@ | |||
| 15 | #include "common/settings.h" | 15 | #include "common/settings.h" |
| 16 | #include "common/vector_math.h" | 16 | #include "common/vector_math.h" |
| 17 | #include "core/hid/hid_types.h" | 17 | #include "core/hid/hid_types.h" |
| 18 | #include "core/hid/irs_types.h" | ||
| 18 | #include "core/hid/motion_input.h" | 19 | #include "core/hid/motion_input.h" |
| 19 | 20 | ||
| 20 | namespace Core::HID { | 21 | namespace Core::HID { |
| 21 | const std::size_t max_emulated_controllers = 2; | 22 | const std::size_t max_emulated_controllers = 2; |
| 23 | const std::size_t output_devices = 3; | ||
| 22 | struct ControllerMotionInfo { | 24 | struct ControllerMotionInfo { |
| 23 | Common::Input::MotionStatus raw_status{}; | 25 | Common::Input::MotionStatus raw_status{}; |
| 24 | MotionInput emulated{}; | 26 | MotionInput emulated{}; |
| @@ -34,15 +36,16 @@ using TriggerDevices = | |||
| 34 | std::array<std::unique_ptr<Common::Input::InputDevice>, Settings::NativeTrigger::NumTriggers>; | 36 | std::array<std::unique_ptr<Common::Input::InputDevice>, Settings::NativeTrigger::NumTriggers>; |
| 35 | using BatteryDevices = | 37 | using BatteryDevices = |
| 36 | std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>; | 38 | std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>; |
| 37 | using OutputDevices = | 39 | using CameraDevices = std::unique_ptr<Common::Input::InputDevice>; |
| 38 | std::array<std::unique_ptr<Common::Input::OutputDevice>, max_emulated_controllers>; | 40 | using OutputDevices = std::array<std::unique_ptr<Common::Input::OutputDevice>, output_devices>; |
| 39 | 41 | ||
| 40 | using ButtonParams = std::array<Common::ParamPackage, Settings::NativeButton::NumButtons>; | 42 | using ButtonParams = std::array<Common::ParamPackage, Settings::NativeButton::NumButtons>; |
| 41 | using StickParams = std::array<Common::ParamPackage, Settings::NativeAnalog::NumAnalogs>; | 43 | using StickParams = std::array<Common::ParamPackage, Settings::NativeAnalog::NumAnalogs>; |
| 42 | using ControllerMotionParams = std::array<Common::ParamPackage, Settings::NativeMotion::NumMotions>; | 44 | using ControllerMotionParams = std::array<Common::ParamPackage, Settings::NativeMotion::NumMotions>; |
| 43 | using TriggerParams = std::array<Common::ParamPackage, Settings::NativeTrigger::NumTriggers>; | 45 | using TriggerParams = std::array<Common::ParamPackage, Settings::NativeTrigger::NumTriggers>; |
| 44 | using BatteryParams = std::array<Common::ParamPackage, max_emulated_controllers>; | 46 | using BatteryParams = std::array<Common::ParamPackage, max_emulated_controllers>; |
| 45 | using OutputParams = std::array<Common::ParamPackage, max_emulated_controllers>; | 47 | using CameraParams = Common::ParamPackage; |
| 48 | using OutputParams = std::array<Common::ParamPackage, output_devices>; | ||
| 46 | 49 | ||
| 47 | using ButtonValues = std::array<Common::Input::ButtonStatus, Settings::NativeButton::NumButtons>; | 50 | using ButtonValues = std::array<Common::Input::ButtonStatus, Settings::NativeButton::NumButtons>; |
| 48 | using SticksValues = std::array<Common::Input::StickStatus, Settings::NativeAnalog::NumAnalogs>; | 51 | using SticksValues = std::array<Common::Input::StickStatus, Settings::NativeAnalog::NumAnalogs>; |
| @@ -51,6 +54,7 @@ using TriggerValues = | |||
| 51 | using ControllerMotionValues = std::array<ControllerMotionInfo, Settings::NativeMotion::NumMotions>; | 54 | using ControllerMotionValues = std::array<ControllerMotionInfo, Settings::NativeMotion::NumMotions>; |
| 52 | using ColorValues = std::array<Common::Input::BodyColorStatus, max_emulated_controllers>; | 55 | using ColorValues = std::array<Common::Input::BodyColorStatus, max_emulated_controllers>; |
| 53 | using BatteryValues = std::array<Common::Input::BatteryStatus, max_emulated_controllers>; | 56 | using BatteryValues = std::array<Common::Input::BatteryStatus, max_emulated_controllers>; |
| 57 | using CameraValues = Common::Input::CameraStatus; | ||
| 54 | using VibrationValues = std::array<Common::Input::VibrationStatus, max_emulated_controllers>; | 58 | using VibrationValues = std::array<Common::Input::VibrationStatus, max_emulated_controllers>; |
| 55 | 59 | ||
| 56 | struct AnalogSticks { | 60 | struct AnalogSticks { |
| @@ -70,6 +74,12 @@ struct BatteryLevelState { | |||
| 70 | NpadPowerInfo right{}; | 74 | NpadPowerInfo right{}; |
| 71 | }; | 75 | }; |
| 72 | 76 | ||
| 77 | struct CameraState { | ||
| 78 | Core::IrSensor::ImageTransferProcessorFormat format{}; | ||
| 79 | std::vector<u8> data{}; | ||
| 80 | std::size_t sample{}; | ||
| 81 | }; | ||
| 82 | |||
| 73 | struct ControllerMotion { | 83 | struct ControllerMotion { |
| 74 | Common::Vec3f accel{}; | 84 | Common::Vec3f accel{}; |
| 75 | Common::Vec3f gyro{}; | 85 | Common::Vec3f gyro{}; |
| @@ -96,6 +106,7 @@ struct ControllerStatus { | |||
| 96 | ColorValues color_values{}; | 106 | ColorValues color_values{}; |
| 97 | BatteryValues battery_values{}; | 107 | BatteryValues battery_values{}; |
| 98 | VibrationValues vibration_values{}; | 108 | VibrationValues vibration_values{}; |
| 109 | CameraValues camera_values{}; | ||
| 99 | 110 | ||
| 100 | // Data for HID serices | 111 | // Data for HID serices |
| 101 | HomeButtonState home_button_state{}; | 112 | HomeButtonState home_button_state{}; |
| @@ -107,6 +118,7 @@ struct ControllerStatus { | |||
| 107 | NpadGcTriggerState gc_trigger_state{}; | 118 | NpadGcTriggerState gc_trigger_state{}; |
| 108 | ControllerColors colors_state{}; | 119 | ControllerColors colors_state{}; |
| 109 | BatteryLevelState battery_state{}; | 120 | BatteryLevelState battery_state{}; |
| 121 | CameraState camera_state{}; | ||
| 110 | }; | 122 | }; |
| 111 | 123 | ||
| 112 | enum class ControllerTriggerType { | 124 | enum class ControllerTriggerType { |
| @@ -117,6 +129,7 @@ enum class ControllerTriggerType { | |||
| 117 | Color, | 129 | Color, |
| 118 | Battery, | 130 | Battery, |
| 119 | Vibration, | 131 | Vibration, |
| 132 | IrSensor, | ||
| 120 | Connected, | 133 | Connected, |
| 121 | Disconnected, | 134 | Disconnected, |
| 122 | Type, | 135 | Type, |
| @@ -269,6 +282,9 @@ public: | |||
| 269 | /// Returns the latest battery status from the controller with parameters | 282 | /// Returns the latest battery status from the controller with parameters |
| 270 | BatteryValues GetBatteryValues() const; | 283 | BatteryValues GetBatteryValues() const; |
| 271 | 284 | ||
| 285 | /// Returns the latest camera status from the controller with parameters | ||
| 286 | CameraValues GetCameraValues() const; | ||
| 287 | |||
| 272 | /// Returns the latest status of button input for the hid::HomeButton service | 288 | /// Returns the latest status of button input for the hid::HomeButton service |
| 273 | HomeButtonState GetHomeButtons() const; | 289 | HomeButtonState GetHomeButtons() const; |
| 274 | 290 | ||
| @@ -296,6 +312,9 @@ public: | |||
| 296 | /// Returns the latest battery status from the controller | 312 | /// Returns the latest battery status from the controller |
| 297 | BatteryLevelState GetBattery() const; | 313 | BatteryLevelState GetBattery() const; |
| 298 | 314 | ||
| 315 | /// Returns the latest camera status from the controller | ||
| 316 | const CameraState& GetCamera() const; | ||
| 317 | |||
| 299 | /** | 318 | /** |
| 300 | * Sends a specific vibration to the output device | 319 | * Sends a specific vibration to the output device |
| 301 | * @return true if vibration had no errors | 320 | * @return true if vibration had no errors |
| @@ -315,6 +334,13 @@ public: | |||
| 315 | */ | 334 | */ |
| 316 | bool SetPollingMode(Common::Input::PollingMode polling_mode); | 335 | bool SetPollingMode(Common::Input::PollingMode polling_mode); |
| 317 | 336 | ||
| 337 | /** | ||
| 338 | * Sets the desired camera format to be polled from a controller | ||
| 339 | * @param camera_format size of each frame | ||
| 340 | * @return true if SetCameraFormat was successfull | ||
| 341 | */ | ||
| 342 | bool SetCameraFormat(Core::IrSensor::ImageTransferProcessorFormat camera_format); | ||
| 343 | |||
| 318 | /// Returns the led pattern corresponding to this emulated controller | 344 | /// Returns the led pattern corresponding to this emulated controller |
| 319 | LedPattern GetLedPattern() const; | 345 | LedPattern GetLedPattern() const; |
| 320 | 346 | ||
| @@ -393,6 +419,12 @@ private: | |||
| 393 | void SetBattery(const Common::Input::CallbackStatus& callback, std::size_t index); | 419 | void SetBattery(const Common::Input::CallbackStatus& callback, std::size_t index); |
| 394 | 420 | ||
| 395 | /** | 421 | /** |
| 422 | * Updates the camera status of the controller | ||
| 423 | * @param callback A CallbackStatus containing the camera status | ||
| 424 | */ | ||
| 425 | void SetCamera(const Common::Input::CallbackStatus& callback); | ||
| 426 | |||
| 427 | /** | ||
| 396 | * Triggers a callback that something has changed on the controller status | 428 | * Triggers a callback that something has changed on the controller status |
| 397 | * @param type Input type of the event to trigger | 429 | * @param type Input type of the event to trigger |
| 398 | * @param is_service_update indicates if this event should only be sent to HID services | 430 | * @param is_service_update indicates if this event should only be sent to HID services |
| @@ -417,6 +449,7 @@ private: | |||
| 417 | ControllerMotionParams motion_params; | 449 | ControllerMotionParams motion_params; |
| 418 | TriggerParams trigger_params; | 450 | TriggerParams trigger_params; |
| 419 | BatteryParams battery_params; | 451 | BatteryParams battery_params; |
| 452 | CameraParams camera_params; | ||
| 420 | OutputParams output_params; | 453 | OutputParams output_params; |
| 421 | 454 | ||
| 422 | ButtonDevices button_devices; | 455 | ButtonDevices button_devices; |
| @@ -424,6 +457,7 @@ private: | |||
| 424 | ControllerMotionDevices motion_devices; | 457 | ControllerMotionDevices motion_devices; |
| 425 | TriggerDevices trigger_devices; | 458 | TriggerDevices trigger_devices; |
| 426 | BatteryDevices battery_devices; | 459 | BatteryDevices battery_devices; |
| 460 | CameraDevices camera_devices; | ||
| 427 | OutputDevices output_devices; | 461 | OutputDevices output_devices; |
| 428 | 462 | ||
| 429 | // TAS related variables | 463 | // TAS related variables |
diff --git a/src/core/hid/input_converter.cpp b/src/core/hid/input_converter.cpp index 18d9f042d..68d143a01 100644 --- a/src/core/hid/input_converter.cpp +++ b/src/core/hid/input_converter.cpp | |||
| @@ -270,6 +270,20 @@ Common::Input::AnalogStatus TransformToAnalog(const Common::Input::CallbackStatu | |||
| 270 | return status; | 270 | return status; |
| 271 | } | 271 | } |
| 272 | 272 | ||
| 273 | Common::Input::CameraStatus TransformToCamera(const Common::Input::CallbackStatus& callback) { | ||
| 274 | Common::Input::CameraStatus camera{}; | ||
| 275 | switch (callback.type) { | ||
| 276 | case Common::Input::InputType::IrSensor: | ||
| 277 | camera = callback.camera_status; | ||
| 278 | break; | ||
| 279 | default: | ||
| 280 | LOG_ERROR(Input, "Conversion from type {} to camera not implemented", callback.type); | ||
| 281 | break; | ||
| 282 | } | ||
| 283 | |||
| 284 | return camera; | ||
| 285 | } | ||
| 286 | |||
| 273 | void SanitizeAnalog(Common::Input::AnalogStatus& analog, bool clamp_value) { | 287 | void SanitizeAnalog(Common::Input::AnalogStatus& analog, bool clamp_value) { |
| 274 | const auto& properties = analog.properties; | 288 | const auto& properties = analog.properties; |
| 275 | float& raw_value = analog.raw_value; | 289 | float& raw_value = analog.raw_value; |
diff --git a/src/core/hid/input_converter.h b/src/core/hid/input_converter.h index 2be36889f..143c50cc0 100644 --- a/src/core/hid/input_converter.h +++ b/src/core/hid/input_converter.h | |||
| @@ -77,6 +77,14 @@ Common::Input::TriggerStatus TransformToTrigger(const Common::Input::CallbackSta | |||
| 77 | Common::Input::AnalogStatus TransformToAnalog(const Common::Input::CallbackStatus& callback); | 77 | Common::Input::AnalogStatus TransformToAnalog(const Common::Input::CallbackStatus& callback); |
| 78 | 78 | ||
| 79 | /** | 79 | /** |
| 80 | * Converts raw input data into a valid camera status. | ||
| 81 | * | ||
| 82 | * @param callback Supported callbacks: Camera. | ||
| 83 | * @return A valid CameraObject object. | ||
| 84 | */ | ||
| 85 | Common::Input::CameraStatus TransformToCamera(const Common::Input::CallbackStatus& callback); | ||
| 86 | |||
| 87 | /** | ||
| 80 | * Converts raw analog data into a valid analog value | 88 | * Converts raw analog data into a valid analog value |
| 81 | * @param analog An analog object containing raw data and properties | 89 | * @param analog An analog object containing raw data and properties |
| 82 | * @param clamp_value determines if the value needs to be clamped between -1.0f and 1.0f. | 90 | * @param clamp_value determines if the value needs to be clamped between -1.0f and 1.0f. |
diff --git a/src/core/hid/irs_types.h b/src/core/hid/irs_types.h new file mode 100644 index 000000000..88c5b016d --- /dev/null +++ b/src/core/hid/irs_types.h | |||
| @@ -0,0 +1,301 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "common/common_funcs.h" | ||
| 7 | #include "common/common_types.h" | ||
| 8 | #include "core/hid/hid_types.h" | ||
| 9 | |||
| 10 | namespace Core::IrSensor { | ||
| 11 | |||
| 12 | // This is nn::irsensor::CameraAmbientNoiseLevel | ||
| 13 | enum class CameraAmbientNoiseLevel : u32 { | ||
| 14 | Low, | ||
| 15 | Medium, | ||
| 16 | High, | ||
| 17 | Unkown3, // This level can't be reached | ||
| 18 | }; | ||
| 19 | |||
| 20 | // This is nn::irsensor::CameraLightTarget | ||
| 21 | enum class CameraLightTarget : u32 { | ||
| 22 | AllLeds, | ||
| 23 | BrightLeds, | ||
| 24 | DimLeds, | ||
| 25 | None, | ||
| 26 | }; | ||
| 27 | |||
| 28 | // This is nn::irsensor::PackedCameraLightTarget | ||
| 29 | enum class PackedCameraLightTarget : u8 { | ||
| 30 | AllLeds, | ||
| 31 | BrightLeds, | ||
| 32 | DimLeds, | ||
| 33 | None, | ||
| 34 | }; | ||
| 35 | |||
| 36 | // This is nn::irsensor::AdaptiveClusteringMode | ||
| 37 | enum class AdaptiveClusteringMode : u32 { | ||
| 38 | StaticFov, | ||
| 39 | DynamicFov, | ||
| 40 | }; | ||
| 41 | |||
| 42 | // This is nn::irsensor::AdaptiveClusteringTargetDistance | ||
| 43 | enum class AdaptiveClusteringTargetDistance : u32 { | ||
| 44 | Near, | ||
| 45 | Middle, | ||
| 46 | Far, | ||
| 47 | }; | ||
| 48 | |||
| 49 | // This is nn::irsensor::ImageTransferProcessorFormat | ||
| 50 | enum class ImageTransferProcessorFormat : u32 { | ||
| 51 | Size320x240, | ||
| 52 | Size160x120, | ||
| 53 | Size80x60, | ||
| 54 | Size40x30, | ||
| 55 | Size20x15, | ||
| 56 | }; | ||
| 57 | |||
| 58 | // This is nn::irsensor::PackedImageTransferProcessorFormat | ||
| 59 | enum class PackedImageTransferProcessorFormat : u8 { | ||
| 60 | Size320x240, | ||
| 61 | Size160x120, | ||
| 62 | Size80x60, | ||
| 63 | Size40x30, | ||
| 64 | Size20x15, | ||
| 65 | }; | ||
| 66 | |||
| 67 | // This is nn::irsensor::IrCameraStatus | ||
| 68 | enum class IrCameraStatus : u32 { | ||
| 69 | Available, | ||
| 70 | Unsupported, | ||
| 71 | Unconnected, | ||
| 72 | }; | ||
| 73 | |||
| 74 | // This is nn::irsensor::IrCameraInternalStatus | ||
| 75 | enum class IrCameraInternalStatus : u32 { | ||
| 76 | Stopped, | ||
| 77 | FirmwareUpdateNeeded, | ||
| 78 | Unkown2, | ||
| 79 | Unkown3, | ||
| 80 | Unkown4, | ||
| 81 | FirmwareVersionRequested, | ||
| 82 | FirmwareVersionIsInvalid, | ||
| 83 | Ready, | ||
| 84 | Setting, | ||
| 85 | }; | ||
| 86 | |||
| 87 | // This is nn::irsensor::detail::StatusManager::IrSensorMode | ||
| 88 | enum class IrSensorMode : u64 { | ||
| 89 | None, | ||
| 90 | MomentProcessor, | ||
| 91 | ClusteringProcessor, | ||
| 92 | ImageTransferProcessor, | ||
| 93 | PointingProcessorMarker, | ||
| 94 | TeraPluginProcessor, | ||
| 95 | IrLedProcessor, | ||
| 96 | }; | ||
| 97 | |||
| 98 | // This is nn::irsensor::ImageProcessorStatus | ||
| 99 | enum ImageProcessorStatus : u32 { | ||
| 100 | Stopped, | ||
| 101 | Running, | ||
| 102 | }; | ||
| 103 | |||
| 104 | // This is nn::irsensor::HandAnalysisMode | ||
| 105 | enum class HandAnalysisMode : u32 { | ||
| 106 | None, | ||
| 107 | Silhouette, | ||
| 108 | Image, | ||
| 109 | SilhoueteAndImage, | ||
| 110 | SilhuetteOnly, | ||
| 111 | }; | ||
| 112 | |||
| 113 | // This is nn::irsensor::IrSensorFunctionLevel | ||
| 114 | enum class IrSensorFunctionLevel : u8 { | ||
| 115 | unknown0, | ||
| 116 | unknown1, | ||
| 117 | unknown2, | ||
| 118 | unknown3, | ||
| 119 | unknown4, | ||
| 120 | }; | ||
| 121 | |||
| 122 | // This is nn::irsensor::MomentProcessorPreprocess | ||
| 123 | enum class MomentProcessorPreprocess : u32 { | ||
| 124 | Unkown0, | ||
| 125 | Unkown1, | ||
| 126 | }; | ||
| 127 | |||
| 128 | // This is nn::irsensor::PackedMomentProcessorPreprocess | ||
| 129 | enum class PackedMomentProcessorPreprocess : u8 { | ||
| 130 | Unkown0, | ||
| 131 | Unkown1, | ||
| 132 | }; | ||
| 133 | |||
| 134 | // This is nn::irsensor::PointingStatus | ||
| 135 | enum class PointingStatus : u32 { | ||
| 136 | Unkown0, | ||
| 137 | Unkown1, | ||
| 138 | }; | ||
| 139 | |||
| 140 | struct IrsRect { | ||
| 141 | s16 x; | ||
| 142 | s16 y; | ||
| 143 | s16 width; | ||
| 144 | s16 height; | ||
| 145 | }; | ||
| 146 | |||
| 147 | struct IrsCentroid { | ||
| 148 | f32 x; | ||
| 149 | f32 y; | ||
| 150 | }; | ||
| 151 | |||
| 152 | struct CameraConfig { | ||
| 153 | u64 exposure_time; | ||
| 154 | CameraLightTarget light_target; | ||
| 155 | u32 gain; | ||
| 156 | bool is_negative_used; | ||
| 157 | INSERT_PADDING_BYTES(7); | ||
| 158 | }; | ||
| 159 | static_assert(sizeof(CameraConfig) == 0x18, "CameraConfig is an invalid size"); | ||
| 160 | |||
| 161 | struct PackedCameraConfig { | ||
| 162 | u64 exposure_time; | ||
| 163 | PackedCameraLightTarget light_target; | ||
| 164 | u8 gain; | ||
| 165 | bool is_negative_used; | ||
| 166 | INSERT_PADDING_BYTES(5); | ||
| 167 | }; | ||
| 168 | static_assert(sizeof(PackedCameraConfig) == 0x10, "PackedCameraConfig is an invalid size"); | ||
| 169 | |||
| 170 | // This is nn::irsensor::IrCameraHandle | ||
| 171 | struct IrCameraHandle { | ||
| 172 | u8 npad_id{}; | ||
| 173 | Core::HID::NpadStyleIndex npad_type{Core::HID::NpadStyleIndex::None}; | ||
| 174 | INSERT_PADDING_BYTES(2); | ||
| 175 | }; | ||
| 176 | static_assert(sizeof(IrCameraHandle) == 4, "IrCameraHandle is an invalid size"); | ||
| 177 | |||
| 178 | // This is nn::irsensor::PackedMcuVersion | ||
| 179 | struct PackedMcuVersion { | ||
| 180 | u16 major; | ||
| 181 | u16 minor; | ||
| 182 | }; | ||
| 183 | static_assert(sizeof(PackedMcuVersion) == 4, "PackedMcuVersion is an invalid size"); | ||
| 184 | |||
| 185 | // This is nn::irsensor::PackedMomentProcessorConfig | ||
| 186 | struct PackedMomentProcessorConfig { | ||
| 187 | PackedCameraConfig camera_config; | ||
| 188 | IrsRect window_of_interest; | ||
| 189 | PackedMcuVersion required_mcu_version; | ||
| 190 | PackedMomentProcessorPreprocess preprocess; | ||
| 191 | u8 preprocess_intensity_threshold; | ||
| 192 | INSERT_PADDING_BYTES(2); | ||
| 193 | }; | ||
| 194 | static_assert(sizeof(PackedMomentProcessorConfig) == 0x20, | ||
| 195 | "PackedMomentProcessorConfig is an invalid size"); | ||
| 196 | |||
| 197 | // This is nn::irsensor::PackedClusteringProcessorConfig | ||
| 198 | struct PackedClusteringProcessorConfig { | ||
| 199 | PackedCameraConfig camera_config; | ||
| 200 | IrsRect window_of_interest; | ||
| 201 | PackedMcuVersion required_mcu_version; | ||
| 202 | u32 pixel_count_min; | ||
| 203 | u32 pixel_count_max; | ||
| 204 | u8 object_intensity_min; | ||
| 205 | bool is_external_light_filter_enabled; | ||
| 206 | INSERT_PADDING_BYTES(2); | ||
| 207 | }; | ||
| 208 | static_assert(sizeof(PackedClusteringProcessorConfig) == 0x28, | ||
| 209 | "PackedClusteringProcessorConfig is an invalid size"); | ||
| 210 | |||
| 211 | // This is nn::irsensor::PackedImageTransferProcessorConfig | ||
| 212 | struct PackedImageTransferProcessorConfig { | ||
| 213 | PackedCameraConfig camera_config; | ||
| 214 | PackedMcuVersion required_mcu_version; | ||
| 215 | PackedImageTransferProcessorFormat format; | ||
| 216 | INSERT_PADDING_BYTES(3); | ||
| 217 | }; | ||
| 218 | static_assert(sizeof(PackedImageTransferProcessorConfig) == 0x18, | ||
| 219 | "PackedImageTransferProcessorConfig is an invalid size"); | ||
| 220 | |||
| 221 | // This is nn::irsensor::PackedTeraPluginProcessorConfig | ||
| 222 | struct PackedTeraPluginProcessorConfig { | ||
| 223 | PackedMcuVersion required_mcu_version; | ||
| 224 | u8 mode; | ||
| 225 | u8 unknown_1; | ||
| 226 | u8 unknown_2; | ||
| 227 | u8 unknown_3; | ||
| 228 | }; | ||
| 229 | static_assert(sizeof(PackedTeraPluginProcessorConfig) == 0x8, | ||
| 230 | "PackedTeraPluginProcessorConfig is an invalid size"); | ||
| 231 | |||
| 232 | // This is nn::irsensor::PackedPointingProcessorConfig | ||
| 233 | struct PackedPointingProcessorConfig { | ||
| 234 | IrsRect window_of_interest; | ||
| 235 | PackedMcuVersion required_mcu_version; | ||
| 236 | }; | ||
| 237 | static_assert(sizeof(PackedPointingProcessorConfig) == 0xC, | ||
| 238 | "PackedPointingProcessorConfig is an invalid size"); | ||
| 239 | |||
| 240 | // This is nn::irsensor::PackedFunctionLevel | ||
| 241 | struct PackedFunctionLevel { | ||
| 242 | IrSensorFunctionLevel function_level; | ||
| 243 | INSERT_PADDING_BYTES(3); | ||
| 244 | }; | ||
| 245 | static_assert(sizeof(PackedFunctionLevel) == 0x4, "PackedFunctionLevel is an invalid size"); | ||
| 246 | |||
| 247 | // This is nn::irsensor::PackedImageTransferProcessorExConfig | ||
| 248 | struct PackedImageTransferProcessorExConfig { | ||
| 249 | PackedCameraConfig camera_config; | ||
| 250 | PackedMcuVersion required_mcu_version; | ||
| 251 | PackedImageTransferProcessorFormat origin_format; | ||
| 252 | PackedImageTransferProcessorFormat trimming_format; | ||
| 253 | u16 trimming_start_x; | ||
| 254 | u16 trimming_start_y; | ||
| 255 | bool is_external_light_filter_enabled; | ||
| 256 | INSERT_PADDING_BYTES(5); | ||
| 257 | }; | ||
| 258 | static_assert(sizeof(PackedImageTransferProcessorExConfig) == 0x20, | ||
| 259 | "PackedImageTransferProcessorExConfig is an invalid size"); | ||
| 260 | |||
| 261 | // This is nn::irsensor::PackedIrLedProcessorConfig | ||
| 262 | struct PackedIrLedProcessorConfig { | ||
| 263 | PackedMcuVersion required_mcu_version; | ||
| 264 | u8 light_target; | ||
| 265 | INSERT_PADDING_BYTES(3); | ||
| 266 | }; | ||
| 267 | static_assert(sizeof(PackedIrLedProcessorConfig) == 0x8, | ||
| 268 | "PackedIrLedProcessorConfig is an invalid size"); | ||
| 269 | |||
| 270 | // This is nn::irsensor::HandAnalysisConfig | ||
| 271 | struct HandAnalysisConfig { | ||
| 272 | HandAnalysisMode mode; | ||
| 273 | }; | ||
| 274 | static_assert(sizeof(HandAnalysisConfig) == 0x4, "HandAnalysisConfig is an invalid size"); | ||
| 275 | |||
| 276 | // This is nn::irsensor::detail::ProcessorState contents are different for each processor | ||
| 277 | struct ProcessorState { | ||
| 278 | std::array<u8, 0xE20> processor_raw_data{}; | ||
| 279 | }; | ||
| 280 | static_assert(sizeof(ProcessorState) == 0xE20, "ProcessorState is an invalid size"); | ||
| 281 | |||
| 282 | // This is nn::irsensor::detail::DeviceFormat | ||
| 283 | struct DeviceFormat { | ||
| 284 | Core::IrSensor::IrCameraStatus camera_status{Core::IrSensor::IrCameraStatus::Unconnected}; | ||
| 285 | Core::IrSensor::IrCameraInternalStatus camera_internal_status{ | ||
| 286 | Core::IrSensor::IrCameraInternalStatus::Ready}; | ||
| 287 | Core::IrSensor::IrSensorMode mode{Core::IrSensor::IrSensorMode::None}; | ||
| 288 | ProcessorState state{}; | ||
| 289 | }; | ||
| 290 | static_assert(sizeof(DeviceFormat) == 0xE30, "DeviceFormat is an invalid size"); | ||
| 291 | |||
| 292 | // This is nn::irsensor::ImageTransferProcessorState | ||
| 293 | struct ImageTransferProcessorState { | ||
| 294 | u64 sampling_number; | ||
| 295 | Core::IrSensor::CameraAmbientNoiseLevel ambient_noise_level; | ||
| 296 | INSERT_PADDING_BYTES(4); | ||
| 297 | }; | ||
| 298 | static_assert(sizeof(ImageTransferProcessorState) == 0x10, | ||
| 299 | "ImageTransferProcessorState is an invalid size"); | ||
| 300 | |||
| 301 | } // namespace Core::IrSensor | ||
diff --git a/src/core/hle/service/hid/errors.h b/src/core/hle/service/hid/errors.h index 46282f42e..4613a4e60 100644 --- a/src/core/hle/service/hid/errors.h +++ b/src/core/hle/service/hid/errors.h | |||
| @@ -19,3 +19,10 @@ constexpr Result InvalidNpadId{ErrorModule::HID, 709}; | |||
| 19 | constexpr Result NpadNotConnected{ErrorModule::HID, 710}; | 19 | constexpr Result NpadNotConnected{ErrorModule::HID, 710}; |
| 20 | 20 | ||
| 21 | } // namespace Service::HID | 21 | } // namespace Service::HID |
| 22 | |||
| 23 | namespace Service::IRS { | ||
| 24 | |||
| 25 | constexpr Result InvalidProcessorState{ErrorModule::Irsensor, 78}; | ||
| 26 | constexpr Result InvalidIrCameraHandle{ErrorModule::Irsensor, 204}; | ||
| 27 | |||
| 28 | } // namespace Service::IRS | ||
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 89bb12442..5ecbddf94 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp | |||
| @@ -2345,8 +2345,8 @@ void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system | |||
| 2345 | std::make_shared<HidSys>(system)->InstallAsService(service_manager); | 2345 | std::make_shared<HidSys>(system)->InstallAsService(service_manager); |
| 2346 | std::make_shared<HidTmp>(system)->InstallAsService(service_manager); | 2346 | std::make_shared<HidTmp>(system)->InstallAsService(service_manager); |
| 2347 | 2347 | ||
| 2348 | std::make_shared<IRS>(system)->InstallAsService(service_manager); | 2348 | std::make_shared<Service::IRS::IRS>(system)->InstallAsService(service_manager); |
| 2349 | std::make_shared<IRS_SYS>(system)->InstallAsService(service_manager); | 2349 | std::make_shared<Service::IRS::IRS_SYS>(system)->InstallAsService(service_manager); |
| 2350 | 2350 | ||
| 2351 | std::make_shared<XCD_SYS>(system)->InstallAsService(service_manager); | 2351 | std::make_shared<XCD_SYS>(system)->InstallAsService(service_manager); |
| 2352 | } | 2352 | } |
diff --git a/src/core/hle/service/hid/irs.cpp b/src/core/hle/service/hid/irs.cpp index d2a91d913..d5107e41f 100644 --- a/src/core/hle/service/hid/irs.cpp +++ b/src/core/hle/service/hid/irs.cpp | |||
| @@ -1,16 +1,28 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2018 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 <algorithm> | ||
| 5 | #include <random> | ||
| 6 | |||
| 4 | #include "core/core.h" | 7 | #include "core/core.h" |
| 5 | #include "core/core_timing.h" | 8 | #include "core/core_timing.h" |
| 9 | #include "core/hid/emulated_controller.h" | ||
| 10 | #include "core/hid/hid_core.h" | ||
| 6 | #include "core/hle/ipc_helpers.h" | 11 | #include "core/hle/ipc_helpers.h" |
| 7 | #include "core/hle/kernel/k_shared_memory.h" | 12 | #include "core/hle/kernel/k_shared_memory.h" |
| 8 | #include "core/hle/kernel/k_transfer_memory.h" | 13 | #include "core/hle/kernel/k_transfer_memory.h" |
| 9 | #include "core/hle/kernel/kernel.h" | 14 | #include "core/hle/kernel/kernel.h" |
| 10 | #include "core/hle/service/hid/errors.h" | 15 | #include "core/hle/service/hid/errors.h" |
| 11 | #include "core/hle/service/hid/irs.h" | 16 | #include "core/hle/service/hid/irs.h" |
| 17 | #include "core/hle/service/hid/irsensor/clustering_processor.h" | ||
| 18 | #include "core/hle/service/hid/irsensor/image_transfer_processor.h" | ||
| 19 | #include "core/hle/service/hid/irsensor/ir_led_processor.h" | ||
| 20 | #include "core/hle/service/hid/irsensor/moment_processor.h" | ||
| 21 | #include "core/hle/service/hid/irsensor/pointing_processor.h" | ||
| 22 | #include "core/hle/service/hid/irsensor/tera_plugin_processor.h" | ||
| 23 | #include "core/memory.h" | ||
| 12 | 24 | ||
| 13 | namespace Service::HID { | 25 | namespace Service::IRS { |
| 14 | 26 | ||
| 15 | IRS::IRS(Core::System& system_) : ServiceFramework{system_, "irs"} { | 27 | IRS::IRS(Core::System& system_) : ServiceFramework{system_, "irs"} { |
| 16 | // clang-format off | 28 | // clang-format off |
| @@ -36,14 +48,19 @@ IRS::IRS(Core::System& system_) : ServiceFramework{system_, "irs"} { | |||
| 36 | }; | 48 | }; |
| 37 | // clang-format on | 49 | // clang-format on |
| 38 | 50 | ||
| 51 | u8* raw_shared_memory = system.Kernel().GetIrsSharedMem().GetPointer(); | ||
| 39 | RegisterHandlers(functions); | 52 | RegisterHandlers(functions); |
| 53 | shared_memory = std::construct_at(reinterpret_cast<StatusManager*>(raw_shared_memory)); | ||
| 54 | |||
| 55 | npad_device = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); | ||
| 40 | } | 56 | } |
| 57 | IRS::~IRS() = default; | ||
| 41 | 58 | ||
| 42 | void IRS::ActivateIrsensor(Kernel::HLERequestContext& ctx) { | 59 | void IRS::ActivateIrsensor(Kernel::HLERequestContext& ctx) { |
| 43 | IPC::RequestParser rp{ctx}; | 60 | IPC::RequestParser rp{ctx}; |
| 44 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 61 | const auto applet_resource_user_id{rp.Pop<u64>()}; |
| 45 | 62 | ||
| 46 | LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}", | 63 | LOG_WARNING(Service_IRS, "(STUBBED) called, applet_resource_user_id={}", |
| 47 | applet_resource_user_id); | 64 | applet_resource_user_id); |
| 48 | 65 | ||
| 49 | IPC::ResponseBuilder rb{ctx, 2}; | 66 | IPC::ResponseBuilder rb{ctx, 2}; |
| @@ -54,7 +71,7 @@ void IRS::DeactivateIrsensor(Kernel::HLERequestContext& ctx) { | |||
| 54 | IPC::RequestParser rp{ctx}; | 71 | IPC::RequestParser rp{ctx}; |
| 55 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 72 | const auto applet_resource_user_id{rp.Pop<u64>()}; |
| 56 | 73 | ||
| 57 | LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}", | 74 | LOG_WARNING(Service_IRS, "(STUBBED) called, applet_resource_user_id={}", |
| 58 | applet_resource_user_id); | 75 | applet_resource_user_id); |
| 59 | 76 | ||
| 60 | IPC::ResponseBuilder rb{ctx, 2}; | 77 | IPC::ResponseBuilder rb{ctx, 2}; |
| @@ -75,7 +92,7 @@ void IRS::GetIrsensorSharedMemoryHandle(Kernel::HLERequestContext& ctx) { | |||
| 75 | void IRS::StopImageProcessor(Kernel::HLERequestContext& ctx) { | 92 | void IRS::StopImageProcessor(Kernel::HLERequestContext& ctx) { |
| 76 | IPC::RequestParser rp{ctx}; | 93 | IPC::RequestParser rp{ctx}; |
| 77 | struct Parameters { | 94 | struct Parameters { |
| 78 | IrCameraHandle camera_handle; | 95 | Core::IrSensor::IrCameraHandle camera_handle; |
| 79 | INSERT_PADDING_WORDS_NOINIT(1); | 96 | INSERT_PADDING_WORDS_NOINIT(1); |
| 80 | u64 applet_resource_user_id; | 97 | u64 applet_resource_user_id; |
| 81 | }; | 98 | }; |
| @@ -88,17 +105,23 @@ void IRS::StopImageProcessor(Kernel::HLERequestContext& ctx) { | |||
| 88 | parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, | 105 | parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, |
| 89 | parameters.applet_resource_user_id); | 106 | parameters.applet_resource_user_id); |
| 90 | 107 | ||
| 108 | auto result = IsIrCameraHandleValid(parameters.camera_handle); | ||
| 109 | if (result.IsSuccess()) { | ||
| 110 | // TODO: Stop Image processor | ||
| 111 | result = ResultSuccess; | ||
| 112 | } | ||
| 113 | |||
| 91 | IPC::ResponseBuilder rb{ctx, 2}; | 114 | IPC::ResponseBuilder rb{ctx, 2}; |
| 92 | rb.Push(ResultSuccess); | 115 | rb.Push(result); |
| 93 | } | 116 | } |
| 94 | 117 | ||
| 95 | void IRS::RunMomentProcessor(Kernel::HLERequestContext& ctx) { | 118 | void IRS::RunMomentProcessor(Kernel::HLERequestContext& ctx) { |
| 96 | IPC::RequestParser rp{ctx}; | 119 | IPC::RequestParser rp{ctx}; |
| 97 | struct Parameters { | 120 | struct Parameters { |
| 98 | IrCameraHandle camera_handle; | 121 | Core::IrSensor::IrCameraHandle camera_handle; |
| 99 | INSERT_PADDING_WORDS_NOINIT(1); | 122 | INSERT_PADDING_WORDS_NOINIT(1); |
| 100 | u64 applet_resource_user_id; | 123 | u64 applet_resource_user_id; |
| 101 | PackedMomentProcessorConfig processor_config; | 124 | Core::IrSensor::PackedMomentProcessorConfig processor_config; |
| 102 | }; | 125 | }; |
| 103 | static_assert(sizeof(Parameters) == 0x30, "Parameters has incorrect size."); | 126 | static_assert(sizeof(Parameters) == 0x30, "Parameters has incorrect size."); |
| 104 | 127 | ||
| @@ -109,19 +132,28 @@ void IRS::RunMomentProcessor(Kernel::HLERequestContext& ctx) { | |||
| 109 | parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, | 132 | parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, |
| 110 | parameters.applet_resource_user_id); | 133 | parameters.applet_resource_user_id); |
| 111 | 134 | ||
| 135 | const auto result = IsIrCameraHandleValid(parameters.camera_handle); | ||
| 136 | |||
| 137 | if (result.IsSuccess()) { | ||
| 138 | auto& device = GetIrCameraSharedMemoryDeviceEntry(parameters.camera_handle); | ||
| 139 | MakeProcessor<MomentProcessor>(parameters.camera_handle, device); | ||
| 140 | auto& image_transfer_processor = GetProcessor<MomentProcessor>(parameters.camera_handle); | ||
| 141 | image_transfer_processor.SetConfig(parameters.processor_config); | ||
| 142 | } | ||
| 143 | |||
| 112 | IPC::ResponseBuilder rb{ctx, 2}; | 144 | IPC::ResponseBuilder rb{ctx, 2}; |
| 113 | rb.Push(ResultSuccess); | 145 | rb.Push(result); |
| 114 | } | 146 | } |
| 115 | 147 | ||
| 116 | void IRS::RunClusteringProcessor(Kernel::HLERequestContext& ctx) { | 148 | void IRS::RunClusteringProcessor(Kernel::HLERequestContext& ctx) { |
| 117 | IPC::RequestParser rp{ctx}; | 149 | IPC::RequestParser rp{ctx}; |
| 118 | struct Parameters { | 150 | struct Parameters { |
| 119 | IrCameraHandle camera_handle; | 151 | Core::IrSensor::IrCameraHandle camera_handle; |
| 120 | INSERT_PADDING_WORDS_NOINIT(1); | 152 | INSERT_PADDING_WORDS_NOINIT(1); |
| 121 | u64 applet_resource_user_id; | 153 | u64 applet_resource_user_id; |
| 122 | PackedClusteringProcessorConfig processor_config; | 154 | Core::IrSensor::PackedClusteringProcessorConfig processor_config; |
| 123 | }; | 155 | }; |
| 124 | static_assert(sizeof(Parameters) == 0x40, "Parameters has incorrect size."); | 156 | static_assert(sizeof(Parameters) == 0x38, "Parameters has incorrect size."); |
| 125 | 157 | ||
| 126 | const auto parameters{rp.PopRaw<Parameters>()}; | 158 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 127 | 159 | ||
| @@ -130,17 +162,27 @@ void IRS::RunClusteringProcessor(Kernel::HLERequestContext& ctx) { | |||
| 130 | parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, | 162 | parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, |
| 131 | parameters.applet_resource_user_id); | 163 | parameters.applet_resource_user_id); |
| 132 | 164 | ||
| 165 | auto result = IsIrCameraHandleValid(parameters.camera_handle); | ||
| 166 | |||
| 167 | if (result.IsSuccess()) { | ||
| 168 | auto& device = GetIrCameraSharedMemoryDeviceEntry(parameters.camera_handle); | ||
| 169 | MakeProcessor<ClusteringProcessor>(parameters.camera_handle, device); | ||
| 170 | auto& image_transfer_processor = | ||
| 171 | GetProcessor<ClusteringProcessor>(parameters.camera_handle); | ||
| 172 | image_transfer_processor.SetConfig(parameters.processor_config); | ||
| 173 | } | ||
| 174 | |||
| 133 | IPC::ResponseBuilder rb{ctx, 2}; | 175 | IPC::ResponseBuilder rb{ctx, 2}; |
| 134 | rb.Push(ResultSuccess); | 176 | rb.Push(result); |
| 135 | } | 177 | } |
| 136 | 178 | ||
| 137 | void IRS::RunImageTransferProcessor(Kernel::HLERequestContext& ctx) { | 179 | void IRS::RunImageTransferProcessor(Kernel::HLERequestContext& ctx) { |
| 138 | IPC::RequestParser rp{ctx}; | 180 | IPC::RequestParser rp{ctx}; |
| 139 | struct Parameters { | 181 | struct Parameters { |
| 140 | IrCameraHandle camera_handle; | 182 | Core::IrSensor::IrCameraHandle camera_handle; |
| 141 | INSERT_PADDING_WORDS_NOINIT(1); | 183 | INSERT_PADDING_WORDS_NOINIT(1); |
| 142 | u64 applet_resource_user_id; | 184 | u64 applet_resource_user_id; |
| 143 | PackedImageTransferProcessorConfig processor_config; | 185 | Core::IrSensor::PackedImageTransferProcessorConfig processor_config; |
| 144 | u32 transfer_memory_size; | 186 | u32 transfer_memory_size; |
| 145 | }; | 187 | }; |
| 146 | static_assert(sizeof(Parameters) == 0x30, "Parameters has incorrect size."); | 188 | static_assert(sizeof(Parameters) == 0x30, "Parameters has incorrect size."); |
| @@ -151,20 +193,42 @@ void IRS::RunImageTransferProcessor(Kernel::HLERequestContext& ctx) { | |||
| 151 | auto t_mem = | 193 | auto t_mem = |
| 152 | system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(t_mem_handle); | 194 | system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(t_mem_handle); |
| 153 | 195 | ||
| 154 | LOG_WARNING(Service_IRS, | 196 | if (t_mem.IsNull()) { |
| 155 | "(STUBBED) called, npad_type={}, npad_id={}, transfer_memory_size={}, " | 197 | LOG_ERROR(Service_IRS, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle); |
| 156 | "applet_resource_user_id={}", | 198 | IPC::ResponseBuilder rb{ctx, 2}; |
| 157 | parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, | 199 | rb.Push(ResultUnknown); |
| 158 | parameters.transfer_memory_size, parameters.applet_resource_user_id); | 200 | return; |
| 201 | } | ||
| 202 | |||
| 203 | ASSERT_MSG(t_mem->GetSize() == parameters.transfer_memory_size, "t_mem has incorrect size"); | ||
| 204 | |||
| 205 | u8* transfer_memory = system.Memory().GetPointer(t_mem->GetSourceAddress()); | ||
| 206 | |||
| 207 | LOG_INFO(Service_IRS, | ||
| 208 | "called, npad_type={}, npad_id={}, transfer_memory_size={}, transfer_memory_size={}, " | ||
| 209 | "applet_resource_user_id={}", | ||
| 210 | parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, | ||
| 211 | parameters.transfer_memory_size, t_mem->GetSize(), parameters.applet_resource_user_id); | ||
| 212 | |||
| 213 | const auto result = IsIrCameraHandleValid(parameters.camera_handle); | ||
| 214 | |||
| 215 | if (result.IsSuccess()) { | ||
| 216 | auto& device = GetIrCameraSharedMemoryDeviceEntry(parameters.camera_handle); | ||
| 217 | MakeProcessorWithCoreContext<ImageTransferProcessor>(parameters.camera_handle, device); | ||
| 218 | auto& image_transfer_processor = | ||
| 219 | GetProcessor<ImageTransferProcessor>(parameters.camera_handle); | ||
| 220 | image_transfer_processor.SetConfig(parameters.processor_config); | ||
| 221 | image_transfer_processor.SetTransferMemoryPointer(transfer_memory); | ||
| 222 | } | ||
| 159 | 223 | ||
| 160 | IPC::ResponseBuilder rb{ctx, 2}; | 224 | IPC::ResponseBuilder rb{ctx, 2}; |
| 161 | rb.Push(ResultSuccess); | 225 | rb.Push(result); |
| 162 | } | 226 | } |
| 163 | 227 | ||
| 164 | void IRS::GetImageTransferProcessorState(Kernel::HLERequestContext& ctx) { | 228 | void IRS::GetImageTransferProcessorState(Kernel::HLERequestContext& ctx) { |
| 165 | IPC::RequestParser rp{ctx}; | 229 | IPC::RequestParser rp{ctx}; |
| 166 | struct Parameters { | 230 | struct Parameters { |
| 167 | IrCameraHandle camera_handle; | 231 | Core::IrSensor::IrCameraHandle camera_handle; |
| 168 | INSERT_PADDING_WORDS_NOINIT(1); | 232 | INSERT_PADDING_WORDS_NOINIT(1); |
| 169 | u64 applet_resource_user_id; | 233 | u64 applet_resource_user_id; |
| 170 | }; | 234 | }; |
| @@ -172,32 +236,68 @@ void IRS::GetImageTransferProcessorState(Kernel::HLERequestContext& ctx) { | |||
| 172 | 236 | ||
| 173 | const auto parameters{rp.PopRaw<Parameters>()}; | 237 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 174 | 238 | ||
| 175 | LOG_WARNING(Service_IRS, | 239 | LOG_DEBUG(Service_IRS, "(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}", |
| 176 | "(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}", | 240 | parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, |
| 177 | parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, | 241 | parameters.applet_resource_user_id); |
| 178 | parameters.applet_resource_user_id); | 242 | |
| 243 | const auto result = IsIrCameraHandleValid(parameters.camera_handle); | ||
| 244 | if (result.IsError()) { | ||
| 245 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 246 | rb.Push(result); | ||
| 247 | return; | ||
| 248 | } | ||
| 249 | |||
| 250 | const auto& device = GetIrCameraSharedMemoryDeviceEntry(parameters.camera_handle); | ||
| 251 | |||
| 252 | if (device.mode != Core::IrSensor::IrSensorMode::ImageTransferProcessor) { | ||
| 253 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 254 | rb.Push(InvalidProcessorState); | ||
| 255 | return; | ||
| 256 | } | ||
| 179 | 257 | ||
| 180 | IPC::ResponseBuilder rb{ctx, 5}; | 258 | std::vector<u8> data{}; |
| 259 | const auto& image_transfer_processor = | ||
| 260 | GetProcessor<ImageTransferProcessor>(parameters.camera_handle); | ||
| 261 | const auto& state = image_transfer_processor.GetState(data); | ||
| 262 | |||
| 263 | ctx.WriteBuffer(data); | ||
| 264 | IPC::ResponseBuilder rb{ctx, 6}; | ||
| 181 | rb.Push(ResultSuccess); | 265 | rb.Push(ResultSuccess); |
| 182 | rb.PushRaw<u64>(system.CoreTiming().GetCPUTicks()); | 266 | rb.PushRaw(state); |
| 183 | rb.PushRaw<u32>(0); | ||
| 184 | } | 267 | } |
| 185 | 268 | ||
| 186 | void IRS::RunTeraPluginProcessor(Kernel::HLERequestContext& ctx) { | 269 | void IRS::RunTeraPluginProcessor(Kernel::HLERequestContext& ctx) { |
| 187 | IPC::RequestParser rp{ctx}; | 270 | IPC::RequestParser rp{ctx}; |
| 188 | const auto camera_handle{rp.PopRaw<IrCameraHandle>()}; | 271 | struct Parameters { |
| 189 | const auto processor_config{rp.PopRaw<PackedTeraPluginProcessorConfig>()}; | 272 | Core::IrSensor::IrCameraHandle camera_handle; |
| 190 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 273 | Core::IrSensor::PackedTeraPluginProcessorConfig processor_config; |
| 274 | INSERT_PADDING_WORDS_NOINIT(1); | ||
| 275 | u64 applet_resource_user_id; | ||
| 276 | }; | ||
| 277 | static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size."); | ||
| 191 | 278 | ||
| 192 | LOG_WARNING(Service_IRS, | 279 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 193 | "(STUBBED) called, npad_type={}, npad_id={}, mode={}, mcu_version={}.{}, " | 280 | |
| 194 | "applet_resource_user_id={}", | 281 | LOG_WARNING( |
| 195 | camera_handle.npad_type, camera_handle.npad_id, processor_config.mode, | 282 | Service_IRS, |
| 196 | processor_config.required_mcu_version.major, | 283 | "(STUBBED) called, npad_type={}, npad_id={}, mode={}, mcu_version={}.{}, " |
| 197 | processor_config.required_mcu_version.minor, applet_resource_user_id); | 284 | "applet_resource_user_id={}", |
| 285 | parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, | ||
| 286 | parameters.processor_config.mode, parameters.processor_config.required_mcu_version.major, | ||
| 287 | parameters.processor_config.required_mcu_version.minor, parameters.applet_resource_user_id); | ||
| 288 | |||
| 289 | const auto result = IsIrCameraHandleValid(parameters.camera_handle); | ||
| 290 | |||
| 291 | if (result.IsSuccess()) { | ||
| 292 | auto& device = GetIrCameraSharedMemoryDeviceEntry(parameters.camera_handle); | ||
| 293 | MakeProcessor<TeraPluginProcessor>(parameters.camera_handle, device); | ||
| 294 | auto& image_transfer_processor = | ||
| 295 | GetProcessor<TeraPluginProcessor>(parameters.camera_handle); | ||
| 296 | image_transfer_processor.SetConfig(parameters.processor_config); | ||
| 297 | } | ||
| 198 | 298 | ||
| 199 | IPC::ResponseBuilder rb{ctx, 2}; | 299 | IPC::ResponseBuilder rb{ctx, 2}; |
| 200 | rb.Push(ResultSuccess); | 300 | rb.Push(result); |
| 201 | } | 301 | } |
| 202 | 302 | ||
| 203 | void IRS::GetNpadIrCameraHandle(Kernel::HLERequestContext& ctx) { | 303 | void IRS::GetNpadIrCameraHandle(Kernel::HLERequestContext& ctx) { |
| @@ -207,17 +307,17 @@ void IRS::GetNpadIrCameraHandle(Kernel::HLERequestContext& ctx) { | |||
| 207 | if (npad_id > Core::HID::NpadIdType::Player8 && npad_id != Core::HID::NpadIdType::Invalid && | 307 | if (npad_id > Core::HID::NpadIdType::Player8 && npad_id != Core::HID::NpadIdType::Invalid && |
| 208 | npad_id != Core::HID::NpadIdType::Handheld) { | 308 | npad_id != Core::HID::NpadIdType::Handheld) { |
| 209 | IPC::ResponseBuilder rb{ctx, 2}; | 309 | IPC::ResponseBuilder rb{ctx, 2}; |
| 210 | rb.Push(InvalidNpadId); | 310 | rb.Push(Service::HID::InvalidNpadId); |
| 211 | return; | 311 | return; |
| 212 | } | 312 | } |
| 213 | 313 | ||
| 214 | IrCameraHandle camera_handle{ | 314 | Core::IrSensor::IrCameraHandle camera_handle{ |
| 215 | .npad_id = static_cast<u8>(NpadIdTypeToIndex(npad_id)), | 315 | .npad_id = static_cast<u8>(NpadIdTypeToIndex(npad_id)), |
| 216 | .npad_type = Core::HID::NpadStyleIndex::None, | 316 | .npad_type = Core::HID::NpadStyleIndex::None, |
| 217 | }; | 317 | }; |
| 218 | 318 | ||
| 219 | LOG_WARNING(Service_IRS, "(STUBBED) called, npad_id={}, camera_npad_id={}, camera_npad_type={}", | 319 | LOG_INFO(Service_IRS, "called, npad_id={}, camera_npad_id={}, camera_npad_type={}", npad_id, |
| 220 | npad_id, camera_handle.npad_id, camera_handle.npad_type); | 320 | camera_handle.npad_id, camera_handle.npad_type); |
| 221 | 321 | ||
| 222 | IPC::ResponseBuilder rb{ctx, 3}; | 322 | IPC::ResponseBuilder rb{ctx, 3}; |
| 223 | rb.Push(ResultSuccess); | 323 | rb.Push(ResultSuccess); |
| @@ -226,8 +326,8 @@ void IRS::GetNpadIrCameraHandle(Kernel::HLERequestContext& ctx) { | |||
| 226 | 326 | ||
| 227 | void IRS::RunPointingProcessor(Kernel::HLERequestContext& ctx) { | 327 | void IRS::RunPointingProcessor(Kernel::HLERequestContext& ctx) { |
| 228 | IPC::RequestParser rp{ctx}; | 328 | IPC::RequestParser rp{ctx}; |
| 229 | const auto camera_handle{rp.PopRaw<IrCameraHandle>()}; | 329 | const auto camera_handle{rp.PopRaw<Core::IrSensor::IrCameraHandle>()}; |
| 230 | const auto processor_config{rp.PopRaw<PackedPointingProcessorConfig>()}; | 330 | const auto processor_config{rp.PopRaw<Core::IrSensor::PackedPointingProcessorConfig>()}; |
| 231 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 331 | const auto applet_resource_user_id{rp.Pop<u64>()}; |
| 232 | 332 | ||
| 233 | LOG_WARNING( | 333 | LOG_WARNING( |
| @@ -236,14 +336,23 @@ void IRS::RunPointingProcessor(Kernel::HLERequestContext& ctx) { | |||
| 236 | camera_handle.npad_type, camera_handle.npad_id, processor_config.required_mcu_version.major, | 336 | camera_handle.npad_type, camera_handle.npad_id, processor_config.required_mcu_version.major, |
| 237 | processor_config.required_mcu_version.minor, applet_resource_user_id); | 337 | processor_config.required_mcu_version.minor, applet_resource_user_id); |
| 238 | 338 | ||
| 339 | auto result = IsIrCameraHandleValid(camera_handle); | ||
| 340 | |||
| 341 | if (result.IsSuccess()) { | ||
| 342 | auto& device = GetIrCameraSharedMemoryDeviceEntry(camera_handle); | ||
| 343 | MakeProcessor<PointingProcessor>(camera_handle, device); | ||
| 344 | auto& image_transfer_processor = GetProcessor<PointingProcessor>(camera_handle); | ||
| 345 | image_transfer_processor.SetConfig(processor_config); | ||
| 346 | } | ||
| 347 | |||
| 239 | IPC::ResponseBuilder rb{ctx, 2}; | 348 | IPC::ResponseBuilder rb{ctx, 2}; |
| 240 | rb.Push(ResultSuccess); | 349 | rb.Push(result); |
| 241 | } | 350 | } |
| 242 | 351 | ||
| 243 | void IRS::SuspendImageProcessor(Kernel::HLERequestContext& ctx) { | 352 | void IRS::SuspendImageProcessor(Kernel::HLERequestContext& ctx) { |
| 244 | IPC::RequestParser rp{ctx}; | 353 | IPC::RequestParser rp{ctx}; |
| 245 | struct Parameters { | 354 | struct Parameters { |
| 246 | IrCameraHandle camera_handle; | 355 | Core::IrSensor::IrCameraHandle camera_handle; |
| 247 | INSERT_PADDING_WORDS_NOINIT(1); | 356 | INSERT_PADDING_WORDS_NOINIT(1); |
| 248 | u64 applet_resource_user_id; | 357 | u64 applet_resource_user_id; |
| 249 | }; | 358 | }; |
| @@ -256,14 +365,20 @@ void IRS::SuspendImageProcessor(Kernel::HLERequestContext& ctx) { | |||
| 256 | parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, | 365 | parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, |
| 257 | parameters.applet_resource_user_id); | 366 | parameters.applet_resource_user_id); |
| 258 | 367 | ||
| 368 | auto result = IsIrCameraHandleValid(parameters.camera_handle); | ||
| 369 | if (result.IsSuccess()) { | ||
| 370 | // TODO: Suspend image processor | ||
| 371 | result = ResultSuccess; | ||
| 372 | } | ||
| 373 | |||
| 259 | IPC::ResponseBuilder rb{ctx, 2}; | 374 | IPC::ResponseBuilder rb{ctx, 2}; |
| 260 | rb.Push(ResultSuccess); | 375 | rb.Push(result); |
| 261 | } | 376 | } |
| 262 | 377 | ||
| 263 | void IRS::CheckFirmwareVersion(Kernel::HLERequestContext& ctx) { | 378 | void IRS::CheckFirmwareVersion(Kernel::HLERequestContext& ctx) { |
| 264 | IPC::RequestParser rp{ctx}; | 379 | IPC::RequestParser rp{ctx}; |
| 265 | const auto camera_handle{rp.PopRaw<IrCameraHandle>()}; | 380 | const auto camera_handle{rp.PopRaw<Core::IrSensor::IrCameraHandle>()}; |
| 266 | const auto mcu_version{rp.PopRaw<PackedMcuVersion>()}; | 381 | const auto mcu_version{rp.PopRaw<Core::IrSensor::PackedMcuVersion>()}; |
| 267 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 382 | const auto applet_resource_user_id{rp.Pop<u64>()}; |
| 268 | 383 | ||
| 269 | LOG_WARNING( | 384 | LOG_WARNING( |
| @@ -272,37 +387,45 @@ void IRS::CheckFirmwareVersion(Kernel::HLERequestContext& ctx) { | |||
| 272 | camera_handle.npad_type, camera_handle.npad_id, applet_resource_user_id, mcu_version.major, | 387 | camera_handle.npad_type, camera_handle.npad_id, applet_resource_user_id, mcu_version.major, |
| 273 | mcu_version.minor); | 388 | mcu_version.minor); |
| 274 | 389 | ||
| 390 | auto result = IsIrCameraHandleValid(camera_handle); | ||
| 391 | if (result.IsSuccess()) { | ||
| 392 | // TODO: Check firmware version | ||
| 393 | result = ResultSuccess; | ||
| 394 | } | ||
| 395 | |||
| 275 | IPC::ResponseBuilder rb{ctx, 2}; | 396 | IPC::ResponseBuilder rb{ctx, 2}; |
| 276 | rb.Push(ResultSuccess); | 397 | rb.Push(result); |
| 277 | } | 398 | } |
| 278 | 399 | ||
| 279 | void IRS::SetFunctionLevel(Kernel::HLERequestContext& ctx) { | 400 | void IRS::SetFunctionLevel(Kernel::HLERequestContext& ctx) { |
| 280 | IPC::RequestParser rp{ctx}; | 401 | IPC::RequestParser rp{ctx}; |
| 281 | struct Parameters { | 402 | const auto camera_handle{rp.PopRaw<Core::IrSensor::IrCameraHandle>()}; |
| 282 | IrCameraHandle camera_handle; | 403 | const auto function_level{rp.PopRaw<Core::IrSensor::PackedFunctionLevel>()}; |
| 283 | PackedFunctionLevel function_level; | 404 | const auto applet_resource_user_id{rp.Pop<u64>()}; |
| 284 | u64 applet_resource_user_id; | ||
| 285 | }; | ||
| 286 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | ||
| 287 | |||
| 288 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 289 | 405 | ||
| 290 | LOG_WARNING(Service_IRS, | 406 | LOG_WARNING( |
| 291 | "(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}", | 407 | Service_IRS, |
| 292 | parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, | 408 | "(STUBBED) called, npad_type={}, npad_id={}, function_level={}, applet_resource_user_id={}", |
| 293 | parameters.applet_resource_user_id); | 409 | camera_handle.npad_type, camera_handle.npad_id, function_level.function_level, |
| 410 | applet_resource_user_id); | ||
| 411 | |||
| 412 | auto result = IsIrCameraHandleValid(camera_handle); | ||
| 413 | if (result.IsSuccess()) { | ||
| 414 | // TODO: Set Function level | ||
| 415 | result = ResultSuccess; | ||
| 416 | } | ||
| 294 | 417 | ||
| 295 | IPC::ResponseBuilder rb{ctx, 2}; | 418 | IPC::ResponseBuilder rb{ctx, 2}; |
| 296 | rb.Push(ResultSuccess); | 419 | rb.Push(result); |
| 297 | } | 420 | } |
| 298 | 421 | ||
| 299 | void IRS::RunImageTransferExProcessor(Kernel::HLERequestContext& ctx) { | 422 | void IRS::RunImageTransferExProcessor(Kernel::HLERequestContext& ctx) { |
| 300 | IPC::RequestParser rp{ctx}; | 423 | IPC::RequestParser rp{ctx}; |
| 301 | struct Parameters { | 424 | struct Parameters { |
| 302 | IrCameraHandle camera_handle; | 425 | Core::IrSensor::IrCameraHandle camera_handle; |
| 303 | INSERT_PADDING_WORDS_NOINIT(1); | 426 | INSERT_PADDING_WORDS_NOINIT(1); |
| 304 | u64 applet_resource_user_id; | 427 | u64 applet_resource_user_id; |
| 305 | PackedImageTransferProcessorExConfig processor_config; | 428 | Core::IrSensor::PackedImageTransferProcessorExConfig processor_config; |
| 306 | u64 transfer_memory_size; | 429 | u64 transfer_memory_size; |
| 307 | }; | 430 | }; |
| 308 | static_assert(sizeof(Parameters) == 0x38, "Parameters has incorrect size."); | 431 | static_assert(sizeof(Parameters) == 0x38, "Parameters has incorrect size."); |
| @@ -313,20 +436,33 @@ void IRS::RunImageTransferExProcessor(Kernel::HLERequestContext& ctx) { | |||
| 313 | auto t_mem = | 436 | auto t_mem = |
| 314 | system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(t_mem_handle); | 437 | system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(t_mem_handle); |
| 315 | 438 | ||
| 316 | LOG_WARNING(Service_IRS, | 439 | u8* transfer_memory = system.Memory().GetPointer(t_mem->GetSourceAddress()); |
| 317 | "(STUBBED) called, npad_type={}, npad_id={}, transfer_memory_size={}, " | 440 | |
| 318 | "applet_resource_user_id={}", | 441 | LOG_INFO(Service_IRS, |
| 319 | parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, | 442 | "called, npad_type={}, npad_id={}, transfer_memory_size={}, " |
| 320 | parameters.transfer_memory_size, parameters.applet_resource_user_id); | 443 | "applet_resource_user_id={}", |
| 444 | parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, | ||
| 445 | parameters.transfer_memory_size, parameters.applet_resource_user_id); | ||
| 446 | |||
| 447 | auto result = IsIrCameraHandleValid(parameters.camera_handle); | ||
| 448 | |||
| 449 | if (result.IsSuccess()) { | ||
| 450 | auto& device = GetIrCameraSharedMemoryDeviceEntry(parameters.camera_handle); | ||
| 451 | MakeProcessorWithCoreContext<ImageTransferProcessor>(parameters.camera_handle, device); | ||
| 452 | auto& image_transfer_processor = | ||
| 453 | GetProcessor<ImageTransferProcessor>(parameters.camera_handle); | ||
| 454 | image_transfer_processor.SetConfig(parameters.processor_config); | ||
| 455 | image_transfer_processor.SetTransferMemoryPointer(transfer_memory); | ||
| 456 | } | ||
| 321 | 457 | ||
| 322 | IPC::ResponseBuilder rb{ctx, 2}; | 458 | IPC::ResponseBuilder rb{ctx, 2}; |
| 323 | rb.Push(ResultSuccess); | 459 | rb.Push(result); |
| 324 | } | 460 | } |
| 325 | 461 | ||
| 326 | void IRS::RunIrLedProcessor(Kernel::HLERequestContext& ctx) { | 462 | void IRS::RunIrLedProcessor(Kernel::HLERequestContext& ctx) { |
| 327 | IPC::RequestParser rp{ctx}; | 463 | IPC::RequestParser rp{ctx}; |
| 328 | const auto camera_handle{rp.PopRaw<IrCameraHandle>()}; | 464 | const auto camera_handle{rp.PopRaw<Core::IrSensor::IrCameraHandle>()}; |
| 329 | const auto processor_config{rp.PopRaw<PackedIrLedProcessorConfig>()}; | 465 | const auto processor_config{rp.PopRaw<Core::IrSensor::PackedIrLedProcessorConfig>()}; |
| 330 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 466 | const auto applet_resource_user_id{rp.Pop<u64>()}; |
| 331 | 467 | ||
| 332 | LOG_WARNING(Service_IRS, | 468 | LOG_WARNING(Service_IRS, |
| @@ -336,14 +472,23 @@ void IRS::RunIrLedProcessor(Kernel::HLERequestContext& ctx) { | |||
| 336 | processor_config.required_mcu_version.major, | 472 | processor_config.required_mcu_version.major, |
| 337 | processor_config.required_mcu_version.minor, applet_resource_user_id); | 473 | processor_config.required_mcu_version.minor, applet_resource_user_id); |
| 338 | 474 | ||
| 475 | auto result = IsIrCameraHandleValid(camera_handle); | ||
| 476 | |||
| 477 | if (result.IsSuccess()) { | ||
| 478 | auto& device = GetIrCameraSharedMemoryDeviceEntry(camera_handle); | ||
| 479 | MakeProcessor<IrLedProcessor>(camera_handle, device); | ||
| 480 | auto& image_transfer_processor = GetProcessor<IrLedProcessor>(camera_handle); | ||
| 481 | image_transfer_processor.SetConfig(processor_config); | ||
| 482 | } | ||
| 483 | |||
| 339 | IPC::ResponseBuilder rb{ctx, 2}; | 484 | IPC::ResponseBuilder rb{ctx, 2}; |
| 340 | rb.Push(ResultSuccess); | 485 | rb.Push(result); |
| 341 | } | 486 | } |
| 342 | 487 | ||
| 343 | void IRS::StopImageProcessorAsync(Kernel::HLERequestContext& ctx) { | 488 | void IRS::StopImageProcessorAsync(Kernel::HLERequestContext& ctx) { |
| 344 | IPC::RequestParser rp{ctx}; | 489 | IPC::RequestParser rp{ctx}; |
| 345 | struct Parameters { | 490 | struct Parameters { |
| 346 | IrCameraHandle camera_handle; | 491 | Core::IrSensor::IrCameraHandle camera_handle; |
| 347 | INSERT_PADDING_WORDS_NOINIT(1); | 492 | INSERT_PADDING_WORDS_NOINIT(1); |
| 348 | u64 applet_resource_user_id; | 493 | u64 applet_resource_user_id; |
| 349 | }; | 494 | }; |
| @@ -356,14 +501,20 @@ void IRS::StopImageProcessorAsync(Kernel::HLERequestContext& ctx) { | |||
| 356 | parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, | 501 | parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, |
| 357 | parameters.applet_resource_user_id); | 502 | parameters.applet_resource_user_id); |
| 358 | 503 | ||
| 504 | auto result = IsIrCameraHandleValid(parameters.camera_handle); | ||
| 505 | if (result.IsSuccess()) { | ||
| 506 | // TODO: Stop image processor async | ||
| 507 | result = ResultSuccess; | ||
| 508 | } | ||
| 509 | |||
| 359 | IPC::ResponseBuilder rb{ctx, 2}; | 510 | IPC::ResponseBuilder rb{ctx, 2}; |
| 360 | rb.Push(ResultSuccess); | 511 | rb.Push(result); |
| 361 | } | 512 | } |
| 362 | 513 | ||
| 363 | void IRS::ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx) { | 514 | void IRS::ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx) { |
| 364 | IPC::RequestParser rp{ctx}; | 515 | IPC::RequestParser rp{ctx}; |
| 365 | struct Parameters { | 516 | struct Parameters { |
| 366 | PackedFunctionLevel function_level; | 517 | Core::IrSensor::PackedFunctionLevel function_level; |
| 367 | INSERT_PADDING_WORDS_NOINIT(1); | 518 | INSERT_PADDING_WORDS_NOINIT(1); |
| 368 | u64 applet_resource_user_id; | 519 | u64 applet_resource_user_id; |
| 369 | }; | 520 | }; |
| @@ -378,7 +529,22 @@ void IRS::ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx) { | |||
| 378 | rb.Push(ResultSuccess); | 529 | rb.Push(ResultSuccess); |
| 379 | } | 530 | } |
| 380 | 531 | ||
| 381 | IRS::~IRS() = default; | 532 | Result IRS::IsIrCameraHandleValid(const Core::IrSensor::IrCameraHandle& camera_handle) const { |
| 533 | if (camera_handle.npad_id > | ||
| 534 | static_cast<u8>(NpadIdTypeToIndex(Core::HID::NpadIdType::Handheld))) { | ||
| 535 | return InvalidIrCameraHandle; | ||
| 536 | } | ||
| 537 | if (camera_handle.npad_type != Core::HID::NpadStyleIndex::None) { | ||
| 538 | return InvalidIrCameraHandle; | ||
| 539 | } | ||
| 540 | return ResultSuccess; | ||
| 541 | } | ||
| 542 | |||
| 543 | Core::IrSensor::DeviceFormat& IRS::GetIrCameraSharedMemoryDeviceEntry( | ||
| 544 | const Core::IrSensor::IrCameraHandle& camera_handle) { | ||
| 545 | ASSERT_MSG(sizeof(StatusManager::device) > camera_handle.npad_id, "invalid npad_id"); | ||
| 546 | return shared_memory->device[camera_handle.npad_id]; | ||
| 547 | } | ||
| 382 | 548 | ||
| 383 | IRS_SYS::IRS_SYS(Core::System& system_) : ServiceFramework{system_, "irs:sys"} { | 549 | IRS_SYS::IRS_SYS(Core::System& system_) : ServiceFramework{system_, "irs:sys"} { |
| 384 | // clang-format off | 550 | // clang-format off |
| @@ -395,4 +561,4 @@ IRS_SYS::IRS_SYS(Core::System& system_) : ServiceFramework{system_, "irs:sys"} { | |||
| 395 | 561 | ||
| 396 | IRS_SYS::~IRS_SYS() = default; | 562 | IRS_SYS::~IRS_SYS() = default; |
| 397 | 563 | ||
| 398 | } // namespace Service::HID | 564 | } // namespace Service::IRS |
diff --git a/src/core/hle/service/hid/irs.h b/src/core/hle/service/hid/irs.h index 361dc2213..2e6115c73 100644 --- a/src/core/hle/service/hid/irs.h +++ b/src/core/hle/service/hid/irs.h | |||
| @@ -4,13 +4,19 @@ | |||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include "core/hid/hid_types.h" | 6 | #include "core/hid/hid_types.h" |
| 7 | #include "core/hid/irs_types.h" | ||
| 8 | #include "core/hle/service/hid/irsensor/processor_base.h" | ||
| 7 | #include "core/hle/service/service.h" | 9 | #include "core/hle/service/service.h" |
| 8 | 10 | ||
| 9 | namespace Core { | 11 | namespace Core { |
| 10 | class System; | 12 | class System; |
| 11 | } | 13 | } |
| 12 | 14 | ||
| 13 | namespace Service::HID { | 15 | namespace Core::HID { |
| 16 | class EmulatedController; | ||
| 17 | } // namespace Core::HID | ||
| 18 | |||
| 19 | namespace Service::IRS { | ||
| 14 | 20 | ||
| 15 | class IRS final : public ServiceFramework<IRS> { | 21 | class IRS final : public ServiceFramework<IRS> { |
| 16 | public: | 22 | public: |
| @@ -18,234 +24,19 @@ public: | |||
| 18 | ~IRS() override; | 24 | ~IRS() override; |
| 19 | 25 | ||
| 20 | private: | 26 | private: |
| 21 | // This is nn::irsensor::IrCameraStatus | 27 | // This is nn::irsensor::detail::AruidFormat |
| 22 | enum IrCameraStatus : u32 { | 28 | struct AruidFormat { |
| 23 | Available, | 29 | u64 sensor_aruid; |
| 24 | Unsupported, | 30 | u64 sensor_aruid_status; |
| 25 | Unconnected, | ||
| 26 | }; | ||
| 27 | |||
| 28 | // This is nn::irsensor::IrCameraInternalStatus | ||
| 29 | enum IrCameraInternalStatus : u32 { | ||
| 30 | Stopped, | ||
| 31 | FirmwareUpdateNeeded, | ||
| 32 | Unkown2, | ||
| 33 | Unkown3, | ||
| 34 | Unkown4, | ||
| 35 | FirmwareVersionRequested, | ||
| 36 | FirmwareVersionIsInvalid, | ||
| 37 | Ready, | ||
| 38 | Setting, | ||
| 39 | }; | ||
| 40 | |||
| 41 | // This is nn::irsensor::detail::StatusManager::IrSensorMode | ||
| 42 | enum IrSensorMode : u64 { | ||
| 43 | None, | ||
| 44 | MomentProcessor, | ||
| 45 | ClusteringProcessor, | ||
| 46 | ImageTransferProcessor, | ||
| 47 | PointingProcessorMarker, | ||
| 48 | TeraPluginProcessor, | ||
| 49 | IrLedProcessor, | ||
| 50 | }; | ||
| 51 | |||
| 52 | // This is nn::irsensor::ImageProcessorStatus | ||
| 53 | enum ImageProcessorStatus : u8 { | ||
| 54 | stopped, | ||
| 55 | running, | ||
| 56 | }; | ||
| 57 | |||
| 58 | // This is nn::irsensor::ImageTransferProcessorFormat | ||
| 59 | enum ImageTransferProcessorFormat : u8 { | ||
| 60 | Size320x240, | ||
| 61 | Size160x120, | ||
| 62 | Size80x60, | ||
| 63 | Size40x30, | ||
| 64 | Size20x15, | ||
| 65 | }; | ||
| 66 | |||
| 67 | // This is nn::irsensor::AdaptiveClusteringMode | ||
| 68 | enum AdaptiveClusteringMode : u8 { | ||
| 69 | StaticFov, | ||
| 70 | DynamicFov, | ||
| 71 | }; | ||
| 72 | |||
| 73 | // This is nn::irsensor::AdaptiveClusteringTargetDistance | ||
| 74 | enum AdaptiveClusteringTargetDistance : u8 { | ||
| 75 | Near, | ||
| 76 | Middle, | ||
| 77 | Far, | ||
| 78 | }; | ||
| 79 | |||
| 80 | // This is nn::irsensor::IrsHandAnalysisMode | ||
| 81 | enum IrsHandAnalysisMode : u8 { | ||
| 82 | Silhouette, | ||
| 83 | Image, | ||
| 84 | SilhoueteAndImage, | ||
| 85 | SilhuetteOnly, | ||
| 86 | }; | ||
| 87 | |||
| 88 | // This is nn::irsensor::IrSensorFunctionLevel | ||
| 89 | enum IrSensorFunctionLevel : u8 { | ||
| 90 | unknown0, | ||
| 91 | unknown1, | ||
| 92 | unknown2, | ||
| 93 | unknown3, | ||
| 94 | unknown4, | ||
| 95 | }; | ||
| 96 | |||
| 97 | // This is nn::irsensor::IrCameraHandle | ||
| 98 | struct IrCameraHandle { | ||
| 99 | u8 npad_id{}; | ||
| 100 | Core::HID::NpadStyleIndex npad_type{Core::HID::NpadStyleIndex::None}; | ||
| 101 | INSERT_PADDING_BYTES(2); | ||
| 102 | }; | ||
| 103 | static_assert(sizeof(IrCameraHandle) == 4, "IrCameraHandle is an invalid size"); | ||
| 104 | |||
| 105 | struct IrsRect { | ||
| 106 | s16 x; | ||
| 107 | s16 y; | ||
| 108 | s16 width; | ||
| 109 | s16 height; | ||
| 110 | }; | 31 | }; |
| 32 | static_assert(sizeof(AruidFormat) == 0x10, "AruidFormat is an invalid size"); | ||
| 111 | 33 | ||
| 112 | // This is nn::irsensor::PackedMcuVersion | 34 | // This is nn::irsensor::detail::StatusManager |
| 113 | struct PackedMcuVersion { | 35 | struct StatusManager { |
| 114 | u16 major; | 36 | std::array<Core::IrSensor::DeviceFormat, 9> device; |
| 115 | u16 minor; | 37 | std::array<AruidFormat, 5> aruid; |
| 116 | }; | 38 | }; |
| 117 | static_assert(sizeof(PackedMcuVersion) == 4, "PackedMcuVersion is an invalid size"); | 39 | static_assert(sizeof(StatusManager) == 0x8000, "StatusManager is an invalid size"); |
| 118 | |||
| 119 | // This is nn::irsensor::MomentProcessorConfig | ||
| 120 | struct MomentProcessorConfig { | ||
| 121 | u64 exposire_time; | ||
| 122 | u8 light_target; | ||
| 123 | u8 gain; | ||
| 124 | u8 is_negative_used; | ||
| 125 | INSERT_PADDING_BYTES(7); | ||
| 126 | IrsRect window_of_interest; | ||
| 127 | u8 preprocess; | ||
| 128 | u8 preprocess_intensity_threshold; | ||
| 129 | INSERT_PADDING_BYTES(5); | ||
| 130 | }; | ||
| 131 | static_assert(sizeof(MomentProcessorConfig) == 0x28, | ||
| 132 | "MomentProcessorConfig is an invalid size"); | ||
| 133 | |||
| 134 | // This is nn::irsensor::PackedMomentProcessorConfig | ||
| 135 | struct PackedMomentProcessorConfig { | ||
| 136 | u64 exposire_time; | ||
| 137 | u8 light_target; | ||
| 138 | u8 gain; | ||
| 139 | u8 is_negative_used; | ||
| 140 | INSERT_PADDING_BYTES(5); | ||
| 141 | IrsRect window_of_interest; | ||
| 142 | PackedMcuVersion required_mcu_version; | ||
| 143 | u8 preprocess; | ||
| 144 | u8 preprocess_intensity_threshold; | ||
| 145 | INSERT_PADDING_BYTES(2); | ||
| 146 | }; | ||
| 147 | static_assert(sizeof(PackedMomentProcessorConfig) == 0x20, | ||
| 148 | "PackedMomentProcessorConfig is an invalid size"); | ||
| 149 | |||
| 150 | // This is nn::irsensor::ClusteringProcessorConfig | ||
| 151 | struct ClusteringProcessorConfig { | ||
| 152 | u64 exposire_time; | ||
| 153 | u32 light_target; | ||
| 154 | u32 gain; | ||
| 155 | u8 is_negative_used; | ||
| 156 | INSERT_PADDING_BYTES(7); | ||
| 157 | IrsRect window_of_interest; | ||
| 158 | u32 pixel_count_min; | ||
| 159 | u32 pixel_count_max; | ||
| 160 | u32 object_intensity_min; | ||
| 161 | u8 is_external_light_filter_enabled; | ||
| 162 | INSERT_PADDING_BYTES(3); | ||
| 163 | }; | ||
| 164 | static_assert(sizeof(ClusteringProcessorConfig) == 0x30, | ||
| 165 | "ClusteringProcessorConfig is an invalid size"); | ||
| 166 | |||
| 167 | // This is nn::irsensor::PackedClusteringProcessorConfig | ||
| 168 | struct PackedClusteringProcessorConfig { | ||
| 169 | u64 exposire_time; | ||
| 170 | u8 light_target; | ||
| 171 | u8 gain; | ||
| 172 | u8 is_negative_used; | ||
| 173 | INSERT_PADDING_BYTES(5); | ||
| 174 | IrsRect window_of_interest; | ||
| 175 | PackedMcuVersion required_mcu_version; | ||
| 176 | u32 pixel_count_min; | ||
| 177 | u32 pixel_count_max; | ||
| 178 | u32 object_intensity_min; | ||
| 179 | u8 is_external_light_filter_enabled; | ||
| 180 | INSERT_PADDING_BYTES(2); | ||
| 181 | }; | ||
| 182 | static_assert(sizeof(PackedClusteringProcessorConfig) == 0x30, | ||
| 183 | "PackedClusteringProcessorConfig is an invalid size"); | ||
| 184 | |||
| 185 | // This is nn::irsensor::PackedImageTransferProcessorConfig | ||
| 186 | struct PackedImageTransferProcessorConfig { | ||
| 187 | u64 exposire_time; | ||
| 188 | u8 light_target; | ||
| 189 | u8 gain; | ||
| 190 | u8 is_negative_used; | ||
| 191 | INSERT_PADDING_BYTES(5); | ||
| 192 | PackedMcuVersion required_mcu_version; | ||
| 193 | u8 format; | ||
| 194 | INSERT_PADDING_BYTES(3); | ||
| 195 | }; | ||
| 196 | static_assert(sizeof(PackedImageTransferProcessorConfig) == 0x18, | ||
| 197 | "PackedImageTransferProcessorConfig is an invalid size"); | ||
| 198 | |||
| 199 | // This is nn::irsensor::PackedTeraPluginProcessorConfig | ||
| 200 | struct PackedTeraPluginProcessorConfig { | ||
| 201 | PackedMcuVersion required_mcu_version; | ||
| 202 | u8 mode; | ||
| 203 | INSERT_PADDING_BYTES(3); | ||
| 204 | }; | ||
| 205 | static_assert(sizeof(PackedTeraPluginProcessorConfig) == 0x8, | ||
| 206 | "PackedTeraPluginProcessorConfig is an invalid size"); | ||
| 207 | |||
| 208 | // This is nn::irsensor::PackedPointingProcessorConfig | ||
| 209 | struct PackedPointingProcessorConfig { | ||
| 210 | IrsRect window_of_interest; | ||
| 211 | PackedMcuVersion required_mcu_version; | ||
| 212 | }; | ||
| 213 | static_assert(sizeof(PackedPointingProcessorConfig) == 0xC, | ||
| 214 | "PackedPointingProcessorConfig is an invalid size"); | ||
| 215 | |||
| 216 | // This is nn::irsensor::PackedFunctionLevel | ||
| 217 | struct PackedFunctionLevel { | ||
| 218 | IrSensorFunctionLevel function_level; | ||
| 219 | INSERT_PADDING_BYTES(3); | ||
| 220 | }; | ||
| 221 | static_assert(sizeof(PackedFunctionLevel) == 0x4, "PackedFunctionLevel is an invalid size"); | ||
| 222 | |||
| 223 | // This is nn::irsensor::PackedImageTransferProcessorExConfig | ||
| 224 | struct PackedImageTransferProcessorExConfig { | ||
| 225 | u64 exposire_time; | ||
| 226 | u8 light_target; | ||
| 227 | u8 gain; | ||
| 228 | u8 is_negative_used; | ||
| 229 | INSERT_PADDING_BYTES(5); | ||
| 230 | PackedMcuVersion required_mcu_version; | ||
| 231 | ImageTransferProcessorFormat origin_format; | ||
| 232 | ImageTransferProcessorFormat trimming_format; | ||
| 233 | u16 trimming_start_x; | ||
| 234 | u16 trimming_start_y; | ||
| 235 | u8 is_external_light_filter_enabled; | ||
| 236 | INSERT_PADDING_BYTES(3); | ||
| 237 | }; | ||
| 238 | static_assert(sizeof(PackedImageTransferProcessorExConfig) == 0x20, | ||
| 239 | "PackedImageTransferProcessorExConfig is an invalid size"); | ||
| 240 | |||
| 241 | // This is nn::irsensor::PackedIrLedProcessorConfig | ||
| 242 | struct PackedIrLedProcessorConfig { | ||
| 243 | PackedMcuVersion required_mcu_version; | ||
| 244 | u8 light_target; | ||
| 245 | INSERT_PADDING_BYTES(3); | ||
| 246 | }; | ||
| 247 | static_assert(sizeof(PackedIrLedProcessorConfig) == 0x8, | ||
| 248 | "PackedIrLedProcessorConfig is an invalid size"); | ||
| 249 | 40 | ||
| 250 | void ActivateIrsensor(Kernel::HLERequestContext& ctx); | 41 | void ActivateIrsensor(Kernel::HLERequestContext& ctx); |
| 251 | void DeactivateIrsensor(Kernel::HLERequestContext& ctx); | 42 | void DeactivateIrsensor(Kernel::HLERequestContext& ctx); |
| @@ -265,6 +56,56 @@ private: | |||
| 265 | void RunIrLedProcessor(Kernel::HLERequestContext& ctx); | 56 | void RunIrLedProcessor(Kernel::HLERequestContext& ctx); |
| 266 | void StopImageProcessorAsync(Kernel::HLERequestContext& ctx); | 57 | void StopImageProcessorAsync(Kernel::HLERequestContext& ctx); |
| 267 | void ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx); | 58 | void ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx); |
| 59 | |||
| 60 | Result IsIrCameraHandleValid(const Core::IrSensor::IrCameraHandle& camera_handle) const; | ||
| 61 | Core::IrSensor::DeviceFormat& GetIrCameraSharedMemoryDeviceEntry( | ||
| 62 | const Core::IrSensor::IrCameraHandle& camera_handle); | ||
| 63 | |||
| 64 | template <typename T> | ||
| 65 | void MakeProcessor(const Core::IrSensor::IrCameraHandle& handle, | ||
| 66 | Core::IrSensor::DeviceFormat& device_state) { | ||
| 67 | const auto index = static_cast<std::size_t>(handle.npad_id); | ||
| 68 | if (index > sizeof(processors)) { | ||
| 69 | LOG_CRITICAL(Service_IRS, "Invalid index {}", index); | ||
| 70 | return; | ||
| 71 | } | ||
| 72 | processors[index] = std::make_unique<T>(device_state); | ||
| 73 | } | ||
| 74 | |||
| 75 | template <typename T> | ||
| 76 | void MakeProcessorWithCoreContext(const Core::IrSensor::IrCameraHandle& handle, | ||
| 77 | Core::IrSensor::DeviceFormat& device_state) { | ||
| 78 | const auto index = static_cast<std::size_t>(handle.npad_id); | ||
| 79 | if (index > sizeof(processors)) { | ||
| 80 | LOG_CRITICAL(Service_IRS, "Invalid index {}", index); | ||
| 81 | return; | ||
| 82 | } | ||
| 83 | processors[index] = std::make_unique<T>(system.HIDCore(), device_state, index); | ||
| 84 | } | ||
| 85 | |||
| 86 | template <typename T> | ||
| 87 | T& GetProcessor(const Core::IrSensor::IrCameraHandle& handle) { | ||
| 88 | const auto index = static_cast<std::size_t>(handle.npad_id); | ||
| 89 | if (index > sizeof(processors)) { | ||
| 90 | LOG_CRITICAL(Service_IRS, "Invalid index {}", index); | ||
| 91 | return static_cast<T&>(*processors[0]); | ||
| 92 | } | ||
| 93 | return static_cast<T&>(*processors[index]); | ||
| 94 | } | ||
| 95 | |||
| 96 | template <typename T> | ||
| 97 | const T& GetProcessor(const Core::IrSensor::IrCameraHandle& handle) const { | ||
| 98 | const auto index = static_cast<std::size_t>(handle.npad_id); | ||
| 99 | if (index > sizeof(processors)) { | ||
| 100 | LOG_CRITICAL(Service_IRS, "Invalid index {}", index); | ||
| 101 | return static_cast<T&>(*processors[0]); | ||
| 102 | } | ||
| 103 | return static_cast<T&>(*processors[index]); | ||
| 104 | } | ||
| 105 | |||
| 106 | Core::HID::EmulatedController* npad_device = nullptr; | ||
| 107 | StatusManager* shared_memory = nullptr; | ||
| 108 | std::array<std::unique_ptr<ProcessorBase>, 9> processors{}; | ||
| 268 | }; | 109 | }; |
| 269 | 110 | ||
| 270 | class IRS_SYS final : public ServiceFramework<IRS_SYS> { | 111 | class IRS_SYS final : public ServiceFramework<IRS_SYS> { |
| @@ -273,4 +114,4 @@ public: | |||
| 273 | ~IRS_SYS() override; | 114 | ~IRS_SYS() override; |
| 274 | }; | 115 | }; |
| 275 | 116 | ||
| 276 | } // namespace Service::HID | 117 | } // namespace Service::IRS |
diff --git a/src/core/hle/service/hid/irsensor/clustering_processor.cpp b/src/core/hle/service/hid/irsensor/clustering_processor.cpp new file mode 100644 index 000000000..6479af212 --- /dev/null +++ b/src/core/hle/service/hid/irsensor/clustering_processor.cpp | |||
| @@ -0,0 +1,34 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/service/hid/irsensor/clustering_processor.h" | ||
| 5 | |||
| 6 | namespace Service::IRS { | ||
| 7 | ClusteringProcessor::ClusteringProcessor(Core::IrSensor::DeviceFormat& device_format) | ||
| 8 | : device(device_format) { | ||
| 9 | device.mode = Core::IrSensor::IrSensorMode::ClusteringProcessor; | ||
| 10 | device.camera_status = Core::IrSensor::IrCameraStatus::Unconnected; | ||
| 11 | device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Stopped; | ||
| 12 | } | ||
| 13 | |||
| 14 | ClusteringProcessor::~ClusteringProcessor() = default; | ||
| 15 | |||
| 16 | void ClusteringProcessor::StartProcessor() {} | ||
| 17 | |||
| 18 | void ClusteringProcessor::SuspendProcessor() {} | ||
| 19 | |||
| 20 | void ClusteringProcessor::StopProcessor() {} | ||
| 21 | |||
| 22 | void ClusteringProcessor::SetConfig(Core::IrSensor::PackedClusteringProcessorConfig config) { | ||
| 23 | current_config.camera_config.exposure_time = config.camera_config.exposure_time; | ||
| 24 | current_config.camera_config.gain = config.camera_config.gain; | ||
| 25 | current_config.camera_config.is_negative_used = config.camera_config.is_negative_used; | ||
| 26 | current_config.camera_config.light_target = | ||
| 27 | static_cast<Core::IrSensor::CameraLightTarget>(config.camera_config.light_target); | ||
| 28 | current_config.pixel_count_min = config.pixel_count_min; | ||
| 29 | current_config.pixel_count_max = config.pixel_count_max; | ||
| 30 | current_config.is_external_light_filter_enabled = config.is_external_light_filter_enabled; | ||
| 31 | current_config.object_intensity_min = config.object_intensity_min; | ||
| 32 | } | ||
| 33 | |||
| 34 | } // namespace Service::IRS | ||
diff --git a/src/core/hle/service/hid/irsensor/clustering_processor.h b/src/core/hle/service/hid/irsensor/clustering_processor.h new file mode 100644 index 000000000..6e2ba8846 --- /dev/null +++ b/src/core/hle/service/hid/irsensor/clustering_processor.h | |||
| @@ -0,0 +1,74 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "common/common_types.h" | ||
| 7 | #include "core/hid/irs_types.h" | ||
| 8 | #include "core/hle/service/hid/irsensor/processor_base.h" | ||
| 9 | |||
| 10 | namespace Service::IRS { | ||
| 11 | class ClusteringProcessor final : public ProcessorBase { | ||
| 12 | public: | ||
| 13 | explicit ClusteringProcessor(Core::IrSensor::DeviceFormat& device_format); | ||
| 14 | ~ClusteringProcessor() override; | ||
| 15 | |||
| 16 | // Called when the processor is initialized | ||
| 17 | void StartProcessor() override; | ||
| 18 | |||
| 19 | // Called when the processor is suspended | ||
| 20 | void SuspendProcessor() override; | ||
| 21 | |||
| 22 | // Called when the processor is stopped | ||
| 23 | void StopProcessor() override; | ||
| 24 | |||
| 25 | // Sets config parameters of the camera | ||
| 26 | void SetConfig(Core::IrSensor::PackedClusteringProcessorConfig config); | ||
| 27 | |||
| 28 | private: | ||
| 29 | // This is nn::irsensor::ClusteringProcessorConfig | ||
| 30 | struct ClusteringProcessorConfig { | ||
| 31 | Core::IrSensor::CameraConfig camera_config; | ||
| 32 | Core::IrSensor::IrsRect window_of_interest; | ||
| 33 | u32 pixel_count_min; | ||
| 34 | u32 pixel_count_max; | ||
| 35 | u32 object_intensity_min; | ||
| 36 | bool is_external_light_filter_enabled; | ||
| 37 | INSERT_PADDING_BYTES(3); | ||
| 38 | }; | ||
| 39 | static_assert(sizeof(ClusteringProcessorConfig) == 0x30, | ||
| 40 | "ClusteringProcessorConfig is an invalid size"); | ||
| 41 | |||
| 42 | // This is nn::irsensor::AdaptiveClusteringProcessorConfig | ||
| 43 | struct AdaptiveClusteringProcessorConfig { | ||
| 44 | Core::IrSensor::AdaptiveClusteringMode mode; | ||
| 45 | Core::IrSensor::AdaptiveClusteringTargetDistance target_distance; | ||
| 46 | }; | ||
| 47 | static_assert(sizeof(AdaptiveClusteringProcessorConfig) == 0x8, | ||
| 48 | "AdaptiveClusteringProcessorConfig is an invalid size"); | ||
| 49 | |||
| 50 | // This is nn::irsensor::ClusteringData | ||
| 51 | struct ClusteringData { | ||
| 52 | f32 average_intensity; | ||
| 53 | Core::IrSensor::IrsCentroid centroid; | ||
| 54 | u32 pixel_count; | ||
| 55 | Core::IrSensor::IrsRect bound; | ||
| 56 | }; | ||
| 57 | static_assert(sizeof(ClusteringData) == 0x18, "ClusteringData is an invalid size"); | ||
| 58 | |||
| 59 | // This is nn::irsensor::ClusteringProcessorState | ||
| 60 | struct ClusteringProcessorState { | ||
| 61 | s64 sampling_number; | ||
| 62 | u64 timestamp; | ||
| 63 | u8 object_count; | ||
| 64 | INSERT_PADDING_BYTES(3); | ||
| 65 | Core::IrSensor::CameraAmbientNoiseLevel ambient_noise_level; | ||
| 66 | std::array<ClusteringData, 0x10> data; | ||
| 67 | }; | ||
| 68 | static_assert(sizeof(ClusteringProcessorState) == 0x198, | ||
| 69 | "ClusteringProcessorState is an invalid size"); | ||
| 70 | |||
| 71 | ClusteringProcessorConfig current_config{}; | ||
| 72 | Core::IrSensor::DeviceFormat& device; | ||
| 73 | }; | ||
| 74 | } // namespace Service::IRS | ||
diff --git a/src/core/hle/service/hid/irsensor/image_transfer_processor.cpp b/src/core/hle/service/hid/irsensor/image_transfer_processor.cpp new file mode 100644 index 000000000..98f0c579d --- /dev/null +++ b/src/core/hle/service/hid/irsensor/image_transfer_processor.cpp | |||
| @@ -0,0 +1,150 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #include "core/hid/emulated_controller.h" | ||
| 5 | #include "core/hid/hid_core.h" | ||
| 6 | #include "core/hle/service/hid/irsensor/image_transfer_processor.h" | ||
| 7 | |||
| 8 | namespace Service::IRS { | ||
| 9 | ImageTransferProcessor::ImageTransferProcessor(Core::HID::HIDCore& hid_core_, | ||
| 10 | Core::IrSensor::DeviceFormat& device_format, | ||
| 11 | std::size_t npad_index) | ||
| 12 | : device{device_format} { | ||
| 13 | npad_device = hid_core_.GetEmulatedControllerByIndex(npad_index); | ||
| 14 | |||
| 15 | Core::HID::ControllerUpdateCallback engine_callback{ | ||
| 16 | .on_change = [this](Core::HID::ControllerTriggerType type) { OnControllerUpdate(type); }, | ||
| 17 | .is_npad_service = true, | ||
| 18 | }; | ||
| 19 | callback_key = npad_device->SetCallback(engine_callback); | ||
| 20 | |||
| 21 | device.mode = Core::IrSensor::IrSensorMode::ImageTransferProcessor; | ||
| 22 | device.camera_status = Core::IrSensor::IrCameraStatus::Unconnected; | ||
| 23 | device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Stopped; | ||
| 24 | } | ||
| 25 | |||
| 26 | ImageTransferProcessor::~ImageTransferProcessor() { | ||
| 27 | npad_device->DeleteCallback(callback_key); | ||
| 28 | }; | ||
| 29 | |||
| 30 | void ImageTransferProcessor::StartProcessor() { | ||
| 31 | is_active = true; | ||
| 32 | device.camera_status = Core::IrSensor::IrCameraStatus::Available; | ||
| 33 | device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Ready; | ||
| 34 | processor_state.sampling_number = 0; | ||
| 35 | processor_state.ambient_noise_level = Core::IrSensor::CameraAmbientNoiseLevel::Low; | ||
| 36 | } | ||
| 37 | |||
| 38 | void ImageTransferProcessor::SuspendProcessor() {} | ||
| 39 | |||
| 40 | void ImageTransferProcessor::StopProcessor() {} | ||
| 41 | |||
| 42 | void ImageTransferProcessor::OnControllerUpdate(Core::HID::ControllerTriggerType type) { | ||
| 43 | if (type != Core::HID::ControllerTriggerType::IrSensor) { | ||
| 44 | return; | ||
| 45 | } | ||
| 46 | if (!is_transfer_memory_set) { | ||
| 47 | return; | ||
| 48 | } | ||
| 49 | |||
| 50 | const auto camera_data = npad_device->GetCamera(); | ||
| 51 | |||
| 52 | // This indicates how much ambient light is precent | ||
| 53 | processor_state.ambient_noise_level = Core::IrSensor::CameraAmbientNoiseLevel::Low; | ||
| 54 | processor_state.sampling_number = camera_data.sample; | ||
| 55 | |||
| 56 | if (camera_data.format != current_config.origin_format) { | ||
| 57 | LOG_WARNING(Service_IRS, "Wrong Input format {} expected {}", camera_data.format, | ||
| 58 | current_config.origin_format); | ||
| 59 | memset(transfer_memory, 0, GetDataSize(current_config.trimming_format)); | ||
| 60 | return; | ||
| 61 | } | ||
| 62 | |||
| 63 | if (current_config.origin_format > current_config.trimming_format) { | ||
| 64 | LOG_WARNING(Service_IRS, "Origin format {} is smaller than trimming format {}", | ||
| 65 | current_config.origin_format, current_config.trimming_format); | ||
| 66 | memset(transfer_memory, 0, GetDataSize(current_config.trimming_format)); | ||
| 67 | return; | ||
| 68 | } | ||
| 69 | |||
| 70 | std::vector<u8> window_data{}; | ||
| 71 | const auto origin_width = GetDataWidth(current_config.origin_format); | ||
| 72 | const auto origin_height = GetDataHeight(current_config.origin_format); | ||
| 73 | const auto trimming_width = GetDataWidth(current_config.trimming_format); | ||
| 74 | const auto trimming_height = GetDataHeight(current_config.trimming_format); | ||
| 75 | window_data.resize(GetDataSize(current_config.trimming_format)); | ||
| 76 | |||
| 77 | if (trimming_width + current_config.trimming_start_x > origin_width || | ||
| 78 | trimming_height + current_config.trimming_start_y > origin_height) { | ||
| 79 | LOG_WARNING(Service_IRS, | ||
| 80 | "Trimming area ({}, {}, {}, {}) is outside of origin area ({}, {})", | ||
| 81 | current_config.trimming_start_x, current_config.trimming_start_y, | ||
| 82 | trimming_width, trimming_height, origin_width, origin_height); | ||
| 83 | memset(transfer_memory, 0, GetDataSize(current_config.trimming_format)); | ||
| 84 | return; | ||
| 85 | } | ||
| 86 | |||
| 87 | for (std::size_t y = 0; y < trimming_height; y++) { | ||
| 88 | for (std::size_t x = 0; x < trimming_width; x++) { | ||
| 89 | const std::size_t window_index = (y * trimming_width) + x; | ||
| 90 | const std::size_t origin_index = | ||
| 91 | ((y + current_config.trimming_start_y) * origin_width) + x + | ||
| 92 | current_config.trimming_start_x; | ||
| 93 | window_data[window_index] = camera_data.data[origin_index]; | ||
| 94 | } | ||
| 95 | } | ||
| 96 | |||
| 97 | memcpy(transfer_memory, window_data.data(), GetDataSize(current_config.trimming_format)); | ||
| 98 | |||
| 99 | if (!IsProcessorActive()) { | ||
| 100 | StartProcessor(); | ||
| 101 | } | ||
| 102 | } | ||
| 103 | |||
| 104 | void ImageTransferProcessor::SetConfig(Core::IrSensor::PackedImageTransferProcessorConfig config) { | ||
| 105 | current_config.camera_config.exposure_time = config.camera_config.exposure_time; | ||
| 106 | current_config.camera_config.gain = config.camera_config.gain; | ||
| 107 | current_config.camera_config.is_negative_used = config.camera_config.is_negative_used; | ||
| 108 | current_config.camera_config.light_target = | ||
| 109 | static_cast<Core::IrSensor::CameraLightTarget>(config.camera_config.light_target); | ||
| 110 | current_config.origin_format = | ||
| 111 | static_cast<Core::IrSensor::ImageTransferProcessorFormat>(config.format); | ||
| 112 | current_config.trimming_format = | ||
| 113 | static_cast<Core::IrSensor::ImageTransferProcessorFormat>(config.format); | ||
| 114 | current_config.trimming_start_x = 0; | ||
| 115 | current_config.trimming_start_y = 0; | ||
| 116 | |||
| 117 | npad_device->SetCameraFormat(current_config.origin_format); | ||
| 118 | } | ||
| 119 | |||
| 120 | void ImageTransferProcessor::SetConfig( | ||
| 121 | Core::IrSensor::PackedImageTransferProcessorExConfig config) { | ||
| 122 | current_config.camera_config.exposure_time = config.camera_config.exposure_time; | ||
| 123 | current_config.camera_config.gain = config.camera_config.gain; | ||
| 124 | current_config.camera_config.is_negative_used = config.camera_config.is_negative_used; | ||
| 125 | current_config.camera_config.light_target = | ||
| 126 | static_cast<Core::IrSensor::CameraLightTarget>(config.camera_config.light_target); | ||
| 127 | current_config.origin_format = | ||
| 128 | static_cast<Core::IrSensor::ImageTransferProcessorFormat>(config.origin_format); | ||
| 129 | current_config.trimming_format = | ||
| 130 | static_cast<Core::IrSensor::ImageTransferProcessorFormat>(config.trimming_format); | ||
| 131 | current_config.trimming_start_x = config.trimming_start_x; | ||
| 132 | current_config.trimming_start_y = config.trimming_start_y; | ||
| 133 | |||
| 134 | npad_device->SetCameraFormat(current_config.origin_format); | ||
| 135 | } | ||
| 136 | |||
| 137 | void ImageTransferProcessor::SetTransferMemoryPointer(u8* t_mem) { | ||
| 138 | is_transfer_memory_set = true; | ||
| 139 | transfer_memory = t_mem; | ||
| 140 | } | ||
| 141 | |||
| 142 | Core::IrSensor::ImageTransferProcessorState ImageTransferProcessor::GetState( | ||
| 143 | std::vector<u8>& data) const { | ||
| 144 | const auto size = GetDataSize(current_config.trimming_format); | ||
| 145 | data.resize(size); | ||
| 146 | memcpy(data.data(), transfer_memory, size); | ||
| 147 | return processor_state; | ||
| 148 | } | ||
| 149 | |||
| 150 | } // namespace Service::IRS | ||
diff --git a/src/core/hle/service/hid/irsensor/image_transfer_processor.h b/src/core/hle/service/hid/irsensor/image_transfer_processor.h new file mode 100644 index 000000000..393df492d --- /dev/null +++ b/src/core/hle/service/hid/irsensor/image_transfer_processor.h | |||
| @@ -0,0 +1,73 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "common/common_types.h" | ||
| 7 | #include "core/hid/irs_types.h" | ||
| 8 | #include "core/hle/service/hid/irsensor/processor_base.h" | ||
| 9 | |||
| 10 | namespace Core::HID { | ||
| 11 | class EmulatedController; | ||
| 12 | } // namespace Core::HID | ||
| 13 | |||
| 14 | namespace Service::IRS { | ||
| 15 | class ImageTransferProcessor final : public ProcessorBase { | ||
| 16 | public: | ||
| 17 | explicit ImageTransferProcessor(Core::HID::HIDCore& hid_core_, | ||
| 18 | Core::IrSensor::DeviceFormat& device_format, | ||
| 19 | std::size_t npad_index); | ||
| 20 | ~ImageTransferProcessor() override; | ||
| 21 | |||
| 22 | // Called when the processor is initialized | ||
| 23 | void StartProcessor() override; | ||
| 24 | |||
| 25 | // Called when the processor is suspended | ||
| 26 | void SuspendProcessor() override; | ||
| 27 | |||
| 28 | // Called when the processor is stopped | ||
| 29 | void StopProcessor() override; | ||
| 30 | |||
| 31 | // Sets config parameters of the camera | ||
| 32 | void SetConfig(Core::IrSensor::PackedImageTransferProcessorConfig config); | ||
| 33 | void SetConfig(Core::IrSensor::PackedImageTransferProcessorExConfig config); | ||
| 34 | |||
| 35 | // Transfer memory where the image data will be stored | ||
| 36 | void SetTransferMemoryPointer(u8* t_mem); | ||
| 37 | |||
| 38 | Core::IrSensor::ImageTransferProcessorState GetState(std::vector<u8>& data) const; | ||
| 39 | |||
| 40 | private: | ||
| 41 | // This is nn::irsensor::ImageTransferProcessorConfig | ||
| 42 | struct ImageTransferProcessorConfig { | ||
| 43 | Core::IrSensor::CameraConfig camera_config; | ||
| 44 | Core::IrSensor::ImageTransferProcessorFormat format; | ||
| 45 | }; | ||
| 46 | static_assert(sizeof(ImageTransferProcessorConfig) == 0x20, | ||
| 47 | "ImageTransferProcessorConfig is an invalid size"); | ||
| 48 | |||
| 49 | // This is nn::irsensor::ImageTransferProcessorExConfig | ||
| 50 | struct ImageTransferProcessorExConfig { | ||
| 51 | Core::IrSensor::CameraConfig camera_config; | ||
| 52 | Core::IrSensor::ImageTransferProcessorFormat origin_format; | ||
| 53 | Core::IrSensor::ImageTransferProcessorFormat trimming_format; | ||
| 54 | u16 trimming_start_x; | ||
| 55 | u16 trimming_start_y; | ||
| 56 | bool is_external_light_filter_enabled; | ||
| 57 | INSERT_PADDING_BYTES(3); | ||
| 58 | }; | ||
| 59 | static_assert(sizeof(ImageTransferProcessorExConfig) == 0x28, | ||
| 60 | "ImageTransferProcessorExConfig is an invalid size"); | ||
| 61 | |||
| 62 | void OnControllerUpdate(Core::HID::ControllerTriggerType type); | ||
| 63 | |||
| 64 | ImageTransferProcessorExConfig current_config{}; | ||
| 65 | Core::IrSensor::ImageTransferProcessorState processor_state{}; | ||
| 66 | Core::IrSensor::DeviceFormat& device; | ||
| 67 | Core::HID::EmulatedController* npad_device; | ||
| 68 | int callback_key{}; | ||
| 69 | |||
| 70 | u8* transfer_memory = nullptr; | ||
| 71 | bool is_transfer_memory_set = false; | ||
| 72 | }; | ||
| 73 | } // namespace Service::IRS | ||
diff --git a/src/core/hle/service/hid/irsensor/ir_led_processor.cpp b/src/core/hle/service/hid/irsensor/ir_led_processor.cpp new file mode 100644 index 000000000..8e6dd99e4 --- /dev/null +++ b/src/core/hle/service/hid/irsensor/ir_led_processor.cpp | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/service/hid/irsensor/ir_led_processor.h" | ||
| 5 | |||
| 6 | namespace Service::IRS { | ||
| 7 | IrLedProcessor::IrLedProcessor(Core::IrSensor::DeviceFormat& device_format) | ||
| 8 | : device(device_format) { | ||
| 9 | device.mode = Core::IrSensor::IrSensorMode::IrLedProcessor; | ||
| 10 | device.camera_status = Core::IrSensor::IrCameraStatus::Unconnected; | ||
| 11 | device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Stopped; | ||
| 12 | } | ||
| 13 | |||
| 14 | IrLedProcessor::~IrLedProcessor() = default; | ||
| 15 | |||
| 16 | void IrLedProcessor::StartProcessor() {} | ||
| 17 | |||
| 18 | void IrLedProcessor::SuspendProcessor() {} | ||
| 19 | |||
| 20 | void IrLedProcessor::StopProcessor() {} | ||
| 21 | |||
| 22 | void IrLedProcessor::SetConfig(Core::IrSensor::PackedIrLedProcessorConfig config) { | ||
| 23 | current_config.light_target = | ||
| 24 | static_cast<Core::IrSensor::CameraLightTarget>(config.light_target); | ||
| 25 | } | ||
| 26 | |||
| 27 | } // namespace Service::IRS | ||
diff --git a/src/core/hle/service/hid/irsensor/ir_led_processor.h b/src/core/hle/service/hid/irsensor/ir_led_processor.h new file mode 100644 index 000000000..c3d8693c9 --- /dev/null +++ b/src/core/hle/service/hid/irsensor/ir_led_processor.h | |||
| @@ -0,0 +1,47 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "common/bit_field.h" | ||
| 7 | #include "common/common_types.h" | ||
| 8 | #include "core/hid/irs_types.h" | ||
| 9 | #include "core/hle/service/hid/irsensor/processor_base.h" | ||
| 10 | |||
| 11 | namespace Service::IRS { | ||
| 12 | class IrLedProcessor final : public ProcessorBase { | ||
| 13 | public: | ||
| 14 | explicit IrLedProcessor(Core::IrSensor::DeviceFormat& device_format); | ||
| 15 | ~IrLedProcessor() override; | ||
| 16 | |||
| 17 | // Called when the processor is initialized | ||
| 18 | void StartProcessor() override; | ||
| 19 | |||
| 20 | // Called when the processor is suspended | ||
| 21 | void SuspendProcessor() override; | ||
| 22 | |||
| 23 | // Called when the processor is stopped | ||
| 24 | void StopProcessor() override; | ||
| 25 | |||
| 26 | // Sets config parameters of the camera | ||
| 27 | void SetConfig(Core::IrSensor::PackedIrLedProcessorConfig config); | ||
| 28 | |||
| 29 | private: | ||
| 30 | // This is nn::irsensor::IrLedProcessorConfig | ||
| 31 | struct IrLedProcessorConfig { | ||
| 32 | Core::IrSensor::CameraLightTarget light_target; | ||
| 33 | }; | ||
| 34 | static_assert(sizeof(IrLedProcessorConfig) == 0x4, "IrLedProcessorConfig is an invalid size"); | ||
| 35 | |||
| 36 | struct IrLedProcessorState { | ||
| 37 | s64 sampling_number; | ||
| 38 | u64 timestamp; | ||
| 39 | std::array<u8, 0x8> data; | ||
| 40 | }; | ||
| 41 | static_assert(sizeof(IrLedProcessorState) == 0x18, "IrLedProcessorState is an invalid size"); | ||
| 42 | |||
| 43 | IrLedProcessorConfig current_config{}; | ||
| 44 | Core::IrSensor::DeviceFormat& device; | ||
| 45 | }; | ||
| 46 | |||
| 47 | } // namespace Service::IRS | ||
diff --git a/src/core/hle/service/hid/irsensor/moment_processor.cpp b/src/core/hle/service/hid/irsensor/moment_processor.cpp new file mode 100644 index 000000000..dbaca420a --- /dev/null +++ b/src/core/hle/service/hid/irsensor/moment_processor.cpp | |||
| @@ -0,0 +1,34 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/service/hid/irsensor/moment_processor.h" | ||
| 5 | |||
| 6 | namespace Service::IRS { | ||
| 7 | MomentProcessor::MomentProcessor(Core::IrSensor::DeviceFormat& device_format) | ||
| 8 | : device(device_format) { | ||
| 9 | device.mode = Core::IrSensor::IrSensorMode::MomentProcessor; | ||
| 10 | device.camera_status = Core::IrSensor::IrCameraStatus::Unconnected; | ||
| 11 | device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Stopped; | ||
| 12 | } | ||
| 13 | |||
| 14 | MomentProcessor::~MomentProcessor() = default; | ||
| 15 | |||
| 16 | void MomentProcessor::StartProcessor() {} | ||
| 17 | |||
| 18 | void MomentProcessor::SuspendProcessor() {} | ||
| 19 | |||
| 20 | void MomentProcessor::StopProcessor() {} | ||
| 21 | |||
| 22 | void MomentProcessor::SetConfig(Core::IrSensor::PackedMomentProcessorConfig config) { | ||
| 23 | current_config.camera_config.exposure_time = config.camera_config.exposure_time; | ||
| 24 | current_config.camera_config.gain = config.camera_config.gain; | ||
| 25 | current_config.camera_config.is_negative_used = config.camera_config.is_negative_used; | ||
| 26 | current_config.camera_config.light_target = | ||
| 27 | static_cast<Core::IrSensor::CameraLightTarget>(config.camera_config.light_target); | ||
| 28 | current_config.window_of_interest = config.window_of_interest; | ||
| 29 | current_config.preprocess = | ||
| 30 | static_cast<Core::IrSensor::MomentProcessorPreprocess>(config.preprocess); | ||
| 31 | current_config.preprocess_intensity_threshold = config.preprocess_intensity_threshold; | ||
| 32 | } | ||
| 33 | |||
| 34 | } // namespace Service::IRS | ||
diff --git a/src/core/hle/service/hid/irsensor/moment_processor.h b/src/core/hle/service/hid/irsensor/moment_processor.h new file mode 100644 index 000000000..d4bd22e0f --- /dev/null +++ b/src/core/hle/service/hid/irsensor/moment_processor.h | |||
| @@ -0,0 +1,61 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "common/bit_field.h" | ||
| 7 | #include "common/common_types.h" | ||
| 8 | #include "core/hid/irs_types.h" | ||
| 9 | #include "core/hle/service/hid/irsensor/processor_base.h" | ||
| 10 | |||
| 11 | namespace Service::IRS { | ||
| 12 | class MomentProcessor final : public ProcessorBase { | ||
| 13 | public: | ||
| 14 | explicit MomentProcessor(Core::IrSensor::DeviceFormat& device_format); | ||
| 15 | ~MomentProcessor() override; | ||
| 16 | |||
| 17 | // Called when the processor is initialized | ||
| 18 | void StartProcessor() override; | ||
| 19 | |||
| 20 | // Called when the processor is suspended | ||
| 21 | void SuspendProcessor() override; | ||
| 22 | |||
| 23 | // Called when the processor is stopped | ||
| 24 | void StopProcessor() override; | ||
| 25 | |||
| 26 | // Sets config parameters of the camera | ||
| 27 | void SetConfig(Core::IrSensor::PackedMomentProcessorConfig config); | ||
| 28 | |||
| 29 | private: | ||
| 30 | // This is nn::irsensor::MomentProcessorConfig | ||
| 31 | struct MomentProcessorConfig { | ||
| 32 | Core::IrSensor::CameraConfig camera_config; | ||
| 33 | Core::IrSensor::IrsRect window_of_interest; | ||
| 34 | Core::IrSensor::MomentProcessorPreprocess preprocess; | ||
| 35 | u32 preprocess_intensity_threshold; | ||
| 36 | }; | ||
| 37 | static_assert(sizeof(MomentProcessorConfig) == 0x28, | ||
| 38 | "MomentProcessorConfig is an invalid size"); | ||
| 39 | |||
| 40 | // This is nn::irsensor::MomentStatistic | ||
| 41 | struct MomentStatistic { | ||
| 42 | f32 average_intensity; | ||
| 43 | Core::IrSensor::IrsCentroid centroid; | ||
| 44 | }; | ||
| 45 | static_assert(sizeof(MomentStatistic) == 0xC, "MomentStatistic is an invalid size"); | ||
| 46 | |||
| 47 | // This is nn::irsensor::MomentProcessorState | ||
| 48 | struct MomentProcessorState { | ||
| 49 | s64 sampling_number; | ||
| 50 | u64 timestamp; | ||
| 51 | Core::IrSensor::CameraAmbientNoiseLevel ambient_noise_level; | ||
| 52 | INSERT_PADDING_BYTES(4); | ||
| 53 | std::array<MomentStatistic, 0x30> stadistic; | ||
| 54 | }; | ||
| 55 | static_assert(sizeof(MomentProcessorState) == 0x258, "MomentProcessorState is an invalid size"); | ||
| 56 | |||
| 57 | MomentProcessorConfig current_config{}; | ||
| 58 | Core::IrSensor::DeviceFormat& device; | ||
| 59 | }; | ||
| 60 | |||
| 61 | } // namespace Service::IRS | ||
diff --git a/src/core/hle/service/hid/irsensor/pointing_processor.cpp b/src/core/hle/service/hid/irsensor/pointing_processor.cpp new file mode 100644 index 000000000..929f177fc --- /dev/null +++ b/src/core/hle/service/hid/irsensor/pointing_processor.cpp | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/service/hid/irsensor/pointing_processor.h" | ||
| 5 | |||
| 6 | namespace Service::IRS { | ||
| 7 | PointingProcessor::PointingProcessor(Core::IrSensor::DeviceFormat& device_format) | ||
| 8 | : device(device_format) { | ||
| 9 | device.mode = Core::IrSensor::IrSensorMode::PointingProcessorMarker; | ||
| 10 | device.camera_status = Core::IrSensor::IrCameraStatus::Unconnected; | ||
| 11 | device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Stopped; | ||
| 12 | } | ||
| 13 | |||
| 14 | PointingProcessor::~PointingProcessor() = default; | ||
| 15 | |||
| 16 | void PointingProcessor::StartProcessor() {} | ||
| 17 | |||
| 18 | void PointingProcessor::SuspendProcessor() {} | ||
| 19 | |||
| 20 | void PointingProcessor::StopProcessor() {} | ||
| 21 | |||
| 22 | void PointingProcessor::SetConfig(Core::IrSensor::PackedPointingProcessorConfig config) { | ||
| 23 | current_config.window_of_interest = config.window_of_interest; | ||
| 24 | } | ||
| 25 | |||
| 26 | } // namespace Service::IRS | ||
diff --git a/src/core/hle/service/hid/irsensor/pointing_processor.h b/src/core/hle/service/hid/irsensor/pointing_processor.h new file mode 100644 index 000000000..cf4930794 --- /dev/null +++ b/src/core/hle/service/hid/irsensor/pointing_processor.h | |||
| @@ -0,0 +1,61 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "common/common_types.h" | ||
| 7 | #include "core/hid/irs_types.h" | ||
| 8 | #include "core/hle/service/hid/irsensor/processor_base.h" | ||
| 9 | |||
| 10 | namespace Service::IRS { | ||
| 11 | class PointingProcessor final : public ProcessorBase { | ||
| 12 | public: | ||
| 13 | explicit PointingProcessor(Core::IrSensor::DeviceFormat& device_format); | ||
| 14 | ~PointingProcessor() override; | ||
| 15 | |||
| 16 | // Called when the processor is initialized | ||
| 17 | void StartProcessor() override; | ||
| 18 | |||
| 19 | // Called when the processor is suspended | ||
| 20 | void SuspendProcessor() override; | ||
| 21 | |||
| 22 | // Called when the processor is stopped | ||
| 23 | void StopProcessor() override; | ||
| 24 | |||
| 25 | // Sets config parameters of the camera | ||
| 26 | void SetConfig(Core::IrSensor::PackedPointingProcessorConfig config); | ||
| 27 | |||
| 28 | private: | ||
| 29 | // This is nn::irsensor::PointingProcessorConfig | ||
| 30 | struct PointingProcessorConfig { | ||
| 31 | Core::IrSensor::IrsRect window_of_interest; | ||
| 32 | }; | ||
| 33 | static_assert(sizeof(PointingProcessorConfig) == 0x8, | ||
| 34 | "PointingProcessorConfig is an invalid size"); | ||
| 35 | |||
| 36 | struct PointingProcessorMarkerData { | ||
| 37 | u8 pointing_status; | ||
| 38 | INSERT_PADDING_BYTES(3); | ||
| 39 | u32 unknown; | ||
| 40 | float unkown_float1; | ||
| 41 | float position_x; | ||
| 42 | float position_y; | ||
| 43 | float unkown_float2; | ||
| 44 | Core::IrSensor::IrsRect window_of_interest; | ||
| 45 | }; | ||
| 46 | static_assert(sizeof(PointingProcessorMarkerData) == 0x20, | ||
| 47 | "PointingProcessorMarkerData is an invalid size"); | ||
| 48 | |||
| 49 | struct PointingProcessorMarkerState { | ||
| 50 | s64 sampling_number; | ||
| 51 | u64 timestamp; | ||
| 52 | std::array<PointingProcessorMarkerData, 0x3> data; | ||
| 53 | }; | ||
| 54 | static_assert(sizeof(PointingProcessorMarkerState) == 0x70, | ||
| 55 | "PointingProcessorMarkerState is an invalid size"); | ||
| 56 | |||
| 57 | PointingProcessorConfig current_config{}; | ||
| 58 | Core::IrSensor::DeviceFormat& device; | ||
| 59 | }; | ||
| 60 | |||
| 61 | } // namespace Service::IRS | ||
diff --git a/src/core/hle/service/hid/irsensor/processor_base.cpp b/src/core/hle/service/hid/irsensor/processor_base.cpp new file mode 100644 index 000000000..4d43ca17a --- /dev/null +++ b/src/core/hle/service/hid/irsensor/processor_base.cpp | |||
| @@ -0,0 +1,67 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/service/hid/irsensor/processor_base.h" | ||
| 5 | |||
| 6 | namespace Service::IRS { | ||
| 7 | |||
| 8 | ProcessorBase::ProcessorBase() {} | ||
| 9 | ProcessorBase::~ProcessorBase() = default; | ||
| 10 | |||
| 11 | bool ProcessorBase::IsProcessorActive() const { | ||
| 12 | return is_active; | ||
| 13 | } | ||
| 14 | |||
| 15 | std::size_t ProcessorBase::GetDataSize(Core::IrSensor::ImageTransferProcessorFormat format) const { | ||
| 16 | switch (format) { | ||
| 17 | case Core::IrSensor::ImageTransferProcessorFormat::Size320x240: | ||
| 18 | return 320 * 240; | ||
| 19 | case Core::IrSensor::ImageTransferProcessorFormat::Size160x120: | ||
| 20 | return 160 * 120; | ||
| 21 | case Core::IrSensor::ImageTransferProcessorFormat::Size80x60: | ||
| 22 | return 80 * 60; | ||
| 23 | case Core::IrSensor::ImageTransferProcessorFormat::Size40x30: | ||
| 24 | return 40 * 30; | ||
| 25 | case Core::IrSensor::ImageTransferProcessorFormat::Size20x15: | ||
| 26 | return 20 * 15; | ||
| 27 | default: | ||
| 28 | return 0; | ||
| 29 | } | ||
| 30 | } | ||
| 31 | |||
| 32 | std::size_t ProcessorBase::GetDataWidth(Core::IrSensor::ImageTransferProcessorFormat format) const { | ||
| 33 | switch (format) { | ||
| 34 | case Core::IrSensor::ImageTransferProcessorFormat::Size320x240: | ||
| 35 | return 320; | ||
| 36 | case Core::IrSensor::ImageTransferProcessorFormat::Size160x120: | ||
| 37 | return 160; | ||
| 38 | case Core::IrSensor::ImageTransferProcessorFormat::Size80x60: | ||
| 39 | return 80; | ||
| 40 | case Core::IrSensor::ImageTransferProcessorFormat::Size40x30: | ||
| 41 | return 40; | ||
| 42 | case Core::IrSensor::ImageTransferProcessorFormat::Size20x15: | ||
| 43 | return 20; | ||
| 44 | default: | ||
| 45 | return 0; | ||
| 46 | } | ||
| 47 | } | ||
| 48 | |||
| 49 | std::size_t ProcessorBase::GetDataHeight( | ||
| 50 | Core::IrSensor::ImageTransferProcessorFormat format) const { | ||
| 51 | switch (format) { | ||
| 52 | case Core::IrSensor::ImageTransferProcessorFormat::Size320x240: | ||
| 53 | return 240; | ||
| 54 | case Core::IrSensor::ImageTransferProcessorFormat::Size160x120: | ||
| 55 | return 120; | ||
| 56 | case Core::IrSensor::ImageTransferProcessorFormat::Size80x60: | ||
| 57 | return 60; | ||
| 58 | case Core::IrSensor::ImageTransferProcessorFormat::Size40x30: | ||
| 59 | return 30; | ||
| 60 | case Core::IrSensor::ImageTransferProcessorFormat::Size20x15: | ||
| 61 | return 15; | ||
| 62 | default: | ||
| 63 | return 0; | ||
| 64 | } | ||
| 65 | } | ||
| 66 | |||
| 67 | } // namespace Service::IRS | ||
diff --git a/src/core/hle/service/hid/irsensor/processor_base.h b/src/core/hle/service/hid/irsensor/processor_base.h new file mode 100644 index 000000000..bc0d2977b --- /dev/null +++ b/src/core/hle/service/hid/irsensor/processor_base.h | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "common/common_types.h" | ||
| 7 | #include "core/hid/irs_types.h" | ||
| 8 | |||
| 9 | namespace Service::IRS { | ||
| 10 | class ProcessorBase { | ||
| 11 | public: | ||
| 12 | explicit ProcessorBase(); | ||
| 13 | virtual ~ProcessorBase(); | ||
| 14 | |||
| 15 | virtual void StartProcessor() = 0; | ||
| 16 | virtual void SuspendProcessor() = 0; | ||
| 17 | virtual void StopProcessor() = 0; | ||
| 18 | |||
| 19 | bool IsProcessorActive() const; | ||
| 20 | |||
| 21 | protected: | ||
| 22 | /// Returns the number of bytes the image uses | ||
| 23 | std::size_t GetDataSize(Core::IrSensor::ImageTransferProcessorFormat format) const; | ||
| 24 | |||
| 25 | /// Returns the width of the image | ||
| 26 | std::size_t GetDataWidth(Core::IrSensor::ImageTransferProcessorFormat format) const; | ||
| 27 | |||
| 28 | /// Returns the height of the image | ||
| 29 | std::size_t GetDataHeight(Core::IrSensor::ImageTransferProcessorFormat format) const; | ||
| 30 | |||
| 31 | bool is_active{false}; | ||
| 32 | }; | ||
| 33 | } // namespace Service::IRS | ||
diff --git a/src/core/hle/service/hid/irsensor/tera_plugin_processor.cpp b/src/core/hle/service/hid/irsensor/tera_plugin_processor.cpp new file mode 100644 index 000000000..e691c840a --- /dev/null +++ b/src/core/hle/service/hid/irsensor/tera_plugin_processor.cpp | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/service/hid/irsensor/tera_plugin_processor.h" | ||
| 5 | |||
| 6 | namespace Service::IRS { | ||
| 7 | TeraPluginProcessor::TeraPluginProcessor(Core::IrSensor::DeviceFormat& device_format) | ||
| 8 | : device(device_format) { | ||
| 9 | device.mode = Core::IrSensor::IrSensorMode::TeraPluginProcessor; | ||
| 10 | device.camera_status = Core::IrSensor::IrCameraStatus::Unconnected; | ||
| 11 | device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Stopped; | ||
| 12 | } | ||
| 13 | |||
| 14 | TeraPluginProcessor::~TeraPluginProcessor() = default; | ||
| 15 | |||
| 16 | void TeraPluginProcessor::StartProcessor() {} | ||
| 17 | |||
| 18 | void TeraPluginProcessor::SuspendProcessor() {} | ||
| 19 | |||
| 20 | void TeraPluginProcessor::StopProcessor() {} | ||
| 21 | |||
| 22 | void TeraPluginProcessor::SetConfig(Core::IrSensor::PackedTeraPluginProcessorConfig config) { | ||
| 23 | current_config.mode = config.mode; | ||
| 24 | current_config.unknown_1 = config.unknown_1; | ||
| 25 | current_config.unknown_2 = config.unknown_2; | ||
| 26 | current_config.unknown_3 = config.unknown_3; | ||
| 27 | } | ||
| 28 | |||
| 29 | } // namespace Service::IRS | ||
diff --git a/src/core/hle/service/hid/irsensor/tera_plugin_processor.h b/src/core/hle/service/hid/irsensor/tera_plugin_processor.h new file mode 100644 index 000000000..bbea7ed0b --- /dev/null +++ b/src/core/hle/service/hid/irsensor/tera_plugin_processor.h | |||
| @@ -0,0 +1,53 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "common/bit_field.h" | ||
| 7 | #include "common/common_types.h" | ||
| 8 | #include "core/hid/irs_types.h" | ||
| 9 | #include "core/hle/service/hid/irsensor/processor_base.h" | ||
| 10 | |||
| 11 | namespace Service::IRS { | ||
| 12 | class TeraPluginProcessor final : public ProcessorBase { | ||
| 13 | public: | ||
| 14 | explicit TeraPluginProcessor(Core::IrSensor::DeviceFormat& device_format); | ||
| 15 | ~TeraPluginProcessor() override; | ||
| 16 | |||
| 17 | // Called when the processor is initialized | ||
| 18 | void StartProcessor() override; | ||
| 19 | |||
| 20 | // Called when the processor is suspended | ||
| 21 | void SuspendProcessor() override; | ||
| 22 | |||
| 23 | // Called when the processor is stopped | ||
| 24 | void StopProcessor() override; | ||
| 25 | |||
| 26 | // Sets config parameters of the camera | ||
| 27 | void SetConfig(Core::IrSensor::PackedTeraPluginProcessorConfig config); | ||
| 28 | |||
| 29 | private: | ||
| 30 | // This is nn::irsensor::TeraPluginProcessorConfig | ||
| 31 | struct TeraPluginProcessorConfig { | ||
| 32 | u8 mode; | ||
| 33 | u8 unknown_1; | ||
| 34 | u8 unknown_2; | ||
| 35 | u8 unknown_3; | ||
| 36 | }; | ||
| 37 | static_assert(sizeof(TeraPluginProcessorConfig) == 0x4, | ||
| 38 | "TeraPluginProcessorConfig is an invalid size"); | ||
| 39 | |||
| 40 | struct TeraPluginProcessorState { | ||
| 41 | s64 sampling_number; | ||
| 42 | u64 timestamp; | ||
| 43 | Core::IrSensor::CameraAmbientNoiseLevel ambient_noise_level; | ||
| 44 | std::array<u8, 0x12c> data; | ||
| 45 | }; | ||
| 46 | static_assert(sizeof(TeraPluginProcessorState) == 0x140, | ||
| 47 | "TeraPluginProcessorState is an invalid size"); | ||
| 48 | |||
| 49 | TeraPluginProcessorConfig current_config{}; | ||
| 50 | Core::IrSensor::DeviceFormat& device; | ||
| 51 | }; | ||
| 52 | |||
| 53 | } // namespace Service::IRS | ||
diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt index 48e799cf5..90dd629c6 100644 --- a/src/input_common/CMakeLists.txt +++ b/src/input_common/CMakeLists.txt | |||
| @@ -1,4 +1,6 @@ | |||
| 1 | add_library(input_common STATIC | 1 | add_library(input_common STATIC |
| 2 | drivers/camera.cpp | ||
| 3 | drivers/camera.h | ||
| 2 | drivers/gc_adapter.cpp | 4 | drivers/gc_adapter.cpp |
| 3 | drivers/gc_adapter.h | 5 | drivers/gc_adapter.h |
| 4 | drivers/keyboard.cpp | 6 | drivers/keyboard.cpp |
diff --git a/src/input_common/drivers/camera.cpp b/src/input_common/drivers/camera.cpp new file mode 100644 index 000000000..dceea67e0 --- /dev/null +++ b/src/input_common/drivers/camera.cpp | |||
| @@ -0,0 +1,82 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <fmt/format.h> | ||
| 5 | |||
| 6 | #include "common/param_package.h" | ||
| 7 | #include "input_common/drivers/camera.h" | ||
| 8 | |||
| 9 | namespace InputCommon { | ||
| 10 | constexpr PadIdentifier identifier = { | ||
| 11 | .guid = Common::UUID{}, | ||
| 12 | .port = 0, | ||
| 13 | .pad = 0, | ||
| 14 | }; | ||
| 15 | |||
| 16 | Camera::Camera(std::string input_engine_) : InputEngine(std::move(input_engine_)) { | ||
| 17 | PreSetController(identifier); | ||
| 18 | } | ||
| 19 | |||
| 20 | void Camera::SetCameraData(std::size_t width, std::size_t height, std::vector<u32> data) { | ||
| 21 | const std::size_t desired_width = getImageWidth(); | ||
| 22 | const std::size_t desired_height = getImageHeight(); | ||
| 23 | status.data.resize(desired_width * desired_height); | ||
| 24 | |||
| 25 | // Resize image to desired format | ||
| 26 | for (std::size_t y = 0; y < desired_height; y++) { | ||
| 27 | for (std::size_t x = 0; x < desired_width; x++) { | ||
| 28 | const std::size_t pixel_index = y * desired_width + x; | ||
| 29 | const std::size_t old_x = width * x / desired_width; | ||
| 30 | const std::size_t old_y = height * y / desired_height; | ||
| 31 | const std::size_t data_pixel_index = old_y * width + old_x; | ||
| 32 | status.data[pixel_index] = static_cast<u8>(data[data_pixel_index] & 0xFF); | ||
| 33 | } | ||
| 34 | } | ||
| 35 | |||
| 36 | SetCamera(identifier, status); | ||
| 37 | } | ||
| 38 | |||
| 39 | std::size_t Camera::getImageWidth() const { | ||
| 40 | switch (status.format) { | ||
| 41 | case Common::Input::CameraFormat::Size320x240: | ||
| 42 | return 320; | ||
| 43 | case Common::Input::CameraFormat::Size160x120: | ||
| 44 | return 160; | ||
| 45 | case Common::Input::CameraFormat::Size80x60: | ||
| 46 | return 80; | ||
| 47 | case Common::Input::CameraFormat::Size40x30: | ||
| 48 | return 40; | ||
| 49 | case Common::Input::CameraFormat::Size20x15: | ||
| 50 | return 20; | ||
| 51 | case Common::Input::CameraFormat::None: | ||
| 52 | default: | ||
| 53 | return 0; | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 57 | std::size_t Camera::getImageHeight() const { | ||
| 58 | switch (status.format) { | ||
| 59 | case Common::Input::CameraFormat::Size320x240: | ||
| 60 | return 240; | ||
| 61 | case Common::Input::CameraFormat::Size160x120: | ||
| 62 | return 120; | ||
| 63 | case Common::Input::CameraFormat::Size80x60: | ||
| 64 | return 60; | ||
| 65 | case Common::Input::CameraFormat::Size40x30: | ||
| 66 | return 30; | ||
| 67 | case Common::Input::CameraFormat::Size20x15: | ||
| 68 | return 15; | ||
| 69 | case Common::Input::CameraFormat::None: | ||
| 70 | default: | ||
| 71 | return 0; | ||
| 72 | } | ||
| 73 | } | ||
| 74 | |||
| 75 | Common::Input::CameraError Camera::SetCameraFormat( | ||
| 76 | [[maybe_unused]] const PadIdentifier& identifier_, | ||
| 77 | const Common::Input::CameraFormat camera_format) { | ||
| 78 | status.format = camera_format; | ||
| 79 | return Common::Input::CameraError::None; | ||
| 80 | } | ||
| 81 | |||
| 82 | } // namespace InputCommon | ||
diff --git a/src/input_common/drivers/camera.h b/src/input_common/drivers/camera.h new file mode 100644 index 000000000..b8a7c75e5 --- /dev/null +++ b/src/input_common/drivers/camera.h | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "input_common/input_engine.h" | ||
| 7 | |||
| 8 | namespace InputCommon { | ||
| 9 | |||
| 10 | /** | ||
| 11 | * A button device factory representing a keyboard. It receives keyboard events and forward them | ||
| 12 | * to all button devices it created. | ||
| 13 | */ | ||
| 14 | class Camera final : public InputEngine { | ||
| 15 | public: | ||
| 16 | explicit Camera(std::string input_engine_); | ||
| 17 | |||
| 18 | void SetCameraData(std::size_t width, std::size_t height, std::vector<u32> data); | ||
| 19 | |||
| 20 | std::size_t getImageWidth() const; | ||
| 21 | std::size_t getImageHeight() const; | ||
| 22 | |||
| 23 | Common::Input::CameraError SetCameraFormat(const PadIdentifier& identifier_, | ||
| 24 | Common::Input::CameraFormat camera_format) override; | ||
| 25 | |||
| 26 | Common::Input::CameraStatus status{}; | ||
| 27 | }; | ||
| 28 | |||
| 29 | } // namespace InputCommon | ||
diff --git a/src/input_common/input_engine.cpp b/src/input_common/input_engine.cpp index 12214d146..6ede0e4b0 100644 --- a/src/input_common/input_engine.cpp +++ b/src/input_common/input_engine.cpp | |||
| @@ -90,6 +90,18 @@ void InputEngine::SetMotion(const PadIdentifier& identifier, int motion, const B | |||
| 90 | TriggerOnMotionChange(identifier, motion, value); | 90 | TriggerOnMotionChange(identifier, motion, value); |
| 91 | } | 91 | } |
| 92 | 92 | ||
| 93 | void InputEngine::SetCamera(const PadIdentifier& identifier, | ||
| 94 | const Common::Input::CameraStatus& value) { | ||
| 95 | { | ||
| 96 | std::scoped_lock lock{mutex}; | ||
| 97 | ControllerData& controller = controller_list.at(identifier); | ||
| 98 | if (!configuring) { | ||
| 99 | controller.camera = value; | ||
| 100 | } | ||
| 101 | } | ||
| 102 | TriggerOnCameraChange(identifier, value); | ||
| 103 | } | ||
| 104 | |||
| 93 | bool InputEngine::GetButton(const PadIdentifier& identifier, int button) const { | 105 | bool InputEngine::GetButton(const PadIdentifier& identifier, int button) const { |
| 94 | std::scoped_lock lock{mutex}; | 106 | std::scoped_lock lock{mutex}; |
| 95 | const auto controller_iter = controller_list.find(identifier); | 107 | const auto controller_iter = controller_list.find(identifier); |
| @@ -165,6 +177,18 @@ BasicMotion InputEngine::GetMotion(const PadIdentifier& identifier, int motion) | |||
| 165 | return controller.motions.at(motion); | 177 | return controller.motions.at(motion); |
| 166 | } | 178 | } |
| 167 | 179 | ||
| 180 | Common::Input::CameraStatus InputEngine::GetCamera(const PadIdentifier& identifier) const { | ||
| 181 | std::scoped_lock lock{mutex}; | ||
| 182 | const auto controller_iter = controller_list.find(identifier); | ||
| 183 | if (controller_iter == controller_list.cend()) { | ||
| 184 | LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.RawString(), | ||
| 185 | identifier.pad, identifier.port); | ||
| 186 | return {}; | ||
| 187 | } | ||
| 188 | const ControllerData& controller = controller_iter->second; | ||
| 189 | return controller.camera; | ||
| 190 | } | ||
| 191 | |||
| 168 | void InputEngine::ResetButtonState() { | 192 | void InputEngine::ResetButtonState() { |
| 169 | for (const auto& controller : controller_list) { | 193 | for (const auto& controller : controller_list) { |
| 170 | for (const auto& button : controller.second.buttons) { | 194 | for (const auto& button : controller.second.buttons) { |
| @@ -317,6 +341,20 @@ void InputEngine::TriggerOnMotionChange(const PadIdentifier& identifier, int mot | |||
| 317 | }); | 341 | }); |
| 318 | } | 342 | } |
| 319 | 343 | ||
| 344 | void InputEngine::TriggerOnCameraChange(const PadIdentifier& identifier, | ||
| 345 | [[maybe_unused]] const Common::Input::CameraStatus& value) { | ||
| 346 | std::scoped_lock lock{mutex_callback}; | ||
| 347 | for (const auto& poller_pair : callback_list) { | ||
| 348 | const InputIdentifier& poller = poller_pair.second; | ||
| 349 | if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::Camera, 0)) { | ||
| 350 | continue; | ||
| 351 | } | ||
| 352 | if (poller.callback.on_change) { | ||
| 353 | poller.callback.on_change(); | ||
| 354 | } | ||
| 355 | } | ||
| 356 | } | ||
| 357 | |||
| 320 | bool InputEngine::IsInputIdentifierEqual(const InputIdentifier& input_identifier, | 358 | bool InputEngine::IsInputIdentifierEqual(const InputIdentifier& input_identifier, |
| 321 | const PadIdentifier& identifier, EngineInputType type, | 359 | const PadIdentifier& identifier, EngineInputType type, |
| 322 | int index) const { | 360 | int index) const { |
diff --git a/src/input_common/input_engine.h b/src/input_common/input_engine.h index 13295bd49..f6b3c4610 100644 --- a/src/input_common/input_engine.h +++ b/src/input_common/input_engine.h | |||
| @@ -36,11 +36,12 @@ struct BasicMotion { | |||
| 36 | // Types of input that are stored in the engine | 36 | // Types of input that are stored in the engine |
| 37 | enum class EngineInputType { | 37 | enum class EngineInputType { |
| 38 | None, | 38 | None, |
| 39 | Analog, | ||
| 40 | Battery, | ||
| 39 | Button, | 41 | Button, |
| 42 | Camera, | ||
| 40 | HatButton, | 43 | HatButton, |
| 41 | Analog, | ||
| 42 | Motion, | 44 | Motion, |
| 43 | Battery, | ||
| 44 | }; | 45 | }; |
| 45 | 46 | ||
| 46 | namespace std { | 47 | namespace std { |
| @@ -115,10 +116,17 @@ public: | |||
| 115 | // Sets polling mode to a controller | 116 | // Sets polling mode to a controller |
| 116 | virtual Common::Input::PollingError SetPollingMode( | 117 | virtual Common::Input::PollingError SetPollingMode( |
| 117 | [[maybe_unused]] const PadIdentifier& identifier, | 118 | [[maybe_unused]] const PadIdentifier& identifier, |
| 118 | [[maybe_unused]] const Common::Input::PollingMode vibration) { | 119 | [[maybe_unused]] const Common::Input::PollingMode polling_mode) { |
| 119 | return Common::Input::PollingError::NotSupported; | 120 | return Common::Input::PollingError::NotSupported; |
| 120 | } | 121 | } |
| 121 | 122 | ||
| 123 | // Sets camera format to a controller | ||
| 124 | virtual Common::Input::CameraError SetCameraFormat( | ||
| 125 | [[maybe_unused]] const PadIdentifier& identifier, | ||
| 126 | [[maybe_unused]] Common::Input::CameraFormat camera_format) { | ||
| 127 | return Common::Input::CameraError::NotSupported; | ||
| 128 | } | ||
| 129 | |||
| 122 | // Returns the engine name | 130 | // Returns the engine name |
| 123 | [[nodiscard]] const std::string& GetEngineName() const; | 131 | [[nodiscard]] const std::string& GetEngineName() const; |
| 124 | 132 | ||
| @@ -174,6 +182,7 @@ public: | |||
| 174 | f32 GetAxis(const PadIdentifier& identifier, int axis) const; | 182 | f32 GetAxis(const PadIdentifier& identifier, int axis) const; |
| 175 | Common::Input::BatteryLevel GetBattery(const PadIdentifier& identifier) const; | 183 | Common::Input::BatteryLevel GetBattery(const PadIdentifier& identifier) const; |
| 176 | BasicMotion GetMotion(const PadIdentifier& identifier, int motion) const; | 184 | BasicMotion GetMotion(const PadIdentifier& identifier, int motion) const; |
| 185 | Common::Input::CameraStatus GetCamera(const PadIdentifier& identifier) const; | ||
| 177 | 186 | ||
| 178 | int SetCallback(InputIdentifier input_identifier); | 187 | int SetCallback(InputIdentifier input_identifier); |
| 179 | void SetMappingCallback(MappingCallback callback); | 188 | void SetMappingCallback(MappingCallback callback); |
| @@ -185,6 +194,7 @@ protected: | |||
| 185 | void SetAxis(const PadIdentifier& identifier, int axis, f32 value); | 194 | void SetAxis(const PadIdentifier& identifier, int axis, f32 value); |
| 186 | void SetBattery(const PadIdentifier& identifier, Common::Input::BatteryLevel value); | 195 | void SetBattery(const PadIdentifier& identifier, Common::Input::BatteryLevel value); |
| 187 | void SetMotion(const PadIdentifier& identifier, int motion, const BasicMotion& value); | 196 | void SetMotion(const PadIdentifier& identifier, int motion, const BasicMotion& value); |
| 197 | void SetCamera(const PadIdentifier& identifier, const Common::Input::CameraStatus& value); | ||
| 188 | 198 | ||
| 189 | virtual std::string GetHatButtonName([[maybe_unused]] u8 direction_value) const { | 199 | virtual std::string GetHatButtonName([[maybe_unused]] u8 direction_value) const { |
| 190 | return "Unknown"; | 200 | return "Unknown"; |
| @@ -197,6 +207,7 @@ private: | |||
| 197 | std::unordered_map<int, float> axes; | 207 | std::unordered_map<int, float> axes; |
| 198 | std::unordered_map<int, BasicMotion> motions; | 208 | std::unordered_map<int, BasicMotion> motions; |
| 199 | Common::Input::BatteryLevel battery{}; | 209 | Common::Input::BatteryLevel battery{}; |
| 210 | Common::Input::CameraStatus camera{}; | ||
| 200 | }; | 211 | }; |
| 201 | 212 | ||
| 202 | void TriggerOnButtonChange(const PadIdentifier& identifier, int button, bool value); | 213 | void TriggerOnButtonChange(const PadIdentifier& identifier, int button, bool value); |
| @@ -205,6 +216,8 @@ private: | |||
| 205 | void TriggerOnBatteryChange(const PadIdentifier& identifier, Common::Input::BatteryLevel value); | 216 | void TriggerOnBatteryChange(const PadIdentifier& identifier, Common::Input::BatteryLevel value); |
| 206 | void TriggerOnMotionChange(const PadIdentifier& identifier, int motion, | 217 | void TriggerOnMotionChange(const PadIdentifier& identifier, int motion, |
| 207 | const BasicMotion& value); | 218 | const BasicMotion& value); |
| 219 | void TriggerOnCameraChange(const PadIdentifier& identifier, | ||
| 220 | const Common::Input::CameraStatus& value); | ||
| 208 | 221 | ||
| 209 | bool IsInputIdentifierEqual(const InputIdentifier& input_identifier, | 222 | bool IsInputIdentifierEqual(const InputIdentifier& input_identifier, |
| 210 | const PadIdentifier& identifier, EngineInputType type, | 223 | const PadIdentifier& identifier, EngineInputType type, |
diff --git a/src/input_common/input_poller.cpp b/src/input_common/input_poller.cpp index 49ccb4422..133422d5c 100644 --- a/src/input_common/input_poller.cpp +++ b/src/input_common/input_poller.cpp | |||
| @@ -664,6 +664,47 @@ private: | |||
| 664 | InputEngine* input_engine; | 664 | InputEngine* input_engine; |
| 665 | }; | 665 | }; |
| 666 | 666 | ||
| 667 | class InputFromCamera final : public Common::Input::InputDevice { | ||
| 668 | public: | ||
| 669 | explicit InputFromCamera(PadIdentifier identifier_, InputEngine* input_engine_) | ||
| 670 | : identifier(identifier_), input_engine(input_engine_) { | ||
| 671 | UpdateCallback engine_callback{[this]() { OnChange(); }}; | ||
| 672 | const InputIdentifier input_identifier{ | ||
| 673 | .identifier = identifier, | ||
| 674 | .type = EngineInputType::Camera, | ||
| 675 | .index = 0, | ||
| 676 | .callback = engine_callback, | ||
| 677 | }; | ||
| 678 | callback_key = input_engine->SetCallback(input_identifier); | ||
| 679 | } | ||
| 680 | |||
| 681 | ~InputFromCamera() override { | ||
| 682 | input_engine->DeleteCallback(callback_key); | ||
| 683 | } | ||
| 684 | |||
| 685 | Common::Input::CameraStatus GetStatus() const { | ||
| 686 | return input_engine->GetCamera(identifier); | ||
| 687 | } | ||
| 688 | |||
| 689 | void ForceUpdate() override { | ||
| 690 | OnChange(); | ||
| 691 | } | ||
| 692 | |||
| 693 | void OnChange() { | ||
| 694 | const Common::Input::CallbackStatus status{ | ||
| 695 | .type = Common::Input::InputType::IrSensor, | ||
| 696 | .camera_status = GetStatus(), | ||
| 697 | }; | ||
| 698 | |||
| 699 | TriggerOnChange(status); | ||
| 700 | } | ||
| 701 | |||
| 702 | private: | ||
| 703 | const PadIdentifier identifier; | ||
| 704 | int callback_key; | ||
| 705 | InputEngine* input_engine; | ||
| 706 | }; | ||
| 707 | |||
| 667 | class OutputFromIdentifier final : public Common::Input::OutputDevice { | 708 | class OutputFromIdentifier final : public Common::Input::OutputDevice { |
| 668 | public: | 709 | public: |
| 669 | explicit OutputFromIdentifier(PadIdentifier identifier_, InputEngine* input_engine_) | 710 | explicit OutputFromIdentifier(PadIdentifier identifier_, InputEngine* input_engine_) |
| @@ -682,6 +723,10 @@ public: | |||
| 682 | return input_engine->SetPollingMode(identifier, polling_mode); | 723 | return input_engine->SetPollingMode(identifier, polling_mode); |
| 683 | } | 724 | } |
| 684 | 725 | ||
| 726 | Common::Input::CameraError SetCameraFormat(Common::Input::CameraFormat camera_format) override { | ||
| 727 | return input_engine->SetCameraFormat(identifier, camera_format); | ||
| 728 | } | ||
| 729 | |||
| 685 | private: | 730 | private: |
| 686 | const PadIdentifier identifier; | 731 | const PadIdentifier identifier; |
| 687 | InputEngine* input_engine; | 732 | InputEngine* input_engine; |
| @@ -920,6 +965,18 @@ std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateMotionDevice( | |||
| 920 | properties_y, properties_z, input_engine.get()); | 965 | properties_y, properties_z, input_engine.get()); |
| 921 | } | 966 | } |
| 922 | 967 | ||
| 968 | std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateCameraDevice( | ||
| 969 | const Common::ParamPackage& params) { | ||
| 970 | const PadIdentifier identifier = { | ||
| 971 | .guid = Common::UUID{params.Get("guid", "")}, | ||
| 972 | .port = static_cast<std::size_t>(params.Get("port", 0)), | ||
| 973 | .pad = static_cast<std::size_t>(params.Get("pad", 0)), | ||
| 974 | }; | ||
| 975 | |||
| 976 | input_engine->PreSetController(identifier); | ||
| 977 | return std::make_unique<InputFromCamera>(identifier, input_engine.get()); | ||
| 978 | } | ||
| 979 | |||
| 923 | InputFactory::InputFactory(std::shared_ptr<InputEngine> input_engine_) | 980 | InputFactory::InputFactory(std::shared_ptr<InputEngine> input_engine_) |
| 924 | : input_engine(std::move(input_engine_)) {} | 981 | : input_engine(std::move(input_engine_)) {} |
| 925 | 982 | ||
| @@ -928,6 +985,9 @@ std::unique_ptr<Common::Input::InputDevice> InputFactory::Create( | |||
| 928 | if (params.Has("battery")) { | 985 | if (params.Has("battery")) { |
| 929 | return CreateBatteryDevice(params); | 986 | return CreateBatteryDevice(params); |
| 930 | } | 987 | } |
| 988 | if (params.Has("camera")) { | ||
| 989 | return CreateCameraDevice(params); | ||
| 990 | } | ||
| 931 | if (params.Has("button") && params.Has("axis")) { | 991 | if (params.Has("button") && params.Has("axis")) { |
| 932 | return CreateTriggerDevice(params); | 992 | return CreateTriggerDevice(params); |
| 933 | } | 993 | } |
diff --git a/src/input_common/input_poller.h b/src/input_common/input_poller.h index 6ebe0dbf5..4410a8415 100644 --- a/src/input_common/input_poller.h +++ b/src/input_common/input_poller.h | |||
| @@ -211,6 +211,17 @@ private: | |||
| 211 | */ | 211 | */ |
| 212 | std::unique_ptr<Common::Input::InputDevice> CreateMotionDevice(Common::ParamPackage params); | 212 | std::unique_ptr<Common::Input::InputDevice> CreateMotionDevice(Common::ParamPackage params); |
| 213 | 213 | ||
| 214 | /** | ||
| 215 | * Creates a camera device from the parameters given. | ||
| 216 | * @param params contains parameters for creating the device: | ||
| 217 | * - "guid": text string for identifying controllers | ||
| 218 | * - "port": port of the connected device | ||
| 219 | * - "pad": slot of the connected controller | ||
| 220 | * @returns a unique input device with the parameters specified | ||
| 221 | */ | ||
| 222 | std::unique_ptr<Common::Input::InputDevice> CreateCameraDevice( | ||
| 223 | const Common::ParamPackage& params); | ||
| 224 | |||
| 214 | std::shared_ptr<InputEngine> input_engine; | 225 | std::shared_ptr<InputEngine> input_engine; |
| 215 | }; | 226 | }; |
| 216 | } // namespace InputCommon | 227 | } // namespace InputCommon |
diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index 21834fb6b..ca1cb9542 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #include <memory> | 5 | #include <memory> |
| 6 | #include "common/input.h" | 6 | #include "common/input.h" |
| 7 | #include "common/param_package.h" | 7 | #include "common/param_package.h" |
| 8 | #include "input_common/drivers/camera.h" | ||
| 8 | #include "input_common/drivers/gc_adapter.h" | 9 | #include "input_common/drivers/gc_adapter.h" |
| 9 | #include "input_common/drivers/keyboard.h" | 10 | #include "input_common/drivers/keyboard.h" |
| 10 | #include "input_common/drivers/mouse.h" | 11 | #include "input_common/drivers/mouse.h" |
| @@ -78,6 +79,15 @@ struct InputSubsystem::Impl { | |||
| 78 | Common::Input::RegisterFactory<Common::Input::OutputDevice>(tas_input->GetEngineName(), | 79 | Common::Input::RegisterFactory<Common::Input::OutputDevice>(tas_input->GetEngineName(), |
| 79 | tas_output_factory); | 80 | tas_output_factory); |
| 80 | 81 | ||
| 82 | camera = std::make_shared<Camera>("camera"); | ||
| 83 | camera->SetMappingCallback(mapping_callback); | ||
| 84 | camera_input_factory = std::make_shared<InputFactory>(camera); | ||
| 85 | camera_output_factory = std::make_shared<OutputFactory>(camera); | ||
| 86 | Common::Input::RegisterFactory<Common::Input::InputDevice>(camera->GetEngineName(), | ||
| 87 | camera_input_factory); | ||
| 88 | Common::Input::RegisterFactory<Common::Input::OutputDevice>(camera->GetEngineName(), | ||
| 89 | camera_output_factory); | ||
| 90 | |||
| 81 | #ifdef HAVE_SDL2 | 91 | #ifdef HAVE_SDL2 |
| 82 | sdl = std::make_shared<SDLDriver>("sdl"); | 92 | sdl = std::make_shared<SDLDriver>("sdl"); |
| 83 | sdl->SetMappingCallback(mapping_callback); | 93 | sdl->SetMappingCallback(mapping_callback); |
| @@ -317,6 +327,7 @@ struct InputSubsystem::Impl { | |||
| 317 | std::shared_ptr<TouchScreen> touch_screen; | 327 | std::shared_ptr<TouchScreen> touch_screen; |
| 318 | std::shared_ptr<TasInput::Tas> tas_input; | 328 | std::shared_ptr<TasInput::Tas> tas_input; |
| 319 | std::shared_ptr<CemuhookUDP::UDPClient> udp_client; | 329 | std::shared_ptr<CemuhookUDP::UDPClient> udp_client; |
| 330 | std::shared_ptr<Camera> camera; | ||
| 320 | 331 | ||
| 321 | std::shared_ptr<InputFactory> keyboard_factory; | 332 | std::shared_ptr<InputFactory> keyboard_factory; |
| 322 | std::shared_ptr<InputFactory> mouse_factory; | 333 | std::shared_ptr<InputFactory> mouse_factory; |
| @@ -324,12 +335,14 @@ struct InputSubsystem::Impl { | |||
| 324 | std::shared_ptr<InputFactory> touch_screen_factory; | 335 | std::shared_ptr<InputFactory> touch_screen_factory; |
| 325 | std::shared_ptr<InputFactory> udp_client_input_factory; | 336 | std::shared_ptr<InputFactory> udp_client_input_factory; |
| 326 | std::shared_ptr<InputFactory> tas_input_factory; | 337 | std::shared_ptr<InputFactory> tas_input_factory; |
| 338 | std::shared_ptr<InputFactory> camera_input_factory; | ||
| 327 | 339 | ||
| 328 | std::shared_ptr<OutputFactory> keyboard_output_factory; | 340 | std::shared_ptr<OutputFactory> keyboard_output_factory; |
| 329 | std::shared_ptr<OutputFactory> mouse_output_factory; | 341 | std::shared_ptr<OutputFactory> mouse_output_factory; |
| 330 | std::shared_ptr<OutputFactory> gcadapter_output_factory; | 342 | std::shared_ptr<OutputFactory> gcadapter_output_factory; |
| 331 | std::shared_ptr<OutputFactory> udp_client_output_factory; | 343 | std::shared_ptr<OutputFactory> udp_client_output_factory; |
| 332 | std::shared_ptr<OutputFactory> tas_output_factory; | 344 | std::shared_ptr<OutputFactory> tas_output_factory; |
| 345 | std::shared_ptr<OutputFactory> camera_output_factory; | ||
| 333 | 346 | ||
| 334 | #ifdef HAVE_SDL2 | 347 | #ifdef HAVE_SDL2 |
| 335 | std::shared_ptr<SDLDriver> sdl; | 348 | std::shared_ptr<SDLDriver> sdl; |
| @@ -382,6 +395,14 @@ const TasInput::Tas* InputSubsystem::GetTas() const { | |||
| 382 | return impl->tas_input.get(); | 395 | return impl->tas_input.get(); |
| 383 | } | 396 | } |
| 384 | 397 | ||
| 398 | Camera* InputSubsystem::GetCamera() { | ||
| 399 | return impl->camera.get(); | ||
| 400 | } | ||
| 401 | |||
| 402 | const Camera* InputSubsystem::GetCamera() const { | ||
| 403 | return impl->camera.get(); | ||
| 404 | } | ||
| 405 | |||
| 385 | std::vector<Common::ParamPackage> InputSubsystem::GetInputDevices() const { | 406 | std::vector<Common::ParamPackage> InputSubsystem::GetInputDevices() const { |
| 386 | return impl->GetInputDevices(); | 407 | return impl->GetInputDevices(); |
| 387 | } | 408 | } |
diff --git a/src/input_common/main.h b/src/input_common/main.h index 147c310c4..b756bb5c6 100644 --- a/src/input_common/main.h +++ b/src/input_common/main.h | |||
| @@ -30,6 +30,7 @@ enum Values : int; | |||
| 30 | } | 30 | } |
| 31 | 31 | ||
| 32 | namespace InputCommon { | 32 | namespace InputCommon { |
| 33 | class Camera; | ||
| 33 | class Keyboard; | 34 | class Keyboard; |
| 34 | class Mouse; | 35 | class Mouse; |
| 35 | class TouchScreen; | 36 | class TouchScreen; |
| @@ -92,9 +93,15 @@ public: | |||
| 92 | /// Retrieves the underlying tas input device. | 93 | /// Retrieves the underlying tas input device. |
| 93 | [[nodiscard]] TasInput::Tas* GetTas(); | 94 | [[nodiscard]] TasInput::Tas* GetTas(); |
| 94 | 95 | ||
| 95 | /// Retrieves the underlying tas input device. | 96 | /// Retrieves the underlying tas input device. |
| 96 | [[nodiscard]] const TasInput::Tas* GetTas() const; | 97 | [[nodiscard]] const TasInput::Tas* GetTas() const; |
| 97 | 98 | ||
| 99 | /// Retrieves the underlying camera input device. | ||
| 100 | [[nodiscard]] Camera* GetCamera(); | ||
| 101 | |||
| 102 | /// Retrieves the underlying camera input device. | ||
| 103 | [[nodiscard]] const Camera* GetCamera() const; | ||
| 104 | |||
| 98 | /** | 105 | /** |
| 99 | * Returns all available input devices that this Factory can create a new device with. | 106 | * Returns all available input devices that this Factory can create a new device with. |
| 100 | * Each returned ParamPackage should have a `display` field used for display, a `engine` field | 107 | * Each returned ParamPackage should have a `display` field used for display, a `engine` field |
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 242867a4f..a11a3b908 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt | |||
| @@ -43,6 +43,9 @@ add_executable(yuzu | |||
| 43 | configuration/configure_audio.cpp | 43 | configuration/configure_audio.cpp |
| 44 | configuration/configure_audio.h | 44 | configuration/configure_audio.h |
| 45 | configuration/configure_audio.ui | 45 | configuration/configure_audio.ui |
| 46 | configuration/configure_camera.cpp | ||
| 47 | configuration/configure_camera.h | ||
| 48 | configuration/configure_camera.ui | ||
| 46 | configuration/configure_cpu.cpp | 49 | configuration/configure_cpu.cpp |
| 47 | configuration/configure_cpu.h | 50 | configuration/configure_cpu.h |
| 48 | configuration/configure_cpu.ui | 51 | configuration/configure_cpu.ui |
| @@ -254,7 +257,7 @@ endif() | |||
| 254 | create_target_directory_groups(yuzu) | 257 | create_target_directory_groups(yuzu) |
| 255 | 258 | ||
| 256 | target_link_libraries(yuzu PRIVATE common core input_common video_core) | 259 | target_link_libraries(yuzu PRIVATE common core input_common video_core) |
| 257 | target_link_libraries(yuzu PRIVATE Boost::boost glad Qt::Widgets) | 260 | target_link_libraries(yuzu PRIVATE Boost::boost glad Qt::Widgets Qt::Multimedia) |
| 258 | target_link_libraries(yuzu PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) | 261 | target_link_libraries(yuzu PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) |
| 259 | 262 | ||
| 260 | target_include_directories(yuzu PRIVATE ../../externals/Vulkan-Headers/include) | 263 | target_include_directories(yuzu PRIVATE ../../externals/Vulkan-Headers/include) |
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 01acda22b..0ee3820a2 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp | |||
| @@ -5,6 +5,8 @@ | |||
| 5 | #include <glad/glad.h> | 5 | #include <glad/glad.h> |
| 6 | 6 | ||
| 7 | #include <QApplication> | 7 | #include <QApplication> |
| 8 | #include <QCameraImageCapture> | ||
| 9 | #include <QCameraInfo> | ||
| 8 | #include <QHBoxLayout> | 10 | #include <QHBoxLayout> |
| 9 | #include <QMessageBox> | 11 | #include <QMessageBox> |
| 10 | #include <QPainter> | 12 | #include <QPainter> |
| @@ -31,6 +33,7 @@ | |||
| 31 | #include "core/core.h" | 33 | #include "core/core.h" |
| 32 | #include "core/cpu_manager.h" | 34 | #include "core/cpu_manager.h" |
| 33 | #include "core/frontend/framebuffer_layout.h" | 35 | #include "core/frontend/framebuffer_layout.h" |
| 36 | #include "input_common/drivers/camera.h" | ||
| 34 | #include "input_common/drivers/keyboard.h" | 37 | #include "input_common/drivers/keyboard.h" |
| 35 | #include "input_common/drivers/mouse.h" | 38 | #include "input_common/drivers/mouse.h" |
| 36 | #include "input_common/drivers/tas_input.h" | 39 | #include "input_common/drivers/tas_input.h" |
| @@ -801,6 +804,85 @@ void GRenderWindow::TouchEndEvent() { | |||
| 801 | input_subsystem->GetTouchScreen()->ReleaseAllTouch(); | 804 | input_subsystem->GetTouchScreen()->ReleaseAllTouch(); |
| 802 | } | 805 | } |
| 803 | 806 | ||
| 807 | void GRenderWindow::InitializeCamera() { | ||
| 808 | if (!Settings::values.enable_ir_sensor) { | ||
| 809 | return; | ||
| 810 | } | ||
| 811 | |||
| 812 | bool camera_found = false; | ||
| 813 | const QList<QCameraInfo> cameras = QCameraInfo::availableCameras(); | ||
| 814 | for (const QCameraInfo& cameraInfo : cameras) { | ||
| 815 | if (Settings::values.ir_sensor_device.GetValue() == cameraInfo.deviceName().toStdString() || | ||
| 816 | Settings::values.ir_sensor_device.GetValue() == "Auto") { | ||
| 817 | camera = std::make_unique<QCamera>(cameraInfo); | ||
| 818 | camera_found = true; | ||
| 819 | break; | ||
| 820 | } | ||
| 821 | } | ||
| 822 | |||
| 823 | if (!camera_found) { | ||
| 824 | return; | ||
| 825 | } | ||
| 826 | |||
| 827 | camera_capture = std::make_unique<QCameraImageCapture>(camera.get()); | ||
| 828 | connect(camera_capture.get(), &QCameraImageCapture::imageCaptured, this, | ||
| 829 | &GRenderWindow::OnCameraCapture); | ||
| 830 | camera->unload(); | ||
| 831 | camera->setCaptureMode(QCamera::CaptureViewfinder); | ||
| 832 | camera->load(); | ||
| 833 | camera->start(); | ||
| 834 | |||
| 835 | pending_camera_snapshots = 0; | ||
| 836 | is_virtual_camera = false; | ||
| 837 | |||
| 838 | camera_timer = std::make_unique<QTimer>(); | ||
| 839 | connect(camera_timer.get(), &QTimer::timeout, [this] { RequestCameraCapture(); }); | ||
| 840 | // This timer should be dependent of camera resolution 5ms for every 100 pixels | ||
| 841 | camera_timer->start(100); | ||
| 842 | } | ||
| 843 | |||
| 844 | void GRenderWindow::FinalizeCamera() { | ||
| 845 | if (camera_timer) { | ||
| 846 | camera_timer->stop(); | ||
| 847 | } | ||
| 848 | if (camera) { | ||
| 849 | camera->unload(); | ||
| 850 | } | ||
| 851 | } | ||
| 852 | |||
| 853 | void GRenderWindow::RequestCameraCapture() { | ||
| 854 | if (!Settings::values.enable_ir_sensor) { | ||
| 855 | return; | ||
| 856 | } | ||
| 857 | |||
| 858 | // If the camera doesn't capture, test for virtual cameras | ||
| 859 | if (pending_camera_snapshots > 5) { | ||
| 860 | is_virtual_camera = true; | ||
| 861 | } | ||
| 862 | // Virtual cameras like obs need to reset the camera every capture | ||
| 863 | if (is_virtual_camera) { | ||
| 864 | camera->stop(); | ||
| 865 | camera->start(); | ||
| 866 | } | ||
| 867 | |||
| 868 | pending_camera_snapshots++; | ||
| 869 | camera_capture->capture(); | ||
| 870 | } | ||
| 871 | |||
| 872 | void GRenderWindow::OnCameraCapture(int requestId, const QImage& img) { | ||
| 873 | constexpr std::size_t camera_width = 320; | ||
| 874 | constexpr std::size_t camera_height = 240; | ||
| 875 | const auto converted = | ||
| 876 | img.scaled(camera_width, camera_height, Qt::AspectRatioMode::IgnoreAspectRatio, | ||
| 877 | Qt::TransformationMode::SmoothTransformation) | ||
| 878 | .mirrored(false, true); | ||
| 879 | std::vector<u32> camera_data{}; | ||
| 880 | camera_data.resize(camera_width * camera_height); | ||
| 881 | std::memcpy(camera_data.data(), converted.bits(), camera_width * camera_height * sizeof(u32)); | ||
| 882 | input_subsystem->GetCamera()->SetCameraData(camera_width, camera_height, camera_data); | ||
| 883 | pending_camera_snapshots = 0; | ||
| 884 | } | ||
| 885 | |||
| 804 | bool GRenderWindow::event(QEvent* event) { | 886 | bool GRenderWindow::event(QEvent* event) { |
| 805 | if (event->type() == QEvent::TouchBegin) { | 887 | if (event->type() == QEvent::TouchBegin) { |
| 806 | TouchBeginEvent(static_cast<QTouchEvent*>(event)); | 888 | TouchBeginEvent(static_cast<QTouchEvent*>(event)); |
diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index 81fe52c0e..b4781e697 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h | |||
| @@ -20,6 +20,8 @@ | |||
| 20 | 20 | ||
| 21 | class GRenderWindow; | 21 | class GRenderWindow; |
| 22 | class GMainWindow; | 22 | class GMainWindow; |
| 23 | class QCamera; | ||
| 24 | class QCameraImageCapture; | ||
| 23 | class QKeyEvent; | 25 | class QKeyEvent; |
| 24 | 26 | ||
| 25 | namespace Core { | 27 | namespace Core { |
| @@ -164,6 +166,9 @@ public: | |||
| 164 | void mouseReleaseEvent(QMouseEvent* event) override; | 166 | void mouseReleaseEvent(QMouseEvent* event) override; |
| 165 | void wheelEvent(QWheelEvent* event) override; | 167 | void wheelEvent(QWheelEvent* event) override; |
| 166 | 168 | ||
| 169 | void InitializeCamera(); | ||
| 170 | void FinalizeCamera(); | ||
| 171 | |||
| 167 | bool event(QEvent* event) override; | 172 | bool event(QEvent* event) override; |
| 168 | 173 | ||
| 169 | void focusOutEvent(QFocusEvent* event) override; | 174 | void focusOutEvent(QFocusEvent* event) override; |
| @@ -207,6 +212,9 @@ private: | |||
| 207 | void TouchUpdateEvent(const QTouchEvent* event); | 212 | void TouchUpdateEvent(const QTouchEvent* event); |
| 208 | void TouchEndEvent(); | 213 | void TouchEndEvent(); |
| 209 | 214 | ||
| 215 | void RequestCameraCapture(); | ||
| 216 | void OnCameraCapture(int requestId, const QImage& img); | ||
| 217 | |||
| 210 | void OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal_size) override; | 218 | void OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal_size) override; |
| 211 | 219 | ||
| 212 | bool InitializeOpenGL(); | 220 | bool InitializeOpenGL(); |
| @@ -232,6 +240,12 @@ private: | |||
| 232 | bool first_frame = false; | 240 | bool first_frame = false; |
| 233 | InputCommon::TasInput::TasState last_tas_state; | 241 | InputCommon::TasInput::TasState last_tas_state; |
| 234 | 242 | ||
| 243 | bool is_virtual_camera; | ||
| 244 | int pending_camera_snapshots; | ||
| 245 | std::unique_ptr<QCamera> camera; | ||
| 246 | std::unique_ptr<QCameraImageCapture> camera_capture; | ||
| 247 | std::unique_ptr<QTimer> camera_timer; | ||
| 248 | |||
| 235 | Core::System& system; | 249 | Core::System& system; |
| 236 | 250 | ||
| 237 | protected: | 251 | protected: |
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 2840bc5eb..1f76e86b9 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp | |||
| @@ -368,6 +368,11 @@ void Config::ReadHidbusValues() { | |||
| 368 | } | 368 | } |
| 369 | } | 369 | } |
| 370 | 370 | ||
| 371 | void Config::ReadIrCameraValues() { | ||
| 372 | ReadBasicSetting(Settings::values.enable_ir_sensor); | ||
| 373 | ReadBasicSetting(Settings::values.ir_sensor_device); | ||
| 374 | } | ||
| 375 | |||
| 371 | void Config::ReadAudioValues() { | 376 | void Config::ReadAudioValues() { |
| 372 | qt_config->beginGroup(QStringLiteral("Audio")); | 377 | qt_config->beginGroup(QStringLiteral("Audio")); |
| 373 | 378 | ||
| @@ -393,6 +398,7 @@ void Config::ReadControlValues() { | |||
| 393 | ReadTouchscreenValues(); | 398 | ReadTouchscreenValues(); |
| 394 | ReadMotionTouchValues(); | 399 | ReadMotionTouchValues(); |
| 395 | ReadHidbusValues(); | 400 | ReadHidbusValues(); |
| 401 | ReadIrCameraValues(); | ||
| 396 | 402 | ||
| 397 | #ifdef _WIN32 | 403 | #ifdef _WIN32 |
| 398 | ReadBasicSetting(Settings::values.enable_raw_input); | 404 | ReadBasicSetting(Settings::values.enable_raw_input); |
| @@ -1005,6 +1011,11 @@ void Config::SaveHidbusValues() { | |||
| 1005 | QString::fromStdString(default_param)); | 1011 | QString::fromStdString(default_param)); |
| 1006 | } | 1012 | } |
| 1007 | 1013 | ||
| 1014 | void Config::SaveIrCameraValues() { | ||
| 1015 | WriteBasicSetting(Settings::values.enable_ir_sensor); | ||
| 1016 | WriteBasicSetting(Settings::values.ir_sensor_device); | ||
| 1017 | } | ||
| 1018 | |||
| 1008 | void Config::SaveValues() { | 1019 | void Config::SaveValues() { |
| 1009 | if (global) { | 1020 | if (global) { |
| 1010 | SaveControlValues(); | 1021 | SaveControlValues(); |
| @@ -1047,6 +1058,7 @@ void Config::SaveControlValues() { | |||
| 1047 | SaveTouchscreenValues(); | 1058 | SaveTouchscreenValues(); |
| 1048 | SaveMotionTouchValues(); | 1059 | SaveMotionTouchValues(); |
| 1049 | SaveHidbusValues(); | 1060 | SaveHidbusValues(); |
| 1061 | SaveIrCameraValues(); | ||
| 1050 | 1062 | ||
| 1051 | WriteGlobalSetting(Settings::values.use_docked_mode); | 1063 | WriteGlobalSetting(Settings::values.use_docked_mode); |
| 1052 | WriteGlobalSetting(Settings::values.vibration_enabled); | 1064 | WriteGlobalSetting(Settings::values.vibration_enabled); |
diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h index d511b3dbd..a71eabe8e 100644 --- a/src/yuzu/configuration/config.h +++ b/src/yuzu/configuration/config.h | |||
| @@ -68,6 +68,7 @@ private: | |||
| 68 | void ReadTouchscreenValues(); | 68 | void ReadTouchscreenValues(); |
| 69 | void ReadMotionTouchValues(); | 69 | void ReadMotionTouchValues(); |
| 70 | void ReadHidbusValues(); | 70 | void ReadHidbusValues(); |
| 71 | void ReadIrCameraValues(); | ||
| 71 | 72 | ||
| 72 | // Read functions bases off the respective config section names. | 73 | // Read functions bases off the respective config section names. |
| 73 | void ReadAudioValues(); | 74 | void ReadAudioValues(); |
| @@ -96,6 +97,7 @@ private: | |||
| 96 | void SaveTouchscreenValues(); | 97 | void SaveTouchscreenValues(); |
| 97 | void SaveMotionTouchValues(); | 98 | void SaveMotionTouchValues(); |
| 98 | void SaveHidbusValues(); | 99 | void SaveHidbusValues(); |
| 100 | void SaveIrCameraValues(); | ||
| 99 | 101 | ||
| 100 | // Save functions based off the respective config section names. | 102 | // Save functions based off the respective config section names. |
| 101 | void SaveAudioValues(); | 103 | void SaveAudioValues(); |
diff --git a/src/yuzu/configuration/configure_camera.cpp b/src/yuzu/configuration/configure_camera.cpp new file mode 100644 index 000000000..73cdcf3f2 --- /dev/null +++ b/src/yuzu/configuration/configure_camera.cpp | |||
| @@ -0,0 +1,138 @@ | |||
| 1 | // Text : Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #include <memory> | ||
| 5 | #include <QCameraImageCapture> | ||
| 6 | #include <QCameraInfo> | ||
| 7 | #include <QStandardItemModel> | ||
| 8 | #include <QTimer> | ||
| 9 | |||
| 10 | #include "input_common/drivers/camera.h" | ||
| 11 | #include "input_common/main.h" | ||
| 12 | #include "ui_configure_camera.h" | ||
| 13 | #include "yuzu/configuration/config.h" | ||
| 14 | #include "yuzu/configuration/configure_camera.h" | ||
| 15 | |||
| 16 | ConfigureCamera::ConfigureCamera(QWidget* parent, InputCommon::InputSubsystem* input_subsystem_) | ||
| 17 | : QDialog(parent), input_subsystem{input_subsystem_}, | ||
| 18 | ui(std::make_unique<Ui::ConfigureCamera>()) { | ||
| 19 | ui->setupUi(this); | ||
| 20 | |||
| 21 | connect(ui->restore_defaults_button, &QPushButton::clicked, this, | ||
| 22 | &ConfigureCamera::RestoreDefaults); | ||
| 23 | connect(ui->preview_button, &QPushButton::clicked, this, &ConfigureCamera::PreviewCamera); | ||
| 24 | |||
| 25 | auto blank_image = QImage(320, 240, QImage::Format::Format_RGB32); | ||
| 26 | blank_image.fill(Qt::black); | ||
| 27 | DisplayCapturedFrame(0, blank_image); | ||
| 28 | |||
| 29 | LoadConfiguration(); | ||
| 30 | resize(0, 0); | ||
| 31 | } | ||
| 32 | |||
| 33 | ConfigureCamera::~ConfigureCamera() = default; | ||
| 34 | |||
| 35 | void ConfigureCamera::PreviewCamera() { | ||
| 36 | const auto index = ui->ir_sensor_combo_box->currentIndex(); | ||
| 37 | bool camera_found = false; | ||
| 38 | const QList<QCameraInfo> cameras = QCameraInfo::availableCameras(); | ||
| 39 | for (const QCameraInfo& cameraInfo : cameras) { | ||
| 40 | if (input_devices[index] == cameraInfo.deviceName().toStdString() || | ||
| 41 | input_devices[index] == "Auto") { | ||
| 42 | LOG_INFO(Frontend, "Selected Camera {} {}", cameraInfo.description().toStdString(), | ||
| 43 | cameraInfo.deviceName().toStdString()); | ||
| 44 | camera = std::make_unique<QCamera>(cameraInfo); | ||
| 45 | camera_found = true; | ||
| 46 | break; | ||
| 47 | } | ||
| 48 | } | ||
| 49 | |||
| 50 | // Clear previous frame | ||
| 51 | auto blank_image = QImage(320, 240, QImage::Format::Format_RGB32); | ||
| 52 | blank_image.fill(Qt::black); | ||
| 53 | DisplayCapturedFrame(0, blank_image); | ||
| 54 | |||
| 55 | if (!camera_found) { | ||
| 56 | return; | ||
| 57 | } | ||
| 58 | |||
| 59 | camera_capture = std::make_unique<QCameraImageCapture>(camera.get()); | ||
| 60 | connect(camera_capture.get(), &QCameraImageCapture::imageCaptured, this, | ||
| 61 | &ConfigureCamera::DisplayCapturedFrame); | ||
| 62 | camera->unload(); | ||
| 63 | camera->setCaptureMode(QCamera::CaptureViewfinder); | ||
| 64 | camera->load(); | ||
| 65 | camera->start(); | ||
| 66 | |||
| 67 | pending_snapshots = 0; | ||
| 68 | is_virtual_camera = false; | ||
| 69 | |||
| 70 | camera_timer = std::make_unique<QTimer>(); | ||
| 71 | connect(camera_timer.get(), &QTimer::timeout, [this] { | ||
| 72 | // If the camera doesn't capture, test for virtual cameras | ||
| 73 | if (pending_snapshots > 5) { | ||
| 74 | is_virtual_camera = true; | ||
| 75 | } | ||
| 76 | // Virtual cameras like obs need to reset the camera every capture | ||
| 77 | if (is_virtual_camera) { | ||
| 78 | camera->stop(); | ||
| 79 | camera->start(); | ||
| 80 | } | ||
| 81 | pending_snapshots++; | ||
| 82 | camera_capture->capture(); | ||
| 83 | }); | ||
| 84 | |||
| 85 | camera_timer->start(250); | ||
| 86 | } | ||
| 87 | |||
| 88 | void ConfigureCamera::DisplayCapturedFrame(int requestId, const QImage& img) { | ||
| 89 | LOG_INFO(Frontend, "ImageCaptured {} {}", img.width(), img.height()); | ||
| 90 | const auto converted = img.scaled(320, 240, Qt::AspectRatioMode::IgnoreAspectRatio, | ||
| 91 | Qt::TransformationMode::SmoothTransformation); | ||
| 92 | ui->preview_box->setPixmap(QPixmap::fromImage(converted)); | ||
| 93 | pending_snapshots = 0; | ||
| 94 | } | ||
| 95 | |||
| 96 | void ConfigureCamera::changeEvent(QEvent* event) { | ||
| 97 | if (event->type() == QEvent::LanguageChange) { | ||
| 98 | RetranslateUI(); | ||
| 99 | } | ||
| 100 | |||
| 101 | QDialog::changeEvent(event); | ||
| 102 | } | ||
| 103 | |||
| 104 | void ConfigureCamera::RetranslateUI() { | ||
| 105 | ui->retranslateUi(this); | ||
| 106 | } | ||
| 107 | |||
| 108 | void ConfigureCamera::ApplyConfiguration() { | ||
| 109 | const auto index = ui->ir_sensor_combo_box->currentIndex(); | ||
| 110 | Settings::values.ir_sensor_device.SetValue(input_devices[index]); | ||
| 111 | } | ||
| 112 | |||
| 113 | void ConfigureCamera::LoadConfiguration() { | ||
| 114 | input_devices.clear(); | ||
| 115 | ui->ir_sensor_combo_box->clear(); | ||
| 116 | input_devices.push_back("Auto"); | ||
| 117 | ui->ir_sensor_combo_box->addItem(tr("Auto")); | ||
| 118 | const auto cameras = QCameraInfo::availableCameras(); | ||
| 119 | for (const QCameraInfo& cameraInfo : cameras) { | ||
| 120 | input_devices.push_back(cameraInfo.deviceName().toStdString()); | ||
| 121 | ui->ir_sensor_combo_box->addItem(cameraInfo.description()); | ||
| 122 | } | ||
| 123 | |||
| 124 | const auto current_device = Settings::values.ir_sensor_device.GetValue(); | ||
| 125 | |||
| 126 | const auto devices_it = std::find_if( | ||
| 127 | input_devices.begin(), input_devices.end(), | ||
| 128 | [current_device](const std::string& device) { return device == current_device; }); | ||
| 129 | const int device_index = | ||
| 130 | devices_it != input_devices.end() | ||
| 131 | ? static_cast<int>(std::distance(input_devices.begin(), devices_it)) | ||
| 132 | : 0; | ||
| 133 | ui->ir_sensor_combo_box->setCurrentIndex(device_index); | ||
| 134 | } | ||
| 135 | |||
| 136 | void ConfigureCamera::RestoreDefaults() { | ||
| 137 | ui->ir_sensor_combo_box->setCurrentIndex(0); | ||
| 138 | } | ||
diff --git a/src/yuzu/configuration/configure_camera.h b/src/yuzu/configuration/configure_camera.h new file mode 100644 index 000000000..db9833b5c --- /dev/null +++ b/src/yuzu/configuration/configure_camera.h | |||
| @@ -0,0 +1,54 @@ | |||
| 1 | // Text : Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <memory> | ||
| 7 | #include <QDialog> | ||
| 8 | |||
| 9 | class QTimer; | ||
| 10 | class QCamera; | ||
| 11 | class QCameraImageCapture; | ||
| 12 | |||
| 13 | namespace InputCommon { | ||
| 14 | class InputSubsystem; | ||
| 15 | } // namespace InputCommon | ||
| 16 | |||
| 17 | namespace Ui { | ||
| 18 | class ConfigureCamera; | ||
| 19 | } | ||
| 20 | |||
| 21 | class ConfigureCamera : public QDialog { | ||
| 22 | Q_OBJECT | ||
| 23 | |||
| 24 | public: | ||
| 25 | explicit ConfigureCamera(QWidget* parent, InputCommon::InputSubsystem* input_subsystem_); | ||
| 26 | ~ConfigureCamera() override; | ||
| 27 | |||
| 28 | void ApplyConfiguration(); | ||
| 29 | |||
| 30 | private: | ||
| 31 | void changeEvent(QEvent* event) override; | ||
| 32 | void RetranslateUI(); | ||
| 33 | |||
| 34 | /// Load configuration settings. | ||
| 35 | void LoadConfiguration(); | ||
| 36 | |||
| 37 | /// Restore all buttons to their default values. | ||
| 38 | void RestoreDefaults(); | ||
| 39 | |||
| 40 | void DisplayCapturedFrame(int requestId, const QImage& img); | ||
| 41 | |||
| 42 | /// Loads and signals the current selected camera to display a frame | ||
| 43 | void PreviewCamera(); | ||
| 44 | |||
| 45 | InputCommon::InputSubsystem* input_subsystem; | ||
| 46 | |||
| 47 | bool is_virtual_camera; | ||
| 48 | int pending_snapshots; | ||
| 49 | std::unique_ptr<QCamera> camera; | ||
| 50 | std::unique_ptr<QCameraImageCapture> camera_capture; | ||
| 51 | std::unique_ptr<QTimer> camera_timer; | ||
| 52 | std::vector<std::string> input_devices; | ||
| 53 | std::unique_ptr<Ui::ConfigureCamera> ui; | ||
| 54 | }; | ||
diff --git a/src/yuzu/configuration/configure_camera.ui b/src/yuzu/configuration/configure_camera.ui new file mode 100644 index 000000000..976a9b1ec --- /dev/null +++ b/src/yuzu/configuration/configure_camera.ui | |||
| @@ -0,0 +1,170 @@ | |||
| 1 | <?xml version="1.0" encoding="UTF-8"?> | ||
| 2 | <ui version="4.0"> | ||
| 3 | <class>ConfigureCamera</class> | ||
| 4 | <widget class="QDialog" name="ConfigureCamera"> | ||
| 5 | <property name="geometry"> | ||
| 6 | <rect> | ||
| 7 | <x>0</x> | ||
| 8 | <y>0</y> | ||
| 9 | <width>298</width> | ||
| 10 | <height>339</height> | ||
| 11 | </rect> | ||
| 12 | </property> | ||
| 13 | <property name="windowTitle"> | ||
| 14 | <string>Configure Infrared Camera</string> | ||
| 15 | </property> | ||
| 16 | <layout class="QVBoxLayout" name="verticalLayout"> | ||
| 17 | <item> | ||
| 18 | <widget class="QLabel" name="label_2"> | ||
| 19 | <property name="minimumSize"> | ||
| 20 | <size> | ||
| 21 | <width>280</width> | ||
| 22 | <height>0</height> | ||
| 23 | </size> | ||
| 24 | </property> | ||
| 25 | <property name="text"> | ||
| 26 | <string>Select where the image of the emulated camera comes from. It may be a virtual camera or a real camera.</string> | ||
| 27 | </property> | ||
| 28 | <property name="wordWrap"> | ||
| 29 | <bool>true</bool> | ||
| 30 | </property> | ||
| 31 | </widget> | ||
| 32 | </item> | ||
| 33 | <item> | ||
| 34 | <spacer name="verticalSpacer_2"> | ||
| 35 | <property name="orientation"> | ||
| 36 | <enum>Qt::Vertical</enum> | ||
| 37 | </property> | ||
| 38 | <property name="sizeType"> | ||
| 39 | <enum>QSizePolicy::Fixed</enum> | ||
| 40 | </property> | ||
| 41 | <property name="sizeHint" stdset="0"> | ||
| 42 | <size> | ||
| 43 | <width>20</width> | ||
| 44 | <height>20</height> | ||
| 45 | </size> | ||
| 46 | </property> | ||
| 47 | </spacer> | ||
| 48 | </item> | ||
| 49 | <item> | ||
| 50 | <widget class="QGroupBox" name="gridGroupBox"> | ||
| 51 | <property name="title"> | ||
| 52 | <string>Camera Image Source:</string> | ||
| 53 | </property> | ||
| 54 | <layout class="QGridLayout" name="gridLayout"> | ||
| 55 | <item row="0" column="0"> | ||
| 56 | <spacer name="horizontalSpacer"> | ||
| 57 | <property name="orientation"> | ||
| 58 | <enum>Qt::Horizontal</enum> | ||
| 59 | </property> | ||
| 60 | <property name="sizeHint" stdset="0"> | ||
| 61 | <size> | ||
| 62 | <width>40</width> | ||
| 63 | <height>20</height> | ||
| 64 | </size> | ||
| 65 | </property> | ||
| 66 | </spacer> | ||
| 67 | </item> | ||
| 68 | <item row="0" column="1"> | ||
| 69 | <widget class="QLabel" name="label_3"> | ||
| 70 | <property name="text"> | ||
| 71 | <string>Input device:</string> | ||
| 72 | </property> | ||
| 73 | </widget> | ||
| 74 | </item> | ||
| 75 | <item row="0" column="2"> | ||
| 76 | <widget class="QComboBox" name="ir_sensor_combo_box"/> | ||
| 77 | </item> | ||
| 78 | <item row="0" column="3"> | ||
| 79 | <spacer name="horizontalSpacer_2"> | ||
| 80 | <property name="orientation"> | ||
| 81 | <enum>Qt::Horizontal</enum> | ||
| 82 | </property> | ||
| 83 | <property name="sizeHint" stdset="0"> | ||
| 84 | <size> | ||
| 85 | <width>40</width> | ||
| 86 | <height>20</height> | ||
| 87 | </size> | ||
| 88 | </property> | ||
| 89 | </spacer> | ||
| 90 | </item> | ||
| 91 | </layout> | ||
| 92 | </widget> | ||
| 93 | </item><item> | ||
| 94 | <widget class="QGroupBox" name="previewBox"> | ||
| 95 | <property name="title"> | ||
| 96 | <string>Preview</string> | ||
| 97 | </property> | ||
| 98 | <layout class="QVBoxLayout" name="verticalLayout_3"> | ||
| 99 | <item> | ||
| 100 | <widget class="QLabel" name="preview_box"> | ||
| 101 | <property name="minimumSize"> | ||
| 102 | <size> | ||
| 103 | <width>320</width> | ||
| 104 | <height>240</height> | ||
| 105 | </size> | ||
| 106 | </property> | ||
| 107 | <property name="toolTip"> | ||
| 108 | <string>Resolution: 320*240</string> | ||
| 109 | </property> | ||
| 110 | </widget> | ||
| 111 | </item> | ||
| 112 | <item> | ||
| 113 | <widget class="QPushButton" name="preview_button"> | ||
| 114 | <property name="text"> | ||
| 115 | <string>Click to preview</string> | ||
| 116 | </property> | ||
| 117 | </widget> | ||
| 118 | </item> | ||
| 119 | </layout> | ||
| 120 | </widget> | ||
| 121 | </item> | ||
| 122 | <item> | ||
| 123 | <spacer name="verticalSpacer"> | ||
| 124 | <property name="orientation"> | ||
| 125 | <enum>Qt::Vertical</enum> | ||
| 126 | </property> | ||
| 127 | <property name="sizeHint" stdset="0"> | ||
| 128 | <size> | ||
| 129 | <width>20</width> | ||
| 130 | <height>40</height> | ||
| 131 | </size> | ||
| 132 | </property> | ||
| 133 | </spacer> | ||
| 134 | </item> | ||
| 135 | <item> | ||
| 136 | <layout class="QHBoxLayout" name="horizontalLayout"> | ||
| 137 | <item> | ||
| 138 | <widget class="QPushButton" name="restore_defaults_button"> | ||
| 139 | <property name="text"> | ||
| 140 | <string>Restore Defaults</string> | ||
| 141 | </property> | ||
| 142 | </widget> | ||
| 143 | </item> | ||
| 144 | <item> | ||
| 145 | <widget class="QDialogButtonBox" name="buttonBox"> | ||
| 146 | <property name="standardButtons"> | ||
| 147 | <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> | ||
| 148 | </property> | ||
| 149 | </widget> | ||
| 150 | </item> | ||
| 151 | </layout> | ||
| 152 | </item> | ||
| 153 | </layout> | ||
| 154 | </widget> | ||
| 155 | <resources/> | ||
| 156 | <connections> | ||
| 157 | <connection> | ||
| 158 | <sender>buttonBox</sender> | ||
| 159 | <signal>accepted()</signal> | ||
| 160 | <receiver>ConfigureCamera</receiver> | ||
| 161 | <slot>accept()</slot> | ||
| 162 | </connection> | ||
| 163 | <connection> | ||
| 164 | <sender>buttonBox</sender> | ||
| 165 | <signal>rejected()</signal> | ||
| 166 | <receiver>ConfigureCamera</receiver> | ||
| 167 | <slot>reject()</slot> | ||
| 168 | </connection> | ||
| 169 | </connections> | ||
| 170 | </ui> | ||
diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp index 73d7ba24b..f1b061b13 100644 --- a/src/yuzu/configuration/configure_input.cpp +++ b/src/yuzu/configuration/configure_input.cpp | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include "ui_configure_input.h" | 15 | #include "ui_configure_input.h" |
| 16 | #include "ui_configure_input_advanced.h" | 16 | #include "ui_configure_input_advanced.h" |
| 17 | #include "ui_configure_input_player.h" | 17 | #include "ui_configure_input_player.h" |
| 18 | #include "yuzu/configuration/configure_camera.h" | ||
| 18 | #include "yuzu/configuration/configure_debug_controller.h" | 19 | #include "yuzu/configuration/configure_debug_controller.h" |
| 19 | #include "yuzu/configuration/configure_input.h" | 20 | #include "yuzu/configuration/configure_input.h" |
| 20 | #include "yuzu/configuration/configure_input_advanced.h" | 21 | #include "yuzu/configuration/configure_input_advanced.h" |
| @@ -163,6 +164,10 @@ void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem, | |||
| 163 | [this, input_subsystem, &hid_core] { | 164 | [this, input_subsystem, &hid_core] { |
| 164 | CallConfigureDialog<ConfigureRingController>(*this, input_subsystem, hid_core); | 165 | CallConfigureDialog<ConfigureRingController>(*this, input_subsystem, hid_core); |
| 165 | }); | 166 | }); |
| 167 | connect(advanced, &ConfigureInputAdvanced::CallCameraDialog, | ||
| 168 | [this, input_subsystem, &hid_core] { | ||
| 169 | CallConfigureDialog<ConfigureCamera>(*this, input_subsystem); | ||
| 170 | }); | ||
| 166 | 171 | ||
| 167 | connect(ui->vibrationButton, &QPushButton::clicked, | 172 | connect(ui->vibrationButton, &QPushButton::clicked, |
| 168 | [this, &hid_core] { CallConfigureDialog<ConfigureVibration>(*this, hid_core); }); | 173 | [this, &hid_core] { CallConfigureDialog<ConfigureVibration>(*this, hid_core); }); |
diff --git a/src/yuzu/configuration/configure_input_advanced.cpp b/src/yuzu/configuration/configure_input_advanced.cpp index f14bdc831..10f841b98 100644 --- a/src/yuzu/configuration/configure_input_advanced.cpp +++ b/src/yuzu/configuration/configure_input_advanced.cpp | |||
| @@ -89,6 +89,7 @@ ConfigureInputAdvanced::ConfigureInputAdvanced(QWidget* parent) | |||
| 89 | [this] { CallMotionTouchConfigDialog(); }); | 89 | [this] { CallMotionTouchConfigDialog(); }); |
| 90 | connect(ui->ring_controller_configure, &QPushButton::clicked, this, | 90 | connect(ui->ring_controller_configure, &QPushButton::clicked, this, |
| 91 | [this] { CallRingControllerDialog(); }); | 91 | [this] { CallRingControllerDialog(); }); |
| 92 | connect(ui->camera_configure, &QPushButton::clicked, this, [this] { CallCameraDialog(); }); | ||
| 92 | 93 | ||
| 93 | #ifndef _WIN32 | 94 | #ifndef _WIN32 |
| 94 | ui->enable_raw_input->setVisible(false); | 95 | ui->enable_raw_input->setVisible(false); |
| @@ -136,6 +137,7 @@ void ConfigureInputAdvanced::ApplyConfiguration() { | |||
| 136 | Settings::values.enable_udp_controller = ui->enable_udp_controller->isChecked(); | 137 | Settings::values.enable_udp_controller = ui->enable_udp_controller->isChecked(); |
| 137 | Settings::values.controller_navigation = ui->controller_navigation->isChecked(); | 138 | Settings::values.controller_navigation = ui->controller_navigation->isChecked(); |
| 138 | Settings::values.enable_ring_controller = ui->enable_ring_controller->isChecked(); | 139 | Settings::values.enable_ring_controller = ui->enable_ring_controller->isChecked(); |
| 140 | Settings::values.enable_ir_sensor = ui->enable_ir_sensor->isChecked(); | ||
| 139 | } | 141 | } |
| 140 | 142 | ||
| 141 | void ConfigureInputAdvanced::LoadConfiguration() { | 143 | void ConfigureInputAdvanced::LoadConfiguration() { |
| @@ -169,6 +171,7 @@ void ConfigureInputAdvanced::LoadConfiguration() { | |||
| 169 | ui->enable_udp_controller->setChecked(Settings::values.enable_udp_controller.GetValue()); | 171 | ui->enable_udp_controller->setChecked(Settings::values.enable_udp_controller.GetValue()); |
| 170 | ui->controller_navigation->setChecked(Settings::values.controller_navigation.GetValue()); | 172 | ui->controller_navigation->setChecked(Settings::values.controller_navigation.GetValue()); |
| 171 | ui->enable_ring_controller->setChecked(Settings::values.enable_ring_controller.GetValue()); | 173 | ui->enable_ring_controller->setChecked(Settings::values.enable_ring_controller.GetValue()); |
| 174 | ui->enable_ir_sensor->setChecked(Settings::values.enable_ir_sensor.GetValue()); | ||
| 172 | 175 | ||
| 173 | UpdateUIEnabled(); | 176 | UpdateUIEnabled(); |
| 174 | } | 177 | } |
diff --git a/src/yuzu/configuration/configure_input_advanced.h b/src/yuzu/configuration/configure_input_advanced.h index 644e56dd8..fc1230284 100644 --- a/src/yuzu/configuration/configure_input_advanced.h +++ b/src/yuzu/configuration/configure_input_advanced.h | |||
| @@ -29,6 +29,7 @@ signals: | |||
| 29 | void CallTouchscreenConfigDialog(); | 29 | void CallTouchscreenConfigDialog(); |
| 30 | void CallMotionTouchConfigDialog(); | 30 | void CallMotionTouchConfigDialog(); |
| 31 | void CallRingControllerDialog(); | 31 | void CallRingControllerDialog(); |
| 32 | void CallCameraDialog(); | ||
| 32 | 33 | ||
| 33 | private: | 34 | private: |
| 34 | void changeEvent(QEvent* event) override; | 35 | void changeEvent(QEvent* event) override; |
diff --git a/src/yuzu/configuration/configure_input_advanced.ui b/src/yuzu/configuration/configure_input_advanced.ui index 14403cb10..fac8cf827 100644 --- a/src/yuzu/configuration/configure_input_advanced.ui +++ b/src/yuzu/configuration/configure_input_advanced.ui | |||
| @@ -2617,6 +2617,20 @@ | |||
| 2617 | </property> | 2617 | </property> |
| 2618 | </widget> | 2618 | </widget> |
| 2619 | </item> | 2619 | </item> |
| 2620 | <item row="5" column="0"> | ||
| 2621 | <widget class="QCheckBox" name="enable_ir_sensor"> | ||
| 2622 | <property name="text"> | ||
| 2623 | <string>Infrared Camera</string> | ||
| 2624 | </property> | ||
| 2625 | </widget> | ||
| 2626 | </item> | ||
| 2627 | <item row="5" column="2"> | ||
| 2628 | <widget class="QPushButton" name="camera_configure"> | ||
| 2629 | <property name="text"> | ||
| 2630 | <string>Configure</string> | ||
| 2631 | </property> | ||
| 2632 | </widget> | ||
| 2633 | </item> | ||
| 2620 | </layout> | 2634 | </layout> |
| 2621 | </widget> | 2635 | </widget> |
| 2622 | </item> | 2636 | </item> |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index a120f2662..08ccc1555 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -1542,6 +1542,8 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t | |||
| 1542 | mouse_hide_timer.start(); | 1542 | mouse_hide_timer.start(); |
| 1543 | } | 1543 | } |
| 1544 | 1544 | ||
| 1545 | render_window->InitializeCamera(); | ||
| 1546 | |||
| 1545 | std::string title_name; | 1547 | std::string title_name; |
| 1546 | std::string title_version; | 1548 | std::string title_version; |
| 1547 | const auto res = system->GetGameName(title_name); | 1549 | const auto res = system->GetGameName(title_name); |
| @@ -1623,6 +1625,7 @@ void GMainWindow::ShutdownGame() { | |||
| 1623 | tas_label->clear(); | 1625 | tas_label->clear(); |
| 1624 | input_subsystem->GetTas()->Stop(); | 1626 | input_subsystem->GetTas()->Stop(); |
| 1625 | OnTasStateChanged(); | 1627 | OnTasStateChanged(); |
| 1628 | render_window->FinalizeCamera(); | ||
| 1626 | 1629 | ||
| 1627 | // Enable all controllers | 1630 | // Enable all controllers |
| 1628 | system->HIDCore().SetSupportedStyleTag({Core::HID::NpadStyleSet::All}); | 1631 | system->HIDCore().SetSupportedStyleTag({Core::HID::NpadStyleSet::All}); |
| @@ -2862,6 +2865,12 @@ void GMainWindow::OnConfigure() { | |||
| 2862 | mouse_hide_timer.start(); | 2865 | mouse_hide_timer.start(); |
| 2863 | } | 2866 | } |
| 2864 | 2867 | ||
| 2868 | // Restart camera config | ||
| 2869 | if (emulation_running) { | ||
| 2870 | render_window->FinalizeCamera(); | ||
| 2871 | render_window->InitializeCamera(); | ||
| 2872 | } | ||
| 2873 | |||
| 2865 | if (!UISettings::values.has_broken_vulkan) { | 2874 | if (!UISettings::values.has_broken_vulkan) { |
| 2866 | renderer_status_button->setEnabled(!emulation_running); | 2875 | renderer_status_button->setEnabled(!emulation_running); |
| 2867 | } | 2876 | } |