From f19e7be6e84357234c9fdae3395f988a9bb1ac5b Mon Sep 17 00:00:00 2001 From: german77 Date: Sat, 18 Jun 2022 23:32:07 -0500 Subject: [PATCH 1/6] input_common: Add camera driver --- src/common/input.h | 29 +++++++++- src/common/settings.h | 3 ++ src/input_common/CMakeLists.txt | 2 + src/input_common/drivers/camera.cpp | 82 +++++++++++++++++++++++++++++ src/input_common/drivers/camera.h | 29 ++++++++++ src/input_common/input_engine.cpp | 38 +++++++++++++ src/input_common/input_engine.h | 21 ++++++-- src/input_common/input_poller.cpp | 60 +++++++++++++++++++++ src/input_common/input_poller.h | 11 ++++ src/input_common/main.cpp | 21 ++++++++ src/input_common/main.h | 9 +++- 11 files changed, 299 insertions(+), 6 deletions(-) create mode 100644 src/input_common/drivers/camera.cpp create mode 100644 src/input_common/drivers/camera.h 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 { Color, Vibration, Nfc, - Ir, + IrSensor, }; // Internal battery charge level @@ -53,6 +53,15 @@ enum class PollingMode { IR, }; +enum class CameraFormat { + Size320x240, + Size160x120, + Size80x60, + Size40x30, + Size20x15, + None, +}; + // Vibration reply from the controller enum class VibrationError { None, @@ -68,6 +77,13 @@ enum class PollingError { Unknown, }; +// Ir camera reply from the controller +enum class CameraError { + None, + NotSupported, + Unknown, +}; + // Hint for amplification curve to be used enum class VibrationAmplificationType { Linear, @@ -176,6 +192,12 @@ struct LedStatus { bool led_4{}; }; +// Raw data fom camera +struct CameraStatus { + CameraFormat format{CameraFormat::None}; + std::vector data{}; +}; + // List of buttons to be passed to Qt that can be translated enum class ButtonNames { Undefined, @@ -233,6 +255,7 @@ struct CallbackStatus { BodyColorStatus color_status{}; BatteryStatus battery_status{}; VibrationStatus vibration_status{}; + CameraStatus camera_status{}; }; // Triggered once every input change @@ -281,6 +304,10 @@ public: virtual PollingError SetPollingMode([[maybe_unused]] PollingMode polling_mode) { return PollingError::NotSupported; } + + virtual CameraError SetCameraFormat([[maybe_unused]] CameraFormat camera_format) { + return CameraError::NotSupported; + } }; /// 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..20959ec89 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -503,6 +503,9 @@ struct Values { Setting enable_ring_controller{true, "enable_ring_controller"}; RingconRaw ringcon_analogs; + BasicSetting enable_ir_sensor{false, "enable_ir_sensor"}; + BasicSetting ir_sensor_device{"auto", "ir_sensor_device"}; + // Data Storage Setting use_virtual_sd{true, "use_virtual_sd"}; Setting gamecard_inserted{false, "gamecard_inserted"}; 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 @@ add_library(input_common STATIC + drivers/camera.cpp + drivers/camera.h drivers/gc_adapter.cpp drivers/gc_adapter.h 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 @@ +// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include + +#include "common/param_package.h" +#include "input_common/drivers/camera.h" + +namespace InputCommon { +constexpr PadIdentifier identifier = { + .guid = Common::UUID{}, + .port = 0, + .pad = 0, +}; + +Camera::Camera(std::string input_engine_) : InputEngine(std::move(input_engine_)) { + PreSetController(identifier); +} + +void Camera::SetCameraData(std::size_t width, std::size_t height, std::vector data) { + const std::size_t desired_width = getImageWidth(); + const std::size_t desired_height = getImageHeight(); + status.data.resize(desired_width * desired_height); + + // Resize image to desired format + for (std::size_t y = 0; y < desired_height; y++) { + for (std::size_t x = 0; x < desired_width; x++) { + const std::size_t pixel_index = y * desired_width + x; + const std::size_t old_x = width * x / desired_width; + const std::size_t old_y = height * y / desired_height; + const std::size_t data_pixel_index = old_y * width + old_x; + status.data[pixel_index] = static_cast(data[data_pixel_index] & 0xFF); + } + } + + SetCamera(identifier, status); +} + +std::size_t Camera::getImageWidth() const { + switch (status.format) { + case Common::Input::CameraFormat::Size320x240: + return 320; + case Common::Input::CameraFormat::Size160x120: + return 160; + case Common::Input::CameraFormat::Size80x60: + return 80; + case Common::Input::CameraFormat::Size40x30: + return 40; + case Common::Input::CameraFormat::Size20x15: + return 20; + case Common::Input::CameraFormat::None: + default: + return 0; + } +} + +std::size_t Camera::getImageHeight() const { + switch (status.format) { + case Common::Input::CameraFormat::Size320x240: + return 240; + case Common::Input::CameraFormat::Size160x120: + return 120; + case Common::Input::CameraFormat::Size80x60: + return 60; + case Common::Input::CameraFormat::Size40x30: + return 30; + case Common::Input::CameraFormat::Size20x15: + return 15; + case Common::Input::CameraFormat::None: + default: + return 0; + } +} + +Common::Input::CameraError Camera::SetCameraFormat( + [[maybe_unused]] const PadIdentifier& identifier_, + const Common::Input::CameraFormat camera_format) { + status.format = camera_format; + return Common::Input::CameraError::None; +} + +} // 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 @@ +// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "input_common/input_engine.h" + +namespace InputCommon { + +/** + * A button device factory representing a keyboard. It receives keyboard events and forward them + * to all button devices it created. + */ +class Camera final : public InputEngine { +public: + explicit Camera(std::string input_engine_); + + void SetCameraData(std::size_t width, std::size_t height, std::vector data); + + std::size_t getImageWidth() const; + std::size_t getImageHeight() const; + + Common::Input::CameraError SetCameraFormat(const PadIdentifier& identifier_, + Common::Input::CameraFormat camera_format) override; + + Common::Input::CameraStatus status{}; +}; + +} // 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 TriggerOnMotionChange(identifier, motion, value); } +void InputEngine::SetCamera(const PadIdentifier& identifier, + const Common::Input::CameraStatus& value) { + { + std::scoped_lock lock{mutex}; + ControllerData& controller = controller_list.at(identifier); + if (!configuring) { + controller.camera = value; + } + } + TriggerOnCameraChange(identifier, value); +} + bool InputEngine::GetButton(const PadIdentifier& identifier, int button) const { std::scoped_lock lock{mutex}; const auto controller_iter = controller_list.find(identifier); @@ -165,6 +177,18 @@ BasicMotion InputEngine::GetMotion(const PadIdentifier& identifier, int motion) return controller.motions.at(motion); } +Common::Input::CameraStatus InputEngine::GetCamera(const PadIdentifier& identifier) const { + std::scoped_lock lock{mutex}; + const auto controller_iter = controller_list.find(identifier); + if (controller_iter == controller_list.cend()) { + LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.RawString(), + identifier.pad, identifier.port); + return {}; + } + const ControllerData& controller = controller_iter->second; + return controller.camera; +} + void InputEngine::ResetButtonState() { for (const auto& controller : controller_list) { for (const auto& button : controller.second.buttons) { @@ -317,6 +341,20 @@ void InputEngine::TriggerOnMotionChange(const PadIdentifier& identifier, int mot }); } +void InputEngine::TriggerOnCameraChange(const PadIdentifier& identifier, + [[maybe_unused]] const Common::Input::CameraStatus& value) { + std::scoped_lock lock{mutex_callback}; + for (const auto& poller_pair : callback_list) { + const InputIdentifier& poller = poller_pair.second; + if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::Camera, 0)) { + continue; + } + if (poller.callback.on_change) { + poller.callback.on_change(); + } + } +} + bool InputEngine::IsInputIdentifierEqual(const InputIdentifier& input_identifier, const PadIdentifier& identifier, EngineInputType type, 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 { // Types of input that are stored in the engine enum class EngineInputType { None, - Button, - HatButton, Analog, - Motion, Battery, + Button, + Camera, + HatButton, + Motion, }; namespace std { @@ -115,10 +116,17 @@ public: // Sets polling mode to a controller virtual Common::Input::PollingError SetPollingMode( [[maybe_unused]] const PadIdentifier& identifier, - [[maybe_unused]] const Common::Input::PollingMode vibration) { + [[maybe_unused]] const Common::Input::PollingMode polling_mode) { return Common::Input::PollingError::NotSupported; } + // Sets camera format to a controller + virtual Common::Input::CameraError SetCameraFormat( + [[maybe_unused]] const PadIdentifier& identifier, + [[maybe_unused]] Common::Input::CameraFormat camera_format) { + return Common::Input::CameraError::NotSupported; + } + // Returns the engine name [[nodiscard]] const std::string& GetEngineName() const; @@ -174,6 +182,7 @@ public: f32 GetAxis(const PadIdentifier& identifier, int axis) const; Common::Input::BatteryLevel GetBattery(const PadIdentifier& identifier) const; BasicMotion GetMotion(const PadIdentifier& identifier, int motion) const; + Common::Input::CameraStatus GetCamera(const PadIdentifier& identifier) const; int SetCallback(InputIdentifier input_identifier); void SetMappingCallback(MappingCallback callback); @@ -185,6 +194,7 @@ protected: void SetAxis(const PadIdentifier& identifier, int axis, f32 value); void SetBattery(const PadIdentifier& identifier, Common::Input::BatteryLevel value); void SetMotion(const PadIdentifier& identifier, int motion, const BasicMotion& value); + void SetCamera(const PadIdentifier& identifier, const Common::Input::CameraStatus& value); virtual std::string GetHatButtonName([[maybe_unused]] u8 direction_value) const { return "Unknown"; @@ -197,6 +207,7 @@ private: std::unordered_map axes; std::unordered_map motions; Common::Input::BatteryLevel battery{}; + Common::Input::CameraStatus camera{}; }; void TriggerOnButtonChange(const PadIdentifier& identifier, int button, bool value); @@ -205,6 +216,8 @@ private: void TriggerOnBatteryChange(const PadIdentifier& identifier, Common::Input::BatteryLevel value); void TriggerOnMotionChange(const PadIdentifier& identifier, int motion, const BasicMotion& value); + void TriggerOnCameraChange(const PadIdentifier& identifier, + const Common::Input::CameraStatus& value); bool IsInputIdentifierEqual(const InputIdentifier& input_identifier, 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: InputEngine* input_engine; }; +class InputFromCamera final : public Common::Input::InputDevice { +public: + explicit InputFromCamera(PadIdentifier identifier_, InputEngine* input_engine_) + : identifier(identifier_), input_engine(input_engine_) { + UpdateCallback engine_callback{[this]() { OnChange(); }}; + const InputIdentifier input_identifier{ + .identifier = identifier, + .type = EngineInputType::Camera, + .index = 0, + .callback = engine_callback, + }; + callback_key = input_engine->SetCallback(input_identifier); + } + + ~InputFromCamera() override { + input_engine->DeleteCallback(callback_key); + } + + Common::Input::CameraStatus GetStatus() const { + return input_engine->GetCamera(identifier); + } + + void ForceUpdate() override { + OnChange(); + } + + void OnChange() { + const Common::Input::CallbackStatus status{ + .type = Common::Input::InputType::IrSensor, + .camera_status = GetStatus(), + }; + + TriggerOnChange(status); + } + +private: + const PadIdentifier identifier; + int callback_key; + InputEngine* input_engine; +}; + class OutputFromIdentifier final : public Common::Input::OutputDevice { public: explicit OutputFromIdentifier(PadIdentifier identifier_, InputEngine* input_engine_) @@ -682,6 +723,10 @@ public: return input_engine->SetPollingMode(identifier, polling_mode); } + Common::Input::CameraError SetCameraFormat(Common::Input::CameraFormat camera_format) override { + return input_engine->SetCameraFormat(identifier, camera_format); + } + private: const PadIdentifier identifier; InputEngine* input_engine; @@ -920,6 +965,18 @@ std::unique_ptr InputFactory::CreateMotionDevice( properties_y, properties_z, input_engine.get()); } +std::unique_ptr InputFactory::CreateCameraDevice( + const Common::ParamPackage& params) { + const PadIdentifier identifier = { + .guid = Common::UUID{params.Get("guid", "")}, + .port = static_cast(params.Get("port", 0)), + .pad = static_cast(params.Get("pad", 0)), + }; + + input_engine->PreSetController(identifier); + return std::make_unique(identifier, input_engine.get()); +} + InputFactory::InputFactory(std::shared_ptr input_engine_) : input_engine(std::move(input_engine_)) {} @@ -928,6 +985,9 @@ std::unique_ptr InputFactory::Create( if (params.Has("battery")) { return CreateBatteryDevice(params); } + if (params.Has("camera")) { + return CreateCameraDevice(params); + } if (params.Has("button") && params.Has("axis")) { return CreateTriggerDevice(params); } 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: */ std::unique_ptr CreateMotionDevice(Common::ParamPackage params); + /** + * Creates a camera device from the parameters given. + * @param params contains parameters for creating the device: + * - "guid": text string for identifying controllers + * - "port": port of the connected device + * - "pad": slot of the connected controller + * @returns a unique input device with the parameters specified + */ + std::unique_ptr CreateCameraDevice( + const Common::ParamPackage& params); + std::shared_ptr input_engine; }; } // 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 @@ #include #include "common/input.h" #include "common/param_package.h" +#include "input_common/drivers/camera.h" #include "input_common/drivers/gc_adapter.h" #include "input_common/drivers/keyboard.h" #include "input_common/drivers/mouse.h" @@ -78,6 +79,15 @@ struct InputSubsystem::Impl { Common::Input::RegisterFactory(tas_input->GetEngineName(), tas_output_factory); + camera = std::make_shared("camera"); + camera->SetMappingCallback(mapping_callback); + camera_input_factory = std::make_shared(camera); + camera_output_factory = std::make_shared(camera); + Common::Input::RegisterFactory(camera->GetEngineName(), + camera_input_factory); + Common::Input::RegisterFactory(camera->GetEngineName(), + camera_output_factory); + #ifdef HAVE_SDL2 sdl = std::make_shared("sdl"); sdl->SetMappingCallback(mapping_callback); @@ -317,6 +327,7 @@ struct InputSubsystem::Impl { std::shared_ptr touch_screen; std::shared_ptr tas_input; std::shared_ptr udp_client; + std::shared_ptr camera; std::shared_ptr keyboard_factory; std::shared_ptr mouse_factory; @@ -324,12 +335,14 @@ struct InputSubsystem::Impl { std::shared_ptr touch_screen_factory; std::shared_ptr udp_client_input_factory; std::shared_ptr tas_input_factory; + std::shared_ptr camera_input_factory; std::shared_ptr keyboard_output_factory; std::shared_ptr mouse_output_factory; std::shared_ptr gcadapter_output_factory; std::shared_ptr udp_client_output_factory; std::shared_ptr tas_output_factory; + std::shared_ptr camera_output_factory; #ifdef HAVE_SDL2 std::shared_ptr sdl; @@ -382,6 +395,14 @@ const TasInput::Tas* InputSubsystem::GetTas() const { return impl->tas_input.get(); } +Camera* InputSubsystem::GetCamera() { + return impl->camera.get(); +} + +const Camera* InputSubsystem::GetCamera() const { + return impl->camera.get(); +} + std::vector InputSubsystem::GetInputDevices() const { return impl->GetInputDevices(); } 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; } namespace InputCommon { +class Camera; class Keyboard; class Mouse; class TouchScreen; @@ -92,9 +93,15 @@ public: /// Retrieves the underlying tas input device. [[nodiscard]] TasInput::Tas* GetTas(); - /// Retrieves the underlying tas input device. + /// Retrieves the underlying tas input device. [[nodiscard]] const TasInput::Tas* GetTas() const; + /// Retrieves the underlying camera input device. + [[nodiscard]] Camera* GetCamera(); + + /// Retrieves the underlying camera input device. + [[nodiscard]] const Camera* GetCamera() const; + /** * Returns all available input devices that this Factory can create a new device with. * Each returned ParamPackage should have a `display` field used for display, a `engine` field From cc83e0a6006667d126a7a83dde23a7f8ae3af994 Mon Sep 17 00:00:00 2001 From: german77 Date: Sat, 18 Jun 2022 23:34:28 -0500 Subject: [PATCH 2/6] yuzu: Hook qt camera to camera driver --- CMakeLists.txt | 6 +- CMakeModules/CopyYuzuQt5Deps.cmake | 7 + src/yuzu/CMakeLists.txt | 5 +- src/yuzu/bootmanager.cpp | 71 ++++++++ src/yuzu/bootmanager.h | 12 ++ src/yuzu/configuration/config.cpp | 12 ++ src/yuzu/configuration/config.h | 2 + src/yuzu/configuration/configure_camera.cpp | 126 +++++++++++++ src/yuzu/configuration/configure_camera.h | 52 ++++++ src/yuzu/configuration/configure_camera.ui | 170 ++++++++++++++++++ src/yuzu/configuration/configure_input.cpp | 5 + .../configure_input_advanced.cpp | 3 + .../configuration/configure_input_advanced.h | 1 + .../configuration/configure_input_advanced.ui | 14 ++ src/yuzu/main.cpp | 9 + 15 files changed, 491 insertions(+), 4 deletions(-) create mode 100644 src/yuzu/configuration/configure_camera.cpp create mode 100644 src/yuzu/configuration/configure_camera.h create mode 100644 src/yuzu/configuration/configure_camera.ui 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) # Check for system Qt on Linux, fallback to bundled Qt if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux") if (NOT YUZU_USE_BUNDLED_QT) - find_package(Qt5 ${QT_VERSION} COMPONENTS Widgets DBus) + find_package(Qt5 ${QT_VERSION} COMPONENTS Widgets DBus Multimedia) endif() if (NOT Qt5_FOUND OR YUZU_USE_BUNDLED_QT) # Check for dependencies, then enable bundled Qt download @@ -300,9 +300,9 @@ if(ENABLE_QT) set(YUZU_QT_NO_CMAKE_SYSTEM_PATH "NO_CMAKE_SYSTEM_PATH") endif() if ((${CMAKE_SYSTEM_NAME} STREQUAL "Linux") AND YUZU_USE_BUNDLED_QT) - find_package(Qt5 ${QT_VERSION} REQUIRED COMPONENTS Widgets Concurrent DBus ${QT_PREFIX_HINT} ${YUZU_QT_NO_CMAKE_SYSTEM_PATH}) + find_package(Qt5 ${QT_VERSION} REQUIRED COMPONENTS Widgets Concurrent Multimedia DBus ${QT_PREFIX_HINT} ${YUZU_QT_NO_CMAKE_SYSTEM_PATH}) else() - find_package(Qt5 ${QT_VERSION} REQUIRED COMPONENTS Widgets Concurrent ${QT_PREFIX_HINT} ${YUZU_QT_NO_CMAKE_SYSTEM_PATH}) + find_package(Qt5 ${QT_VERSION} REQUIRED COMPONENTS Widgets Concurrent Multimedia ${QT_PREFIX_HINT} ${YUZU_QT_NO_CMAKE_SYSTEM_PATH}) endif() if (YUZU_USE_QT_WEB_ENGINE) find_package(Qt5 REQUIRED COMPONENTS WebEngineCore WebEngineWidgets) diff --git a/CMakeModules/CopyYuzuQt5Deps.cmake b/CMakeModules/CopyYuzuQt5Deps.cmake index 0c27d51a6..4702a504c 100644 --- a/CMakeModules/CopyYuzuQt5Deps.cmake +++ b/CMakeModules/CopyYuzuQt5Deps.cmake @@ -10,11 +10,13 @@ function(copy_yuzu_Qt5_deps target_dir) set(Qt5_PLATFORMS_DIR "${Qt5_DIR}/../../../plugins/platforms/") set(Qt5_PLATFORMTHEMES_DIR "${Qt5_DIR}/../../../plugins/platformthemes/") set(Qt5_PLATFORMINPUTCONTEXTS_DIR "${Qt5_DIR}/../../../plugins/platforminputcontexts/") + set(Qt5_MEDIASERVICE_DIR "${Qt5_DIR}/../../../plugins/mediaservice/") set(Qt5_XCBGLINTEGRATIONS_DIR "${Qt5_DIR}/../../../plugins/xcbglintegrations/") set(Qt5_STYLES_DIR "${Qt5_DIR}/../../../plugins/styles/") set(Qt5_IMAGEFORMATS_DIR "${Qt5_DIR}/../../../plugins/imageformats/") set(Qt5_RESOURCES_DIR "${Qt5_DIR}/../../../resources/") set(PLATFORMS ${DLL_DEST}plugins/platforms/) + set(MEDIASERVICE ${DLL_DEST}mediaservice/) set(STYLES ${DLL_DEST}plugins/styles/) set(IMAGEFORMATS ${DLL_DEST}plugins/imageformats/) if (MSVC) @@ -22,6 +24,7 @@ function(copy_yuzu_Qt5_deps target_dir) Qt5Core$<$:d>.* Qt5Gui$<$:d>.* Qt5Widgets$<$:d>.* + Qt5Multimedia$<$:d>.* ) if (YUZU_USE_QT_WEB_ENGINE) @@ -53,6 +56,10 @@ function(copy_yuzu_Qt5_deps target_dir) qjpeg$<$:d>.* qgif$<$:d>.* ) + windows_copy_files(yuzu ${Qt5_MEDIASERVICE_DIR} ${MEDIASERVICE} + dsengine$<$:d>.* + wmfengine$<$:d>.* + ) else() set(Qt5_DLLS "${Qt5_DLL_DIR}libQt5Core.so.5" 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 configuration/configure_audio.cpp configuration/configure_audio.h configuration/configure_audio.ui + configuration/configure_camera.cpp + configuration/configure_camera.h + configuration/configure_camera.ui configuration/configure_cpu.cpp configuration/configure_cpu.h configuration/configure_cpu.ui @@ -254,7 +257,7 @@ endif() create_target_directory_groups(yuzu) target_link_libraries(yuzu PRIVATE common core input_common video_core) -target_link_libraries(yuzu PRIVATE Boost::boost glad Qt::Widgets) +target_link_libraries(yuzu PRIVATE Boost::boost glad Qt::Widgets Qt::Multimedia) target_link_libraries(yuzu PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) target_include_directories(yuzu PRIVATE ../../externals/Vulkan-Headers/include) diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 01acda22b..774085809 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -5,6 +5,8 @@ #include #include +#include +#include #include #include #include @@ -31,6 +33,7 @@ #include "core/core.h" #include "core/cpu_manager.h" #include "core/frontend/framebuffer_layout.h" +#include "input_common/drivers/camera.h" #include "input_common/drivers/keyboard.h" #include "input_common/drivers/mouse.h" #include "input_common/drivers/tas_input.h" @@ -801,6 +804,74 @@ void GRenderWindow::TouchEndEvent() { input_subsystem->GetTouchScreen()->ReleaseAllTouch(); } +void GRenderWindow::InitializeCamera() { + if (!Settings::values.enable_ir_sensor) { + return; + } + + bool camera_found = false; + const QList cameras = QCameraInfo::availableCameras(); + for (const QCameraInfo& cameraInfo : cameras) { + if (Settings::values.ir_sensor_device.GetValue() == cameraInfo.deviceName().toStdString() || + Settings::values.ir_sensor_device.GetValue() == "Auto") { + camera = std::make_unique(cameraInfo); + camera_found = true; + break; + } + } + + if (!camera_found) { + return; + } + + camera_capture = std::make_unique(camera.get()); + connect(camera_capture.get(), &QCameraImageCapture::imageCaptured, this, + &GRenderWindow::OnCameraCapture); + camera->unload(); + camera->setCaptureMode(QCamera::CaptureViewfinder); + camera->load(); + + camera_timer = std::make_unique(); + connect(camera_timer.get(), &QTimer::timeout, [this] { RequestCameraCapture(); }); + // This timer should be dependent of camera resolution 5ms for every 100 pixels + camera_timer->start(100); +} + +void GRenderWindow::FinalizeCamera() { + if (camera_timer) { + camera_timer->stop(); + } + if (camera) { + camera->unload(); + } +} + +void GRenderWindow::RequestCameraCapture() { + if (!Settings::values.enable_ir_sensor) { + return; + } + + // Idealy one should only call capture but Qt refuses to take a second capture without + // stopping the camera + camera->stop(); + camera->start(); + + camera_capture->capture(); +} + +void GRenderWindow::OnCameraCapture(int requestId, const QImage& img) { + constexpr std::size_t camera_width = 320; + constexpr std::size_t camera_height = 240; + const auto converted = + img.scaled(camera_width, camera_height, Qt::AspectRatioMode::IgnoreAspectRatio, + Qt::TransformationMode::SmoothTransformation) + .mirrored(false, true); + std::vector camera_data{}; + camera_data.resize(camera_width * camera_height); + std::memcpy(camera_data.data(), converted.bits(), camera_width * camera_height * sizeof(u32)); + input_subsystem->GetCamera()->SetCameraData(camera_width, camera_height, camera_data); +} + bool GRenderWindow::event(QEvent* event) { if (event->type() == QEvent::TouchBegin) { TouchBeginEvent(static_cast(event)); diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index 81fe52c0e..346201768 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h @@ -20,6 +20,8 @@ class GRenderWindow; class GMainWindow; +class QCamera; +class QCameraImageCapture; class QKeyEvent; namespace Core { @@ -164,6 +166,9 @@ public: void mouseReleaseEvent(QMouseEvent* event) override; void wheelEvent(QWheelEvent* event) override; + void InitializeCamera(); + void FinalizeCamera(); + bool event(QEvent* event) override; void focusOutEvent(QFocusEvent* event) override; @@ -207,6 +212,9 @@ private: void TouchUpdateEvent(const QTouchEvent* event); void TouchEndEvent(); + void RequestCameraCapture(); + void OnCameraCapture(int requestId, const QImage& img); + void OnMinimalClientAreaChangeRequest(std::pair minimal_size) override; bool InitializeOpenGL(); @@ -232,6 +240,10 @@ private: bool first_frame = false; InputCommon::TasInput::TasState last_tas_state; + std::unique_ptr camera; + std::unique_ptr camera_capture; + std::unique_ptr camera_timer; + Core::System& system; 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() { } } +void Config::ReadIrCameraValues() { + ReadBasicSetting(Settings::values.enable_ir_sensor); + ReadBasicSetting(Settings::values.ir_sensor_device); +} + void Config::ReadAudioValues() { qt_config->beginGroup(QStringLiteral("Audio")); @@ -393,6 +398,7 @@ void Config::ReadControlValues() { ReadTouchscreenValues(); ReadMotionTouchValues(); ReadHidbusValues(); + ReadIrCameraValues(); #ifdef _WIN32 ReadBasicSetting(Settings::values.enable_raw_input); @@ -1005,6 +1011,11 @@ void Config::SaveHidbusValues() { QString::fromStdString(default_param)); } +void Config::SaveIrCameraValues() { + WriteBasicSetting(Settings::values.enable_ir_sensor); + WriteBasicSetting(Settings::values.ir_sensor_device); +} + void Config::SaveValues() { if (global) { SaveControlValues(); @@ -1047,6 +1058,7 @@ void Config::SaveControlValues() { SaveTouchscreenValues(); SaveMotionTouchValues(); SaveHidbusValues(); + SaveIrCameraValues(); WriteGlobalSetting(Settings::values.use_docked_mode); 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: void ReadTouchscreenValues(); void ReadMotionTouchValues(); void ReadHidbusValues(); + void ReadIrCameraValues(); // Read functions bases off the respective config section names. void ReadAudioValues(); @@ -96,6 +97,7 @@ private: void SaveTouchscreenValues(); void SaveMotionTouchValues(); void SaveHidbusValues(); + void SaveIrCameraValues(); // Save functions based off the respective config section names. void SaveAudioValues(); diff --git a/src/yuzu/configuration/configure_camera.cpp b/src/yuzu/configuration/configure_camera.cpp new file mode 100644 index 000000000..97febb33c --- /dev/null +++ b/src/yuzu/configuration/configure_camera.cpp @@ -0,0 +1,126 @@ +// Text : Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include +#include +#include +#include +#include + +#include "input_common/drivers/camera.h" +#include "input_common/main.h" +#include "ui_configure_camera.h" +#include "yuzu/configuration/config.h" +#include "yuzu/configuration/configure_camera.h" + +ConfigureCamera::ConfigureCamera(QWidget* parent, InputCommon::InputSubsystem* input_subsystem_) + : QDialog(parent), input_subsystem{input_subsystem_}, + ui(std::make_unique()) { + ui->setupUi(this); + + connect(ui->restore_defaults_button, &QPushButton::clicked, this, + &ConfigureCamera::RestoreDefaults); + connect(ui->preview_button, &QPushButton::clicked, this, &ConfigureCamera::PreviewCamera); + + auto blank_image = QImage(320, 240, QImage::Format::Format_RGB32); + blank_image.fill(Qt::black); + DisplayCapturedFrame(0, blank_image); + + LoadConfiguration(); + resize(0, 0); +} + +ConfigureCamera::~ConfigureCamera() = default; + +void ConfigureCamera::PreviewCamera() { + const auto index = ui->ir_sensor_combo_box->currentIndex(); + bool camera_found = false; + const QList cameras = QCameraInfo::availableCameras(); + for (const QCameraInfo& cameraInfo : cameras) { + if (input_devices[index] == cameraInfo.deviceName().toStdString() || + input_devices[index] == "Auto") { + LOG_ERROR(Frontend, "Selected Camera {} {}", cameraInfo.description().toStdString(), + cameraInfo.deviceName().toStdString()); + camera = std::make_unique(cameraInfo); + camera_found = true; + break; + } + } + + // Clear previous frame + auto blank_image = QImage(320, 240, QImage::Format::Format_RGB32); + blank_image.fill(Qt::black); + DisplayCapturedFrame(0, blank_image); + + if (!camera_found) { + return; + } + + camera_capture = std::make_unique(camera.get()); + connect(camera_capture.get(), &QCameraImageCapture::imageCaptured, this, + &ConfigureCamera::DisplayCapturedFrame); + camera->unload(); + camera->setCaptureMode(QCamera::CaptureViewfinder); + camera->load(); + + camera_timer = std::make_unique(); + connect(camera_timer.get(), &QTimer::timeout, [this] { + camera->stop(); + camera->start(); + + camera_capture->capture(); + }); + + camera_timer->start(250); +} + +void ConfigureCamera::DisplayCapturedFrame(int requestId, const QImage& img) { + LOG_ERROR(Frontend, "ImageCaptured {} {}", img.width(), img.height()); + const auto converted = img.scaled(320, 240, Qt::AspectRatioMode::IgnoreAspectRatio, + Qt::TransformationMode::SmoothTransformation); + ui->preview_box->setPixmap(QPixmap::fromImage(converted)); +} + +void ConfigureCamera::changeEvent(QEvent* event) { + if (event->type() == QEvent::LanguageChange) { + RetranslateUI(); + } + + QDialog::changeEvent(event); +} + +void ConfigureCamera::RetranslateUI() { + ui->retranslateUi(this); +} + +void ConfigureCamera::ApplyConfiguration() { + const auto index = ui->ir_sensor_combo_box->currentIndex(); + Settings::values.ir_sensor_device.SetValue(input_devices[index]); +} + +void ConfigureCamera::LoadConfiguration() { + input_devices.clear(); + ui->ir_sensor_combo_box->clear(); + input_devices.push_back("Auto"); + ui->ir_sensor_combo_box->addItem(tr("Auto")); + const auto cameras = QCameraInfo::availableCameras(); + for (const QCameraInfo& cameraInfo : cameras) { + input_devices.push_back(cameraInfo.deviceName().toStdString()); + ui->ir_sensor_combo_box->addItem(cameraInfo.description()); + } + + const auto current_device = Settings::values.ir_sensor_device.GetValue(); + + const auto devices_it = std::find_if( + input_devices.begin(), input_devices.end(), + [current_device](const std::string& device) { return device == current_device; }); + const int device_index = + devices_it != input_devices.end() + ? static_cast(std::distance(input_devices.begin(), devices_it)) + : 0; + ui->ir_sensor_combo_box->setCurrentIndex(device_index); +} + +void ConfigureCamera::RestoreDefaults() { + ui->ir_sensor_combo_box->setCurrentIndex(0); +} diff --git a/src/yuzu/configuration/configure_camera.h b/src/yuzu/configuration/configure_camera.h new file mode 100644 index 000000000..af7551c03 --- /dev/null +++ b/src/yuzu/configuration/configure_camera.h @@ -0,0 +1,52 @@ +// Text : Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include +#include + +class QTimer; +class QCamera; +class QCameraImageCapture; + +namespace InputCommon { +class InputSubsystem; +} // namespace InputCommon + +namespace Ui { +class ConfigureCamera; +} + +class ConfigureCamera : public QDialog { + Q_OBJECT + +public: + explicit ConfigureCamera(QWidget* parent, InputCommon::InputSubsystem* input_subsystem_); + ~ConfigureCamera() override; + + void ApplyConfiguration(); + +private: + void changeEvent(QEvent* event) override; + void RetranslateUI(); + + /// Load configuration settings. + void LoadConfiguration(); + + /// Restore all buttons to their default values. + void RestoreDefaults(); + + void DisplayCapturedFrame(int requestId, const QImage& img); + + /// Loads and signals the current selected camera to display a frame + void PreviewCamera(); + + InputCommon::InputSubsystem* input_subsystem; + + std::unique_ptr camera; + std::unique_ptr camera_capture; + std::unique_ptr camera_timer; + std::vector input_devices; + std::unique_ptr ui; +}; 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 @@ + + + ConfigureCamera + + + + 0 + 0 + 298 + 339 + + + + Configure Infrared Camera + + + + + + + 280 + 0 + + + + Select where the image of the emulated camera comes from. It may be a virtual camera or a real camera. + + + true + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + Camera Image Source: + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Input device: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Preview + + + + + + + 320 + 240 + + + + Resolution: 320*240 + + + + + + + Click to preview + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + Restore Defaults + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + + buttonBox + accepted() + ConfigureCamera + accept() + + + buttonBox + rejected() + ConfigureCamera + reject() + + + 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 @@ #include "ui_configure_input.h" #include "ui_configure_input_advanced.h" #include "ui_configure_input_player.h" +#include "yuzu/configuration/configure_camera.h" #include "yuzu/configuration/configure_debug_controller.h" #include "yuzu/configuration/configure_input.h" #include "yuzu/configuration/configure_input_advanced.h" @@ -163,6 +164,10 @@ void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem, [this, input_subsystem, &hid_core] { CallConfigureDialog(*this, input_subsystem, hid_core); }); + connect(advanced, &ConfigureInputAdvanced::CallCameraDialog, + [this, input_subsystem, &hid_core] { + CallConfigureDialog(*this, input_subsystem); + }); connect(ui->vibrationButton, &QPushButton::clicked, [this, &hid_core] { CallConfigureDialog(*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) [this] { CallMotionTouchConfigDialog(); }); connect(ui->ring_controller_configure, &QPushButton::clicked, this, [this] { CallRingControllerDialog(); }); + connect(ui->camera_configure, &QPushButton::clicked, this, [this] { CallCameraDialog(); }); #ifndef _WIN32 ui->enable_raw_input->setVisible(false); @@ -136,6 +137,7 @@ void ConfigureInputAdvanced::ApplyConfiguration() { Settings::values.enable_udp_controller = ui->enable_udp_controller->isChecked(); Settings::values.controller_navigation = ui->controller_navigation->isChecked(); Settings::values.enable_ring_controller = ui->enable_ring_controller->isChecked(); + Settings::values.enable_ir_sensor = ui->enable_ir_sensor->isChecked(); } void ConfigureInputAdvanced::LoadConfiguration() { @@ -169,6 +171,7 @@ void ConfigureInputAdvanced::LoadConfiguration() { ui->enable_udp_controller->setChecked(Settings::values.enable_udp_controller.GetValue()); ui->controller_navigation->setChecked(Settings::values.controller_navigation.GetValue()); ui->enable_ring_controller->setChecked(Settings::values.enable_ring_controller.GetValue()); + ui->enable_ir_sensor->setChecked(Settings::values.enable_ir_sensor.GetValue()); UpdateUIEnabled(); } 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: void CallTouchscreenConfigDialog(); void CallMotionTouchConfigDialog(); void CallRingControllerDialog(); + void CallCameraDialog(); private: 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 @@ + + + + Infrared Camera + + + + + + + Configure + + + 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 mouse_hide_timer.start(); } + render_window->InitializeCamera(); + std::string title_name; std::string title_version; const auto res = system->GetGameName(title_name); @@ -1623,6 +1625,7 @@ void GMainWindow::ShutdownGame() { tas_label->clear(); input_subsystem->GetTas()->Stop(); OnTasStateChanged(); + render_window->FinalizeCamera(); // Enable all controllers system->HIDCore().SetSupportedStyleTag({Core::HID::NpadStyleSet::All}); @@ -2862,6 +2865,12 @@ void GMainWindow::OnConfigure() { mouse_hide_timer.start(); } + // Restart camera config + if (emulation_running) { + render_window->FinalizeCamera(); + render_window->InitializeCamera(); + } + if (!UISettings::values.has_broken_vulkan) { renderer_status_button->setEnabled(!emulation_running); } From 57311b2c8b1b9ee1d2c5775866e9591605815246 Mon Sep 17 00:00:00 2001 From: german77 Date: Sat, 18 Jun 2022 23:36:29 -0500 Subject: [PATCH 3/6] core: hid: Add cammera support --- src/core/CMakeLists.txt | 1 + src/core/hid/emulated_controller.cpp | 59 ++++++ src/core/hid/emulated_controller.h | 40 +++- src/core/hid/input_converter.cpp | 14 ++ src/core/hid/input_converter.h | 8 + src/core/hid/irs_types.h | 304 +++++++++++++++++++++++++++ 6 files changed, 423 insertions(+), 3 deletions(-) create mode 100644 src/core/hid/irs_types.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 11d554bad..1f8439f91 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -158,6 +158,7 @@ add_library(core STATIC hid/input_converter.h hid/input_interpreter.cpp hid/input_interpreter.h + hid/irs_types.h hid/motion_input.cpp hid/motion_input.h hle/api_version.h 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() { battery_params[LeftIndex].Set("battery", true); battery_params[RightIndex].Set("battery", true); + camera_params = Common::ParamPackage{"engine:camera,camera:1"}; + output_params[LeftIndex] = left_joycon; output_params[RightIndex] = right_joycon; + output_params[2] = camera_params; output_params[LeftIndex].Set("output", true); output_params[RightIndex].Set("output", true); + output_params[2].Set("output", true); LoadTASParams(); @@ -146,6 +150,7 @@ void EmulatedController::LoadDevices() { Common::Input::CreateDevice); std::transform(battery_params.begin(), battery_params.end(), battery_devices.begin(), Common::Input::CreateDevice); + camera_devices = Common::Input::CreateDevice(camera_params); std::transform(output_params.begin(), output_params.end(), output_devices.begin(), Common::Input::CreateDevice); @@ -267,6 +272,14 @@ void EmulatedController::ReloadInput() { motion_devices[index]->ForceUpdate(); } + if (camera_devices) { + camera_devices->SetCallback({ + .on_change = + [this](const Common::Input::CallbackStatus& callback) { SetCamera(callback); }, + }); + camera_devices->ForceUpdate(); + } + // Use a common UUID for TAS static constexpr Common::UUID TAS_UUID = Common::UUID{ {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 TriggerOnChange(ControllerTriggerType::Battery, true); } +void EmulatedController::SetCamera(const Common::Input::CallbackStatus& callback) { + std::unique_lock lock{mutex}; + controller.camera_values = TransformToCamera(callback); + + if (is_configuring) { + lock.unlock(); + TriggerOnChange(ControllerTriggerType::IrSensor, false); + return; + } + + controller.camera_state.sample++; + controller.camera_state.format = + static_cast(controller.camera_values.format); + controller.camera_state.data = controller.camera_values.data; + + lock.unlock(); + TriggerOnChange(ControllerTriggerType::IrSensor, true); +} + bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue vibration) { if (device_index >= output_devices.size()) { return false; @@ -928,6 +960,23 @@ bool EmulatedController::SetPollingMode(Common::Input::PollingMode polling_mode) return output_device->SetPollingMode(polling_mode) == Common::Input::PollingError::None; } +bool EmulatedController::SetCameraFormat( + Core::IrSensor::ImageTransferProcessorFormat camera_format) { + LOG_INFO(Service_HID, "Set camera format {}", camera_format); + + auto& right_output_device = output_devices[static_cast(DeviceIndex::Right)]; + auto& camera_output_device = output_devices[2]; + + if (right_output_device->SetCameraFormat(static_cast( + camera_format)) == Common::Input::CameraError::None) { + return true; + } + + // Fallback to Qt camera if native device doesn't have support + return camera_output_device->SetCameraFormat(static_cast( + camera_format)) == Common::Input::CameraError::None; +} + void EmulatedController::SetLedPattern() { for (auto& device : output_devices) { if (!device) { @@ -1163,6 +1212,11 @@ BatteryValues EmulatedController::GetBatteryValues() const { return controller.battery_values; } +CameraValues EmulatedController::GetCameraValues() const { + std::scoped_lock lock{mutex}; + return controller.camera_values; +} + HomeButtonState EmulatedController::GetHomeButtons() const { std::scoped_lock lock{mutex}; if (is_configuring) { @@ -1251,6 +1305,11 @@ BatteryLevelState EmulatedController::GetBattery() const { return controller.battery_state; } +const CameraState& EmulatedController::GetCamera() const { + std::scoped_lock lock{mutex}; + return controller.camera_state; +} + void EmulatedController::TriggerOnChange(ControllerTriggerType type, bool is_npad_service_update) { std::scoped_lock lock{callback_mutex}; 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 @@ #include "common/settings.h" #include "common/vector_math.h" #include "core/hid/hid_types.h" +#include "core/hid/irs_types.h" #include "core/hid/motion_input.h" namespace Core::HID { const std::size_t max_emulated_controllers = 2; +const std::size_t output_devices = 3; struct ControllerMotionInfo { Common::Input::MotionStatus raw_status{}; MotionInput emulated{}; @@ -34,15 +36,16 @@ using TriggerDevices = std::array, Settings::NativeTrigger::NumTriggers>; using BatteryDevices = std::array, max_emulated_controllers>; -using OutputDevices = - std::array, max_emulated_controllers>; +using CameraDevices = std::unique_ptr; +using OutputDevices = std::array, output_devices>; using ButtonParams = std::array; using StickParams = std::array; using ControllerMotionParams = std::array; using TriggerParams = std::array; using BatteryParams = std::array; -using OutputParams = std::array; +using CameraParams = Common::ParamPackage; +using OutputParams = std::array; using ButtonValues = std::array; using SticksValues = std::array; @@ -51,6 +54,7 @@ using TriggerValues = using ControllerMotionValues = std::array; using ColorValues = std::array; using BatteryValues = std::array; +using CameraValues = Common::Input::CameraStatus; using VibrationValues = std::array; struct AnalogSticks { @@ -70,6 +74,12 @@ struct BatteryLevelState { NpadPowerInfo right{}; }; +struct CameraState { + Core::IrSensor::ImageTransferProcessorFormat format{}; + std::vector data{}; + std::size_t sample{}; +}; + struct ControllerMotion { Common::Vec3f accel{}; Common::Vec3f gyro{}; @@ -96,6 +106,7 @@ struct ControllerStatus { ColorValues color_values{}; BatteryValues battery_values{}; VibrationValues vibration_values{}; + CameraValues camera_values{}; // Data for HID serices HomeButtonState home_button_state{}; @@ -107,6 +118,7 @@ struct ControllerStatus { NpadGcTriggerState gc_trigger_state{}; ControllerColors colors_state{}; BatteryLevelState battery_state{}; + CameraState camera_state{}; }; enum class ControllerTriggerType { @@ -117,6 +129,7 @@ enum class ControllerTriggerType { Color, Battery, Vibration, + IrSensor, Connected, Disconnected, Type, @@ -269,6 +282,9 @@ public: /// Returns the latest battery status from the controller with parameters BatteryValues GetBatteryValues() const; + /// Returns the latest camera status from the controller with parameters + CameraValues GetCameraValues() const; + /// Returns the latest status of button input for the hid::HomeButton service HomeButtonState GetHomeButtons() const; @@ -296,6 +312,9 @@ public: /// Returns the latest battery status from the controller BatteryLevelState GetBattery() const; + /// Returns the latest camera status from the controller + const CameraState& GetCamera() const; + /** * Sends a specific vibration to the output device * @return true if vibration had no errors @@ -315,6 +334,13 @@ public: */ bool SetPollingMode(Common::Input::PollingMode polling_mode); + /** + * Sets the desired camera format to be polled from a controller + * @param camera_format size of each frame + * @return true if SetCameraFormat was successfull + */ + bool SetCameraFormat(Core::IrSensor::ImageTransferProcessorFormat camera_format); + /// Returns the led pattern corresponding to this emulated controller LedPattern GetLedPattern() const; @@ -392,6 +418,12 @@ private: */ void SetBattery(const Common::Input::CallbackStatus& callback, std::size_t index); + /** + * Updates the camera status of the controller + * @param callback A CallbackStatus containing the camera status + */ + void SetCamera(const Common::Input::CallbackStatus& callback); + /** * Triggers a callback that something has changed on the controller status * @param type Input type of the event to trigger @@ -417,6 +449,7 @@ private: ControllerMotionParams motion_params; TriggerParams trigger_params; BatteryParams battery_params; + CameraParams camera_params; OutputParams output_params; ButtonDevices button_devices; @@ -424,6 +457,7 @@ private: ControllerMotionDevices motion_devices; TriggerDevices trigger_devices; BatteryDevices battery_devices; + CameraDevices camera_devices; OutputDevices output_devices; // 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 return status; } +Common::Input::CameraStatus TransformToCamera(const Common::Input::CallbackStatus& callback) { + Common::Input::CameraStatus camera{}; + switch (callback.type) { + case Common::Input::InputType::IrSensor: + camera = callback.camera_status; + break; + default: + LOG_ERROR(Input, "Conversion from type {} to camera not implemented", callback.type); + break; + } + + return camera; +} + void SanitizeAnalog(Common::Input::AnalogStatus& analog, bool clamp_value) { const auto& properties = analog.properties; 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 @@ -76,6 +76,14 @@ Common::Input::TriggerStatus TransformToTrigger(const Common::Input::CallbackSta */ Common::Input::AnalogStatus TransformToAnalog(const Common::Input::CallbackStatus& callback); +/** + * Converts raw input data into a valid camera status. + * + * @param callback Supported callbacks: Camera. + * @return A valid CameraObject object. + */ +Common::Input::CameraStatus TransformToCamera(const Common::Input::CallbackStatus& callback); + /** * Converts raw analog data into a valid analog value * @param analog An analog object containing raw data and properties diff --git a/src/core/hid/irs_types.h b/src/core/hid/irs_types.h new file mode 100644 index 000000000..c73d008a0 --- /dev/null +++ b/src/core/hid/irs_types.h @@ -0,0 +1,304 @@ +// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "common/common_funcs.h" +#include "common/common_types.h" +#include "core/hid/hid_types.h" + +namespace Core::IrSensor { + +// This is nn::irsensor::CameraAmbientNoiseLevel +enum class CameraAmbientNoiseLevel : u32 { + Low, + Medium, + High, + Unkown3, // This level can't be reached +}; + +// This is nn::irsensor::CameraLightTarget +enum class CameraLightTarget : u32 { + AllLeds, + BrightLeds, + DimLeds, + None, +}; + +// This is nn::irsensor::PackedCameraLightTarget +enum class PackedCameraLightTarget : u8 { + AllLeds, + BrightLeds, + DimLeds, + None, +}; + +// This is nn::irsensor::AdaptiveClusteringMode +enum class AdaptiveClusteringMode : u32 { + StaticFov, + DynamicFov, +}; + +// This is nn::irsensor::AdaptiveClusteringTargetDistance +enum class AdaptiveClusteringTargetDistance : u32 { + Near, + Middle, + Far, +}; + +// This is nn::irsensor::ImageTransferProcessorFormat +enum class ImageTransferProcessorFormat : u32 { + Size320x240, + Size160x120, + Size80x60, + Size40x30, + Size20x15, +}; + +// This is nn::irsensor::PackedImageTransferProcessorFormat +enum class PackedImageTransferProcessorFormat : u8 { + Size320x240, + Size160x120, + Size80x60, + Size40x30, + Size20x15, +}; + +// This is nn::irsensor::IrCameraStatus +enum class IrCameraStatus : u32 { + Available, + Unsupported, + Unconnected, +}; + +// This is nn::irsensor::IrCameraInternalStatus +enum class IrCameraInternalStatus : u32 { + Stopped, + FirmwareUpdateNeeded, + Unkown2, + Unkown3, + Unkown4, + FirmwareVersionRequested, + FirmwareVersionIsInvalid, + Ready, + Setting, +}; + +// This is nn::irsensor::detail::StatusManager::IrSensorMode +enum class IrSensorMode : u64 { + None, + MomentProcessor, + ClusteringProcessor, + ImageTransferProcessor, + PointingProcessorMarker, + TeraPluginProcessor, + IrLedProcessor, +}; + +// This is nn::irsensor::ImageProcessorStatus +enum ImageProcessorStatus : u32 { + Stopped, + Running, +}; + +// This is nn::irsensor::HandAnalysisMode +enum class HandAnalysisMode : u32 { + None, + Silhouette, + Image, + SilhoueteAndImage, + SilhuetteOnly, +}; + +// This is nn::irsensor::IrSensorFunctionLevel +enum class IrSensorFunctionLevel : u8 { + unknown0, + unknown1, + unknown2, + unknown3, + unknown4, +}; + +// This is nn::irsensor::MomentProcessorPreprocess +enum class MomentProcessorPreprocess : u32 { + Unkown0, + Unkown1, +}; + +// This is nn::irsensor::PackedMomentProcessorPreprocess +enum class PackedMomentProcessorPreprocess : u8 { + Unkown0, + Unkown1, +}; + +// This is nn::irsensor::PointingStatus +enum class PointingStatus : u32 { + Unkown0, + Unkown1, +}; + +struct IrsRect { + s16 x; + s16 y; + s16 width; + s16 height; +}; + +struct IrsCentroid { + f32 x; + f32 y; +}; + +struct CameraConfig { + u64 exposure_time; + CameraLightTarget light_target; + u32 gain; + bool is_negative_used; + INSERT_PADDING_BYTES(7); +}; +static_assert(sizeof(CameraConfig) == 0x18, "CameraConfig is an invalid size"); + +struct PackedCameraConfig { + u64 exposure_time; + PackedCameraLightTarget light_target; + u8 gain; + bool is_negative_used; + INSERT_PADDING_BYTES(5); +}; +static_assert(sizeof(PackedCameraConfig) == 0x10, "PackedCameraConfig is an invalid size"); + +// This is nn::irsensor::IrCameraHandle +struct IrCameraHandle { + u8 npad_id{}; + Core::HID::NpadStyleIndex npad_type{Core::HID::NpadStyleIndex::None}; + INSERT_PADDING_BYTES(2); +}; +static_assert(sizeof(IrCameraHandle) == 4, "IrCameraHandle is an invalid size"); + +// This is nn::irsensor::PackedMcuVersion +struct PackedMcuVersion { + u16 major; + u16 minor; +}; +static_assert(sizeof(PackedMcuVersion) == 4, "PackedMcuVersion is an invalid size"); + +// This is nn::irsensor::PackedMomentProcessorConfig +struct PackedMomentProcessorConfig { + PackedCameraConfig camera_config; + IrsRect window_of_interest; + PackedMcuVersion required_mcu_version; + PackedMomentProcessorPreprocess preprocess; + u8 preprocess_intensity_threshold; + INSERT_PADDING_BYTES(2); +}; +static_assert(sizeof(PackedMomentProcessorConfig) == 0x20, + "PackedMomentProcessorConfig is an invalid size"); + +// This is nn::irsensor::PackedClusteringProcessorConfig +struct PackedClusteringProcessorConfig { + PackedCameraConfig camera_config; + IrsRect window_of_interest; + PackedMcuVersion required_mcu_version; + u32 pixel_count_min; + u32 pixel_count_max; + u32 object_intensity_min; + bool is_external_light_filter_enabled; + INSERT_PADDING_BYTES(2); +}; +static_assert(sizeof(PackedClusteringProcessorConfig) == 0x30, + "PackedClusteringProcessorConfig is an invalid size"); + +// This is nn::irsensor::PackedImageTransferProcessorConfig +struct PackedImageTransferProcessorConfig { + PackedCameraConfig camera_config; + PackedMcuVersion required_mcu_version; + PackedImageTransferProcessorFormat format; + INSERT_PADDING_BYTES(3); +}; +static_assert(sizeof(PackedImageTransferProcessorConfig) == 0x18, + "PackedImageTransferProcessorConfig is an invalid size"); + +// This is nn::irsensor::PackedTeraPluginProcessorConfig +struct PackedTeraPluginProcessorConfig { + PackedMcuVersion required_mcu_version; + u8 mode; + u8 unknown_1; + u8 unknown_2; + u8 unknown_3; +}; +static_assert(sizeof(PackedTeraPluginProcessorConfig) == 0x8, + "PackedTeraPluginProcessorConfig is an invalid size"); + +// This is nn::irsensor::PackedPointingProcessorConfig +struct PackedPointingProcessorConfig { + IrsRect window_of_interest; + PackedMcuVersion required_mcu_version; +}; +static_assert(sizeof(PackedPointingProcessorConfig) == 0xC, + "PackedPointingProcessorConfig is an invalid size"); + +// This is nn::irsensor::PackedFunctionLevel +struct PackedFunctionLevel { + IrSensorFunctionLevel function_level; + INSERT_PADDING_BYTES(3); +}; +static_assert(sizeof(PackedFunctionLevel) == 0x4, "PackedFunctionLevel is an invalid size"); + +// This is nn::irsensor::PackedImageTransferProcessorExConfig +struct PackedImageTransferProcessorExConfig { + PackedCameraConfig camera_config; + PackedMcuVersion required_mcu_version; + PackedImageTransferProcessorFormat origin_format; + PackedImageTransferProcessorFormat trimming_format; + u16 trimming_start_x; + u16 trimming_start_y; + bool is_external_light_filter_enabled; + INSERT_PADDING_BYTES(5); +}; +static_assert(sizeof(PackedImageTransferProcessorExConfig) == 0x20, + "PackedImageTransferProcessorExConfig is an invalid size"); + +// This is nn::irsensor::PackedIrLedProcessorConfig +struct PackedIrLedProcessorConfig { + PackedMcuVersion required_mcu_version; + u8 light_target; + INSERT_PADDING_BYTES(3); +}; +static_assert(sizeof(PackedIrLedProcessorConfig) == 0x8, + "PackedIrLedProcessorConfig is an invalid size"); + +// This is nn::irsensor::HandAnalysisConfig +struct HandAnalysisConfig { + HandAnalysisMode mode; +}; +static_assert(sizeof(HandAnalysisConfig) == 0x4, "HandAnalysisConfig is an invalid size"); + +// This is nn::irsensor::detail::ProcessorState +struct ProcessorState { + u64 start{}; + u32 count{}; + INSERT_PADDING_BYTES(4); + std::array processor_raw_data{}; +}; +static_assert(sizeof(ProcessorState) == 0xE20, "ProcessorState is an invalid size"); + +// This is nn::irsensor::detail::DeviceFormat +struct DeviceFormat { + Core::IrSensor::IrCameraStatus camera_status{Core::IrSensor::IrCameraStatus::Unconnected}; + Core::IrSensor::IrCameraInternalStatus camera_internal_status{ + Core::IrSensor::IrCameraInternalStatus::Ready}; + Core::IrSensor::IrSensorMode mode{Core::IrSensor::IrSensorMode::None}; + ProcessorState state{}; +}; +static_assert(sizeof(DeviceFormat) == 0xE30, "DeviceFormat is an invalid size"); + +// This is nn::irsensor::ImageTransferProcessorState +struct ImageTransferProcessorState { + u64 sampling_number; + Core::IrSensor::CameraAmbientNoiseLevel ambient_noise_level; + INSERT_PADDING_BYTES(4); +}; +static_assert(sizeof(ImageTransferProcessorState) == 0x10, + "ImageTransferProcessorState is an invalid size"); + +} // namespace Core::IrSensor From 453970059528d564d9ef88f7f9096c05946fbefe Mon Sep 17 00:00:00 2001 From: german77 Date: Sat, 18 Jun 2022 23:45:06 -0500 Subject: [PATCH 4/6] service: irs: Split processors and implement ImageTransferProcessor --- src/core/CMakeLists.txt | 14 + src/core/hle/service/hid/errors.h | 3 + src/core/hle/service/hid/irs.cpp | 288 +++++++++++++---- src/core/hle/service/hid/irs.h | 291 ++++-------------- .../hid/irsensor/clustering_processor.cpp | 36 +++ .../hid/irsensor/clustering_processor.h | 74 +++++ .../hid/irsensor/image_transfer_processor.cpp | 154 +++++++++ .../hid/irsensor/image_transfer_processor.h | 73 +++++ .../service/hid/irsensor/ir_led_processor.cpp | 29 ++ .../service/hid/irsensor/ir_led_processor.h | 47 +++ .../service/hid/irsensor/moment_processor.cpp | 36 +++ .../service/hid/irsensor/moment_processor.h | 61 ++++ .../hid/irsensor/pointing_processor.cpp | 28 ++ .../service/hid/irsensor/pointing_processor.h | 62 ++++ .../service/hid/irsensor/processor_base.cpp | 67 ++++ .../hle/service/hid/irsensor/processor_base.h | 33 ++ .../hid/irsensor/tera_plugin_processor.cpp | 31 ++ .../hid/irsensor/tera_plugin_processor.h | 53 ++++ 18 files changed, 1090 insertions(+), 290 deletions(-) create mode 100644 src/core/hle/service/hid/irsensor/clustering_processor.cpp create mode 100644 src/core/hle/service/hid/irsensor/clustering_processor.h create mode 100644 src/core/hle/service/hid/irsensor/image_transfer_processor.cpp create mode 100644 src/core/hle/service/hid/irsensor/image_transfer_processor.h create mode 100644 src/core/hle/service/hid/irsensor/ir_led_processor.cpp create mode 100644 src/core/hle/service/hid/irsensor/ir_led_processor.h create mode 100644 src/core/hle/service/hid/irsensor/moment_processor.cpp create mode 100644 src/core/hle/service/hid/irsensor/moment_processor.h create mode 100644 src/core/hle/service/hid/irsensor/pointing_processor.cpp create mode 100644 src/core/hle/service/hid/irsensor/pointing_processor.h create mode 100644 src/core/hle/service/hid/irsensor/processor_base.cpp create mode 100644 src/core/hle/service/hid/irsensor/processor_base.h create mode 100644 src/core/hle/service/hid/irsensor/tera_plugin_processor.cpp create mode 100644 src/core/hle/service/hid/irsensor/tera_plugin_processor.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 1f8439f91..32cc2f392 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -478,6 +478,20 @@ add_library(core STATIC hle/service/hid/hidbus/starlink.h hle/service/hid/hidbus/stubbed.cpp hle/service/hid/hidbus/stubbed.h + hle/service/hid/irsensor/clustering_processor.cpp + hle/service/hid/irsensor/clustering_processor.h + hle/service/hid/irsensor/image_transfer_processor.cpp + hle/service/hid/irsensor/image_transfer_processor.h + hle/service/hid/irsensor/ir_led_processor.cpp + hle/service/hid/irsensor/ir_led_processor.h + hle/service/hid/irsensor/moment_processor.cpp + hle/service/hid/irsensor/moment_processor.h + hle/service/hid/irsensor/pointing_processor.cpp + hle/service/hid/irsensor/pointing_processor.h + hle/service/hid/irsensor/processor_base.cpp + hle/service/hid/irsensor/processor_base.h + hle/service/hid/irsensor/tera_plugin_processor.cpp + hle/service/hid/irsensor/tera_plugin_processor.h hle/service/jit/jit_context.cpp hle/service/jit/jit_context.h hle/service/jit/jit.cpp diff --git a/src/core/hle/service/hid/errors.h b/src/core/hle/service/hid/errors.h index 46282f42e..1bd62461c 100644 --- a/src/core/hle/service/hid/errors.h +++ b/src/core/hle/service/hid/errors.h @@ -18,4 +18,7 @@ constexpr Result NpadIsSameType{ErrorModule::HID, 602}; constexpr Result InvalidNpadId{ErrorModule::HID, 709}; constexpr Result NpadNotConnected{ErrorModule::HID, 710}; +constexpr ResultCode InvalidProcessorState{ErrorModule::Irsensor, 78}; +constexpr ResultCode InvalidIrCameraHandle{ErrorModule::Irsensor, 204}; + } // namespace Service::HID diff --git a/src/core/hle/service/hid/irs.cpp b/src/core/hle/service/hid/irs.cpp index d2a91d913..53a31df79 100644 --- a/src/core/hle/service/hid/irs.cpp +++ b/src/core/hle/service/hid/irs.cpp @@ -1,14 +1,26 @@ // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include +#include + #include "core/core.h" #include "core/core_timing.h" +#include "core/hid/emulated_controller.h" +#include "core/hid/hid_core.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/k_shared_memory.h" #include "core/hle/kernel/k_transfer_memory.h" #include "core/hle/kernel/kernel.h" #include "core/hle/service/hid/errors.h" #include "core/hle/service/hid/irs.h" +#include "core/hle/service/hid/irsensor/clustering_processor.h" +#include "core/hle/service/hid/irsensor/image_transfer_processor.h" +#include "core/hle/service/hid/irsensor/ir_led_processor.h" +#include "core/hle/service/hid/irsensor/moment_processor.h" +#include "core/hle/service/hid/irsensor/pointing_processor.h" +#include "core/hle/service/hid/irsensor/tera_plugin_processor.h" +#include "core/memory.h" namespace Service::HID { @@ -36,8 +48,13 @@ IRS::IRS(Core::System& system_) : ServiceFramework{system_, "irs"} { }; // clang-format on + u8* raw_shared_memory = system.Kernel().GetIrsSharedMem().GetPointer(); RegisterHandlers(functions); + shared_memory = std::construct_at(reinterpret_cast(raw_shared_memory)); + + npad_device = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); } +IRS::~IRS() = default; void IRS::ActivateIrsensor(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; @@ -75,7 +92,7 @@ void IRS::GetIrsensorSharedMemoryHandle(Kernel::HLERequestContext& ctx) { void IRS::StopImageProcessor(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - IrCameraHandle camera_handle; + Core::IrSensor::IrCameraHandle camera_handle; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; @@ -88,17 +105,23 @@ void IRS::StopImageProcessor(Kernel::HLERequestContext& ctx) { parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, parameters.applet_resource_user_id); + auto result = IsIrCameraHandleValid(parameters.camera_handle); + if (result.IsSuccess()) { + // TODO: Stop Image processor + result = ResultSuccess; + } + IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + rb.Push(result); } void IRS::RunMomentProcessor(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - IrCameraHandle camera_handle; + Core::IrSensor::IrCameraHandle camera_handle; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; - PackedMomentProcessorConfig processor_config; + Core::IrSensor::PackedMomentProcessorConfig processor_config; }; static_assert(sizeof(Parameters) == 0x30, "Parameters has incorrect size."); @@ -109,17 +132,26 @@ void IRS::RunMomentProcessor(Kernel::HLERequestContext& ctx) { parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, parameters.applet_resource_user_id); + const auto result = IsIrCameraHandleValid(parameters.camera_handle); + + if (result.IsSuccess()) { + auto& device = GetIrCameraSharedMemoryDeviceEntry(parameters.camera_handle); + MakeProcessor(parameters.camera_handle, device); + auto& image_transfer_processor = GetProcessor(parameters.camera_handle); + image_transfer_processor.SetConfig(parameters.processor_config); + } + IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + rb.Push(result); } void IRS::RunClusteringProcessor(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - IrCameraHandle camera_handle; + Core::IrSensor::IrCameraHandle camera_handle; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; - PackedClusteringProcessorConfig processor_config; + Core::IrSensor::PackedClusteringProcessorConfig processor_config; }; static_assert(sizeof(Parameters) == 0x40, "Parameters has incorrect size."); @@ -130,17 +162,27 @@ void IRS::RunClusteringProcessor(Kernel::HLERequestContext& ctx) { parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, parameters.applet_resource_user_id); + auto result = IsIrCameraHandleValid(parameters.camera_handle); + + if (result.IsSuccess()) { + auto& device = GetIrCameraSharedMemoryDeviceEntry(parameters.camera_handle); + MakeProcessor(parameters.camera_handle, device); + auto& image_transfer_processor = + GetProcessor(parameters.camera_handle); + image_transfer_processor.SetConfig(parameters.processor_config); + } + IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + rb.Push(result); } void IRS::RunImageTransferProcessor(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - IrCameraHandle camera_handle; + Core::IrSensor::IrCameraHandle camera_handle; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; - PackedImageTransferProcessorConfig processor_config; + Core::IrSensor::PackedImageTransferProcessorConfig processor_config; u32 transfer_memory_size; }; static_assert(sizeof(Parameters) == 0x30, "Parameters has incorrect size."); @@ -151,20 +193,42 @@ void IRS::RunImageTransferProcessor(Kernel::HLERequestContext& ctx) { auto t_mem = system.CurrentProcess()->GetHandleTable().GetObject(t_mem_handle); - LOG_WARNING(Service_IRS, - "(STUBBED) called, npad_type={}, npad_id={}, transfer_memory_size={}, " - "applet_resource_user_id={}", - parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, - parameters.transfer_memory_size, parameters.applet_resource_user_id); + if (t_mem.IsNull()) { + LOG_ERROR(Service_HID, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultUnknown); + return; + } + + ASSERT_MSG(t_mem->GetSize() == parameters.transfer_memory_size, "t_mem has incorrect size"); + + u8* transfer_memory = system.Memory().GetPointer(t_mem->GetSourceAddress()); + + LOG_INFO(Service_IRS, + "called, npad_type={}, npad_id={}, transfer_memory_size={}, transfer_memory_size={}, " + "applet_resource_user_id={}", + parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, + parameters.transfer_memory_size, t_mem->GetSize(), parameters.applet_resource_user_id); + + const auto result = IsIrCameraHandleValid(parameters.camera_handle); + + if (result.IsSuccess()) { + auto& device = GetIrCameraSharedMemoryDeviceEntry(parameters.camera_handle); + MakeProcessorWithCoreContext(parameters.camera_handle, device); + auto& image_transfer_processor = + GetProcessor(parameters.camera_handle); + image_transfer_processor.SetConfig(parameters.processor_config); + image_transfer_processor.SetTransferMemoryPointer(transfer_memory); + } IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + rb.Push(result); } void IRS::GetImageTransferProcessorState(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - IrCameraHandle camera_handle; + Core::IrSensor::IrCameraHandle camera_handle; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; @@ -172,21 +236,40 @@ void IRS::GetImageTransferProcessorState(Kernel::HLERequestContext& ctx) { const auto parameters{rp.PopRaw()}; - LOG_WARNING(Service_IRS, - "(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}", - parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, - parameters.applet_resource_user_id); + LOG_DEBUG(Service_IRS, "(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}", + parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, + parameters.applet_resource_user_id); - IPC::ResponseBuilder rb{ctx, 5}; + const auto result = IsIrCameraHandleValid(parameters.camera_handle); + if (result.IsError()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); + return; + } + + const auto& device = GetIrCameraSharedMemoryDeviceEntry(parameters.camera_handle); + + if (device.mode != Core::IrSensor::IrSensorMode::ImageTransferProcessor) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(InvalidProcessorState); + return; + } + + std::vector data{}; + const auto& image_transfer_processor = + GetProcessor(parameters.camera_handle); + const auto& state = image_transfer_processor.GetState(data); + + ctx.WriteBuffer(data); + IPC::ResponseBuilder rb{ctx, 6}; rb.Push(ResultSuccess); - rb.PushRaw(system.CoreTiming().GetCPUTicks()); - rb.PushRaw(0); + rb.PushRaw(state); } void IRS::RunTeraPluginProcessor(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto camera_handle{rp.PopRaw()}; - const auto processor_config{rp.PopRaw()}; + const auto camera_handle{rp.PopRaw()}; + const auto processor_config{rp.PopRaw()}; const auto applet_resource_user_id{rp.Pop()}; LOG_WARNING(Service_IRS, @@ -196,8 +279,17 @@ void IRS::RunTeraPluginProcessor(Kernel::HLERequestContext& ctx) { processor_config.required_mcu_version.major, processor_config.required_mcu_version.minor, applet_resource_user_id); + const auto result = IsIrCameraHandleValid(camera_handle); + + if (result.IsSuccess()) { + auto& device = GetIrCameraSharedMemoryDeviceEntry(camera_handle); + MakeProcessor(camera_handle, device); + auto& image_transfer_processor = GetProcessor(camera_handle); + image_transfer_processor.SetConfig(processor_config); + } + IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + rb.Push(result); } void IRS::GetNpadIrCameraHandle(Kernel::HLERequestContext& ctx) { @@ -211,13 +303,13 @@ void IRS::GetNpadIrCameraHandle(Kernel::HLERequestContext& ctx) { return; } - IrCameraHandle camera_handle{ + Core::IrSensor::IrCameraHandle camera_handle{ .npad_id = static_cast(NpadIdTypeToIndex(npad_id)), .npad_type = Core::HID::NpadStyleIndex::None, }; - LOG_WARNING(Service_IRS, "(STUBBED) called, npad_id={}, camera_npad_id={}, camera_npad_type={}", - npad_id, camera_handle.npad_id, camera_handle.npad_type); + LOG_INFO(Service_IRS, "called, npad_id={}, camera_npad_id={}, camera_npad_type={}", npad_id, + camera_handle.npad_id, camera_handle.npad_type); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); @@ -226,8 +318,8 @@ void IRS::GetNpadIrCameraHandle(Kernel::HLERequestContext& ctx) { void IRS::RunPointingProcessor(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto camera_handle{rp.PopRaw()}; - const auto processor_config{rp.PopRaw()}; + const auto camera_handle{rp.PopRaw()}; + const auto processor_config{rp.PopRaw()}; const auto applet_resource_user_id{rp.Pop()}; LOG_WARNING( @@ -236,14 +328,23 @@ void IRS::RunPointingProcessor(Kernel::HLERequestContext& ctx) { camera_handle.npad_type, camera_handle.npad_id, processor_config.required_mcu_version.major, processor_config.required_mcu_version.minor, applet_resource_user_id); + auto result = IsIrCameraHandleValid(camera_handle); + + if (result.IsSuccess()) { + auto& device = GetIrCameraSharedMemoryDeviceEntry(camera_handle); + MakeProcessor(camera_handle, device); + auto& image_transfer_processor = GetProcessor(camera_handle); + image_transfer_processor.SetConfig(processor_config); + } + IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + rb.Push(result); } void IRS::SuspendImageProcessor(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - IrCameraHandle camera_handle; + Core::IrSensor::IrCameraHandle camera_handle; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; @@ -256,14 +357,20 @@ void IRS::SuspendImageProcessor(Kernel::HLERequestContext& ctx) { parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, parameters.applet_resource_user_id); + auto result = IsIrCameraHandleValid(parameters.camera_handle); + if (result.IsSuccess()) { + // TODO: Suspend image processor + result = ResultSuccess; + } + IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + rb.Push(result); } void IRS::CheckFirmwareVersion(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto camera_handle{rp.PopRaw()}; - const auto mcu_version{rp.PopRaw()}; + const auto camera_handle{rp.PopRaw()}; + const auto mcu_version{rp.PopRaw()}; const auto applet_resource_user_id{rp.Pop()}; LOG_WARNING( @@ -272,37 +379,45 @@ void IRS::CheckFirmwareVersion(Kernel::HLERequestContext& ctx) { camera_handle.npad_type, camera_handle.npad_id, applet_resource_user_id, mcu_version.major, mcu_version.minor); + auto result = IsIrCameraHandleValid(camera_handle); + if (result.IsSuccess()) { + // TODO: Check firmware version + result = ResultSuccess; + } + IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + rb.Push(result); } void IRS::SetFunctionLevel(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - struct Parameters { - IrCameraHandle camera_handle; - PackedFunctionLevel function_level; - u64 applet_resource_user_id; - }; - static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); + const auto camera_handle{rp.PopRaw()}; + const auto function_level{rp.PopRaw()}; + const auto applet_resource_user_id{rp.Pop()}; - const auto parameters{rp.PopRaw()}; + LOG_WARNING( + Service_IRS, + "(STUBBED) called, npad_type={}, npad_id={}, function_level={}, applet_resource_user_id={}", + camera_handle.npad_type, camera_handle.npad_id, function_level.function_level, + applet_resource_user_id); - LOG_WARNING(Service_IRS, - "(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}", - parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, - parameters.applet_resource_user_id); + auto result = IsIrCameraHandleValid(camera_handle); + if (result.IsSuccess()) { + // TODO: Set Function level + result = ResultSuccess; + } IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + rb.Push(result); } void IRS::RunImageTransferExProcessor(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - IrCameraHandle camera_handle; + Core::IrSensor::IrCameraHandle camera_handle; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; - PackedImageTransferProcessorExConfig processor_config; + Core::IrSensor::PackedImageTransferProcessorExConfig processor_config; u64 transfer_memory_size; }; static_assert(sizeof(Parameters) == 0x38, "Parameters has incorrect size."); @@ -313,20 +428,33 @@ void IRS::RunImageTransferExProcessor(Kernel::HLERequestContext& ctx) { auto t_mem = system.CurrentProcess()->GetHandleTable().GetObject(t_mem_handle); - LOG_WARNING(Service_IRS, - "(STUBBED) called, npad_type={}, npad_id={}, transfer_memory_size={}, " - "applet_resource_user_id={}", - parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, - parameters.transfer_memory_size, parameters.applet_resource_user_id); + u8* transfer_memory = system.Memory().GetPointer(t_mem->GetSourceAddress()); + + LOG_INFO(Service_IRS, + "called, npad_type={}, npad_id={}, transfer_memory_size={}, " + "applet_resource_user_id={}", + parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, + parameters.transfer_memory_size, parameters.applet_resource_user_id); + + auto result = IsIrCameraHandleValid(parameters.camera_handle); + + if (result.IsSuccess()) { + auto& device = GetIrCameraSharedMemoryDeviceEntry(parameters.camera_handle); + MakeProcessorWithCoreContext(parameters.camera_handle, device); + auto& image_transfer_processor = + GetProcessor(parameters.camera_handle); + image_transfer_processor.SetConfig(parameters.processor_config); + image_transfer_processor.SetTransferMemoryPointer(transfer_memory); + } IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + rb.Push(result); } void IRS::RunIrLedProcessor(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto camera_handle{rp.PopRaw()}; - const auto processor_config{rp.PopRaw()}; + const auto camera_handle{rp.PopRaw()}; + const auto processor_config{rp.PopRaw()}; const auto applet_resource_user_id{rp.Pop()}; LOG_WARNING(Service_IRS, @@ -336,14 +464,23 @@ void IRS::RunIrLedProcessor(Kernel::HLERequestContext& ctx) { processor_config.required_mcu_version.major, processor_config.required_mcu_version.minor, applet_resource_user_id); + auto result = IsIrCameraHandleValid(camera_handle); + + if (result.IsSuccess()) { + auto& device = GetIrCameraSharedMemoryDeviceEntry(camera_handle); + MakeProcessor(camera_handle, device); + auto& image_transfer_processor = GetProcessor(camera_handle); + image_transfer_processor.SetConfig(processor_config); + } + IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + rb.Push(result); } void IRS::StopImageProcessorAsync(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - IrCameraHandle camera_handle; + Core::IrSensor::IrCameraHandle camera_handle; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; @@ -356,14 +493,20 @@ void IRS::StopImageProcessorAsync(Kernel::HLERequestContext& ctx) { parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, parameters.applet_resource_user_id); + auto result = IsIrCameraHandleValid(parameters.camera_handle); + if (result.IsSuccess()) { + // TODO: Stop image processor async + result = ResultSuccess; + } + IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + rb.Push(result); } void IRS::ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - PackedFunctionLevel function_level; + Core::IrSensor::PackedFunctionLevel function_level; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; @@ -378,7 +521,22 @@ void IRS::ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx) { rb.Push(ResultSuccess); } -IRS::~IRS() = default; +ResultCode IRS::IsIrCameraHandleValid(const Core::IrSensor::IrCameraHandle& camera_handle) const { + if (camera_handle.npad_id > + static_cast(NpadIdTypeToIndex(Core::HID::NpadIdType::Handheld))) { + return InvalidIrCameraHandle; + } + if (camera_handle.npad_type != Core::HID::NpadStyleIndex::None) { + return InvalidIrCameraHandle; + } + return ResultSuccess; +} + +Core::IrSensor::DeviceFormat& IRS::GetIrCameraSharedMemoryDeviceEntry( + const Core::IrSensor::IrCameraHandle& camera_handle) { + ASSERT_MSG(sizeof(StatusManager::device) > camera_handle.npad_id, "invalid npad_id"); + return shared_memory->device[camera_handle.npad_id]; +} IRS_SYS::IRS_SYS(Core::System& system_) : ServiceFramework{system_, "irs:sys"} { // clang-format off diff --git a/src/core/hle/service/hid/irs.h b/src/core/hle/service/hid/irs.h index 361dc2213..ae7f7719b 100644 --- a/src/core/hle/service/hid/irs.h +++ b/src/core/hle/service/hid/irs.h @@ -4,12 +4,18 @@ #pragma once #include "core/hid/hid_types.h" +#include "core/hid/irs_types.h" +#include "core/hle/service/hid/irsensor/processor_base.h" #include "core/hle/service/service.h" namespace Core { class System; } +namespace Core::HID { +class EmulatedController; +} // namespace Core::HID + namespace Service::HID { class IRS final : public ServiceFramework { @@ -18,234 +24,19 @@ public: ~IRS() override; private: - // This is nn::irsensor::IrCameraStatus - enum IrCameraStatus : u32 { - Available, - Unsupported, - Unconnected, + // This is nn::irsensor::detail::AruidFormat + struct AruidFormat { + u64 sensor_aruid; + u64 sensor_aruid_status; }; + static_assert(sizeof(AruidFormat) == 0x10, "AruidFormat is an invalid size"); - // This is nn::irsensor::IrCameraInternalStatus - enum IrCameraInternalStatus : u32 { - Stopped, - FirmwareUpdateNeeded, - Unkown2, - Unkown3, - Unkown4, - FirmwareVersionRequested, - FirmwareVersionIsInvalid, - Ready, - Setting, + // This is nn::irsensor::detail::StatusManager + struct StatusManager { + std::array device; + std::array aruid; }; - - // This is nn::irsensor::detail::StatusManager::IrSensorMode - enum IrSensorMode : u64 { - None, - MomentProcessor, - ClusteringProcessor, - ImageTransferProcessor, - PointingProcessorMarker, - TeraPluginProcessor, - IrLedProcessor, - }; - - // This is nn::irsensor::ImageProcessorStatus - enum ImageProcessorStatus : u8 { - stopped, - running, - }; - - // This is nn::irsensor::ImageTransferProcessorFormat - enum ImageTransferProcessorFormat : u8 { - Size320x240, - Size160x120, - Size80x60, - Size40x30, - Size20x15, - }; - - // This is nn::irsensor::AdaptiveClusteringMode - enum AdaptiveClusteringMode : u8 { - StaticFov, - DynamicFov, - }; - - // This is nn::irsensor::AdaptiveClusteringTargetDistance - enum AdaptiveClusteringTargetDistance : u8 { - Near, - Middle, - Far, - }; - - // This is nn::irsensor::IrsHandAnalysisMode - enum IrsHandAnalysisMode : u8 { - Silhouette, - Image, - SilhoueteAndImage, - SilhuetteOnly, - }; - - // This is nn::irsensor::IrSensorFunctionLevel - enum IrSensorFunctionLevel : u8 { - unknown0, - unknown1, - unknown2, - unknown3, - unknown4, - }; - - // This is nn::irsensor::IrCameraHandle - struct IrCameraHandle { - u8 npad_id{}; - Core::HID::NpadStyleIndex npad_type{Core::HID::NpadStyleIndex::None}; - INSERT_PADDING_BYTES(2); - }; - static_assert(sizeof(IrCameraHandle) == 4, "IrCameraHandle is an invalid size"); - - struct IrsRect { - s16 x; - s16 y; - s16 width; - s16 height; - }; - - // This is nn::irsensor::PackedMcuVersion - struct PackedMcuVersion { - u16 major; - u16 minor; - }; - static_assert(sizeof(PackedMcuVersion) == 4, "PackedMcuVersion is an invalid size"); - - // This is nn::irsensor::MomentProcessorConfig - struct MomentProcessorConfig { - u64 exposire_time; - u8 light_target; - u8 gain; - u8 is_negative_used; - INSERT_PADDING_BYTES(7); - IrsRect window_of_interest; - u8 preprocess; - u8 preprocess_intensity_threshold; - INSERT_PADDING_BYTES(5); - }; - static_assert(sizeof(MomentProcessorConfig) == 0x28, - "MomentProcessorConfig is an invalid size"); - - // This is nn::irsensor::PackedMomentProcessorConfig - struct PackedMomentProcessorConfig { - u64 exposire_time; - u8 light_target; - u8 gain; - u8 is_negative_used; - INSERT_PADDING_BYTES(5); - IrsRect window_of_interest; - PackedMcuVersion required_mcu_version; - u8 preprocess; - u8 preprocess_intensity_threshold; - INSERT_PADDING_BYTES(2); - }; - static_assert(sizeof(PackedMomentProcessorConfig) == 0x20, - "PackedMomentProcessorConfig is an invalid size"); - - // This is nn::irsensor::ClusteringProcessorConfig - struct ClusteringProcessorConfig { - u64 exposire_time; - u32 light_target; - u32 gain; - u8 is_negative_used; - INSERT_PADDING_BYTES(7); - IrsRect window_of_interest; - u32 pixel_count_min; - u32 pixel_count_max; - u32 object_intensity_min; - u8 is_external_light_filter_enabled; - INSERT_PADDING_BYTES(3); - }; - static_assert(sizeof(ClusteringProcessorConfig) == 0x30, - "ClusteringProcessorConfig is an invalid size"); - - // This is nn::irsensor::PackedClusteringProcessorConfig - struct PackedClusteringProcessorConfig { - u64 exposire_time; - u8 light_target; - u8 gain; - u8 is_negative_used; - INSERT_PADDING_BYTES(5); - IrsRect window_of_interest; - PackedMcuVersion required_mcu_version; - u32 pixel_count_min; - u32 pixel_count_max; - u32 object_intensity_min; - u8 is_external_light_filter_enabled; - INSERT_PADDING_BYTES(2); - }; - static_assert(sizeof(PackedClusteringProcessorConfig) == 0x30, - "PackedClusteringProcessorConfig is an invalid size"); - - // This is nn::irsensor::PackedImageTransferProcessorConfig - struct PackedImageTransferProcessorConfig { - u64 exposire_time; - u8 light_target; - u8 gain; - u8 is_negative_used; - INSERT_PADDING_BYTES(5); - PackedMcuVersion required_mcu_version; - u8 format; - INSERT_PADDING_BYTES(3); - }; - static_assert(sizeof(PackedImageTransferProcessorConfig) == 0x18, - "PackedImageTransferProcessorConfig is an invalid size"); - - // This is nn::irsensor::PackedTeraPluginProcessorConfig - struct PackedTeraPluginProcessorConfig { - PackedMcuVersion required_mcu_version; - u8 mode; - INSERT_PADDING_BYTES(3); - }; - static_assert(sizeof(PackedTeraPluginProcessorConfig) == 0x8, - "PackedTeraPluginProcessorConfig is an invalid size"); - - // This is nn::irsensor::PackedPointingProcessorConfig - struct PackedPointingProcessorConfig { - IrsRect window_of_interest; - PackedMcuVersion required_mcu_version; - }; - static_assert(sizeof(PackedPointingProcessorConfig) == 0xC, - "PackedPointingProcessorConfig is an invalid size"); - - // This is nn::irsensor::PackedFunctionLevel - struct PackedFunctionLevel { - IrSensorFunctionLevel function_level; - INSERT_PADDING_BYTES(3); - }; - static_assert(sizeof(PackedFunctionLevel) == 0x4, "PackedFunctionLevel is an invalid size"); - - // This is nn::irsensor::PackedImageTransferProcessorExConfig - struct PackedImageTransferProcessorExConfig { - u64 exposire_time; - u8 light_target; - u8 gain; - u8 is_negative_used; - INSERT_PADDING_BYTES(5); - PackedMcuVersion required_mcu_version; - ImageTransferProcessorFormat origin_format; - ImageTransferProcessorFormat trimming_format; - u16 trimming_start_x; - u16 trimming_start_y; - u8 is_external_light_filter_enabled; - INSERT_PADDING_BYTES(3); - }; - static_assert(sizeof(PackedImageTransferProcessorExConfig) == 0x20, - "PackedImageTransferProcessorExConfig is an invalid size"); - - // This is nn::irsensor::PackedIrLedProcessorConfig - struct PackedIrLedProcessorConfig { - PackedMcuVersion required_mcu_version; - u8 light_target; - INSERT_PADDING_BYTES(3); - }; - static_assert(sizeof(PackedIrLedProcessorConfig) == 0x8, - "PackedIrLedProcessorConfig is an invalid size"); + static_assert(sizeof(StatusManager) == 0x8000, "StatusManager is an invalid size"); void ActivateIrsensor(Kernel::HLERequestContext& ctx); void DeactivateIrsensor(Kernel::HLERequestContext& ctx); @@ -265,6 +56,56 @@ private: void RunIrLedProcessor(Kernel::HLERequestContext& ctx); void StopImageProcessorAsync(Kernel::HLERequestContext& ctx); void ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx); + + ResultCode IsIrCameraHandleValid(const Core::IrSensor::IrCameraHandle& camera_handle) const; + Core::IrSensor::DeviceFormat& GetIrCameraSharedMemoryDeviceEntry( + const Core::IrSensor::IrCameraHandle& camera_handle); + + template + void MakeProcessor(const Core::IrSensor::IrCameraHandle& handle, + Core::IrSensor::DeviceFormat& device_state) { + const auto index = static_cast(handle.npad_id); + if (index > sizeof(processors)) { + LOG_CRITICAL(Service_IRS, "Invalid index {}", index); + return; + } + processors[index] = std::make_unique(device_state); + } + + template + void MakeProcessorWithCoreContext(const Core::IrSensor::IrCameraHandle& handle, + Core::IrSensor::DeviceFormat& device_state) { + const auto index = static_cast(handle.npad_id); + if (index > sizeof(processors)) { + LOG_CRITICAL(Service_IRS, "Invalid index {}", index); + return; + } + processors[index] = std::make_unique(system.HIDCore(), device_state, index); + } + + template + T& GetProcessor(const Core::IrSensor::IrCameraHandle& handle) { + const auto index = static_cast(handle.npad_id); + if (index > sizeof(processors)) { + LOG_CRITICAL(Service_IRS, "Invalid index {}", index); + return static_cast(*processors[0]); + } + return static_cast(*processors[index]); + } + + template + const T& GetProcessor(const Core::IrSensor::IrCameraHandle& handle) const { + const auto index = static_cast(handle.npad_id); + if (index > sizeof(processors)) { + LOG_CRITICAL(Service_IRS, "Invalid index {}", index); + return static_cast(*processors[0]); + } + return static_cast(*processors[index]); + } + + Core::HID::EmulatedController* npad_device = nullptr; + StatusManager* shared_memory = nullptr; + std::array, 9> processors{}; }; class IRS_SYS final : public ServiceFramework { 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..aac3e4fec --- /dev/null +++ b/src/core/hle/service/hid/irsensor/clustering_processor.cpp @@ -0,0 +1,36 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "core/hle/service/hid/irsensor/clustering_processor.h" + +namespace Service::HID { +ClusteringProcessor::ClusteringProcessor(Core::IrSensor::DeviceFormat& device_format) + : device(device_format) { + device.mode = Core::IrSensor::IrSensorMode::ClusteringProcessor; + device.camera_status = Core::IrSensor::IrCameraStatus::Unconnected; + device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Stopped; + device.state.start = 0; + device.state.count = 0; +} + +ClusteringProcessor::~ClusteringProcessor() = default; + +void ClusteringProcessor::StartProcessor() {} + +void ClusteringProcessor::SuspendProcessor() {} + +void ClusteringProcessor::StopProcessor() {} + +void ClusteringProcessor::SetConfig(Core::IrSensor::PackedClusteringProcessorConfig config) { + current_config.camera_config.exposure_time = config.camera_config.exposure_time; + current_config.camera_config.gain = config.camera_config.gain; + current_config.camera_config.is_negative_used = config.camera_config.is_negative_used; + current_config.camera_config.light_target = + static_cast(config.camera_config.light_target); + current_config.pixel_count_min = config.pixel_count_min; + current_config.pixel_count_max = config.pixel_count_max; + current_config.is_external_light_filter_enabled = config.is_external_light_filter_enabled; + current_config.object_intensity_min = config.object_intensity_min; +} + +} // namespace Service::HID 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..58b2acf1c --- /dev/null +++ b/src/core/hle/service/hid/irsensor/clustering_processor.h @@ -0,0 +1,74 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "common/common_types.h" +#include "core/hid/irs_types.h" +#include "core/hle/service/hid/irsensor/processor_base.h" + +namespace Service::HID { +class ClusteringProcessor final : public ProcessorBase { +public: + explicit ClusteringProcessor(Core::IrSensor::DeviceFormat& device_format); + ~ClusteringProcessor() override; + + // Called when the processor is initialized + void StartProcessor() override; + + // Called when the processor is suspended + void SuspendProcessor() override; + + // Called when the processor is stopped + void StopProcessor() override; + + // Sets config parameters of the camera + void SetConfig(Core::IrSensor::PackedClusteringProcessorConfig config); + +private: + // This is nn::irsensor::ClusteringProcessorConfig + struct ClusteringProcessorConfig { + Core::IrSensor::CameraConfig camera_config; + Core::IrSensor::IrsRect window_of_interest; + u32 pixel_count_min; + u32 pixel_count_max; + u32 object_intensity_min; + bool is_external_light_filter_enabled; + INSERT_PADDING_BYTES(3); + }; + static_assert(sizeof(ClusteringProcessorConfig) == 0x30, + "ClusteringProcessorConfig is an invalid size"); + + // This is nn::irsensor::AdaptiveClusteringProcessorConfig + struct AdaptiveClusteringProcessorConfig { + Core::IrSensor::AdaptiveClusteringMode mode; + Core::IrSensor::AdaptiveClusteringTargetDistance target_distance; + }; + static_assert(sizeof(AdaptiveClusteringProcessorConfig) == 0x8, + "AdaptiveClusteringProcessorConfig is an invalid size"); + + // This is nn::irsensor::ClusteringData + struct ClusteringData { + f32 average_intensity; + Core::IrSensor::IrsCentroid centroid; + u32 pixel_count; + Core::IrSensor::IrsRect bound; + }; + static_assert(sizeof(ClusteringData) == 0x18, "ClusteringData is an invalid size"); + + // This is nn::irsensor::ClusteringProcessorState + struct ClusteringProcessorState { + s64 sampling_number; + u64 timestamp; + u8 object_count; + INSERT_PADDING_BYTES(3); + Core::IrSensor::CameraAmbientNoiseLevel ambient_noise_level; + std::array data; + }; + static_assert(sizeof(ClusteringProcessorState) == 0x198, + "ClusteringProcessorState is an invalid size"); + + ClusteringProcessorConfig current_config{}; + Core::IrSensor::DeviceFormat& device; +}; +} // namespace Service::HID 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..703e825e6 --- /dev/null +++ b/src/core/hle/service/hid/irsensor/image_transfer_processor.cpp @@ -0,0 +1,154 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "core/hid/emulated_controller.h" +#include "core/hid/hid_core.h" +#include "core/hle/service/hid/irsensor/image_transfer_processor.h" + +namespace Service::HID { +ImageTransferProcessor::ImageTransferProcessor(Core::HID::HIDCore& hid_core_, + Core::IrSensor::DeviceFormat& device_format, + std::size_t npad_index) + : device{device_format} { + npad_device = hid_core_.GetEmulatedControllerByIndex(npad_index); + + Core::HID::ControllerUpdateCallback engine_callback{ + .on_change = [this](Core::HID::ControllerTriggerType type) { OnControllerUpdate(type); }, + .is_npad_service = true, + }; + callback_key = npad_device->SetCallback(engine_callback); + + device.mode = Core::IrSensor::IrSensorMode::ImageTransferProcessor; + device.camera_status = Core::IrSensor::IrCameraStatus::Unconnected; + device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Stopped; + device.state.start = 0; + device.state.count = 0; +} + +ImageTransferProcessor::~ImageTransferProcessor() { + npad_device->DeleteCallback(callback_key); +}; + +void ImageTransferProcessor::StartProcessor() { + is_active = true; + device.camera_status = Core::IrSensor::IrCameraStatus::Available; + device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Ready; + device.state.start = 0; + device.state.count = 1; + processor_state.sampling_number = 0; + processor_state.ambient_noise_level = Core::IrSensor::CameraAmbientNoiseLevel::Low; +} + +void ImageTransferProcessor::SuspendProcessor() {} + +void ImageTransferProcessor::StopProcessor() {} + +void ImageTransferProcessor::OnControllerUpdate(Core::HID::ControllerTriggerType type) { + if (type != Core::HID::ControllerTriggerType::IrSensor) { + return; + } + if (!is_transfer_memory_set) { + return; + } + + const auto camera_data = npad_device->GetCamera(); + + // This indicates how much ambient light is precent + processor_state.ambient_noise_level = Core::IrSensor::CameraAmbientNoiseLevel::Low; + processor_state.sampling_number = camera_data.sample; + + if (camera_data.format != current_config.origin_format) { + LOG_WARNING(Service_IRS, "Wrong Input format {} expected {}", camera_data.format, + current_config.origin_format); + memset(transfer_memory, 0, GetDataSize(current_config.trimming_format)); + return; + } + + if (current_config.origin_format > current_config.trimming_format) { + LOG_WARNING(Service_IRS, "Origin format {} is smaller than trimming format {}", + current_config.origin_format, current_config.trimming_format); + memset(transfer_memory, 0, GetDataSize(current_config.trimming_format)); + return; + } + + std::vector window_data{}; + const auto origin_width = GetDataWidth(current_config.origin_format); + const auto origin_height = GetDataHeight(current_config.origin_format); + const auto trimming_width = GetDataWidth(current_config.trimming_format); + const auto trimming_height = GetDataHeight(current_config.trimming_format); + window_data.resize(GetDataSize(current_config.trimming_format)); + + if (trimming_width + current_config.trimming_start_x > origin_width || + trimming_height + current_config.trimming_start_y > origin_height) { + LOG_WARNING(Service_IRS, + "Trimming area ({}, {}, {}, {}) is outside of origin area ({}, {})", + current_config.trimming_start_x, current_config.trimming_start_y, + trimming_width, trimming_height, origin_width, origin_height); + memset(transfer_memory, 0, GetDataSize(current_config.trimming_format)); + return; + } + + for (std::size_t y = 0; y < trimming_height; y++) { + for (std::size_t x = 0; x < trimming_width; x++) { + const std::size_t window_index = (y * trimming_width) + x; + const std::size_t origin_index = + ((y + current_config.trimming_start_y) * origin_width) + x + + current_config.trimming_start_x; + window_data[window_index] = camera_data.data[origin_index]; + } + } + + memcpy(transfer_memory, window_data.data(), GetDataSize(current_config.trimming_format)); + + if (!IsProcessorActive()) { + StartProcessor(); + } +} + +void ImageTransferProcessor::SetConfig(Core::IrSensor::PackedImageTransferProcessorConfig config) { + current_config.camera_config.exposure_time = config.camera_config.exposure_time; + current_config.camera_config.gain = config.camera_config.gain; + current_config.camera_config.is_negative_used = config.camera_config.is_negative_used; + current_config.camera_config.light_target = + static_cast(config.camera_config.light_target); + current_config.origin_format = + static_cast(config.format); + current_config.trimming_format = + static_cast(config.format); + current_config.trimming_start_x = 0; + current_config.trimming_start_y = 0; + + npad_device->SetCameraFormat(current_config.origin_format); +} + +void ImageTransferProcessor::SetConfig( + Core::IrSensor::PackedImageTransferProcessorExConfig config) { + current_config.camera_config.exposure_time = config.camera_config.exposure_time; + current_config.camera_config.gain = config.camera_config.gain; + current_config.camera_config.is_negative_used = config.camera_config.is_negative_used; + current_config.camera_config.light_target = + static_cast(config.camera_config.light_target); + current_config.origin_format = + static_cast(config.origin_format); + current_config.trimming_format = + static_cast(config.trimming_format); + current_config.trimming_start_x = config.trimming_start_x; + current_config.trimming_start_y = config.trimming_start_y; + + npad_device->SetCameraFormat(current_config.origin_format); +} + +void ImageTransferProcessor::SetTransferMemoryPointer(u8* t_mem) { + is_transfer_memory_set = true; + transfer_memory = t_mem; +} + +Core::IrSensor::ImageTransferProcessorState ImageTransferProcessor::GetState( + std::vector& data) const { + const auto size = GetDataSize(current_config.trimming_format); + data.resize(size); + memcpy(data.data(), transfer_memory, size); + return processor_state; +} + +} // namespace Service::HID 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..b557eaf20 --- /dev/null +++ b/src/core/hle/service/hid/irsensor/image_transfer_processor.h @@ -0,0 +1,73 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "common/common_types.h" +#include "core/hid/irs_types.h" +#include "core/hle/service/hid/irsensor/processor_base.h" + +namespace Core::HID { +class EmulatedController; +} // namespace Core::HID + +namespace Service::HID { +class ImageTransferProcessor final : public ProcessorBase { +public: + explicit ImageTransferProcessor(Core::HID::HIDCore& hid_core_, + Core::IrSensor::DeviceFormat& device_format, + std::size_t npad_index); + ~ImageTransferProcessor() override; + + // Called when the processor is initialized + void StartProcessor() override; + + // Called when the processor is suspended + void SuspendProcessor() override; + + // Called when the processor is stopped + void StopProcessor() override; + + // Sets config parameters of the camera + void SetConfig(Core::IrSensor::PackedImageTransferProcessorConfig config); + void SetConfig(Core::IrSensor::PackedImageTransferProcessorExConfig config); + + // Transfer memory where the image data will be stored + void SetTransferMemoryPointer(u8* t_mem); + + Core::IrSensor::ImageTransferProcessorState GetState(std::vector& data) const; + +private: + // This is nn::irsensor::ImageTransferProcessorConfig + struct ImageTransferProcessorConfig { + Core::IrSensor::CameraConfig camera_config; + Core::IrSensor::ImageTransferProcessorFormat format; + }; + static_assert(sizeof(ImageTransferProcessorConfig) == 0x20, + "ImageTransferProcessorConfig is an invalid size"); + + // This is nn::irsensor::ImageTransferProcessorExConfig + struct ImageTransferProcessorExConfig { + Core::IrSensor::CameraConfig camera_config; + Core::IrSensor::ImageTransferProcessorFormat origin_format; + Core::IrSensor::ImageTransferProcessorFormat trimming_format; + u16 trimming_start_x; + u16 trimming_start_y; + bool is_external_light_filter_enabled; + INSERT_PADDING_BYTES(3); + }; + static_assert(sizeof(ImageTransferProcessorExConfig) == 0x28, + "ImageTransferProcessorExConfig is an invalid size"); + + void OnControllerUpdate(Core::HID::ControllerTriggerType type); + + ImageTransferProcessorExConfig current_config{}; + Core::IrSensor::ImageTransferProcessorState processor_state{}; + Core::IrSensor::DeviceFormat& device; + Core::HID::EmulatedController* npad_device; + int callback_key{}; + + u8* transfer_memory = nullptr; + bool is_transfer_memory_set = false; +}; +} // namespace Service::HID 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..656e17c95 --- /dev/null +++ b/src/core/hle/service/hid/irsensor/ir_led_processor.cpp @@ -0,0 +1,29 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "core/hle/service/hid/irsensor/ir_led_processor.h" + +namespace Service::HID { +IrLedProcessor::IrLedProcessor(Core::IrSensor::DeviceFormat& device_format) + : device(device_format) { + device.mode = Core::IrSensor::IrSensorMode::IrLedProcessor; + device.camera_status = Core::IrSensor::IrCameraStatus::Unconnected; + device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Stopped; + device.state.start = 0; + device.state.count = 0; +} + +IrLedProcessor::~IrLedProcessor() = default; + +void IrLedProcessor::StartProcessor() {} + +void IrLedProcessor::SuspendProcessor() {} + +void IrLedProcessor::StopProcessor() {} + +void IrLedProcessor::SetConfig(Core::IrSensor::PackedIrLedProcessorConfig config) { + current_config.light_target = + static_cast(config.light_target); +} + +} // namespace Service::HID 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..cb04d0b94 --- /dev/null +++ b/src/core/hle/service/hid/irsensor/ir_led_processor.h @@ -0,0 +1,47 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "common/bit_field.h" +#include "common/common_types.h" +#include "core/hid/irs_types.h" +#include "core/hle/service/hid/irsensor/processor_base.h" + +namespace Service::HID { +class IrLedProcessor final : public ProcessorBase { +public: + explicit IrLedProcessor(Core::IrSensor::DeviceFormat& device_format); + ~IrLedProcessor() override; + + // Called when the processor is initialized + void StartProcessor() override; + + // Called when the processor is suspended + void SuspendProcessor() override; + + // Called when the processor is stopped + void StopProcessor() override; + + // Sets config parameters of the camera + void SetConfig(Core::IrSensor::PackedIrLedProcessorConfig config); + +private: + // This is nn::irsensor::IrLedProcessorConfig + struct IrLedProcessorConfig { + Core::IrSensor::CameraLightTarget light_target; + }; + static_assert(sizeof(IrLedProcessorConfig) == 0x4, "IrLedProcessorConfig is an invalid size"); + + struct IrLedProcessorState { + s64 sampling_number; + u64 timestamp; + std::array data; + }; + static_assert(sizeof(IrLedProcessorState) == 0x18, "IrLedProcessorState is an invalid size"); + + IrLedProcessorConfig current_config{}; + Core::IrSensor::DeviceFormat& device; +}; + +} // namespace Service::HID 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..fb36be577 --- /dev/null +++ b/src/core/hle/service/hid/irsensor/moment_processor.cpp @@ -0,0 +1,36 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "core/hle/service/hid/irsensor/moment_processor.h" + +namespace Service::HID { +MomentProcessor::MomentProcessor(Core::IrSensor::DeviceFormat& device_format) + : device(device_format) { + device.mode = Core::IrSensor::IrSensorMode::MomentProcessor; + device.camera_status = Core::IrSensor::IrCameraStatus::Unconnected; + device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Stopped; + device.state.start = 0; + device.state.count = 0; +} + +MomentProcessor::~MomentProcessor() = default; + +void MomentProcessor::StartProcessor() {} + +void MomentProcessor::SuspendProcessor() {} + +void MomentProcessor::StopProcessor() {} + +void MomentProcessor::SetConfig(Core::IrSensor::PackedMomentProcessorConfig config) { + current_config.camera_config.exposure_time = config.camera_config.exposure_time; + current_config.camera_config.gain = config.camera_config.gain; + current_config.camera_config.is_negative_used = config.camera_config.is_negative_used; + current_config.camera_config.light_target = + static_cast(config.camera_config.light_target); + current_config.window_of_interest = config.window_of_interest; + current_config.preprocess = + static_cast(config.preprocess); + current_config.preprocess_intensity_threshold = config.preprocess_intensity_threshold; +} + +} // namespace Service::HID 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..63cdadfda --- /dev/null +++ b/src/core/hle/service/hid/irsensor/moment_processor.h @@ -0,0 +1,61 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "common/bit_field.h" +#include "common/common_types.h" +#include "core/hid/irs_types.h" +#include "core/hle/service/hid/irsensor/processor_base.h" + +namespace Service::HID { +class MomentProcessor final : public ProcessorBase { +public: + explicit MomentProcessor(Core::IrSensor::DeviceFormat& device_format); + ~MomentProcessor() override; + + // Called when the processor is initialized + void StartProcessor() override; + + // Called when the processor is suspended + void SuspendProcessor() override; + + // Called when the processor is stopped + void StopProcessor() override; + + // Sets config parameters of the camera + void SetConfig(Core::IrSensor::PackedMomentProcessorConfig config); + +private: + // This is nn::irsensor::MomentProcessorConfig + struct MomentProcessorConfig { + Core::IrSensor::CameraConfig camera_config; + Core::IrSensor::IrsRect window_of_interest; + Core::IrSensor::MomentProcessorPreprocess preprocess; + u32 preprocess_intensity_threshold; + }; + static_assert(sizeof(MomentProcessorConfig) == 0x28, + "MomentProcessorConfig is an invalid size"); + + // This is nn::irsensor::MomentStatistic + struct MomentStatistic { + f32 average_intensity; + Core::IrSensor::IrsCentroid centroid; + }; + static_assert(sizeof(MomentStatistic) == 0xC, "MomentStatistic is an invalid size"); + + // This is nn::irsensor::MomentProcessorState + struct MomentProcessorState { + s64 sampling_number; + u64 timestamp; + Core::IrSensor::CameraAmbientNoiseLevel ambient_noise_level; + INSERT_PADDING_BYTES(4); + std::array stadistic; + }; + static_assert(sizeof(MomentProcessorState) == 0x258, "MomentProcessorState is an invalid size"); + + MomentProcessorConfig current_config{}; + Core::IrSensor::DeviceFormat& device; +}; + +} // namespace Service::HID 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..7eb123636 --- /dev/null +++ b/src/core/hle/service/hid/irsensor/pointing_processor.cpp @@ -0,0 +1,28 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "core/hle/service/hid/irsensor/pointing_processor.h" + +namespace Service::HID { +PointingProcessor::PointingProcessor(Core::IrSensor::DeviceFormat& device_format) + : device(device_format) { + device.mode = Core::IrSensor::IrSensorMode::PointingProcessorMarker; + device.camera_status = Core::IrSensor::IrCameraStatus::Unconnected; + device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Stopped; + device.state.start = 0; + device.state.count = 0; +} + +PointingProcessor::~PointingProcessor() = default; + +void PointingProcessor::StartProcessor() {} + +void PointingProcessor::SuspendProcessor() {} + +void PointingProcessor::StopProcessor() {} + +void PointingProcessor::SetConfig(Core::IrSensor::PackedPointingProcessorConfig config) { + current_config.window_of_interest = config.window_of_interest; +} + +} // namespace Service::HID 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..2f67eff91 --- /dev/null +++ b/src/core/hle/service/hid/irsensor/pointing_processor.h @@ -0,0 +1,62 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "common/bit_field.h" +#include "common/common_types.h" +#include "core/hid/irs_types.h" +#include "core/hle/service/hid/irsensor/processor_base.h" + +namespace Service::HID { +class PointingProcessor final : public ProcessorBase { +public: + explicit PointingProcessor(Core::IrSensor::DeviceFormat& device_format); + ~PointingProcessor() override; + + // Called when the processor is initialized + void StartProcessor() override; + + // Called when the processor is suspended + void SuspendProcessor() override; + + // Called when the processor is stopped + void StopProcessor() override; + + // Sets config parameters of the camera + void SetConfig(Core::IrSensor::PackedPointingProcessorConfig config); + +private: + // This is nn::irsensor::PointingProcessorConfig + struct PointingProcessorConfig { + Core::IrSensor::IrsRect window_of_interest; + }; + static_assert(sizeof(PointingProcessorConfig) == 0x8, + "PointingProcessorConfig is an invalid size"); + + struct PointingProcessorMarkerData { + u8 pointing_status; + INSERT_PADDING_BYTES(3); + u32 unknown; + float unkown_float1; + float position_x; + float position_y; + float unkown_float2; + Core::IrSensor::IrsRect window_of_interest; + }; + static_assert(sizeof(PointingProcessorMarkerData) == 0x20, + "PointingProcessorMarkerData is an invalid size"); + + struct PointingProcessorMarkerState { + s64 sampling_number; + u64 timestamp; + std::array data; + }; + static_assert(sizeof(PointingProcessorMarkerState) == 0x70, + "PointingProcessorMarkerState is an invalid size"); + + PointingProcessorConfig current_config{}; + Core::IrSensor::DeviceFormat& device; +}; + +} // namespace Service::HID 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..bc8025375 --- /dev/null +++ b/src/core/hle/service/hid/irsensor/processor_base.cpp @@ -0,0 +1,67 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "core/hle/service/hid/irsensor/processor_base.h" + +namespace Service::HID { + +ProcessorBase::ProcessorBase() {} +ProcessorBase::~ProcessorBase() = default; + +bool ProcessorBase::IsProcessorActive() const { + return is_active; +} + +std::size_t ProcessorBase::GetDataSize(Core::IrSensor::ImageTransferProcessorFormat format) const { + switch (format) { + case Core::IrSensor::ImageTransferProcessorFormat::Size320x240: + return 320 * 240; + case Core::IrSensor::ImageTransferProcessorFormat::Size160x120: + return 160 * 120; + case Core::IrSensor::ImageTransferProcessorFormat::Size80x60: + return 80 * 60; + case Core::IrSensor::ImageTransferProcessorFormat::Size40x30: + return 40 * 30; + case Core::IrSensor::ImageTransferProcessorFormat::Size20x15: + return 20 * 15; + default: + return 0; + } +} + +std::size_t ProcessorBase::GetDataWidth(Core::IrSensor::ImageTransferProcessorFormat format) const { + switch (format) { + case Core::IrSensor::ImageTransferProcessorFormat::Size320x240: + return 320; + case Core::IrSensor::ImageTransferProcessorFormat::Size160x120: + return 160; + case Core::IrSensor::ImageTransferProcessorFormat::Size80x60: + return 80; + case Core::IrSensor::ImageTransferProcessorFormat::Size40x30: + return 40; + case Core::IrSensor::ImageTransferProcessorFormat::Size20x15: + return 20; + default: + return 0; + } +} + +std::size_t ProcessorBase::GetDataHeight( + Core::IrSensor::ImageTransferProcessorFormat format) const { + switch (format) { + case Core::IrSensor::ImageTransferProcessorFormat::Size320x240: + return 240; + case Core::IrSensor::ImageTransferProcessorFormat::Size160x120: + return 120; + case Core::IrSensor::ImageTransferProcessorFormat::Size80x60: + return 60; + case Core::IrSensor::ImageTransferProcessorFormat::Size40x30: + return 30; + case Core::IrSensor::ImageTransferProcessorFormat::Size20x15: + return 15; + default: + return 0; + } +} + +} // namespace Service::HID 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..49831aab6 --- /dev/null +++ b/src/core/hle/service/hid/irsensor/processor_base.h @@ -0,0 +1,33 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "common/common_types.h" +#include "core/hid/irs_types.h" + +namespace Service::HID { +class ProcessorBase { +public: + explicit ProcessorBase(); + virtual ~ProcessorBase(); + + virtual void StartProcessor() = 0; + virtual void SuspendProcessor() = 0; + virtual void StopProcessor() = 0; + + bool IsProcessorActive() const; + +protected: + /// Returns the number of bytes the image uses + std::size_t GetDataSize(Core::IrSensor::ImageTransferProcessorFormat format) const; + + /// Returns the width of the image + std::size_t GetDataWidth(Core::IrSensor::ImageTransferProcessorFormat format) const; + + /// Returns the height of the image + std::size_t GetDataHeight(Core::IrSensor::ImageTransferProcessorFormat format) const; + + bool is_active{false}; +}; +} // namespace Service::HID 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..deec22072 --- /dev/null +++ b/src/core/hle/service/hid/irsensor/tera_plugin_processor.cpp @@ -0,0 +1,31 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "core/hle/service/hid/irsensor/tera_plugin_processor.h" + +namespace Service::HID { +TeraPluginProcessor::TeraPluginProcessor(Core::IrSensor::DeviceFormat& device_format) + : device(device_format) { + device.mode = Core::IrSensor::IrSensorMode::TeraPluginProcessor; + device.camera_status = Core::IrSensor::IrCameraStatus::Unconnected; + device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Stopped; + device.state.start = 0; + device.state.count = 0; +} + +TeraPluginProcessor::~TeraPluginProcessor() = default; + +void TeraPluginProcessor::StartProcessor() {} + +void TeraPluginProcessor::SuspendProcessor() {} + +void TeraPluginProcessor::StopProcessor() {} + +void TeraPluginProcessor::SetConfig(Core::IrSensor::PackedTeraPluginProcessorConfig config) { + current_config.mode = config.mode; + current_config.unknown_1 = config.unknown_1; + current_config.unknown_2 = config.unknown_2; + current_config.unknown_3 = config.unknown_3; +} + +} // namespace Service::HID 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..60f8057a5 --- /dev/null +++ b/src/core/hle/service/hid/irsensor/tera_plugin_processor.h @@ -0,0 +1,53 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "common/bit_field.h" +#include "common/common_types.h" +#include "core/hid/irs_types.h" +#include "core/hle/service/hid/irsensor/processor_base.h" + +namespace Service::HID { +class TeraPluginProcessor final : public ProcessorBase { +public: + explicit TeraPluginProcessor(Core::IrSensor::DeviceFormat& device_format); + ~TeraPluginProcessor() override; + + // Called when the processor is initialized + void StartProcessor() override; + + // Called when the processor is suspended + void SuspendProcessor() override; + + // Called when the processor is stopped + void StopProcessor() override; + + // Sets config parameters of the camera + void SetConfig(Core::IrSensor::PackedTeraPluginProcessorConfig config); + +private: + // This is nn::irsensor::TeraPluginProcessorConfig + struct TeraPluginProcessorConfig { + u8 mode; + u8 unknown_1; + u8 unknown_2; + u8 unknown_3; + }; + static_assert(sizeof(TeraPluginProcessorConfig) == 0x4, + "TeraPluginProcessorConfig is an invalid size"); + + struct TeraPluginProcessorState { + s64 sampling_number; + u64 timestamp; + Core::IrSensor::CameraAmbientNoiseLevel ambient_noise_level; + std::array data; + }; + static_assert(sizeof(TeraPluginProcessorState) == 0x140, + "TeraPluginProcessorState is an invalid size"); + + TeraPluginProcessorConfig current_config{}; + Core::IrSensor::DeviceFormat& device; +}; + +} // namespace Service::HID From 097785e19e3865ac1060b9fae564a3a1e36c695d Mon Sep 17 00:00:00 2001 From: german77 Date: Sun, 19 Jun 2022 16:27:48 -0500 Subject: [PATCH 5/6] service: irs: Move to IRS namespace and minor fixes --- CMakeModules/CopyYuzuQt5Deps.cmake | 1 + src/core/hid/irs_types.h | 11 ++-- src/core/hle/service/hid/errors.h | 6 ++- src/core/hle/service/hid/hid.cpp | 4 +- src/core/hle/service/hid/irs.cpp | 50 +++++++++++-------- src/core/hle/service/hid/irs.h | 4 +- .../hid/irsensor/clustering_processor.cpp | 6 +-- .../hid/irsensor/clustering_processor.h | 4 +- .../hid/irsensor/image_transfer_processor.cpp | 8 +-- .../hid/irsensor/image_transfer_processor.h | 4 +- .../service/hid/irsensor/ir_led_processor.cpp | 6 +-- .../service/hid/irsensor/ir_led_processor.h | 4 +- .../service/hid/irsensor/moment_processor.cpp | 6 +-- .../service/hid/irsensor/moment_processor.h | 4 +- .../hid/irsensor/pointing_processor.cpp | 6 +-- .../service/hid/irsensor/pointing_processor.h | 5 +- .../service/hid/irsensor/processor_base.cpp | 4 +- .../hle/service/hid/irsensor/processor_base.h | 4 +- .../hid/irsensor/tera_plugin_processor.cpp | 6 +-- .../hid/irsensor/tera_plugin_processor.h | 4 +- 20 files changed, 71 insertions(+), 76 deletions(-) diff --git a/CMakeModules/CopyYuzuQt5Deps.cmake b/CMakeModules/CopyYuzuQt5Deps.cmake index 4702a504c..6c5044caa 100644 --- a/CMakeModules/CopyYuzuQt5Deps.cmake +++ b/CMakeModules/CopyYuzuQt5Deps.cmake @@ -25,6 +25,7 @@ function(copy_yuzu_Qt5_deps target_dir) Qt5Gui$<$:d>.* Qt5Widgets$<$:d>.* Qt5Multimedia$<$:d>.* + Qt5Network$<$:d>.* ) if (YUZU_USE_QT_WEB_ENGINE) diff --git a/src/core/hid/irs_types.h b/src/core/hid/irs_types.h index c73d008a0..88c5b016d 100644 --- a/src/core/hid/irs_types.h +++ b/src/core/hid/irs_types.h @@ -201,11 +201,11 @@ struct PackedClusteringProcessorConfig { PackedMcuVersion required_mcu_version; u32 pixel_count_min; u32 pixel_count_max; - u32 object_intensity_min; + u8 object_intensity_min; bool is_external_light_filter_enabled; INSERT_PADDING_BYTES(2); }; -static_assert(sizeof(PackedClusteringProcessorConfig) == 0x30, +static_assert(sizeof(PackedClusteringProcessorConfig) == 0x28, "PackedClusteringProcessorConfig is an invalid size"); // This is nn::irsensor::PackedImageTransferProcessorConfig @@ -273,12 +273,9 @@ struct HandAnalysisConfig { }; static_assert(sizeof(HandAnalysisConfig) == 0x4, "HandAnalysisConfig is an invalid size"); -// This is nn::irsensor::detail::ProcessorState +// This is nn::irsensor::detail::ProcessorState contents are different for each processor struct ProcessorState { - u64 start{}; - u32 count{}; - INSERT_PADDING_BYTES(4); - std::array processor_raw_data{}; + std::array processor_raw_data{}; }; static_assert(sizeof(ProcessorState) == 0xE20, "ProcessorState is an invalid size"); diff --git a/src/core/hle/service/hid/errors.h b/src/core/hle/service/hid/errors.h index 1bd62461c..accc2b646 100644 --- a/src/core/hle/service/hid/errors.h +++ b/src/core/hle/service/hid/errors.h @@ -18,7 +18,11 @@ constexpr Result NpadIsSameType{ErrorModule::HID, 602}; constexpr Result InvalidNpadId{ErrorModule::HID, 709}; constexpr Result NpadNotConnected{ErrorModule::HID, 710}; +} // namespace Service::HID + +namespace Service::IRS { + constexpr ResultCode InvalidProcessorState{ErrorModule::Irsensor, 78}; constexpr ResultCode InvalidIrCameraHandle{ErrorModule::Irsensor, 204}; -} // namespace Service::HID +} // 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 std::make_shared(system)->InstallAsService(service_manager); std::make_shared(system)->InstallAsService(service_manager); - std::make_shared(system)->InstallAsService(service_manager); - std::make_shared(system)->InstallAsService(service_manager); + std::make_shared(system)->InstallAsService(service_manager); + std::make_shared(system)->InstallAsService(service_manager); std::make_shared(system)->InstallAsService(service_manager); } diff --git a/src/core/hle/service/hid/irs.cpp b/src/core/hle/service/hid/irs.cpp index 53a31df79..b6e7c0792 100644 --- a/src/core/hle/service/hid/irs.cpp +++ b/src/core/hle/service/hid/irs.cpp @@ -22,7 +22,7 @@ #include "core/hle/service/hid/irsensor/tera_plugin_processor.h" #include "core/memory.h" -namespace Service::HID { +namespace Service::IRS { IRS::IRS(Core::System& system_) : ServiceFramework{system_, "irs"} { // clang-format off @@ -60,7 +60,7 @@ void IRS::ActivateIrsensor(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto applet_resource_user_id{rp.Pop()}; - LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}", + LOG_WARNING(Service_IRS, "(STUBBED) called, applet_resource_user_id={}", applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; @@ -71,7 +71,7 @@ void IRS::DeactivateIrsensor(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto applet_resource_user_id{rp.Pop()}; - LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}", + LOG_WARNING(Service_IRS, "(STUBBED) called, applet_resource_user_id={}", applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; @@ -153,7 +153,7 @@ void IRS::RunClusteringProcessor(Kernel::HLERequestContext& ctx) { u64 applet_resource_user_id; Core::IrSensor::PackedClusteringProcessorConfig processor_config; }; - static_assert(sizeof(Parameters) == 0x40, "Parameters has incorrect size."); + static_assert(sizeof(Parameters) == 0x38, "Parameters has incorrect size."); const auto parameters{rp.PopRaw()}; @@ -194,7 +194,7 @@ void IRS::RunImageTransferProcessor(Kernel::HLERequestContext& ctx) { system.CurrentProcess()->GetHandleTable().GetObject(t_mem_handle); if (t_mem.IsNull()) { - LOG_ERROR(Service_HID, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle); + LOG_ERROR(Service_IRS, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultUnknown); return; @@ -268,24 +268,32 @@ void IRS::GetImageTransferProcessorState(Kernel::HLERequestContext& ctx) { void IRS::RunTeraPluginProcessor(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto camera_handle{rp.PopRaw()}; - const auto processor_config{rp.PopRaw()}; - const auto applet_resource_user_id{rp.Pop()}; + struct Parameters { + Core::IrSensor::IrCameraHandle camera_handle; + Core::IrSensor::PackedTeraPluginProcessorConfig processor_config; + INSERT_PADDING_WORDS_NOINIT(1); + u64 applet_resource_user_id; + }; + static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size."); - LOG_WARNING(Service_IRS, - "(STUBBED) called, npad_type={}, npad_id={}, mode={}, mcu_version={}.{}, " - "applet_resource_user_id={}", - camera_handle.npad_type, camera_handle.npad_id, processor_config.mode, - processor_config.required_mcu_version.major, - processor_config.required_mcu_version.minor, applet_resource_user_id); + const auto parameters{rp.PopRaw()}; - const auto result = IsIrCameraHandleValid(camera_handle); + LOG_WARNING( + Service_IRS, + "(STUBBED) called, npad_type={}, npad_id={}, mode={}, mcu_version={}.{}, " + "applet_resource_user_id={}", + parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, + parameters.processor_config.mode, parameters.processor_config.required_mcu_version.major, + parameters.processor_config.required_mcu_version.minor, parameters.applet_resource_user_id); + + const auto result = IsIrCameraHandleValid(parameters.camera_handle); if (result.IsSuccess()) { - auto& device = GetIrCameraSharedMemoryDeviceEntry(camera_handle); - MakeProcessor(camera_handle, device); - auto& image_transfer_processor = GetProcessor(camera_handle); - image_transfer_processor.SetConfig(processor_config); + auto& device = GetIrCameraSharedMemoryDeviceEntry(parameters.camera_handle); + MakeProcessor(parameters.camera_handle, device); + auto& image_transfer_processor = + GetProcessor(parameters.camera_handle); + image_transfer_processor.SetConfig(parameters.processor_config); } IPC::ResponseBuilder rb{ctx, 2}; @@ -299,7 +307,7 @@ void IRS::GetNpadIrCameraHandle(Kernel::HLERequestContext& ctx) { if (npad_id > Core::HID::NpadIdType::Player8 && npad_id != Core::HID::NpadIdType::Invalid && npad_id != Core::HID::NpadIdType::Handheld) { IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(InvalidNpadId); + rb.Push(Service::HID::InvalidNpadId); return; } @@ -553,4 +561,4 @@ IRS_SYS::IRS_SYS(Core::System& system_) : ServiceFramework{system_, "irs:sys"} { IRS_SYS::~IRS_SYS() = default; -} // namespace Service::HID +} // namespace Service::IRS diff --git a/src/core/hle/service/hid/irs.h b/src/core/hle/service/hid/irs.h index ae7f7719b..516620b4d 100644 --- a/src/core/hle/service/hid/irs.h +++ b/src/core/hle/service/hid/irs.h @@ -16,7 +16,7 @@ namespace Core::HID { class EmulatedController; } // namespace Core::HID -namespace Service::HID { +namespace Service::IRS { class IRS final : public ServiceFramework { public: @@ -114,4 +114,4 @@ public: ~IRS_SYS() override; }; -} // namespace Service::HID +} // 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 index aac3e4fec..6479af212 100644 --- a/src/core/hle/service/hid/irsensor/clustering_processor.cpp +++ b/src/core/hle/service/hid/irsensor/clustering_processor.cpp @@ -3,14 +3,12 @@ #include "core/hle/service/hid/irsensor/clustering_processor.h" -namespace Service::HID { +namespace Service::IRS { ClusteringProcessor::ClusteringProcessor(Core::IrSensor::DeviceFormat& device_format) : device(device_format) { device.mode = Core::IrSensor::IrSensorMode::ClusteringProcessor; device.camera_status = Core::IrSensor::IrCameraStatus::Unconnected; device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Stopped; - device.state.start = 0; - device.state.count = 0; } ClusteringProcessor::~ClusteringProcessor() = default; @@ -33,4 +31,4 @@ void ClusteringProcessor::SetConfig(Core::IrSensor::PackedClusteringProcessorCon current_config.object_intensity_min = config.object_intensity_min; } -} // namespace Service::HID +} // 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 index 58b2acf1c..6e2ba8846 100644 --- a/src/core/hle/service/hid/irsensor/clustering_processor.h +++ b/src/core/hle/service/hid/irsensor/clustering_processor.h @@ -7,7 +7,7 @@ #include "core/hid/irs_types.h" #include "core/hle/service/hid/irsensor/processor_base.h" -namespace Service::HID { +namespace Service::IRS { class ClusteringProcessor final : public ProcessorBase { public: explicit ClusteringProcessor(Core::IrSensor::DeviceFormat& device_format); @@ -71,4 +71,4 @@ private: ClusteringProcessorConfig current_config{}; Core::IrSensor::DeviceFormat& device; }; -} // namespace Service::HID +} // 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 index 703e825e6..98f0c579d 100644 --- a/src/core/hle/service/hid/irsensor/image_transfer_processor.cpp +++ b/src/core/hle/service/hid/irsensor/image_transfer_processor.cpp @@ -5,7 +5,7 @@ #include "core/hid/hid_core.h" #include "core/hle/service/hid/irsensor/image_transfer_processor.h" -namespace Service::HID { +namespace Service::IRS { ImageTransferProcessor::ImageTransferProcessor(Core::HID::HIDCore& hid_core_, Core::IrSensor::DeviceFormat& device_format, std::size_t npad_index) @@ -21,8 +21,6 @@ ImageTransferProcessor::ImageTransferProcessor(Core::HID::HIDCore& hid_core_, device.mode = Core::IrSensor::IrSensorMode::ImageTransferProcessor; device.camera_status = Core::IrSensor::IrCameraStatus::Unconnected; device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Stopped; - device.state.start = 0; - device.state.count = 0; } ImageTransferProcessor::~ImageTransferProcessor() { @@ -33,8 +31,6 @@ void ImageTransferProcessor::StartProcessor() { is_active = true; device.camera_status = Core::IrSensor::IrCameraStatus::Available; device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Ready; - device.state.start = 0; - device.state.count = 1; processor_state.sampling_number = 0; processor_state.ambient_noise_level = Core::IrSensor::CameraAmbientNoiseLevel::Low; } @@ -151,4 +147,4 @@ Core::IrSensor::ImageTransferProcessorState ImageTransferProcessor::GetState( return processor_state; } -} // namespace Service::HID +} // 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 index b557eaf20..393df492d 100644 --- a/src/core/hle/service/hid/irsensor/image_transfer_processor.h +++ b/src/core/hle/service/hid/irsensor/image_transfer_processor.h @@ -11,7 +11,7 @@ namespace Core::HID { class EmulatedController; } // namespace Core::HID -namespace Service::HID { +namespace Service::IRS { class ImageTransferProcessor final : public ProcessorBase { public: explicit ImageTransferProcessor(Core::HID::HIDCore& hid_core_, @@ -70,4 +70,4 @@ private: u8* transfer_memory = nullptr; bool is_transfer_memory_set = false; }; -} // namespace Service::HID +} // 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 index 656e17c95..8e6dd99e4 100644 --- a/src/core/hle/service/hid/irsensor/ir_led_processor.cpp +++ b/src/core/hle/service/hid/irsensor/ir_led_processor.cpp @@ -3,14 +3,12 @@ #include "core/hle/service/hid/irsensor/ir_led_processor.h" -namespace Service::HID { +namespace Service::IRS { IrLedProcessor::IrLedProcessor(Core::IrSensor::DeviceFormat& device_format) : device(device_format) { device.mode = Core::IrSensor::IrSensorMode::IrLedProcessor; device.camera_status = Core::IrSensor::IrCameraStatus::Unconnected; device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Stopped; - device.state.start = 0; - device.state.count = 0; } IrLedProcessor::~IrLedProcessor() = default; @@ -26,4 +24,4 @@ void IrLedProcessor::SetConfig(Core::IrSensor::PackedIrLedProcessorConfig config static_cast(config.light_target); } -} // namespace Service::HID +} // 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 index cb04d0b94..c3d8693c9 100644 --- a/src/core/hle/service/hid/irsensor/ir_led_processor.h +++ b/src/core/hle/service/hid/irsensor/ir_led_processor.h @@ -8,7 +8,7 @@ #include "core/hid/irs_types.h" #include "core/hle/service/hid/irsensor/processor_base.h" -namespace Service::HID { +namespace Service::IRS { class IrLedProcessor final : public ProcessorBase { public: explicit IrLedProcessor(Core::IrSensor::DeviceFormat& device_format); @@ -44,4 +44,4 @@ private: Core::IrSensor::DeviceFormat& device; }; -} // namespace Service::HID +} // 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 index fb36be577..dbaca420a 100644 --- a/src/core/hle/service/hid/irsensor/moment_processor.cpp +++ b/src/core/hle/service/hid/irsensor/moment_processor.cpp @@ -3,14 +3,12 @@ #include "core/hle/service/hid/irsensor/moment_processor.h" -namespace Service::HID { +namespace Service::IRS { MomentProcessor::MomentProcessor(Core::IrSensor::DeviceFormat& device_format) : device(device_format) { device.mode = Core::IrSensor::IrSensorMode::MomentProcessor; device.camera_status = Core::IrSensor::IrCameraStatus::Unconnected; device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Stopped; - device.state.start = 0; - device.state.count = 0; } MomentProcessor::~MomentProcessor() = default; @@ -33,4 +31,4 @@ void MomentProcessor::SetConfig(Core::IrSensor::PackedMomentProcessorConfig conf current_config.preprocess_intensity_threshold = config.preprocess_intensity_threshold; } -} // namespace Service::HID +} // 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 index 63cdadfda..d4bd22e0f 100644 --- a/src/core/hle/service/hid/irsensor/moment_processor.h +++ b/src/core/hle/service/hid/irsensor/moment_processor.h @@ -8,7 +8,7 @@ #include "core/hid/irs_types.h" #include "core/hle/service/hid/irsensor/processor_base.h" -namespace Service::HID { +namespace Service::IRS { class MomentProcessor final : public ProcessorBase { public: explicit MomentProcessor(Core::IrSensor::DeviceFormat& device_format); @@ -58,4 +58,4 @@ private: Core::IrSensor::DeviceFormat& device; }; -} // namespace Service::HID +} // 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 index 7eb123636..929f177fc 100644 --- a/src/core/hle/service/hid/irsensor/pointing_processor.cpp +++ b/src/core/hle/service/hid/irsensor/pointing_processor.cpp @@ -3,14 +3,12 @@ #include "core/hle/service/hid/irsensor/pointing_processor.h" -namespace Service::HID { +namespace Service::IRS { PointingProcessor::PointingProcessor(Core::IrSensor::DeviceFormat& device_format) : device(device_format) { device.mode = Core::IrSensor::IrSensorMode::PointingProcessorMarker; device.camera_status = Core::IrSensor::IrCameraStatus::Unconnected; device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Stopped; - device.state.start = 0; - device.state.count = 0; } PointingProcessor::~PointingProcessor() = default; @@ -25,4 +23,4 @@ void PointingProcessor::SetConfig(Core::IrSensor::PackedPointingProcessorConfig current_config.window_of_interest = config.window_of_interest; } -} // namespace Service::HID +} // 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 index 2f67eff91..cf4930794 100644 --- a/src/core/hle/service/hid/irsensor/pointing_processor.h +++ b/src/core/hle/service/hid/irsensor/pointing_processor.h @@ -3,12 +3,11 @@ #pragma once -#include "common/bit_field.h" #include "common/common_types.h" #include "core/hid/irs_types.h" #include "core/hle/service/hid/irsensor/processor_base.h" -namespace Service::HID { +namespace Service::IRS { class PointingProcessor final : public ProcessorBase { public: explicit PointingProcessor(Core::IrSensor::DeviceFormat& device_format); @@ -59,4 +58,4 @@ private: Core::IrSensor::DeviceFormat& device; }; -} // namespace Service::HID +} // 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 index bc8025375..4d43ca17a 100644 --- a/src/core/hle/service/hid/irsensor/processor_base.cpp +++ b/src/core/hle/service/hid/irsensor/processor_base.cpp @@ -3,7 +3,7 @@ #include "core/hle/service/hid/irsensor/processor_base.h" -namespace Service::HID { +namespace Service::IRS { ProcessorBase::ProcessorBase() {} ProcessorBase::~ProcessorBase() = default; @@ -64,4 +64,4 @@ std::size_t ProcessorBase::GetDataHeight( } } -} // namespace Service::HID +} // 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 index 49831aab6..bc0d2977b 100644 --- a/src/core/hle/service/hid/irsensor/processor_base.h +++ b/src/core/hle/service/hid/irsensor/processor_base.h @@ -6,7 +6,7 @@ #include "common/common_types.h" #include "core/hid/irs_types.h" -namespace Service::HID { +namespace Service::IRS { class ProcessorBase { public: explicit ProcessorBase(); @@ -30,4 +30,4 @@ protected: bool is_active{false}; }; -} // namespace Service::HID +} // 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 index deec22072..e691c840a 100644 --- a/src/core/hle/service/hid/irsensor/tera_plugin_processor.cpp +++ b/src/core/hle/service/hid/irsensor/tera_plugin_processor.cpp @@ -3,14 +3,12 @@ #include "core/hle/service/hid/irsensor/tera_plugin_processor.h" -namespace Service::HID { +namespace Service::IRS { TeraPluginProcessor::TeraPluginProcessor(Core::IrSensor::DeviceFormat& device_format) : device(device_format) { device.mode = Core::IrSensor::IrSensorMode::TeraPluginProcessor; device.camera_status = Core::IrSensor::IrCameraStatus::Unconnected; device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Stopped; - device.state.start = 0; - device.state.count = 0; } TeraPluginProcessor::~TeraPluginProcessor() = default; @@ -28,4 +26,4 @@ void TeraPluginProcessor::SetConfig(Core::IrSensor::PackedTeraPluginProcessorCon current_config.unknown_3 = config.unknown_3; } -} // namespace Service::HID +} // 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 index 60f8057a5..bbea7ed0b 100644 --- a/src/core/hle/service/hid/irsensor/tera_plugin_processor.h +++ b/src/core/hle/service/hid/irsensor/tera_plugin_processor.h @@ -8,7 +8,7 @@ #include "core/hid/irs_types.h" #include "core/hle/service/hid/irsensor/processor_base.h" -namespace Service::HID { +namespace Service::IRS { class TeraPluginProcessor final : public ProcessorBase { public: explicit TeraPluginProcessor(Core::IrSensor::DeviceFormat& device_format); @@ -50,4 +50,4 @@ private: Core::IrSensor::DeviceFormat& device; }; -} // namespace Service::HID +} // namespace Service::IRS From 403bdc4dafe89a463f3d93b9a389a1010ca5ff16 Mon Sep 17 00:00:00 2001 From: Narr the Reg Date: Tue, 28 Jun 2022 19:35:51 -0500 Subject: [PATCH 6/6] yuzu: Add webcam support and rebase to latest master --- src/common/settings.h | 4 ++-- src/core/hle/service/hid/errors.h | 4 ++-- src/core/hle/service/hid/irs.cpp | 2 +- src/core/hle/service/hid/irs.h | 2 +- src/yuzu/bootmanager.cpp | 19 ++++++++++++---- src/yuzu/bootmanager.h | 2 ++ src/yuzu/configuration/configure_camera.cpp | 24 +++++++++++++++------ src/yuzu/configuration/configure_camera.h | 2 ++ 8 files changed, 43 insertions(+), 16 deletions(-) diff --git a/src/common/settings.h b/src/common/settings.h index 20959ec89..1079cf8cb 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -503,8 +503,8 @@ struct Values { Setting enable_ring_controller{true, "enable_ring_controller"}; RingconRaw ringcon_analogs; - BasicSetting enable_ir_sensor{false, "enable_ir_sensor"}; - BasicSetting ir_sensor_device{"auto", "ir_sensor_device"}; + Setting enable_ir_sensor{false, "enable_ir_sensor"}; + Setting ir_sensor_device{"auto", "ir_sensor_device"}; // Data Storage Setting use_virtual_sd{true, "use_virtual_sd"}; diff --git a/src/core/hle/service/hid/errors.h b/src/core/hle/service/hid/errors.h index accc2b646..4613a4e60 100644 --- a/src/core/hle/service/hid/errors.h +++ b/src/core/hle/service/hid/errors.h @@ -22,7 +22,7 @@ constexpr Result NpadNotConnected{ErrorModule::HID, 710}; namespace Service::IRS { -constexpr ResultCode InvalidProcessorState{ErrorModule::Irsensor, 78}; -constexpr ResultCode InvalidIrCameraHandle{ErrorModule::Irsensor, 204}; +constexpr Result InvalidProcessorState{ErrorModule::Irsensor, 78}; +constexpr Result InvalidIrCameraHandle{ErrorModule::Irsensor, 204}; } // namespace Service::IRS diff --git a/src/core/hle/service/hid/irs.cpp b/src/core/hle/service/hid/irs.cpp index b6e7c0792..d5107e41f 100644 --- a/src/core/hle/service/hid/irs.cpp +++ b/src/core/hle/service/hid/irs.cpp @@ -529,7 +529,7 @@ void IRS::ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx) { rb.Push(ResultSuccess); } -ResultCode IRS::IsIrCameraHandleValid(const Core::IrSensor::IrCameraHandle& camera_handle) const { +Result IRS::IsIrCameraHandleValid(const Core::IrSensor::IrCameraHandle& camera_handle) const { if (camera_handle.npad_id > static_cast(NpadIdTypeToIndex(Core::HID::NpadIdType::Handheld))) { return InvalidIrCameraHandle; diff --git a/src/core/hle/service/hid/irs.h b/src/core/hle/service/hid/irs.h index 516620b4d..2e6115c73 100644 --- a/src/core/hle/service/hid/irs.h +++ b/src/core/hle/service/hid/irs.h @@ -57,7 +57,7 @@ private: void StopImageProcessorAsync(Kernel::HLERequestContext& ctx); void ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx); - ResultCode IsIrCameraHandleValid(const Core::IrSensor::IrCameraHandle& camera_handle) const; + Result IsIrCameraHandleValid(const Core::IrSensor::IrCameraHandle& camera_handle) const; Core::IrSensor::DeviceFormat& GetIrCameraSharedMemoryDeviceEntry( const Core::IrSensor::IrCameraHandle& camera_handle); diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 774085809..0ee3820a2 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -830,6 +830,10 @@ void GRenderWindow::InitializeCamera() { camera->unload(); camera->setCaptureMode(QCamera::CaptureViewfinder); camera->load(); + camera->start(); + + pending_camera_snapshots = 0; + is_virtual_camera = false; camera_timer = std::make_unique(); connect(camera_timer.get(), &QTimer::timeout, [this] { RequestCameraCapture(); }); @@ -851,11 +855,17 @@ void GRenderWindow::RequestCameraCapture() { return; } - // Idealy one should only call capture but Qt refuses to take a second capture without - // stopping the camera - camera->stop(); - camera->start(); + // If the camera doesn't capture, test for virtual cameras + if (pending_camera_snapshots > 5) { + is_virtual_camera = true; + } + // Virtual cameras like obs need to reset the camera every capture + if (is_virtual_camera) { + camera->stop(); + camera->start(); + } + pending_camera_snapshots++; camera_capture->capture(); } @@ -870,6 +880,7 @@ void GRenderWindow::OnCameraCapture(int requestId, const QImage& img) { camera_data.resize(camera_width * camera_height); std::memcpy(camera_data.data(), converted.bits(), camera_width * camera_height * sizeof(u32)); input_subsystem->GetCamera()->SetCameraData(camera_width, camera_height, camera_data); + pending_camera_snapshots = 0; } bool GRenderWindow::event(QEvent* event) { diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index 346201768..b4781e697 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h @@ -240,6 +240,8 @@ private: bool first_frame = false; InputCommon::TasInput::TasState last_tas_state; + bool is_virtual_camera; + int pending_camera_snapshots; std::unique_ptr camera; std::unique_ptr camera_capture; std::unique_ptr camera_timer; diff --git a/src/yuzu/configuration/configure_camera.cpp b/src/yuzu/configuration/configure_camera.cpp index 97febb33c..73cdcf3f2 100644 --- a/src/yuzu/configuration/configure_camera.cpp +++ b/src/yuzu/configuration/configure_camera.cpp @@ -39,8 +39,8 @@ void ConfigureCamera::PreviewCamera() { for (const QCameraInfo& cameraInfo : cameras) { if (input_devices[index] == cameraInfo.deviceName().toStdString() || input_devices[index] == "Auto") { - LOG_ERROR(Frontend, "Selected Camera {} {}", cameraInfo.description().toStdString(), - cameraInfo.deviceName().toStdString()); + LOG_INFO(Frontend, "Selected Camera {} {}", cameraInfo.description().toStdString(), + cameraInfo.deviceName().toStdString()); camera = std::make_unique(cameraInfo); camera_found = true; break; @@ -62,12 +62,23 @@ void ConfigureCamera::PreviewCamera() { camera->unload(); camera->setCaptureMode(QCamera::CaptureViewfinder); camera->load(); + camera->start(); + + pending_snapshots = 0; + is_virtual_camera = false; camera_timer = std::make_unique(); connect(camera_timer.get(), &QTimer::timeout, [this] { - camera->stop(); - camera->start(); - + // If the camera doesn't capture, test for virtual cameras + if (pending_snapshots > 5) { + is_virtual_camera = true; + } + // Virtual cameras like obs need to reset the camera every capture + if (is_virtual_camera) { + camera->stop(); + camera->start(); + } + pending_snapshots++; camera_capture->capture(); }); @@ -75,10 +86,11 @@ void ConfigureCamera::PreviewCamera() { } void ConfigureCamera::DisplayCapturedFrame(int requestId, const QImage& img) { - LOG_ERROR(Frontend, "ImageCaptured {} {}", img.width(), img.height()); + LOG_INFO(Frontend, "ImageCaptured {} {}", img.width(), img.height()); const auto converted = img.scaled(320, 240, Qt::AspectRatioMode::IgnoreAspectRatio, Qt::TransformationMode::SmoothTransformation); ui->preview_box->setPixmap(QPixmap::fromImage(converted)); + pending_snapshots = 0; } void ConfigureCamera::changeEvent(QEvent* event) { diff --git a/src/yuzu/configuration/configure_camera.h b/src/yuzu/configuration/configure_camera.h index af7551c03..db9833b5c 100644 --- a/src/yuzu/configuration/configure_camera.h +++ b/src/yuzu/configuration/configure_camera.h @@ -44,6 +44,8 @@ private: InputCommon::InputSubsystem* input_subsystem; + bool is_virtual_camera; + int pending_snapshots; std::unique_ptr camera; std::unique_ptr camera_capture; std::unique_ptr camera_timer;