diff options
| author | 2022-07-27 15:54:28 -0400 | |
|---|---|---|
| committer | 2022-07-27 15:54:28 -0400 | |
| commit | 64fd9f41a7d1170dbfa827f796033c4f2cad0cf0 (patch) | |
| tree | 4ccf48f3361f4bd2e4c35b5c9a48e42c12892564 /src | |
| parent | Merge pull request #8633 from Morph1984/optional-keys (diff) | |
| parent | Address comments (diff) | |
| download | yuzu-64fd9f41a7d1170dbfa827f796033c4f2cad0cf0.tar.gz yuzu-64fd9f41a7d1170dbfa827f796033c4f2cad0cf0.tar.xz yuzu-64fd9f41a7d1170dbfa827f796033c4f2cad0cf0.zip | |
Merge pull request #8636 from german77/irs_cluster_release
service: irs: Implement clustering processor
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | src/core/hle/service/hid/irs.cpp | 2 | ||||
| -rw-r--r-- | src/core/hle/service/hid/irs_ring_lifo.h | 47 | ||||
| -rw-r--r-- | src/core/hle/service/hid/irsensor/clustering_processor.cpp | 239 | ||||
| -rw-r--r-- | src/core/hle/service/hid/irsensor/clustering_processor.h | 38 | ||||
| -rw-r--r-- | src/yuzu/bootmanager.cpp | 3 |
6 files changed, 323 insertions, 7 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index a614b176b..40b1ea4a2 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -451,6 +451,7 @@ add_library(core STATIC | |||
| 451 | hle/service/hid/hidbus.h | 451 | hle/service/hid/hidbus.h |
| 452 | hle/service/hid/irs.cpp | 452 | hle/service/hid/irs.cpp |
| 453 | hle/service/hid/irs.h | 453 | hle/service/hid/irs.h |
| 454 | hle/service/hid/irs_ring_lifo.h | ||
| 454 | hle/service/hid/ring_lifo.h | 455 | hle/service/hid/ring_lifo.h |
| 455 | hle/service/hid/xcd.cpp | 456 | hle/service/hid/xcd.cpp |
| 456 | hle/service/hid/xcd.h | 457 | hle/service/hid/xcd.h |
diff --git a/src/core/hle/service/hid/irs.cpp b/src/core/hle/service/hid/irs.cpp index d5107e41f..c4b44cbf9 100644 --- a/src/core/hle/service/hid/irs.cpp +++ b/src/core/hle/service/hid/irs.cpp | |||
| @@ -166,7 +166,7 @@ void IRS::RunClusteringProcessor(Kernel::HLERequestContext& ctx) { | |||
| 166 | 166 | ||
| 167 | if (result.IsSuccess()) { | 167 | if (result.IsSuccess()) { |
| 168 | auto& device = GetIrCameraSharedMemoryDeviceEntry(parameters.camera_handle); | 168 | auto& device = GetIrCameraSharedMemoryDeviceEntry(parameters.camera_handle); |
| 169 | MakeProcessor<ClusteringProcessor>(parameters.camera_handle, device); | 169 | MakeProcessorWithCoreContext<ClusteringProcessor>(parameters.camera_handle, device); |
| 170 | auto& image_transfer_processor = | 170 | auto& image_transfer_processor = |
| 171 | GetProcessor<ClusteringProcessor>(parameters.camera_handle); | 171 | GetProcessor<ClusteringProcessor>(parameters.camera_handle); |
| 172 | image_transfer_processor.SetConfig(parameters.processor_config); | 172 | image_transfer_processor.SetConfig(parameters.processor_config); |
diff --git a/src/core/hle/service/hid/irs_ring_lifo.h b/src/core/hle/service/hid/irs_ring_lifo.h new file mode 100644 index 000000000..255d1d296 --- /dev/null +++ b/src/core/hle/service/hid/irs_ring_lifo.h | |||
| @@ -0,0 +1,47 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <array> | ||
| 7 | |||
| 8 | #include "common/common_types.h" | ||
| 9 | |||
| 10 | namespace Service::IRS { | ||
| 11 | |||
| 12 | template <typename State, std::size_t max_buffer_size> | ||
| 13 | struct Lifo { | ||
| 14 | s64 sampling_number{}; | ||
| 15 | s64 buffer_count{}; | ||
| 16 | std::array<State, max_buffer_size> entries{}; | ||
| 17 | |||
| 18 | const State& ReadCurrentEntry() const { | ||
| 19 | return entries[GetBufferTail()]; | ||
| 20 | } | ||
| 21 | |||
| 22 | const State& ReadPreviousEntry() const { | ||
| 23 | return entries[GetPreviousEntryIndex()]; | ||
| 24 | } | ||
| 25 | |||
| 26 | s64 GetBufferTail() const { | ||
| 27 | return sampling_number % max_buffer_size; | ||
| 28 | } | ||
| 29 | |||
| 30 | std::size_t GetPreviousEntryIndex() const { | ||
| 31 | return static_cast<size_t>((GetBufferTail() + max_buffer_size - 1) % max_buffer_size); | ||
| 32 | } | ||
| 33 | |||
| 34 | std::size_t GetNextEntryIndex() const { | ||
| 35 | return static_cast<size_t>((GetBufferTail() + 1) % max_buffer_size); | ||
| 36 | } | ||
| 37 | |||
| 38 | void WriteNextEntry(const State& new_state) { | ||
| 39 | if (buffer_count < static_cast<s64>(max_buffer_size)) { | ||
| 40 | buffer_count++; | ||
| 41 | } | ||
| 42 | sampling_number++; | ||
| 43 | entries[GetBufferTail()] = new_state; | ||
| 44 | } | ||
| 45 | }; | ||
| 46 | |||
| 47 | } // 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 6479af212..e2f4ae876 100644 --- a/src/core/hle/service/hid/irsensor/clustering_processor.cpp +++ b/src/core/hle/service/hid/irsensor/clustering_processor.cpp | |||
| @@ -1,34 +1,265 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | 2 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 3 | 3 | ||
| 4 | #include <queue> | ||
| 5 | |||
| 6 | #include "core/hid/emulated_controller.h" | ||
| 7 | #include "core/hid/hid_core.h" | ||
| 4 | #include "core/hle/service/hid/irsensor/clustering_processor.h" | 8 | #include "core/hle/service/hid/irsensor/clustering_processor.h" |
| 5 | 9 | ||
| 6 | namespace Service::IRS { | 10 | namespace Service::IRS { |
| 7 | ClusteringProcessor::ClusteringProcessor(Core::IrSensor::DeviceFormat& device_format) | 11 | ClusteringProcessor::ClusteringProcessor(Core::HID::HIDCore& hid_core_, |
| 8 | : device(device_format) { | 12 | Core::IrSensor::DeviceFormat& device_format, |
| 13 | std::size_t npad_index) | ||
| 14 | : device{device_format} { | ||
| 15 | npad_device = hid_core_.GetEmulatedControllerByIndex(npad_index); | ||
| 16 | |||
| 9 | device.mode = Core::IrSensor::IrSensorMode::ClusteringProcessor; | 17 | device.mode = Core::IrSensor::IrSensorMode::ClusteringProcessor; |
| 10 | device.camera_status = Core::IrSensor::IrCameraStatus::Unconnected; | 18 | device.camera_status = Core::IrSensor::IrCameraStatus::Unconnected; |
| 11 | device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Stopped; | 19 | device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Stopped; |
| 20 | SetDefaultConfig(); | ||
| 21 | |||
| 22 | shared_memory = std::construct_at( | ||
| 23 | reinterpret_cast<ClusteringSharedMemory*>(&device_format.state.processor_raw_data)); | ||
| 24 | |||
| 25 | Core::HID::ControllerUpdateCallback engine_callback{ | ||
| 26 | .on_change = [this](Core::HID::ControllerTriggerType type) { OnControllerUpdate(type); }, | ||
| 27 | .is_npad_service = true, | ||
| 28 | }; | ||
| 29 | callback_key = npad_device->SetCallback(engine_callback); | ||
| 12 | } | 30 | } |
| 13 | 31 | ||
| 14 | ClusteringProcessor::~ClusteringProcessor() = default; | 32 | ClusteringProcessor::~ClusteringProcessor() { |
| 33 | npad_device->DeleteCallback(callback_key); | ||
| 34 | }; | ||
| 15 | 35 | ||
| 16 | void ClusteringProcessor::StartProcessor() {} | 36 | void ClusteringProcessor::StartProcessor() { |
| 37 | device.camera_status = Core::IrSensor::IrCameraStatus::Available; | ||
| 38 | device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Ready; | ||
| 39 | } | ||
| 17 | 40 | ||
| 18 | void ClusteringProcessor::SuspendProcessor() {} | 41 | void ClusteringProcessor::SuspendProcessor() {} |
| 19 | 42 | ||
| 20 | void ClusteringProcessor::StopProcessor() {} | 43 | void ClusteringProcessor::StopProcessor() {} |
| 21 | 44 | ||
| 45 | void ClusteringProcessor::OnControllerUpdate(Core::HID::ControllerTriggerType type) { | ||
| 46 | if (type != Core::HID::ControllerTriggerType::IrSensor) { | ||
| 47 | return; | ||
| 48 | } | ||
| 49 | |||
| 50 | next_state = {}; | ||
| 51 | const auto camera_data = npad_device->GetCamera(); | ||
| 52 | auto filtered_image = camera_data.data; | ||
| 53 | |||
| 54 | RemoveLowIntensityData(filtered_image); | ||
| 55 | |||
| 56 | const auto window_start_x = static_cast<std::size_t>(current_config.window_of_interest.x); | ||
| 57 | const auto window_start_y = static_cast<std::size_t>(current_config.window_of_interest.y); | ||
| 58 | const auto window_end_x = | ||
| 59 | window_start_x + static_cast<std::size_t>(current_config.window_of_interest.width); | ||
| 60 | const auto window_end_y = | ||
| 61 | window_start_y + static_cast<std::size_t>(current_config.window_of_interest.height); | ||
| 62 | |||
| 63 | for (std::size_t y = window_start_y; y < window_end_y; y++) { | ||
| 64 | for (std::size_t x = window_start_x; x < window_end_x; x++) { | ||
| 65 | u8 pixel = GetPixel(filtered_image, x, y); | ||
| 66 | if (pixel == 0) { | ||
| 67 | continue; | ||
| 68 | } | ||
| 69 | const auto cluster = GetClusterProperties(filtered_image, x, y); | ||
| 70 | if (cluster.pixel_count > current_config.pixel_count_max) { | ||
| 71 | continue; | ||
| 72 | } | ||
| 73 | if (cluster.pixel_count < current_config.pixel_count_min) { | ||
| 74 | continue; | ||
| 75 | } | ||
| 76 | // Cluster object limit reached | ||
| 77 | if (next_state.object_count >= next_state.data.size()) { | ||
| 78 | continue; | ||
| 79 | } | ||
| 80 | next_state.data[next_state.object_count] = cluster; | ||
| 81 | next_state.object_count++; | ||
| 82 | } | ||
| 83 | } | ||
| 84 | |||
| 85 | next_state.sampling_number = camera_data.sample; | ||
| 86 | next_state.timestamp = next_state.timestamp + 131; | ||
| 87 | next_state.ambient_noise_level = Core::IrSensor::CameraAmbientNoiseLevel::Low; | ||
| 88 | shared_memory->clustering_lifo.WriteNextEntry(next_state); | ||
| 89 | |||
| 90 | if (!IsProcessorActive()) { | ||
| 91 | StartProcessor(); | ||
| 92 | } | ||
| 93 | } | ||
| 94 | |||
| 95 | void ClusteringProcessor::RemoveLowIntensityData(std::vector<u8>& data) { | ||
| 96 | for (u8& pixel : data) { | ||
| 97 | if (pixel < current_config.pixel_count_min) { | ||
| 98 | pixel = 0; | ||
| 99 | } | ||
| 100 | } | ||
| 101 | } | ||
| 102 | |||
| 103 | ClusteringProcessor::ClusteringData ClusteringProcessor::GetClusterProperties(std::vector<u8>& data, | ||
| 104 | std::size_t x, | ||
| 105 | std::size_t y) { | ||
| 106 | using DataPoint = Common::Point<std::size_t>; | ||
| 107 | std::queue<DataPoint> search_points{}; | ||
| 108 | ClusteringData current_cluster = GetPixelProperties(data, x, y); | ||
| 109 | SetPixel(data, x, y, 0); | ||
| 110 | search_points.emplace<DataPoint>({x, y}); | ||
| 111 | |||
| 112 | while (!search_points.empty()) { | ||
| 113 | const auto point = search_points.front(); | ||
| 114 | search_points.pop(); | ||
| 115 | |||
| 116 | // Avoid negative numbers | ||
| 117 | if (point.x == 0 || point.y == 0) { | ||
| 118 | continue; | ||
| 119 | } | ||
| 120 | |||
| 121 | std::array<DataPoint, 4> new_points{ | ||
| 122 | DataPoint{point.x - 1, point.y}, | ||
| 123 | {point.x, point.y - 1}, | ||
| 124 | {point.x + 1, point.y}, | ||
| 125 | {point.x, point.y + 1}, | ||
| 126 | }; | ||
| 127 | |||
| 128 | for (const auto new_point : new_points) { | ||
| 129 | if (new_point.x >= width) { | ||
| 130 | continue; | ||
| 131 | } | ||
| 132 | if (new_point.y >= height) { | ||
| 133 | continue; | ||
| 134 | } | ||
| 135 | if (GetPixel(data, new_point.x, new_point.y) < current_config.object_intensity_min) { | ||
| 136 | continue; | ||
| 137 | } | ||
| 138 | const ClusteringData cluster = GetPixelProperties(data, new_point.x, new_point.y); | ||
| 139 | current_cluster = MergeCluster(current_cluster, cluster); | ||
| 140 | SetPixel(data, new_point.x, new_point.y, 0); | ||
| 141 | search_points.emplace<DataPoint>({new_point.x, new_point.y}); | ||
| 142 | } | ||
| 143 | } | ||
| 144 | |||
| 145 | return current_cluster; | ||
| 146 | } | ||
| 147 | |||
| 148 | ClusteringProcessor::ClusteringData ClusteringProcessor::GetPixelProperties( | ||
| 149 | const std::vector<u8>& data, std::size_t x, std::size_t y) const { | ||
| 150 | return { | ||
| 151 | .average_intensity = GetPixel(data, x, y) / 255.0f, | ||
| 152 | .centroid = | ||
| 153 | { | ||
| 154 | .x = static_cast<f32>(x), | ||
| 155 | .y = static_cast<f32>(y), | ||
| 156 | |||
| 157 | }, | ||
| 158 | .pixel_count = 1, | ||
| 159 | .bound = | ||
| 160 | { | ||
| 161 | .x = static_cast<s16>(x), | ||
| 162 | .y = static_cast<s16>(y), | ||
| 163 | .width = 1, | ||
| 164 | .height = 1, | ||
| 165 | }, | ||
| 166 | }; | ||
| 167 | } | ||
| 168 | |||
| 169 | ClusteringProcessor::ClusteringData ClusteringProcessor::MergeCluster( | ||
| 170 | const ClusteringData a, const ClusteringData b) const { | ||
| 171 | const f32 a_pixel_count = static_cast<f32>(a.pixel_count); | ||
| 172 | const f32 b_pixel_count = static_cast<f32>(b.pixel_count); | ||
| 173 | const f32 pixel_count = a_pixel_count + b_pixel_count; | ||
| 174 | const f32 average_intensity = | ||
| 175 | (a.average_intensity * a_pixel_count + b.average_intensity * b_pixel_count) / pixel_count; | ||
| 176 | const Core::IrSensor::IrsCentroid centroid = { | ||
| 177 | .x = (a.centroid.x * a_pixel_count + b.centroid.x * b_pixel_count) / pixel_count, | ||
| 178 | .y = (a.centroid.y * a_pixel_count + b.centroid.y * b_pixel_count) / pixel_count, | ||
| 179 | }; | ||
| 180 | s16 bound_start_x = a.bound.x < b.bound.x ? a.bound.x : b.bound.x; | ||
| 181 | s16 bound_start_y = a.bound.y < b.bound.y ? a.bound.y : b.bound.y; | ||
| 182 | s16 a_bound_end_x = a.bound.x + a.bound.width; | ||
| 183 | s16 a_bound_end_y = a.bound.y + a.bound.height; | ||
| 184 | s16 b_bound_end_x = b.bound.x + b.bound.width; | ||
| 185 | s16 b_bound_end_y = b.bound.y + b.bound.height; | ||
| 186 | |||
| 187 | const Core::IrSensor::IrsRect bound = { | ||
| 188 | .x = bound_start_x, | ||
| 189 | .y = bound_start_y, | ||
| 190 | .width = a_bound_end_x > b_bound_end_x ? static_cast<s16>(a_bound_end_x - bound_start_x) | ||
| 191 | : static_cast<s16>(b_bound_end_x - bound_start_x), | ||
| 192 | .height = a_bound_end_y > b_bound_end_y ? static_cast<s16>(a_bound_end_y - bound_start_y) | ||
| 193 | : static_cast<s16>(b_bound_end_y - bound_start_y), | ||
| 194 | }; | ||
| 195 | |||
| 196 | return { | ||
| 197 | .average_intensity = average_intensity, | ||
| 198 | .centroid = centroid, | ||
| 199 | .pixel_count = static_cast<u32>(pixel_count), | ||
| 200 | .bound = bound, | ||
| 201 | }; | ||
| 202 | } | ||
| 203 | |||
| 204 | u8 ClusteringProcessor::GetPixel(const std::vector<u8>& data, std::size_t x, std::size_t y) const { | ||
| 205 | if ((y * width) + x > data.size()) { | ||
| 206 | return 0; | ||
| 207 | } | ||
| 208 | return data[(y * width) + x]; | ||
| 209 | } | ||
| 210 | |||
| 211 | void ClusteringProcessor::SetPixel(std::vector<u8>& data, std::size_t x, std::size_t y, u8 value) { | ||
| 212 | if ((y * width) + x > data.size()) { | ||
| 213 | return; | ||
| 214 | } | ||
| 215 | data[(y * width) + x] = value; | ||
| 216 | } | ||
| 217 | |||
| 218 | void ClusteringProcessor::SetDefaultConfig() { | ||
| 219 | using namespace std::literals::chrono_literals; | ||
| 220 | current_config.camera_config.exposure_time = std::chrono::microseconds(200ms).count(); | ||
| 221 | current_config.camera_config.gain = 2; | ||
| 222 | current_config.camera_config.is_negative_used = false; | ||
| 223 | current_config.camera_config.light_target = Core::IrSensor::CameraLightTarget::BrightLeds; | ||
| 224 | current_config.window_of_interest = { | ||
| 225 | .x = 0, | ||
| 226 | .y = 0, | ||
| 227 | .width = width, | ||
| 228 | .height = height, | ||
| 229 | }; | ||
| 230 | current_config.pixel_count_min = 3; | ||
| 231 | current_config.pixel_count_max = static_cast<u32>(GetDataSize(format)); | ||
| 232 | current_config.is_external_light_filter_enabled = true; | ||
| 233 | current_config.object_intensity_min = 150; | ||
| 234 | |||
| 235 | npad_device->SetCameraFormat(format); | ||
| 236 | } | ||
| 237 | |||
| 22 | void ClusteringProcessor::SetConfig(Core::IrSensor::PackedClusteringProcessorConfig config) { | 238 | void ClusteringProcessor::SetConfig(Core::IrSensor::PackedClusteringProcessorConfig config) { |
| 23 | current_config.camera_config.exposure_time = config.camera_config.exposure_time; | 239 | current_config.camera_config.exposure_time = config.camera_config.exposure_time; |
| 24 | current_config.camera_config.gain = config.camera_config.gain; | 240 | current_config.camera_config.gain = config.camera_config.gain; |
| 25 | current_config.camera_config.is_negative_used = config.camera_config.is_negative_used; | 241 | current_config.camera_config.is_negative_used = config.camera_config.is_negative_used; |
| 26 | current_config.camera_config.light_target = | 242 | current_config.camera_config.light_target = |
| 27 | static_cast<Core::IrSensor::CameraLightTarget>(config.camera_config.light_target); | 243 | static_cast<Core::IrSensor::CameraLightTarget>(config.camera_config.light_target); |
| 244 | current_config.window_of_interest = config.window_of_interest; | ||
| 28 | current_config.pixel_count_min = config.pixel_count_min; | 245 | current_config.pixel_count_min = config.pixel_count_min; |
| 29 | current_config.pixel_count_max = config.pixel_count_max; | 246 | current_config.pixel_count_max = config.pixel_count_max; |
| 30 | current_config.is_external_light_filter_enabled = config.is_external_light_filter_enabled; | 247 | current_config.is_external_light_filter_enabled = config.is_external_light_filter_enabled; |
| 31 | current_config.object_intensity_min = config.object_intensity_min; | 248 | current_config.object_intensity_min = config.object_intensity_min; |
| 249 | |||
| 250 | LOG_INFO(Service_IRS, | ||
| 251 | "Processor config, exposure_time={}, gain={}, is_negative_used={}, " | ||
| 252 | "light_target={}, window_of_interest=({}, {}, {}, {}), pixel_count_min={}, " | ||
| 253 | "pixel_count_max={}, is_external_light_filter_enabled={}, object_intensity_min={}", | ||
| 254 | current_config.camera_config.exposure_time, current_config.camera_config.gain, | ||
| 255 | current_config.camera_config.is_negative_used, | ||
| 256 | current_config.camera_config.light_target, current_config.window_of_interest.x, | ||
| 257 | current_config.window_of_interest.y, current_config.window_of_interest.width, | ||
| 258 | current_config.window_of_interest.height, current_config.pixel_count_min, | ||
| 259 | current_config.pixel_count_max, current_config.is_external_light_filter_enabled, | ||
| 260 | current_config.object_intensity_min); | ||
| 261 | |||
| 262 | npad_device->SetCameraFormat(format); | ||
| 32 | } | 263 | } |
| 33 | 264 | ||
| 34 | } // namespace Service::IRS | 265 | } // 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 6e2ba8846..dc01a8ea7 100644 --- a/src/core/hle/service/hid/irsensor/clustering_processor.h +++ b/src/core/hle/service/hid/irsensor/clustering_processor.h | |||
| @@ -5,12 +5,19 @@ | |||
| 5 | 5 | ||
| 6 | #include "common/common_types.h" | 6 | #include "common/common_types.h" |
| 7 | #include "core/hid/irs_types.h" | 7 | #include "core/hid/irs_types.h" |
| 8 | #include "core/hle/service/hid/irs_ring_lifo.h" | ||
| 8 | #include "core/hle/service/hid/irsensor/processor_base.h" | 9 | #include "core/hle/service/hid/irsensor/processor_base.h" |
| 9 | 10 | ||
| 11 | namespace Core::HID { | ||
| 12 | class EmulatedController; | ||
| 13 | } // namespace Core::HID | ||
| 14 | |||
| 10 | namespace Service::IRS { | 15 | namespace Service::IRS { |
| 11 | class ClusteringProcessor final : public ProcessorBase { | 16 | class ClusteringProcessor final : public ProcessorBase { |
| 12 | public: | 17 | public: |
| 13 | explicit ClusteringProcessor(Core::IrSensor::DeviceFormat& device_format); | 18 | explicit ClusteringProcessor(Core::HID::HIDCore& hid_core_, |
| 19 | Core::IrSensor::DeviceFormat& device_format, | ||
| 20 | std::size_t npad_index); | ||
| 14 | ~ClusteringProcessor() override; | 21 | ~ClusteringProcessor() override; |
| 15 | 22 | ||
| 16 | // Called when the processor is initialized | 23 | // Called when the processor is initialized |
| @@ -26,6 +33,10 @@ public: | |||
| 26 | void SetConfig(Core::IrSensor::PackedClusteringProcessorConfig config); | 33 | void SetConfig(Core::IrSensor::PackedClusteringProcessorConfig config); |
| 27 | 34 | ||
| 28 | private: | 35 | private: |
| 36 | static constexpr auto format = Core::IrSensor::ImageTransferProcessorFormat::Size320x240; | ||
| 37 | static constexpr std::size_t width = 320; | ||
| 38 | static constexpr std::size_t height = 240; | ||
| 39 | |||
| 29 | // This is nn::irsensor::ClusteringProcessorConfig | 40 | // This is nn::irsensor::ClusteringProcessorConfig |
| 30 | struct ClusteringProcessorConfig { | 41 | struct ClusteringProcessorConfig { |
| 31 | Core::IrSensor::CameraConfig camera_config; | 42 | Core::IrSensor::CameraConfig camera_config; |
| @@ -68,7 +79,32 @@ private: | |||
| 68 | static_assert(sizeof(ClusteringProcessorState) == 0x198, | 79 | static_assert(sizeof(ClusteringProcessorState) == 0x198, |
| 69 | "ClusteringProcessorState is an invalid size"); | 80 | "ClusteringProcessorState is an invalid size"); |
| 70 | 81 | ||
| 82 | struct ClusteringSharedMemory { | ||
| 83 | Service::IRS::Lifo<ClusteringProcessorState, 6> clustering_lifo; | ||
| 84 | static_assert(sizeof(clustering_lifo) == 0x9A0, "clustering_lifo is an invalid size"); | ||
| 85 | INSERT_PADDING_WORDS(0x11F); | ||
| 86 | }; | ||
| 87 | static_assert(sizeof(ClusteringSharedMemory) == 0xE20, | ||
| 88 | "ClusteringSharedMemory is an invalid size"); | ||
| 89 | |||
| 90 | void OnControllerUpdate(Core::HID::ControllerTriggerType type); | ||
| 91 | void RemoveLowIntensityData(std::vector<u8>& data); | ||
| 92 | ClusteringData GetClusterProperties(std::vector<u8>& data, std::size_t x, std::size_t y); | ||
| 93 | ClusteringData GetPixelProperties(const std::vector<u8>& data, std::size_t x, | ||
| 94 | std::size_t y) const; | ||
| 95 | ClusteringData MergeCluster(const ClusteringData a, const ClusteringData b) const; | ||
| 96 | u8 GetPixel(const std::vector<u8>& data, std::size_t x, std::size_t y) const; | ||
| 97 | void SetPixel(std::vector<u8>& data, std::size_t x, std::size_t y, u8 value); | ||
| 98 | |||
| 99 | // Sets config parameters of the camera | ||
| 100 | void SetDefaultConfig(); | ||
| 101 | |||
| 102 | ClusteringSharedMemory* shared_memory = nullptr; | ||
| 103 | ClusteringProcessorState next_state{}; | ||
| 104 | |||
| 71 | ClusteringProcessorConfig current_config{}; | 105 | ClusteringProcessorConfig current_config{}; |
| 72 | Core::IrSensor::DeviceFormat& device; | 106 | Core::IrSensor::DeviceFormat& device; |
| 107 | Core::HID::EmulatedController* npad_device; | ||
| 108 | int callback_key{}; | ||
| 73 | }; | 109 | }; |
| 74 | } // namespace Service::IRS | 110 | } // namespace Service::IRS |
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 6a7f48b6f..ef3bdfb1a 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp | |||
| @@ -804,6 +804,7 @@ void GRenderWindow::TouchEndEvent() { | |||
| 804 | } | 804 | } |
| 805 | 805 | ||
| 806 | void GRenderWindow::InitializeCamera() { | 806 | void GRenderWindow::InitializeCamera() { |
| 807 | constexpr auto camera_update_ms = std::chrono::milliseconds{50}; // (50ms, 20Hz) | ||
| 807 | if (!Settings::values.enable_ir_sensor) { | 808 | if (!Settings::values.enable_ir_sensor) { |
| 808 | return; | 809 | return; |
| 809 | } | 810 | } |
| @@ -837,7 +838,7 @@ void GRenderWindow::InitializeCamera() { | |||
| 837 | camera_timer = std::make_unique<QTimer>(); | 838 | camera_timer = std::make_unique<QTimer>(); |
| 838 | connect(camera_timer.get(), &QTimer::timeout, [this] { RequestCameraCapture(); }); | 839 | connect(camera_timer.get(), &QTimer::timeout, [this] { RequestCameraCapture(); }); |
| 839 | // This timer should be dependent of camera resolution 5ms for every 100 pixels | 840 | // This timer should be dependent of camera resolution 5ms for every 100 pixels |
| 840 | camera_timer->start(100); | 841 | camera_timer->start(camera_update_ms); |
| 841 | } | 842 | } |
| 842 | 843 | ||
| 843 | void GRenderWindow::FinalizeCamera() { | 844 | void GRenderWindow::FinalizeCamera() { |