diff options
37 files changed, 692 insertions, 325 deletions
diff --git a/.ci/scripts/clang/docker.sh b/.ci/scripts/clang/docker.sh index 7d3ae4a1a..51769545e 100755 --- a/.ci/scripts/clang/docker.sh +++ b/.ci/scripts/clang/docker.sh | |||
| @@ -11,6 +11,7 @@ ccache -s | |||
| 11 | mkdir build || true && cd build | 11 | mkdir build || true && cd build |
| 12 | cmake .. \ | 12 | cmake .. \ |
| 13 | -DCMAKE_BUILD_TYPE=Release \ | 13 | -DCMAKE_BUILD_TYPE=Release \ |
| 14 | -DCMAKE_CXX_FLAGS="-march=x86-64-v2" \ | ||
| 14 | -DCMAKE_CXX_COMPILER=/usr/lib/ccache/clang++ \ | 15 | -DCMAKE_CXX_COMPILER=/usr/lib/ccache/clang++ \ |
| 15 | -DCMAKE_C_COMPILER=/usr/lib/ccache/clang \ | 16 | -DCMAKE_C_COMPILER=/usr/lib/ccache/clang \ |
| 16 | -DCMAKE_INSTALL_PREFIX="/usr" \ | 17 | -DCMAKE_INSTALL_PREFIX="/usr" \ |
diff --git a/.ci/scripts/linux/docker.sh b/.ci/scripts/linux/docker.sh index 35c4a4368..c8bc56c9a 100755 --- a/.ci/scripts/linux/docker.sh +++ b/.ci/scripts/linux/docker.sh | |||
| @@ -12,6 +12,7 @@ mkdir build || true && cd build | |||
| 12 | cmake .. \ | 12 | cmake .. \ |
| 13 | -DBoost_USE_STATIC_LIBS=ON \ | 13 | -DBoost_USE_STATIC_LIBS=ON \ |
| 14 | -DCMAKE_BUILD_TYPE=Release \ | 14 | -DCMAKE_BUILD_TYPE=Release \ |
| 15 | -DCMAKE_CXX_FLAGS="-march=x86-64-v2" \ | ||
| 15 | -DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ \ | 16 | -DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ \ |
| 16 | -DCMAKE_C_COMPILER=/usr/lib/ccache/gcc \ | 17 | -DCMAKE_C_COMPILER=/usr/lib/ccache/gcc \ |
| 17 | -DCMAKE_INSTALL_PREFIX="/usr" \ | 18 | -DCMAKE_INSTALL_PREFIX="/usr" \ |
diff --git a/.ci/templates/build-msvc.yml b/.ci/templates/build-msvc.yml index ea405e5dc..c379dd757 100644 --- a/.ci/templates/build-msvc.yml +++ b/.ci/templates/build-msvc.yml | |||
| @@ -9,7 +9,7 @@ parameters: | |||
| 9 | steps: | 9 | steps: |
| 10 | - script: choco install vulkan-sdk | 10 | - script: choco install vulkan-sdk |
| 11 | displayName: 'Install vulkan-sdk' | 11 | displayName: 'Install vulkan-sdk' |
| 12 | - script: refreshenv && mkdir build && cd build && cmake -G "Visual Studio 17 2022" -A x64 -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_BUNDLED_SDL2=1 -DYUZU_USE_QT_WEB_ENGINE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DYUZU_TESTS=OFF -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON -DDISPLAY_VERSION=${{ parameters['version'] }} -DCMAKE_BUILD_TYPE=Release -DYUZU_CRASH_DUMPS=ON .. && cd .. | 12 | - script: refreshenv && mkdir build && cd build && cmake -E env CXXFLAGS="/Gw /GA /Gr /Ob2" cmake -G "Visual Studio 17 2022" -A x64 -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON -DCMAKE_POLICY_DEFAULT_CMP0069=NEW -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_BUNDLED_SDL2=1 -DYUZU_USE_QT_WEB_ENGINE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DYUZU_TESTS=OFF -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON -DDISPLAY_VERSION=${{ parameters['version'] }} -DCMAKE_BUILD_TYPE=Release -DYUZU_CRASH_DUMPS=ON .. && cd .. |
| 13 | displayName: 'Configure CMake' | 13 | displayName: 'Configure CMake' |
| 14 | - task: MSBuild@1 | 14 | - task: MSBuild@1 |
| 15 | displayName: 'Build' | 15 | displayName: 'Build' |
diff --git a/CMakeLists.txt b/CMakeLists.txt index 47eddf99e..f71a8b3e3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt | |||
| @@ -208,7 +208,7 @@ find_package(libusb 1.0.24) | |||
| 208 | find_package(lz4 REQUIRED) | 208 | find_package(lz4 REQUIRED) |
| 209 | find_package(nlohmann_json 3.8 REQUIRED) | 209 | find_package(nlohmann_json 3.8 REQUIRED) |
| 210 | find_package(Opus 1.3) | 210 | find_package(Opus 1.3) |
| 211 | find_package(Vulkan 1.3.213) | 211 | find_package(Vulkan 1.3.238) |
| 212 | find_package(ZLIB 1.2 REQUIRED) | 212 | find_package(ZLIB 1.2 REQUIRED) |
| 213 | find_package(zstd 1.5 REQUIRED) | 213 | find_package(zstd 1.5 REQUIRED) |
| 214 | 214 | ||
diff --git a/externals/Vulkan-Headers b/externals/Vulkan-Headers | |||
| Subproject 2826791bed6a793f164bf534cd859968f13df8a | Subproject 00671c64ba5c488ade22ad572a0ef81d5e64c80 | ||
diff --git a/src/common/assert.h b/src/common/assert.h index 8c927fcc0..67e7e9375 100644 --- a/src/common/assert.h +++ b/src/common/assert.h | |||
| @@ -69,7 +69,7 @@ void assert_fail_impl(); | |||
| 69 | #define ASSERT_OR_EXECUTE(_a_, _b_) \ | 69 | #define ASSERT_OR_EXECUTE(_a_, _b_) \ |
| 70 | do { \ | 70 | do { \ |
| 71 | ASSERT(_a_); \ | 71 | ASSERT(_a_); \ |
| 72 | if (!(_a_)) { \ | 72 | if (!(_a_)) [[unlikely]] { \ |
| 73 | _b_ \ | 73 | _b_ \ |
| 74 | } \ | 74 | } \ |
| 75 | } while (0) | 75 | } while (0) |
| @@ -78,7 +78,7 @@ void assert_fail_impl(); | |||
| 78 | #define ASSERT_OR_EXECUTE_MSG(_a_, _b_, ...) \ | 78 | #define ASSERT_OR_EXECUTE_MSG(_a_, _b_, ...) \ |
| 79 | do { \ | 79 | do { \ |
| 80 | ASSERT_MSG(_a_, __VA_ARGS__); \ | 80 | ASSERT_MSG(_a_, __VA_ARGS__); \ |
| 81 | if (!(_a_)) { \ | 81 | if (!(_a_)) [[unlikely]] { \ |
| 82 | _b_ \ | 82 | _b_ \ |
| 83 | } \ | 83 | } \ |
| 84 | } while (0) | 84 | } while (0) |
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index c6b5ac196..0252c8c31 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -201,6 +201,9 @@ add_library(core STATIC | |||
| 201 | hle/kernel/k_event_info.h | 201 | hle/kernel/k_event_info.h |
| 202 | hle/kernel/k_handle_table.cpp | 202 | hle/kernel/k_handle_table.cpp |
| 203 | hle/kernel/k_handle_table.h | 203 | hle/kernel/k_handle_table.h |
| 204 | hle/kernel/k_hardware_timer_base.h | ||
| 205 | hle/kernel/k_hardware_timer.cpp | ||
| 206 | hle/kernel/k_hardware_timer.h | ||
| 204 | hle/kernel/k_interrupt_manager.cpp | 207 | hle/kernel/k_interrupt_manager.cpp |
| 205 | hle/kernel/k_interrupt_manager.h | 208 | hle/kernel/k_interrupt_manager.h |
| 206 | hle/kernel/k_light_condition_variable.cpp | 209 | hle/kernel/k_light_condition_variable.cpp |
| @@ -268,6 +271,7 @@ add_library(core STATIC | |||
| 268 | hle/kernel/k_thread_local_page.h | 271 | hle/kernel/k_thread_local_page.h |
| 269 | hle/kernel/k_thread_queue.cpp | 272 | hle/kernel/k_thread_queue.cpp |
| 270 | hle/kernel/k_thread_queue.h | 273 | hle/kernel/k_thread_queue.h |
| 274 | hle/kernel/k_timer_task.h | ||
| 271 | hle/kernel/k_trace.h | 275 | hle/kernel/k_trace.h |
| 272 | hle/kernel/k_transfer_memory.cpp | 276 | hle/kernel/k_transfer_memory.cpp |
| 273 | hle/kernel/k_transfer_memory.h | 277 | hle/kernel/k_transfer_memory.h |
| @@ -290,8 +294,6 @@ add_library(core STATIC | |||
| 290 | hle/kernel/svc_common.h | 294 | hle/kernel/svc_common.h |
| 291 | hle/kernel/svc_types.h | 295 | hle/kernel/svc_types.h |
| 292 | hle/kernel/svc_wrap.h | 296 | hle/kernel/svc_wrap.h |
| 293 | hle/kernel/time_manager.cpp | ||
| 294 | hle/kernel/time_manager.h | ||
| 295 | hle/result.h | 297 | hle/result.h |
| 296 | hle/service/acc/acc.cpp | 298 | hle/service/acc/acc.cpp |
| 297 | hle/service/acc/acc.h | 299 | hle/service/acc/acc.h |
diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 67969e938..f238d6ccd 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp | |||
| @@ -145,6 +145,7 @@ void EmulatedController::LoadDevices() { | |||
| 145 | output_params[3].Set("output", true); | 145 | output_params[3].Set("output", true); |
| 146 | 146 | ||
| 147 | LoadTASParams(); | 147 | LoadTASParams(); |
| 148 | LoadVirtualGamepadParams(); | ||
| 148 | 149 | ||
| 149 | std::ranges::transform(button_params, button_devices.begin(), Common::Input::CreateInputDevice); | 150 | std::ranges::transform(button_params, button_devices.begin(), Common::Input::CreateInputDevice); |
| 150 | std::ranges::transform(stick_params, stick_devices.begin(), Common::Input::CreateInputDevice); | 151 | std::ranges::transform(stick_params, stick_devices.begin(), Common::Input::CreateInputDevice); |
| @@ -163,6 +164,12 @@ void EmulatedController::LoadDevices() { | |||
| 163 | Common::Input::CreateInputDevice); | 164 | Common::Input::CreateInputDevice); |
| 164 | std::ranges::transform(tas_stick_params, tas_stick_devices.begin(), | 165 | std::ranges::transform(tas_stick_params, tas_stick_devices.begin(), |
| 165 | Common::Input::CreateInputDevice); | 166 | Common::Input::CreateInputDevice); |
| 167 | |||
| 168 | // Initialize virtual gamepad devices | ||
| 169 | std::ranges::transform(virtual_button_params, virtual_button_devices.begin(), | ||
| 170 | Common::Input::CreateInputDevice); | ||
| 171 | std::ranges::transform(virtual_stick_params, virtual_stick_devices.begin(), | ||
| 172 | Common::Input::CreateInputDevice); | ||
| 166 | } | 173 | } |
| 167 | 174 | ||
| 168 | void EmulatedController::LoadTASParams() { | 175 | void EmulatedController::LoadTASParams() { |
| @@ -205,6 +212,46 @@ void EmulatedController::LoadTASParams() { | |||
| 205 | tas_stick_params[Settings::NativeAnalog::RStick].Set("axis_y", 3); | 212 | tas_stick_params[Settings::NativeAnalog::RStick].Set("axis_y", 3); |
| 206 | } | 213 | } |
| 207 | 214 | ||
| 215 | void EmulatedController::LoadVirtualGamepadParams() { | ||
| 216 | const auto player_index = NpadIdTypeToIndex(npad_id_type); | ||
| 217 | Common::ParamPackage common_params{}; | ||
| 218 | common_params.Set("engine", "virtual_gamepad"); | ||
| 219 | common_params.Set("port", static_cast<int>(player_index)); | ||
| 220 | for (auto& param : virtual_button_params) { | ||
| 221 | param = common_params; | ||
| 222 | } | ||
| 223 | for (auto& param : virtual_stick_params) { | ||
| 224 | param = common_params; | ||
| 225 | } | ||
| 226 | |||
| 227 | // TODO(german77): Replace this with an input profile or something better | ||
| 228 | virtual_button_params[Settings::NativeButton::A].Set("button", 0); | ||
| 229 | virtual_button_params[Settings::NativeButton::B].Set("button", 1); | ||
| 230 | virtual_button_params[Settings::NativeButton::X].Set("button", 2); | ||
| 231 | virtual_button_params[Settings::NativeButton::Y].Set("button", 3); | ||
| 232 | virtual_button_params[Settings::NativeButton::LStick].Set("button", 4); | ||
| 233 | virtual_button_params[Settings::NativeButton::RStick].Set("button", 5); | ||
| 234 | virtual_button_params[Settings::NativeButton::L].Set("button", 6); | ||
| 235 | virtual_button_params[Settings::NativeButton::R].Set("button", 7); | ||
| 236 | virtual_button_params[Settings::NativeButton::ZL].Set("button", 8); | ||
| 237 | virtual_button_params[Settings::NativeButton::ZR].Set("button", 9); | ||
| 238 | virtual_button_params[Settings::NativeButton::Plus].Set("button", 10); | ||
| 239 | virtual_button_params[Settings::NativeButton::Minus].Set("button", 11); | ||
| 240 | virtual_button_params[Settings::NativeButton::DLeft].Set("button", 12); | ||
| 241 | virtual_button_params[Settings::NativeButton::DUp].Set("button", 13); | ||
| 242 | virtual_button_params[Settings::NativeButton::DRight].Set("button", 14); | ||
| 243 | virtual_button_params[Settings::NativeButton::DDown].Set("button", 15); | ||
| 244 | virtual_button_params[Settings::NativeButton::SL].Set("button", 16); | ||
| 245 | virtual_button_params[Settings::NativeButton::SR].Set("button", 17); | ||
| 246 | virtual_button_params[Settings::NativeButton::Home].Set("button", 18); | ||
| 247 | virtual_button_params[Settings::NativeButton::Screenshot].Set("button", 19); | ||
| 248 | |||
| 249 | virtual_stick_params[Settings::NativeAnalog::LStick].Set("axis_x", 0); | ||
| 250 | virtual_stick_params[Settings::NativeAnalog::LStick].Set("axis_y", 1); | ||
| 251 | virtual_stick_params[Settings::NativeAnalog::RStick].Set("axis_x", 2); | ||
| 252 | virtual_stick_params[Settings::NativeAnalog::RStick].Set("axis_y", 3); | ||
| 253 | } | ||
| 254 | |||
| 208 | void EmulatedController::ReloadInput() { | 255 | void EmulatedController::ReloadInput() { |
| 209 | // If you load any device here add the equivalent to the UnloadInput() function | 256 | // If you load any device here add the equivalent to the UnloadInput() function |
| 210 | LoadDevices(); | 257 | LoadDevices(); |
| @@ -322,6 +369,35 @@ void EmulatedController::ReloadInput() { | |||
| 322 | }, | 369 | }, |
| 323 | }); | 370 | }); |
| 324 | } | 371 | } |
| 372 | |||
| 373 | // Use a common UUID for Virtual Gamepad | ||
| 374 | static constexpr Common::UUID VIRTUAL_UUID = Common::UUID{ | ||
| 375 | {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}; | ||
| 376 | |||
| 377 | // Register virtual devices. No need to force update | ||
| 378 | for (std::size_t index = 0; index < virtual_button_devices.size(); ++index) { | ||
| 379 | if (!virtual_button_devices[index]) { | ||
| 380 | continue; | ||
| 381 | } | ||
| 382 | virtual_button_devices[index]->SetCallback({ | ||
| 383 | .on_change = | ||
| 384 | [this, index](const Common::Input::CallbackStatus& callback) { | ||
| 385 | SetButton(callback, index, VIRTUAL_UUID); | ||
| 386 | }, | ||
| 387 | }); | ||
| 388 | } | ||
| 389 | |||
| 390 | for (std::size_t index = 0; index < virtual_stick_devices.size(); ++index) { | ||
| 391 | if (!virtual_stick_devices[index]) { | ||
| 392 | continue; | ||
| 393 | } | ||
| 394 | virtual_stick_devices[index]->SetCallback({ | ||
| 395 | .on_change = | ||
| 396 | [this, index](const Common::Input::CallbackStatus& callback) { | ||
| 397 | SetStick(callback, index, VIRTUAL_UUID); | ||
| 398 | }, | ||
| 399 | }); | ||
| 400 | } | ||
| 325 | } | 401 | } |
| 326 | 402 | ||
| 327 | void EmulatedController::UnloadInput() { | 403 | void EmulatedController::UnloadInput() { |
| @@ -349,6 +425,12 @@ void EmulatedController::UnloadInput() { | |||
| 349 | for (auto& stick : tas_stick_devices) { | 425 | for (auto& stick : tas_stick_devices) { |
| 350 | stick.reset(); | 426 | stick.reset(); |
| 351 | } | 427 | } |
| 428 | for (auto& button : virtual_button_devices) { | ||
| 429 | button.reset(); | ||
| 430 | } | ||
| 431 | for (auto& stick : virtual_stick_devices) { | ||
| 432 | stick.reset(); | ||
| 433 | } | ||
| 352 | camera_devices.reset(); | 434 | camera_devices.reset(); |
| 353 | nfc_devices.reset(); | 435 | nfc_devices.reset(); |
| 354 | } | 436 | } |
diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index fa7a34278..a398543a6 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h | |||
| @@ -385,6 +385,9 @@ private: | |||
| 385 | /// Set the params for TAS devices | 385 | /// Set the params for TAS devices |
| 386 | void LoadTASParams(); | 386 | void LoadTASParams(); |
| 387 | 387 | ||
| 388 | /// Set the params for virtual pad devices | ||
| 389 | void LoadVirtualGamepadParams(); | ||
| 390 | |||
| 388 | /** | 391 | /** |
| 389 | * @param use_temporary_value If true tmp_npad_type will be used | 392 | * @param use_temporary_value If true tmp_npad_type will be used |
| 390 | * @return true if the controller style is fullkey | 393 | * @return true if the controller style is fullkey |
| @@ -500,6 +503,12 @@ private: | |||
| 500 | ButtonDevices tas_button_devices; | 503 | ButtonDevices tas_button_devices; |
| 501 | StickDevices tas_stick_devices; | 504 | StickDevices tas_stick_devices; |
| 502 | 505 | ||
| 506 | // Virtual gamepad related variables | ||
| 507 | ButtonParams virtual_button_params; | ||
| 508 | StickParams virtual_stick_params; | ||
| 509 | ButtonDevices virtual_button_devices; | ||
| 510 | StickDevices virtual_stick_devices; | ||
| 511 | |||
| 503 | mutable std::mutex mutex; | 512 | mutable std::mutex mutex; |
| 504 | mutable std::mutex callback_mutex; | 513 | mutable std::mutex callback_mutex; |
| 505 | std::unordered_map<int, ControllerUpdateCallback> callback_list; | 514 | std::unordered_map<int, ControllerUpdateCallback> callback_list; |
diff --git a/src/core/hle/kernel/k_address_arbiter.cpp b/src/core/hle/kernel/k_address_arbiter.cpp index f85b11557..a442a3b98 100644 --- a/src/core/hle/kernel/k_address_arbiter.cpp +++ b/src/core/hle/kernel/k_address_arbiter.cpp | |||
| @@ -10,7 +10,6 @@ | |||
| 10 | #include "core/hle/kernel/k_thread_queue.h" | 10 | #include "core/hle/kernel/k_thread_queue.h" |
| 11 | #include "core/hle/kernel/kernel.h" | 11 | #include "core/hle/kernel/kernel.h" |
| 12 | #include "core/hle/kernel/svc_results.h" | 12 | #include "core/hle/kernel/svc_results.h" |
| 13 | #include "core/hle/kernel/time_manager.h" | ||
| 14 | #include "core/memory.h" | 13 | #include "core/memory.h" |
| 15 | 14 | ||
| 16 | namespace Kernel { | 15 | namespace Kernel { |
diff --git a/src/core/hle/kernel/k_hardware_timer.cpp b/src/core/hle/kernel/k_hardware_timer.cpp new file mode 100644 index 000000000..6bba79ea0 --- /dev/null +++ b/src/core/hle/kernel/k_hardware_timer.cpp | |||
| @@ -0,0 +1,74 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/core.h" | ||
| 5 | #include "core/core_timing.h" | ||
| 6 | #include "core/hle/kernel/k_hardware_timer.h" | ||
| 7 | #include "core/hle/kernel/k_scheduler.h" | ||
| 8 | |||
| 9 | namespace Kernel { | ||
| 10 | |||
| 11 | void KHardwareTimer::Initialize() { | ||
| 12 | // Create the timing callback to register with CoreTiming. | ||
| 13 | m_event_type = Core::Timing::CreateEvent( | ||
| 14 | "KHardwareTimer::Callback", [](std::uintptr_t timer_handle, s64, std::chrono::nanoseconds) { | ||
| 15 | reinterpret_cast<KHardwareTimer*>(timer_handle)->DoTask(); | ||
| 16 | return std::nullopt; | ||
| 17 | }); | ||
| 18 | } | ||
| 19 | |||
| 20 | void KHardwareTimer::Finalize() { | ||
| 21 | this->DisableInterrupt(); | ||
| 22 | m_event_type.reset(); | ||
| 23 | } | ||
| 24 | |||
| 25 | void KHardwareTimer::DoTask() { | ||
| 26 | // Handle the interrupt. | ||
| 27 | { | ||
| 28 | KScopedSchedulerLock slk{m_kernel}; | ||
| 29 | KScopedSpinLock lk(this->GetLock()); | ||
| 30 | |||
| 31 | //! Ignore this event if needed. | ||
| 32 | if (!this->GetInterruptEnabled()) { | ||
| 33 | return; | ||
| 34 | } | ||
| 35 | |||
| 36 | // Disable the timer interrupt while we handle this. | ||
| 37 | this->DisableInterrupt(); | ||
| 38 | |||
| 39 | if (const s64 next_time = this->DoInterruptTaskImpl(GetTick()); | ||
| 40 | 0 < next_time && next_time <= m_wakeup_time) { | ||
| 41 | // We have a next time, so we should set the time to interrupt and turn the interrupt | ||
| 42 | // on. | ||
| 43 | this->EnableInterrupt(next_time); | ||
| 44 | } | ||
| 45 | } | ||
| 46 | |||
| 47 | // Clear the timer interrupt. | ||
| 48 | // Kernel::GetInterruptManager().ClearInterrupt(KInterruptName_NonSecurePhysicalTimer, | ||
| 49 | // GetCurrentCoreId()); | ||
| 50 | } | ||
| 51 | |||
| 52 | void KHardwareTimer::EnableInterrupt(s64 wakeup_time) { | ||
| 53 | this->DisableInterrupt(); | ||
| 54 | |||
| 55 | m_wakeup_time = wakeup_time; | ||
| 56 | m_kernel.System().CoreTiming().ScheduleEvent(std::chrono::nanoseconds{m_wakeup_time}, | ||
| 57 | m_event_type, reinterpret_cast<uintptr_t>(this), | ||
| 58 | true); | ||
| 59 | } | ||
| 60 | |||
| 61 | void KHardwareTimer::DisableInterrupt() { | ||
| 62 | m_kernel.System().CoreTiming().UnscheduleEvent(m_event_type, reinterpret_cast<uintptr_t>(this)); | ||
| 63 | m_wakeup_time = std::numeric_limits<s64>::max(); | ||
| 64 | } | ||
| 65 | |||
| 66 | s64 KHardwareTimer::GetTick() const { | ||
| 67 | return m_kernel.System().CoreTiming().GetGlobalTimeNs().count(); | ||
| 68 | } | ||
| 69 | |||
| 70 | bool KHardwareTimer::GetInterruptEnabled() { | ||
| 71 | return m_wakeup_time != std::numeric_limits<s64>::max(); | ||
| 72 | } | ||
| 73 | |||
| 74 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/k_hardware_timer.h b/src/core/hle/kernel/k_hardware_timer.h new file mode 100644 index 000000000..00bef6ea1 --- /dev/null +++ b/src/core/hle/kernel/k_hardware_timer.h | |||
| @@ -0,0 +1,54 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/kernel/k_hardware_timer_base.h" | ||
| 7 | |||
| 8 | namespace Core::Timing { | ||
| 9 | struct EventType; | ||
| 10 | } // namespace Core::Timing | ||
| 11 | |||
| 12 | namespace Kernel { | ||
| 13 | |||
| 14 | class KHardwareTimer : /* public KInterruptTask, */ public KHardwareTimerBase { | ||
| 15 | public: | ||
| 16 | explicit KHardwareTimer(KernelCore& kernel) : KHardwareTimerBase{kernel} {} | ||
| 17 | |||
| 18 | // Public API. | ||
| 19 | void Initialize(); | ||
| 20 | void Finalize(); | ||
| 21 | |||
| 22 | s64 GetCount() const { | ||
| 23 | return GetTick(); | ||
| 24 | } | ||
| 25 | |||
| 26 | void RegisterTask(KTimerTask* task, s64 time_from_now) { | ||
| 27 | this->RegisterAbsoluteTask(task, GetTick() + time_from_now); | ||
| 28 | } | ||
| 29 | |||
| 30 | void RegisterAbsoluteTask(KTimerTask* task, s64 task_time) { | ||
| 31 | KScopedDisableDispatch dd{m_kernel}; | ||
| 32 | KScopedSpinLock lk{this->GetLock()}; | ||
| 33 | |||
| 34 | if (this->RegisterAbsoluteTaskImpl(task, task_time)) { | ||
| 35 | if (task_time <= m_wakeup_time) { | ||
| 36 | this->EnableInterrupt(task_time); | ||
| 37 | } | ||
| 38 | } | ||
| 39 | } | ||
| 40 | |||
| 41 | private: | ||
| 42 | void EnableInterrupt(s64 wakeup_time); | ||
| 43 | void DisableInterrupt(); | ||
| 44 | bool GetInterruptEnabled(); | ||
| 45 | s64 GetTick() const; | ||
| 46 | void DoTask(); | ||
| 47 | |||
| 48 | private: | ||
| 49 | // Absolute time in nanoseconds | ||
| 50 | s64 m_wakeup_time{std::numeric_limits<s64>::max()}; | ||
| 51 | std::shared_ptr<Core::Timing::EventType> m_event_type{}; | ||
| 52 | }; | ||
| 53 | |||
| 54 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/k_hardware_timer_base.h b/src/core/hle/kernel/k_hardware_timer_base.h new file mode 100644 index 000000000..6318b35bd --- /dev/null +++ b/src/core/hle/kernel/k_hardware_timer_base.h | |||
| @@ -0,0 +1,92 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/kernel/k_spin_lock.h" | ||
| 7 | #include "core/hle/kernel/k_thread.h" | ||
| 8 | #include "core/hle/kernel/k_timer_task.h" | ||
| 9 | |||
| 10 | namespace Kernel { | ||
| 11 | |||
| 12 | class KHardwareTimerBase { | ||
| 13 | public: | ||
| 14 | explicit KHardwareTimerBase(KernelCore& kernel) : m_kernel{kernel} {} | ||
| 15 | |||
| 16 | void CancelTask(KTimerTask* task) { | ||
| 17 | KScopedDisableDispatch dd{m_kernel}; | ||
| 18 | KScopedSpinLock lk{m_lock}; | ||
| 19 | |||
| 20 | if (const s64 task_time = task->GetTime(); task_time > 0) { | ||
| 21 | this->RemoveTaskFromTree(task); | ||
| 22 | } | ||
| 23 | } | ||
| 24 | |||
| 25 | protected: | ||
| 26 | KSpinLock& GetLock() { | ||
| 27 | return m_lock; | ||
| 28 | } | ||
| 29 | |||
| 30 | s64 DoInterruptTaskImpl(s64 cur_time) { | ||
| 31 | // We want to handle all tasks, returning the next time that a task is scheduled. | ||
| 32 | while (true) { | ||
| 33 | // Get the next task. If there isn't one, return 0. | ||
| 34 | KTimerTask* task = m_next_task; | ||
| 35 | if (task == nullptr) { | ||
| 36 | return 0; | ||
| 37 | } | ||
| 38 | |||
| 39 | // If the task needs to be done in the future, do it in the future and not now. | ||
| 40 | if (const s64 task_time = task->GetTime(); task_time > cur_time) { | ||
| 41 | return task_time; | ||
| 42 | } | ||
| 43 | |||
| 44 | // Remove the task from the tree of tasks, and update our next task. | ||
| 45 | this->RemoveTaskFromTree(task); | ||
| 46 | |||
| 47 | // Handle the task. | ||
| 48 | task->OnTimer(); | ||
| 49 | } | ||
| 50 | } | ||
| 51 | |||
| 52 | bool RegisterAbsoluteTaskImpl(KTimerTask* task, s64 task_time) { | ||
| 53 | ASSERT(task_time > 0); | ||
| 54 | |||
| 55 | // Set the task's time, and insert it into our tree. | ||
| 56 | task->SetTime(task_time); | ||
| 57 | m_task_tree.insert(*task); | ||
| 58 | |||
| 59 | // Update our next task if relevant. | ||
| 60 | if (m_next_task != nullptr && m_next_task->GetTime() <= task_time) { | ||
| 61 | return false; | ||
| 62 | } | ||
| 63 | m_next_task = task; | ||
| 64 | return true; | ||
| 65 | } | ||
| 66 | |||
| 67 | private: | ||
| 68 | void RemoveTaskFromTree(KTimerTask* task) { | ||
| 69 | // Erase from the tree. | ||
| 70 | auto it = m_task_tree.erase(m_task_tree.iterator_to(*task)); | ||
| 71 | |||
| 72 | // Clear the task's scheduled time. | ||
| 73 | task->SetTime(0); | ||
| 74 | |||
| 75 | // Update our next task if relevant. | ||
| 76 | if (m_next_task == task) { | ||
| 77 | m_next_task = (it != m_task_tree.end()) ? std::addressof(*it) : nullptr; | ||
| 78 | } | ||
| 79 | } | ||
| 80 | |||
| 81 | protected: | ||
| 82 | KernelCore& m_kernel; | ||
| 83 | |||
| 84 | private: | ||
| 85 | using TimerTaskTree = Common::IntrusiveRedBlackTreeBaseTraits<KTimerTask>::TreeType<KTimerTask>; | ||
| 86 | |||
| 87 | KSpinLock m_lock{}; | ||
| 88 | TimerTaskTree m_task_tree{}; | ||
| 89 | KTimerTask* m_next_task{}; | ||
| 90 | }; | ||
| 91 | |||
| 92 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h b/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h index 76c095e69..76db65a4d 100644 --- a/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h +++ b/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h | |||
| @@ -5,9 +5,9 @@ | |||
| 5 | 5 | ||
| 6 | #include "common/common_types.h" | 6 | #include "common/common_types.h" |
| 7 | #include "core/hle/kernel/global_scheduler_context.h" | 7 | #include "core/hle/kernel/global_scheduler_context.h" |
| 8 | #include "core/hle/kernel/k_hardware_timer.h" | ||
| 8 | #include "core/hle/kernel/k_thread.h" | 9 | #include "core/hle/kernel/k_thread.h" |
| 9 | #include "core/hle/kernel/kernel.h" | 10 | #include "core/hle/kernel/kernel.h" |
| 10 | #include "core/hle/kernel/time_manager.h" | ||
| 11 | 11 | ||
| 12 | namespace Kernel { | 12 | namespace Kernel { |
| 13 | 13 | ||
| @@ -22,7 +22,7 @@ public: | |||
| 22 | ~KScopedSchedulerLockAndSleep() { | 22 | ~KScopedSchedulerLockAndSleep() { |
| 23 | // Register the sleep. | 23 | // Register the sleep. |
| 24 | if (timeout_tick > 0) { | 24 | if (timeout_tick > 0) { |
| 25 | kernel.TimeManager().ScheduleTimeEvent(thread, timeout_tick); | 25 | kernel.HardwareTimer().RegisterTask(thread, timeout_tick); |
| 26 | } | 26 | } |
| 27 | 27 | ||
| 28 | // Unlock the scheduler. | 28 | // Unlock the scheduler. |
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index dc52b4ed3..7cd94a340 100644 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h | |||
| @@ -22,6 +22,7 @@ | |||
| 22 | #include "core/hle/kernel/k_light_lock.h" | 22 | #include "core/hle/kernel/k_light_lock.h" |
| 23 | #include "core/hle/kernel/k_spin_lock.h" | 23 | #include "core/hle/kernel/k_spin_lock.h" |
| 24 | #include "core/hle/kernel/k_synchronization_object.h" | 24 | #include "core/hle/kernel/k_synchronization_object.h" |
| 25 | #include "core/hle/kernel/k_timer_task.h" | ||
| 25 | #include "core/hle/kernel/k_worker_task.h" | 26 | #include "core/hle/kernel/k_worker_task.h" |
| 26 | #include "core/hle/kernel/slab_helpers.h" | 27 | #include "core/hle/kernel/slab_helpers.h" |
| 27 | #include "core/hle/kernel/svc_common.h" | 28 | #include "core/hle/kernel/svc_common.h" |
| @@ -112,7 +113,8 @@ void SetCurrentThread(KernelCore& kernel, KThread* thread); | |||
| 112 | [[nodiscard]] s32 GetCurrentCoreId(KernelCore& kernel); | 113 | [[nodiscard]] s32 GetCurrentCoreId(KernelCore& kernel); |
| 113 | 114 | ||
| 114 | class KThread final : public KAutoObjectWithSlabHeapAndContainer<KThread, KWorkerTask>, | 115 | class KThread final : public KAutoObjectWithSlabHeapAndContainer<KThread, KWorkerTask>, |
| 115 | public boost::intrusive::list_base_hook<> { | 116 | public boost::intrusive::list_base_hook<>, |
| 117 | public KTimerTask { | ||
| 116 | KERNEL_AUTOOBJECT_TRAITS(KThread, KSynchronizationObject); | 118 | KERNEL_AUTOOBJECT_TRAITS(KThread, KSynchronizationObject); |
| 117 | 119 | ||
| 118 | private: | 120 | private: |
| @@ -840,4 +842,8 @@ private: | |||
| 840 | KernelCore& kernel; | 842 | KernelCore& kernel; |
| 841 | }; | 843 | }; |
| 842 | 844 | ||
| 845 | inline void KTimerTask::OnTimer() { | ||
| 846 | static_cast<KThread*>(this)->OnTimer(); | ||
| 847 | } | ||
| 848 | |||
| 843 | } // namespace Kernel | 849 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/k_thread_queue.cpp b/src/core/hle/kernel/k_thread_queue.cpp index 9f4e081ba..5f1dc97eb 100644 --- a/src/core/hle/kernel/k_thread_queue.cpp +++ b/src/core/hle/kernel/k_thread_queue.cpp | |||
| @@ -1,9 +1,9 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include "core/hle/kernel/k_hardware_timer.h" | ||
| 4 | #include "core/hle/kernel/k_thread_queue.h" | 5 | #include "core/hle/kernel/k_thread_queue.h" |
| 5 | #include "core/hle/kernel/kernel.h" | 6 | #include "core/hle/kernel/kernel.h" |
| 6 | #include "core/hle/kernel/time_manager.h" | ||
| 7 | 7 | ||
| 8 | namespace Kernel { | 8 | namespace Kernel { |
| 9 | 9 | ||
| @@ -22,7 +22,7 @@ void KThreadQueue::EndWait(KThread* waiting_thread, Result wait_result) { | |||
| 22 | waiting_thread->ClearWaitQueue(); | 22 | waiting_thread->ClearWaitQueue(); |
| 23 | 23 | ||
| 24 | // Cancel the thread task. | 24 | // Cancel the thread task. |
| 25 | kernel.TimeManager().UnscheduleTimeEvent(waiting_thread); | 25 | kernel.HardwareTimer().CancelTask(waiting_thread); |
| 26 | } | 26 | } |
| 27 | 27 | ||
| 28 | void KThreadQueue::CancelWait(KThread* waiting_thread, Result wait_result, bool cancel_timer_task) { | 28 | void KThreadQueue::CancelWait(KThread* waiting_thread, Result wait_result, bool cancel_timer_task) { |
| @@ -37,7 +37,7 @@ void KThreadQueue::CancelWait(KThread* waiting_thread, Result wait_result, bool | |||
| 37 | 37 | ||
| 38 | // Cancel the thread task. | 38 | // Cancel the thread task. |
| 39 | if (cancel_timer_task) { | 39 | if (cancel_timer_task) { |
| 40 | kernel.TimeManager().UnscheduleTimeEvent(waiting_thread); | 40 | kernel.HardwareTimer().CancelTask(waiting_thread); |
| 41 | } | 41 | } |
| 42 | } | 42 | } |
| 43 | 43 | ||
diff --git a/src/core/hle/kernel/k_timer_task.h b/src/core/hle/kernel/k_timer_task.h new file mode 100644 index 000000000..66f0a5a90 --- /dev/null +++ b/src/core/hle/kernel/k_timer_task.h | |||
| @@ -0,0 +1,40 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "common/intrusive_red_black_tree.h" | ||
| 7 | |||
| 8 | namespace Kernel { | ||
| 9 | |||
| 10 | class KTimerTask : public Common::IntrusiveRedBlackTreeBaseNode<KTimerTask> { | ||
| 11 | public: | ||
| 12 | static constexpr int Compare(const KTimerTask& lhs, const KTimerTask& rhs) { | ||
| 13 | if (lhs.GetTime() < rhs.GetTime()) { | ||
| 14 | return -1; | ||
| 15 | } else { | ||
| 16 | return 1; | ||
| 17 | } | ||
| 18 | } | ||
| 19 | |||
| 20 | constexpr explicit KTimerTask() = default; | ||
| 21 | |||
| 22 | constexpr void SetTime(s64 t) { | ||
| 23 | m_time = t; | ||
| 24 | } | ||
| 25 | |||
| 26 | constexpr s64 GetTime() const { | ||
| 27 | return m_time; | ||
| 28 | } | ||
| 29 | |||
| 30 | // NOTE: This is virtual in Nintendo's kernel. Prior to 13.0.0, KWaitObject was also a | ||
| 31 | // TimerTask; this is no longer the case. Since this is now KThread exclusive, we have | ||
| 32 | // devirtualized (see inline declaration for this inside k_thread.h). | ||
| 33 | void OnTimer(); | ||
| 34 | |||
| 35 | private: | ||
| 36 | // Absolute time in nanoseconds | ||
| 37 | s64 m_time{}; | ||
| 38 | }; | ||
| 39 | |||
| 40 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 0eb74a422..b75bac5df 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -26,6 +26,7 @@ | |||
| 26 | #include "core/hle/kernel/k_client_port.h" | 26 | #include "core/hle/kernel/k_client_port.h" |
| 27 | #include "core/hle/kernel/k_dynamic_resource_manager.h" | 27 | #include "core/hle/kernel/k_dynamic_resource_manager.h" |
| 28 | #include "core/hle/kernel/k_handle_table.h" | 28 | #include "core/hle/kernel/k_handle_table.h" |
| 29 | #include "core/hle/kernel/k_hardware_timer.h" | ||
| 29 | #include "core/hle/kernel/k_memory_layout.h" | 30 | #include "core/hle/kernel/k_memory_layout.h" |
| 30 | #include "core/hle/kernel/k_memory_manager.h" | 31 | #include "core/hle/kernel/k_memory_manager.h" |
| 31 | #include "core/hle/kernel/k_page_buffer.h" | 32 | #include "core/hle/kernel/k_page_buffer.h" |
| @@ -39,7 +40,6 @@ | |||
| 39 | #include "core/hle/kernel/kernel.h" | 40 | #include "core/hle/kernel/kernel.h" |
| 40 | #include "core/hle/kernel/physical_core.h" | 41 | #include "core/hle/kernel/physical_core.h" |
| 41 | #include "core/hle/kernel/service_thread.h" | 42 | #include "core/hle/kernel/service_thread.h" |
| 42 | #include "core/hle/kernel/time_manager.h" | ||
| 43 | #include "core/hle/result.h" | 43 | #include "core/hle/result.h" |
| 44 | #include "core/hle/service/sm/sm.h" | 44 | #include "core/hle/service/sm/sm.h" |
| 45 | #include "core/memory.h" | 45 | #include "core/memory.h" |
| @@ -55,7 +55,7 @@ struct KernelCore::Impl { | |||
| 55 | static constexpr size_t ReservedDynamicPageCount = 64; | 55 | static constexpr size_t ReservedDynamicPageCount = 64; |
| 56 | 56 | ||
| 57 | explicit Impl(Core::System& system_, KernelCore& kernel_) | 57 | explicit Impl(Core::System& system_, KernelCore& kernel_) |
| 58 | : time_manager{system_}, service_threads_manager{1, "ServiceThreadsManager"}, | 58 | : service_threads_manager{1, "ServiceThreadsManager"}, |
| 59 | service_thread_barrier{2}, system{system_} {} | 59 | service_thread_barrier{2}, system{system_} {} |
| 60 | 60 | ||
| 61 | void SetMulticore(bool is_multi) { | 61 | void SetMulticore(bool is_multi) { |
| @@ -63,6 +63,9 @@ struct KernelCore::Impl { | |||
| 63 | } | 63 | } |
| 64 | 64 | ||
| 65 | void Initialize(KernelCore& kernel) { | 65 | void Initialize(KernelCore& kernel) { |
| 66 | hardware_timer = std::make_unique<Kernel::KHardwareTimer>(kernel); | ||
| 67 | hardware_timer->Initialize(); | ||
| 68 | |||
| 66 | global_object_list_container = std::make_unique<KAutoObjectWithListContainer>(kernel); | 69 | global_object_list_container = std::make_unique<KAutoObjectWithListContainer>(kernel); |
| 67 | global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel); | 70 | global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel); |
| 68 | global_handle_table = std::make_unique<Kernel::KHandleTable>(kernel); | 71 | global_handle_table = std::make_unique<Kernel::KHandleTable>(kernel); |
| @@ -193,6 +196,9 @@ struct KernelCore::Impl { | |||
| 193 | // Ensure that the object list container is finalized and properly shutdown. | 196 | // Ensure that the object list container is finalized and properly shutdown. |
| 194 | global_object_list_container->Finalize(); | 197 | global_object_list_container->Finalize(); |
| 195 | global_object_list_container.reset(); | 198 | global_object_list_container.reset(); |
| 199 | |||
| 200 | hardware_timer->Finalize(); | ||
| 201 | hardware_timer.reset(); | ||
| 196 | } | 202 | } |
| 197 | 203 | ||
| 198 | void CloseServices() { | 204 | void CloseServices() { |
| @@ -832,7 +838,7 @@ struct KernelCore::Impl { | |||
| 832 | std::vector<KProcess*> process_list; | 838 | std::vector<KProcess*> process_list; |
| 833 | std::atomic<KProcess*> current_process{}; | 839 | std::atomic<KProcess*> current_process{}; |
| 834 | std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context; | 840 | std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context; |
| 835 | Kernel::TimeManager time_manager; | 841 | std::unique_ptr<Kernel::KHardwareTimer> hardware_timer; |
| 836 | 842 | ||
| 837 | Init::KSlabResourceCounts slab_resource_counts{}; | 843 | Init::KSlabResourceCounts slab_resource_counts{}; |
| 838 | KResourceLimit* system_resource_limit{}; | 844 | KResourceLimit* system_resource_limit{}; |
| @@ -1019,12 +1025,8 @@ Kernel::KScheduler* KernelCore::CurrentScheduler() { | |||
| 1019 | return impl->schedulers[core_id].get(); | 1025 | return impl->schedulers[core_id].get(); |
| 1020 | } | 1026 | } |
| 1021 | 1027 | ||
| 1022 | Kernel::TimeManager& KernelCore::TimeManager() { | 1028 | Kernel::KHardwareTimer& KernelCore::HardwareTimer() { |
| 1023 | return impl->time_manager; | 1029 | return *impl->hardware_timer; |
| 1024 | } | ||
| 1025 | |||
| 1026 | const Kernel::TimeManager& KernelCore::TimeManager() const { | ||
| 1027 | return impl->time_manager; | ||
| 1028 | } | 1030 | } |
| 1029 | 1031 | ||
| 1030 | Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() { | 1032 | Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() { |
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 2e22fe0f6..8d22f8d2c 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h | |||
| @@ -39,6 +39,7 @@ class KDynamicPageManager; | |||
| 39 | class KEvent; | 39 | class KEvent; |
| 40 | class KEventInfo; | 40 | class KEventInfo; |
| 41 | class KHandleTable; | 41 | class KHandleTable; |
| 42 | class KHardwareTimer; | ||
| 42 | class KLinkedListNode; | 43 | class KLinkedListNode; |
| 43 | class KMemoryLayout; | 44 | class KMemoryLayout; |
| 44 | class KMemoryManager; | 45 | class KMemoryManager; |
| @@ -63,7 +64,6 @@ class KCodeMemory; | |||
| 63 | class PhysicalCore; | 64 | class PhysicalCore; |
| 64 | class ServiceThread; | 65 | class ServiceThread; |
| 65 | class Synchronization; | 66 | class Synchronization; |
| 66 | class TimeManager; | ||
| 67 | 67 | ||
| 68 | using ServiceInterfaceFactory = | 68 | using ServiceInterfaceFactory = |
| 69 | std::function<KClientPort&(Service::SM::ServiceManager&, Core::System&)>; | 69 | std::function<KClientPort&(Service::SM::ServiceManager&, Core::System&)>; |
| @@ -175,11 +175,8 @@ public: | |||
| 175 | /// Gets the an instance of the current physical CPU core. | 175 | /// Gets the an instance of the current physical CPU core. |
| 176 | const Kernel::PhysicalCore& CurrentPhysicalCore() const; | 176 | const Kernel::PhysicalCore& CurrentPhysicalCore() const; |
| 177 | 177 | ||
| 178 | /// Gets the an instance of the TimeManager Interface. | 178 | /// Gets the an instance of the hardware timer. |
| 179 | Kernel::TimeManager& TimeManager(); | 179 | Kernel::KHardwareTimer& HardwareTimer(); |
| 180 | |||
| 181 | /// Gets the an instance of the TimeManager Interface. | ||
| 182 | const Kernel::TimeManager& TimeManager() const; | ||
| 183 | 180 | ||
| 184 | /// Stops execution of 'id' core, in order to reschedule a new thread. | 181 | /// Stops execution of 'id' core, in order to reschedule a new thread. |
| 185 | void PrepareReschedule(std::size_t id); | 182 | void PrepareReschedule(std::size_t id); |
diff --git a/src/core/hle/kernel/time_manager.cpp b/src/core/hle/kernel/time_manager.cpp deleted file mode 100644 index 5ee72c432..000000000 --- a/src/core/hle/kernel/time_manager.cpp +++ /dev/null | |||
| @@ -1,44 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "common/assert.h" | ||
| 5 | #include "core/core.h" | ||
| 6 | #include "core/core_timing.h" | ||
| 7 | #include "core/hle/kernel/k_scheduler.h" | ||
| 8 | #include "core/hle/kernel/k_thread.h" | ||
| 9 | #include "core/hle/kernel/time_manager.h" | ||
| 10 | |||
| 11 | namespace Kernel { | ||
| 12 | |||
| 13 | TimeManager::TimeManager(Core::System& system_) : system{system_} { | ||
| 14 | time_manager_event_type = Core::Timing::CreateEvent( | ||
| 15 | "Kernel::TimeManagerCallback", | ||
| 16 | [this](std::uintptr_t thread_handle, s64 time, | ||
| 17 | std::chrono::nanoseconds) -> std::optional<std::chrono::nanoseconds> { | ||
| 18 | KThread* thread = reinterpret_cast<KThread*>(thread_handle); | ||
| 19 | { | ||
| 20 | KScopedSchedulerLock sl(system.Kernel()); | ||
| 21 | thread->OnTimer(); | ||
| 22 | } | ||
| 23 | return std::nullopt; | ||
| 24 | }); | ||
| 25 | } | ||
| 26 | |||
| 27 | void TimeManager::ScheduleTimeEvent(KThread* thread, s64 nanoseconds) { | ||
| 28 | std::scoped_lock lock{mutex}; | ||
| 29 | if (nanoseconds > 0) { | ||
| 30 | ASSERT(thread); | ||
| 31 | ASSERT(thread->GetState() != ThreadState::Runnable); | ||
| 32 | system.CoreTiming().ScheduleEvent(std::chrono::nanoseconds{nanoseconds}, | ||
| 33 | time_manager_event_type, | ||
| 34 | reinterpret_cast<uintptr_t>(thread)); | ||
| 35 | } | ||
| 36 | } | ||
| 37 | |||
| 38 | void TimeManager::UnscheduleTimeEvent(KThread* thread) { | ||
| 39 | std::scoped_lock lock{mutex}; | ||
| 40 | system.CoreTiming().UnscheduleEvent(time_manager_event_type, | ||
| 41 | reinterpret_cast<uintptr_t>(thread)); | ||
| 42 | } | ||
| 43 | |||
| 44 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/time_manager.h b/src/core/hle/kernel/time_manager.h deleted file mode 100644 index 94d16b3b4..000000000 --- a/src/core/hle/kernel/time_manager.h +++ /dev/null | |||
| @@ -1,41 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <memory> | ||
| 7 | #include <mutex> | ||
| 8 | |||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } // namespace Core | ||
| 12 | |||
| 13 | namespace Core::Timing { | ||
| 14 | struct EventType; | ||
| 15 | } // namespace Core::Timing | ||
| 16 | |||
| 17 | namespace Kernel { | ||
| 18 | |||
| 19 | class KThread; | ||
| 20 | |||
| 21 | /** | ||
| 22 | * The `TimeManager` takes care of scheduling time events on threads and executes their TimeUp | ||
| 23 | * method when the event is triggered. | ||
| 24 | */ | ||
| 25 | class TimeManager { | ||
| 26 | public: | ||
| 27 | explicit TimeManager(Core::System& system); | ||
| 28 | |||
| 29 | /// Schedule a time event on `timetask` thread that will expire in 'nanoseconds' | ||
| 30 | void ScheduleTimeEvent(KThread* time_task, s64 nanoseconds); | ||
| 31 | |||
| 32 | /// Unschedule an existing time event | ||
| 33 | void UnscheduleTimeEvent(KThread* thread); | ||
| 34 | |||
| 35 | private: | ||
| 36 | Core::System& system; | ||
| 37 | std::shared_ptr<Core::Timing::EventType> time_manager_event_type; | ||
| 38 | std::mutex mutex; | ||
| 39 | }; | ||
| 40 | |||
| 41 | } // namespace Kernel | ||
diff --git a/src/core/hle/service/nfc/nfc_user.cpp b/src/core/hle/service/nfc/nfc_user.cpp index 4615697e2..89aa6b3f5 100644 --- a/src/core/hle/service/nfc/nfc_user.cpp +++ b/src/core/hle/service/nfc/nfc_user.cpp | |||
| @@ -97,7 +97,7 @@ void IUser::IsNfcEnabled(Kernel::HLERequestContext& ctx) { | |||
| 97 | } | 97 | } |
| 98 | 98 | ||
| 99 | void IUser::ListDevices(Kernel::HLERequestContext& ctx) { | 99 | void IUser::ListDevices(Kernel::HLERequestContext& ctx) { |
| 100 | LOG_INFO(Service_NFC, "called"); | 100 | LOG_DEBUG(Service_NFC, "called"); |
| 101 | 101 | ||
| 102 | if (state == State::NonInitialized) { | 102 | if (state == State::NonInitialized) { |
| 103 | IPC::ResponseBuilder rb{ctx, 2}; | 103 | IPC::ResponseBuilder rb{ctx, 2}; |
diff --git a/src/core/hle/service/nfp/nfp_user.cpp b/src/core/hle/service/nfp/nfp_user.cpp index 49816b4c7..a4d3d1bc7 100644 --- a/src/core/hle/service/nfp/nfp_user.cpp +++ b/src/core/hle/service/nfp/nfp_user.cpp | |||
| @@ -83,7 +83,7 @@ void IUser::Finalize(Kernel::HLERequestContext& ctx) { | |||
| 83 | } | 83 | } |
| 84 | 84 | ||
| 85 | void IUser::ListDevices(Kernel::HLERequestContext& ctx) { | 85 | void IUser::ListDevices(Kernel::HLERequestContext& ctx) { |
| 86 | LOG_INFO(Service_NFP, "called"); | 86 | LOG_DEBUG(Service_NFP, "called"); |
| 87 | 87 | ||
| 88 | if (state == State::NonInitialized) { | 88 | if (state == State::NonInitialized) { |
| 89 | IPC::ResponseBuilder rb{ctx, 2}; | 89 | IPC::ResponseBuilder rb{ctx, 2}; |
diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt index 7932aaab0..f24c89b04 100644 --- a/src/input_common/CMakeLists.txt +++ b/src/input_common/CMakeLists.txt | |||
| @@ -20,6 +20,8 @@ add_library(input_common STATIC | |||
| 20 | drivers/udp_client.h | 20 | drivers/udp_client.h |
| 21 | drivers/virtual_amiibo.cpp | 21 | drivers/virtual_amiibo.cpp |
| 22 | drivers/virtual_amiibo.h | 22 | drivers/virtual_amiibo.h |
| 23 | drivers/virtual_gamepad.cpp | ||
| 24 | drivers/virtual_gamepad.h | ||
| 23 | helpers/stick_from_buttons.cpp | 25 | helpers/stick_from_buttons.cpp |
| 24 | helpers/stick_from_buttons.h | 26 | helpers/stick_from_buttons.h |
| 25 | helpers/touch_from_buttons.cpp | 27 | helpers/touch_from_buttons.cpp |
diff --git a/src/input_common/drivers/camera.h b/src/input_common/drivers/camera.h index 38fb1ae4c..ead3e0fde 100644 --- a/src/input_common/drivers/camera.h +++ b/src/input_common/drivers/camera.h | |||
| @@ -25,6 +25,7 @@ public: | |||
| 25 | Common::Input::CameraError SetCameraFormat(const PadIdentifier& identifier_, | 25 | Common::Input::CameraError SetCameraFormat(const PadIdentifier& identifier_, |
| 26 | Common::Input::CameraFormat camera_format) override; | 26 | Common::Input::CameraFormat camera_format) override; |
| 27 | 27 | ||
| 28 | private: | ||
| 28 | Common::Input::CameraStatus status{}; | 29 | Common::Input::CameraStatus status{}; |
| 29 | }; | 30 | }; |
| 30 | 31 | ||
diff --git a/src/input_common/drivers/virtual_gamepad.cpp b/src/input_common/drivers/virtual_gamepad.cpp new file mode 100644 index 000000000..7db945aa6 --- /dev/null +++ b/src/input_common/drivers/virtual_gamepad.cpp | |||
| @@ -0,0 +1,78 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "input_common/drivers/virtual_gamepad.h" | ||
| 5 | |||
| 6 | namespace InputCommon { | ||
| 7 | constexpr std::size_t PlayerIndexCount = 10; | ||
| 8 | |||
| 9 | VirtualGamepad::VirtualGamepad(std::string input_engine_) : InputEngine(std::move(input_engine_)) { | ||
| 10 | for (std::size_t i = 0; i < PlayerIndexCount; i++) { | ||
| 11 | PreSetController(GetIdentifier(i)); | ||
| 12 | } | ||
| 13 | } | ||
| 14 | |||
| 15 | void VirtualGamepad::SetButtonState(std::size_t player_index, int button_id, bool value) { | ||
| 16 | if (player_index > PlayerIndexCount) { | ||
| 17 | return; | ||
| 18 | } | ||
| 19 | const auto identifier = GetIdentifier(player_index); | ||
| 20 | SetButton(identifier, button_id, value); | ||
| 21 | } | ||
| 22 | |||
| 23 | void VirtualGamepad::SetButtonState(std::size_t player_index, VirtualButton button_id, bool value) { | ||
| 24 | SetButtonState(player_index, static_cast<int>(button_id), value); | ||
| 25 | } | ||
| 26 | |||
| 27 | void VirtualGamepad::SetStickPosition(std::size_t player_index, int axis_id, float x_value, | ||
| 28 | float y_value) { | ||
| 29 | if (player_index > PlayerIndexCount) { | ||
| 30 | return; | ||
| 31 | } | ||
| 32 | const auto identifier = GetIdentifier(player_index); | ||
| 33 | SetAxis(identifier, axis_id * 2, x_value); | ||
| 34 | SetAxis(identifier, (axis_id * 2) + 1, y_value); | ||
| 35 | } | ||
| 36 | |||
| 37 | void VirtualGamepad::SetStickPosition(std::size_t player_index, VirtualStick axis_id, float x_value, | ||
| 38 | float y_value) { | ||
| 39 | SetStickPosition(player_index, static_cast<int>(axis_id), x_value, y_value); | ||
| 40 | } | ||
| 41 | |||
| 42 | void VirtualGamepad::ResetControllers() { | ||
| 43 | for (std::size_t i = 0; i < PlayerIndexCount; i++) { | ||
| 44 | SetStickPosition(i, VirtualStick::Left, 0.0f, 0.0f); | ||
| 45 | SetStickPosition(i, VirtualStick::Right, 0.0f, 0.0f); | ||
| 46 | |||
| 47 | SetButtonState(i, VirtualButton::ButtonA, false); | ||
| 48 | SetButtonState(i, VirtualButton::ButtonB, false); | ||
| 49 | SetButtonState(i, VirtualButton::ButtonX, false); | ||
| 50 | SetButtonState(i, VirtualButton::ButtonY, false); | ||
| 51 | SetButtonState(i, VirtualButton::StickL, false); | ||
| 52 | SetButtonState(i, VirtualButton::StickR, false); | ||
| 53 | SetButtonState(i, VirtualButton::TriggerL, false); | ||
| 54 | SetButtonState(i, VirtualButton::TriggerR, false); | ||
| 55 | SetButtonState(i, VirtualButton::TriggerZL, false); | ||
| 56 | SetButtonState(i, VirtualButton::TriggerZR, false); | ||
| 57 | SetButtonState(i, VirtualButton::ButtonPlus, false); | ||
| 58 | SetButtonState(i, VirtualButton::ButtonMinus, false); | ||
| 59 | SetButtonState(i, VirtualButton::ButtonLeft, false); | ||
| 60 | SetButtonState(i, VirtualButton::ButtonUp, false); | ||
| 61 | SetButtonState(i, VirtualButton::ButtonRight, false); | ||
| 62 | SetButtonState(i, VirtualButton::ButtonDown, false); | ||
| 63 | SetButtonState(i, VirtualButton::ButtonSL, false); | ||
| 64 | SetButtonState(i, VirtualButton::ButtonSR, false); | ||
| 65 | SetButtonState(i, VirtualButton::ButtonHome, false); | ||
| 66 | SetButtonState(i, VirtualButton::ButtonCapture, false); | ||
| 67 | } | ||
| 68 | } | ||
| 69 | |||
| 70 | PadIdentifier VirtualGamepad::GetIdentifier(std::size_t player_index) const { | ||
| 71 | return { | ||
| 72 | .guid = Common::UUID{}, | ||
| 73 | .port = player_index, | ||
| 74 | .pad = 0, | ||
| 75 | }; | ||
| 76 | } | ||
| 77 | |||
| 78 | } // namespace InputCommon | ||
diff --git a/src/input_common/drivers/virtual_gamepad.h b/src/input_common/drivers/virtual_gamepad.h new file mode 100644 index 000000000..3df91cc6f --- /dev/null +++ b/src/input_common/drivers/virtual_gamepad.h | |||
| @@ -0,0 +1,73 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "input_common/input_engine.h" | ||
| 7 | |||
| 8 | namespace InputCommon { | ||
| 9 | |||
| 10 | /** | ||
| 11 | * A virtual controller that is always assigned to the game input | ||
| 12 | */ | ||
| 13 | class VirtualGamepad final : public InputEngine { | ||
| 14 | public: | ||
| 15 | enum class VirtualButton { | ||
| 16 | ButtonA, | ||
| 17 | ButtonB, | ||
| 18 | ButtonX, | ||
| 19 | ButtonY, | ||
| 20 | StickL, | ||
| 21 | StickR, | ||
| 22 | TriggerL, | ||
| 23 | TriggerR, | ||
| 24 | TriggerZL, | ||
| 25 | TriggerZR, | ||
| 26 | ButtonPlus, | ||
| 27 | ButtonMinus, | ||
| 28 | ButtonLeft, | ||
| 29 | ButtonUp, | ||
| 30 | ButtonRight, | ||
| 31 | ButtonDown, | ||
| 32 | ButtonSL, | ||
| 33 | ButtonSR, | ||
| 34 | ButtonHome, | ||
| 35 | ButtonCapture, | ||
| 36 | }; | ||
| 37 | |||
| 38 | enum class VirtualStick { | ||
| 39 | Left = 0, | ||
| 40 | Right = 1, | ||
| 41 | }; | ||
| 42 | |||
| 43 | explicit VirtualGamepad(std::string input_engine_); | ||
| 44 | |||
| 45 | /** | ||
| 46 | * Sets the status of all buttons bound with the key to pressed | ||
| 47 | * @param player_index the player number that will take this action | ||
| 48 | * @param button_id the id of the button | ||
| 49 | * @param value indicates if the button is pressed or not | ||
| 50 | */ | ||
| 51 | void SetButtonState(std::size_t player_index, int button_id, bool value); | ||
| 52 | void SetButtonState(std::size_t player_index, VirtualButton button_id, bool value); | ||
| 53 | |||
| 54 | /** | ||
| 55 | * Sets the status of all buttons bound with the key to released | ||
| 56 | * @param player_index the player number that will take this action | ||
| 57 | * @param axis_id the id of the axis to move | ||
| 58 | * @param x_value the position of the stick in the x axis | ||
| 59 | * @param y_value the position of the stick in the y axis | ||
| 60 | */ | ||
| 61 | void SetStickPosition(std::size_t player_index, int axis_id, float x_value, float y_value); | ||
| 62 | void SetStickPosition(std::size_t player_index, VirtualStick axis_id, float x_value, | ||
| 63 | float y_value); | ||
| 64 | |||
| 65 | /// Restores all inputs into the neutral position | ||
| 66 | void ResetControllers(); | ||
| 67 | |||
| 68 | private: | ||
| 69 | /// Returns the correct identifier corresponding to the player index | ||
| 70 | PadIdentifier GetIdentifier(std::size_t player_index) const; | ||
| 71 | }; | ||
| 72 | |||
| 73 | } // namespace InputCommon | ||
diff --git a/src/input_common/input_mapping.cpp b/src/input_common/input_mapping.cpp index 0fa4b1ddb..edd5287c1 100644 --- a/src/input_common/input_mapping.cpp +++ b/src/input_common/input_mapping.cpp | |||
| @@ -200,12 +200,6 @@ bool MappingFactory::IsDriverValid(const MappingData& data) const { | |||
| 200 | return false; | 200 | return false; |
| 201 | } | 201 | } |
| 202 | // The following drivers don't need to be mapped | 202 | // The following drivers don't need to be mapped |
| 203 | if (data.engine == "tas") { | ||
| 204 | return false; | ||
| 205 | } | ||
| 206 | if (data.engine == "touch") { | ||
| 207 | return false; | ||
| 208 | } | ||
| 209 | if (data.engine == "touch_from_button") { | 203 | if (data.engine == "touch_from_button") { |
| 210 | return false; | 204 | return false; |
| 211 | } | 205 | } |
diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index 942a13535..86deb4c7c 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | #include "input_common/drivers/touch_screen.h" | 12 | #include "input_common/drivers/touch_screen.h" |
| 13 | #include "input_common/drivers/udp_client.h" | 13 | #include "input_common/drivers/udp_client.h" |
| 14 | #include "input_common/drivers/virtual_amiibo.h" | 14 | #include "input_common/drivers/virtual_amiibo.h" |
| 15 | #include "input_common/drivers/virtual_gamepad.h" | ||
| 15 | #include "input_common/helpers/stick_from_buttons.h" | 16 | #include "input_common/helpers/stick_from_buttons.h" |
| 16 | #include "input_common/helpers/touch_from_buttons.h" | 17 | #include "input_common/helpers/touch_from_buttons.h" |
| 17 | #include "input_common/input_engine.h" | 18 | #include "input_common/input_engine.h" |
| @@ -25,73 +26,33 @@ | |||
| 25 | namespace InputCommon { | 26 | namespace InputCommon { |
| 26 | 27 | ||
| 27 | struct InputSubsystem::Impl { | 28 | struct InputSubsystem::Impl { |
| 28 | void Initialize() { | 29 | template <typename Engine> |
| 29 | mapping_factory = std::make_shared<MappingFactory>(); | 30 | void RegisterEngine(std::string name, std::shared_ptr<Engine>& engine) { |
| 30 | MappingCallback mapping_callback{[this](const MappingData& data) { RegisterInput(data); }}; | 31 | MappingCallback mapping_callback{[this](const MappingData& data) { RegisterInput(data); }}; |
| 31 | 32 | ||
| 32 | keyboard = std::make_shared<Keyboard>("keyboard"); | 33 | engine = std::make_shared<Engine>(name); |
| 33 | keyboard->SetMappingCallback(mapping_callback); | 34 | engine->SetMappingCallback(mapping_callback); |
| 34 | keyboard_factory = std::make_shared<InputFactory>(keyboard); | 35 | |
| 35 | keyboard_output_factory = std::make_shared<OutputFactory>(keyboard); | 36 | std::shared_ptr<InputFactory> input_factory = std::make_shared<InputFactory>(engine); |
| 36 | Common::Input::RegisterInputFactory(keyboard->GetEngineName(), keyboard_factory); | 37 | std::shared_ptr<OutputFactory> output_factory = std::make_shared<OutputFactory>(engine); |
| 37 | Common::Input::RegisterOutputFactory(keyboard->GetEngineName(), keyboard_output_factory); | 38 | Common::Input::RegisterInputFactory(engine->GetEngineName(), std::move(input_factory)); |
| 38 | 39 | Common::Input::RegisterOutputFactory(engine->GetEngineName(), std::move(output_factory)); | |
| 39 | mouse = std::make_shared<Mouse>("mouse"); | 40 | } |
| 40 | mouse->SetMappingCallback(mapping_callback); | 41 | |
| 41 | mouse_factory = std::make_shared<InputFactory>(mouse); | 42 | void Initialize() { |
| 42 | mouse_output_factory = std::make_shared<OutputFactory>(mouse); | 43 | mapping_factory = std::make_shared<MappingFactory>(); |
| 43 | Common::Input::RegisterInputFactory(mouse->GetEngineName(), mouse_factory); | ||
| 44 | Common::Input::RegisterOutputFactory(mouse->GetEngineName(), mouse_output_factory); | ||
| 45 | |||
| 46 | touch_screen = std::make_shared<TouchScreen>("touch"); | ||
| 47 | touch_screen_factory = std::make_shared<InputFactory>(touch_screen); | ||
| 48 | Common::Input::RegisterInputFactory(touch_screen->GetEngineName(), touch_screen_factory); | ||
| 49 | |||
| 50 | gcadapter = std::make_shared<GCAdapter>("gcpad"); | ||
| 51 | gcadapter->SetMappingCallback(mapping_callback); | ||
| 52 | gcadapter_input_factory = std::make_shared<InputFactory>(gcadapter); | ||
| 53 | gcadapter_output_factory = std::make_shared<OutputFactory>(gcadapter); | ||
| 54 | Common::Input::RegisterInputFactory(gcadapter->GetEngineName(), gcadapter_input_factory); | ||
| 55 | Common::Input::RegisterOutputFactory(gcadapter->GetEngineName(), gcadapter_output_factory); | ||
| 56 | |||
| 57 | udp_client = std::make_shared<CemuhookUDP::UDPClient>("cemuhookudp"); | ||
| 58 | udp_client->SetMappingCallback(mapping_callback); | ||
| 59 | udp_client_input_factory = std::make_shared<InputFactory>(udp_client); | ||
| 60 | udp_client_output_factory = std::make_shared<OutputFactory>(udp_client); | ||
| 61 | Common::Input::RegisterInputFactory(udp_client->GetEngineName(), udp_client_input_factory); | ||
| 62 | Common::Input::RegisterOutputFactory(udp_client->GetEngineName(), | ||
| 63 | udp_client_output_factory); | ||
| 64 | |||
| 65 | tas_input = std::make_shared<TasInput::Tas>("tas"); | ||
| 66 | tas_input->SetMappingCallback(mapping_callback); | ||
| 67 | tas_input_factory = std::make_shared<InputFactory>(tas_input); | ||
| 68 | tas_output_factory = std::make_shared<OutputFactory>(tas_input); | ||
| 69 | Common::Input::RegisterInputFactory(tas_input->GetEngineName(), tas_input_factory); | ||
| 70 | Common::Input::RegisterOutputFactory(tas_input->GetEngineName(), tas_output_factory); | ||
| 71 | |||
| 72 | camera = std::make_shared<Camera>("camera"); | ||
| 73 | camera->SetMappingCallback(mapping_callback); | ||
| 74 | camera_input_factory = std::make_shared<InputFactory>(camera); | ||
| 75 | camera_output_factory = std::make_shared<OutputFactory>(camera); | ||
| 76 | Common::Input::RegisterInputFactory(camera->GetEngineName(), camera_input_factory); | ||
| 77 | Common::Input::RegisterOutputFactory(camera->GetEngineName(), camera_output_factory); | ||
| 78 | |||
| 79 | virtual_amiibo = std::make_shared<VirtualAmiibo>("virtual_amiibo"); | ||
| 80 | virtual_amiibo->SetMappingCallback(mapping_callback); | ||
| 81 | virtual_amiibo_input_factory = std::make_shared<InputFactory>(virtual_amiibo); | ||
| 82 | virtual_amiibo_output_factory = std::make_shared<OutputFactory>(virtual_amiibo); | ||
| 83 | Common::Input::RegisterInputFactory(virtual_amiibo->GetEngineName(), | ||
| 84 | virtual_amiibo_input_factory); | ||
| 85 | Common::Input::RegisterOutputFactory(virtual_amiibo->GetEngineName(), | ||
| 86 | virtual_amiibo_output_factory); | ||
| 87 | 44 | ||
| 45 | RegisterEngine("keyboard", keyboard); | ||
| 46 | RegisterEngine("mouse", mouse); | ||
| 47 | RegisterEngine("touch", touch_screen); | ||
| 48 | RegisterEngine("gcpad", gcadapter); | ||
| 49 | RegisterEngine("cemuhookudp", udp_client); | ||
| 50 | RegisterEngine("tas", tas_input); | ||
| 51 | RegisterEngine("camera", camera); | ||
| 52 | RegisterEngine("virtual_amiibo", virtual_amiibo); | ||
| 53 | RegisterEngine("virtual_gamepad", virtual_gamepad); | ||
| 88 | #ifdef HAVE_SDL2 | 54 | #ifdef HAVE_SDL2 |
| 89 | sdl = std::make_shared<SDLDriver>("sdl"); | 55 | RegisterEngine("sdl", sdl); |
| 90 | sdl->SetMappingCallback(mapping_callback); | ||
| 91 | sdl_input_factory = std::make_shared<InputFactory>(sdl); | ||
| 92 | sdl_output_factory = std::make_shared<OutputFactory>(sdl); | ||
| 93 | Common::Input::RegisterInputFactory(sdl->GetEngineName(), sdl_input_factory); | ||
| 94 | Common::Input::RegisterOutputFactory(sdl->GetEngineName(), sdl_output_factory); | ||
| 95 | #endif | 56 | #endif |
| 96 | 57 | ||
| 97 | Common::Input::RegisterInputFactory("touch_from_button", | 58 | Common::Input::RegisterInputFactory("touch_from_button", |
| @@ -100,42 +61,25 @@ struct InputSubsystem::Impl { | |||
| 100 | std::make_shared<StickFromButton>()); | 61 | std::make_shared<StickFromButton>()); |
| 101 | } | 62 | } |
| 102 | 63 | ||
| 103 | void Shutdown() { | 64 | template <typename Engine> |
| 104 | Common::Input::UnregisterInputFactory(keyboard->GetEngineName()); | 65 | void UnregisterEngine(std::shared_ptr<Engine>& engine) { |
| 105 | Common::Input::UnregisterOutputFactory(keyboard->GetEngineName()); | 66 | Common::Input::UnregisterInputFactory(engine->GetEngineName()); |
| 106 | keyboard.reset(); | 67 | Common::Input::UnregisterOutputFactory(engine->GetEngineName()); |
| 107 | 68 | engine.reset(); | |
| 108 | Common::Input::UnregisterInputFactory(mouse->GetEngineName()); | 69 | } |
| 109 | Common::Input::UnregisterOutputFactory(mouse->GetEngineName()); | ||
| 110 | mouse.reset(); | ||
| 111 | |||
| 112 | Common::Input::UnregisterInputFactory(touch_screen->GetEngineName()); | ||
| 113 | touch_screen.reset(); | ||
| 114 | |||
| 115 | Common::Input::UnregisterInputFactory(gcadapter->GetEngineName()); | ||
| 116 | Common::Input::UnregisterOutputFactory(gcadapter->GetEngineName()); | ||
| 117 | gcadapter.reset(); | ||
| 118 | |||
| 119 | Common::Input::UnregisterInputFactory(udp_client->GetEngineName()); | ||
| 120 | Common::Input::UnregisterOutputFactory(udp_client->GetEngineName()); | ||
| 121 | udp_client.reset(); | ||
| 122 | |||
| 123 | Common::Input::UnregisterInputFactory(tas_input->GetEngineName()); | ||
| 124 | Common::Input::UnregisterOutputFactory(tas_input->GetEngineName()); | ||
| 125 | tas_input.reset(); | ||
| 126 | |||
| 127 | Common::Input::UnregisterInputFactory(camera->GetEngineName()); | ||
| 128 | Common::Input::UnregisterOutputFactory(camera->GetEngineName()); | ||
| 129 | camera.reset(); | ||
| 130 | |||
| 131 | Common::Input::UnregisterInputFactory(virtual_amiibo->GetEngineName()); | ||
| 132 | Common::Input::UnregisterOutputFactory(virtual_amiibo->GetEngineName()); | ||
| 133 | virtual_amiibo.reset(); | ||
| 134 | 70 | ||
| 71 | void Shutdown() { | ||
| 72 | UnregisterEngine(keyboard); | ||
| 73 | UnregisterEngine(mouse); | ||
| 74 | UnregisterEngine(touch_screen); | ||
| 75 | UnregisterEngine(gcadapter); | ||
| 76 | UnregisterEngine(udp_client); | ||
| 77 | UnregisterEngine(tas_input); | ||
| 78 | UnregisterEngine(camera); | ||
| 79 | UnregisterEngine(virtual_amiibo); | ||
| 80 | UnregisterEngine(virtual_gamepad); | ||
| 135 | #ifdef HAVE_SDL2 | 81 | #ifdef HAVE_SDL2 |
| 136 | Common::Input::UnregisterInputFactory(sdl->GetEngineName()); | 82 | UnregisterEngine(sdl); |
| 137 | Common::Input::UnregisterOutputFactory(sdl->GetEngineName()); | ||
| 138 | sdl.reset(); | ||
| 139 | #endif | 83 | #endif |
| 140 | 84 | ||
| 141 | Common::Input::UnregisterInputFactory("touch_from_button"); | 85 | Common::Input::UnregisterInputFactory("touch_from_button"); |
| @@ -163,117 +107,86 @@ struct InputSubsystem::Impl { | |||
| 163 | return devices; | 107 | return devices; |
| 164 | } | 108 | } |
| 165 | 109 | ||
| 166 | [[nodiscard]] AnalogMapping GetAnalogMappingForDevice( | 110 | [[nodiscard]] std::shared_ptr<InputEngine> GetInputEngine( |
| 167 | const Common::ParamPackage& params) const { | 111 | const Common::ParamPackage& params) const { |
| 168 | if (!params.Has("engine") || params.Get("engine", "") == "any") { | 112 | if (!params.Has("engine") || params.Get("engine", "") == "any") { |
| 169 | return {}; | 113 | return nullptr; |
| 170 | } | 114 | } |
| 171 | const std::string engine = params.Get("engine", ""); | 115 | const std::string engine = params.Get("engine", ""); |
| 116 | if (engine == keyboard->GetEngineName()) { | ||
| 117 | return keyboard; | ||
| 118 | } | ||
| 172 | if (engine == mouse->GetEngineName()) { | 119 | if (engine == mouse->GetEngineName()) { |
| 173 | return mouse->GetAnalogMappingForDevice(params); | 120 | return mouse; |
| 174 | } | 121 | } |
| 175 | if (engine == gcadapter->GetEngineName()) { | 122 | if (engine == gcadapter->GetEngineName()) { |
| 176 | return gcadapter->GetAnalogMappingForDevice(params); | 123 | return gcadapter; |
| 177 | } | 124 | } |
| 178 | if (engine == udp_client->GetEngineName()) { | 125 | if (engine == udp_client->GetEngineName()) { |
| 179 | return udp_client->GetAnalogMappingForDevice(params); | 126 | return udp_client; |
| 180 | } | ||
| 181 | if (engine == tas_input->GetEngineName()) { | ||
| 182 | return tas_input->GetAnalogMappingForDevice(params); | ||
| 183 | } | 127 | } |
| 184 | #ifdef HAVE_SDL2 | 128 | #ifdef HAVE_SDL2 |
| 185 | if (engine == sdl->GetEngineName()) { | 129 | if (engine == sdl->GetEngineName()) { |
| 186 | return sdl->GetAnalogMappingForDevice(params); | 130 | return sdl; |
| 187 | } | 131 | } |
| 188 | #endif | 132 | #endif |
| 189 | return {}; | 133 | return nullptr; |
| 190 | } | 134 | } |
| 191 | 135 | ||
| 192 | [[nodiscard]] ButtonMapping GetButtonMappingForDevice( | 136 | [[nodiscard]] AnalogMapping GetAnalogMappingForDevice( |
| 193 | const Common::ParamPackage& params) const { | 137 | const Common::ParamPackage& params) const { |
| 194 | if (!params.Has("engine") || params.Get("engine", "") == "any") { | 138 | const auto input_engine = GetInputEngine(params); |
| 139 | |||
| 140 | if (input_engine == nullptr) { | ||
| 195 | return {}; | 141 | return {}; |
| 196 | } | 142 | } |
| 197 | const std::string engine = params.Get("engine", ""); | 143 | |
| 198 | if (engine == gcadapter->GetEngineName()) { | 144 | return input_engine->GetAnalogMappingForDevice(params); |
| 199 | return gcadapter->GetButtonMappingForDevice(params); | 145 | } |
| 200 | } | 146 | |
| 201 | if (engine == udp_client->GetEngineName()) { | 147 | [[nodiscard]] ButtonMapping GetButtonMappingForDevice( |
| 202 | return udp_client->GetButtonMappingForDevice(params); | 148 | const Common::ParamPackage& params) const { |
| 203 | } | 149 | const auto input_engine = GetInputEngine(params); |
| 204 | if (engine == tas_input->GetEngineName()) { | 150 | |
| 205 | return tas_input->GetButtonMappingForDevice(params); | 151 | if (input_engine == nullptr) { |
| 206 | } | 152 | return {}; |
| 207 | #ifdef HAVE_SDL2 | ||
| 208 | if (engine == sdl->GetEngineName()) { | ||
| 209 | return sdl->GetButtonMappingForDevice(params); | ||
| 210 | } | 153 | } |
| 211 | #endif | 154 | |
| 212 | return {}; | 155 | return input_engine->GetButtonMappingForDevice(params); |
| 213 | } | 156 | } |
| 214 | 157 | ||
| 215 | [[nodiscard]] MotionMapping GetMotionMappingForDevice( | 158 | [[nodiscard]] MotionMapping GetMotionMappingForDevice( |
| 216 | const Common::ParamPackage& params) const { | 159 | const Common::ParamPackage& params) const { |
| 217 | if (!params.Has("engine") || params.Get("engine", "") == "any") { | 160 | const auto input_engine = GetInputEngine(params); |
| 161 | |||
| 162 | if (input_engine == nullptr) { | ||
| 218 | return {}; | 163 | return {}; |
| 219 | } | 164 | } |
| 220 | const std::string engine = params.Get("engine", ""); | 165 | |
| 221 | if (engine == udp_client->GetEngineName()) { | 166 | return input_engine->GetMotionMappingForDevice(params); |
| 222 | return udp_client->GetMotionMappingForDevice(params); | ||
| 223 | } | ||
| 224 | #ifdef HAVE_SDL2 | ||
| 225 | if (engine == sdl->GetEngineName()) { | ||
| 226 | return sdl->GetMotionMappingForDevice(params); | ||
| 227 | } | ||
| 228 | #endif | ||
| 229 | return {}; | ||
| 230 | } | 167 | } |
| 231 | 168 | ||
| 232 | Common::Input::ButtonNames GetButtonName(const Common::ParamPackage& params) const { | 169 | Common::Input::ButtonNames GetButtonName(const Common::ParamPackage& params) const { |
| 233 | if (!params.Has("engine") || params.Get("engine", "") == "any") { | 170 | if (!params.Has("engine") || params.Get("engine", "") == "any") { |
| 234 | return Common::Input::ButtonNames::Undefined; | 171 | return Common::Input::ButtonNames::Undefined; |
| 235 | } | 172 | } |
| 236 | const std::string engine = params.Get("engine", ""); | 173 | const auto input_engine = GetInputEngine(params); |
| 237 | if (engine == mouse->GetEngineName()) { | 174 | |
| 238 | return mouse->GetUIName(params); | 175 | if (input_engine == nullptr) { |
| 239 | } | 176 | return Common::Input::ButtonNames::Invalid; |
| 240 | if (engine == gcadapter->GetEngineName()) { | ||
| 241 | return gcadapter->GetUIName(params); | ||
| 242 | } | ||
| 243 | if (engine == udp_client->GetEngineName()) { | ||
| 244 | return udp_client->GetUIName(params); | ||
| 245 | } | ||
| 246 | if (engine == tas_input->GetEngineName()) { | ||
| 247 | return tas_input->GetUIName(params); | ||
| 248 | } | ||
| 249 | #ifdef HAVE_SDL2 | ||
| 250 | if (engine == sdl->GetEngineName()) { | ||
| 251 | return sdl->GetUIName(params); | ||
| 252 | } | 177 | } |
| 253 | #endif | 178 | |
| 254 | return Common::Input::ButtonNames::Invalid; | 179 | return input_engine->GetUIName(params); |
| 255 | } | 180 | } |
| 256 | 181 | ||
| 257 | bool IsStickInverted(const Common::ParamPackage& params) { | 182 | bool IsStickInverted(const Common::ParamPackage& params) { |
| 258 | const std::string engine = params.Get("engine", ""); | 183 | const auto input_engine = GetInputEngine(params); |
| 259 | if (engine == mouse->GetEngineName()) { | 184 | |
| 260 | return mouse->IsStickInverted(params); | 185 | if (input_engine == nullptr) { |
| 261 | } | 186 | return false; |
| 262 | if (engine == gcadapter->GetEngineName()) { | ||
| 263 | return gcadapter->IsStickInverted(params); | ||
| 264 | } | ||
| 265 | if (engine == udp_client->GetEngineName()) { | ||
| 266 | return udp_client->IsStickInverted(params); | ||
| 267 | } | ||
| 268 | if (engine == tas_input->GetEngineName()) { | ||
| 269 | return tas_input->IsStickInverted(params); | ||
| 270 | } | ||
| 271 | #ifdef HAVE_SDL2 | ||
| 272 | if (engine == sdl->GetEngineName()) { | ||
| 273 | return sdl->IsStickInverted(params); | ||
| 274 | } | 187 | } |
| 275 | #endif | 188 | |
| 276 | return false; | 189 | return input_engine->IsStickInverted(params); |
| 277 | } | 190 | } |
| 278 | 191 | ||
| 279 | bool IsController(const Common::ParamPackage& params) { | 192 | bool IsController(const Common::ParamPackage& params) { |
| @@ -290,6 +203,9 @@ struct InputSubsystem::Impl { | |||
| 290 | if (engine == tas_input->GetEngineName()) { | 203 | if (engine == tas_input->GetEngineName()) { |
| 291 | return true; | 204 | return true; |
| 292 | } | 205 | } |
| 206 | if (engine == virtual_gamepad->GetEngineName()) { | ||
| 207 | return true; | ||
| 208 | } | ||
| 293 | #ifdef HAVE_SDL2 | 209 | #ifdef HAVE_SDL2 |
| 294 | if (engine == sdl->GetEngineName()) { | 210 | if (engine == sdl->GetEngineName()) { |
| 295 | return true; | 211 | return true; |
| @@ -338,28 +254,10 @@ struct InputSubsystem::Impl { | |||
| 338 | std::shared_ptr<CemuhookUDP::UDPClient> udp_client; | 254 | std::shared_ptr<CemuhookUDP::UDPClient> udp_client; |
| 339 | std::shared_ptr<Camera> camera; | 255 | std::shared_ptr<Camera> camera; |
| 340 | std::shared_ptr<VirtualAmiibo> virtual_amiibo; | 256 | std::shared_ptr<VirtualAmiibo> virtual_amiibo; |
| 341 | 257 | std::shared_ptr<VirtualGamepad> virtual_gamepad; | |
| 342 | std::shared_ptr<InputFactory> keyboard_factory; | ||
| 343 | std::shared_ptr<InputFactory> mouse_factory; | ||
| 344 | std::shared_ptr<InputFactory> gcadapter_input_factory; | ||
| 345 | std::shared_ptr<InputFactory> touch_screen_factory; | ||
| 346 | std::shared_ptr<InputFactory> udp_client_input_factory; | ||
| 347 | std::shared_ptr<InputFactory> tas_input_factory; | ||
| 348 | std::shared_ptr<InputFactory> camera_input_factory; | ||
| 349 | std::shared_ptr<InputFactory> virtual_amiibo_input_factory; | ||
| 350 | |||
| 351 | std::shared_ptr<OutputFactory> keyboard_output_factory; | ||
| 352 | std::shared_ptr<OutputFactory> mouse_output_factory; | ||
| 353 | std::shared_ptr<OutputFactory> gcadapter_output_factory; | ||
| 354 | std::shared_ptr<OutputFactory> udp_client_output_factory; | ||
| 355 | std::shared_ptr<OutputFactory> tas_output_factory; | ||
| 356 | std::shared_ptr<OutputFactory> camera_output_factory; | ||
| 357 | std::shared_ptr<OutputFactory> virtual_amiibo_output_factory; | ||
| 358 | 258 | ||
| 359 | #ifdef HAVE_SDL2 | 259 | #ifdef HAVE_SDL2 |
| 360 | std::shared_ptr<SDLDriver> sdl; | 260 | std::shared_ptr<SDLDriver> sdl; |
| 361 | std::shared_ptr<InputFactory> sdl_input_factory; | ||
| 362 | std::shared_ptr<OutputFactory> sdl_output_factory; | ||
| 363 | #endif | 261 | #endif |
| 364 | }; | 262 | }; |
| 365 | 263 | ||
| @@ -423,6 +321,14 @@ const VirtualAmiibo* InputSubsystem::GetVirtualAmiibo() const { | |||
| 423 | return impl->virtual_amiibo.get(); | 321 | return impl->virtual_amiibo.get(); |
| 424 | } | 322 | } |
| 425 | 323 | ||
| 324 | VirtualGamepad* InputSubsystem::GetVirtualGamepad() { | ||
| 325 | return impl->virtual_gamepad.get(); | ||
| 326 | } | ||
| 327 | |||
| 328 | const VirtualGamepad* InputSubsystem::GetVirtualGamepad() const { | ||
| 329 | return impl->virtual_gamepad.get(); | ||
| 330 | } | ||
| 331 | |||
| 426 | std::vector<Common::ParamPackage> InputSubsystem::GetInputDevices() const { | 332 | std::vector<Common::ParamPackage> InputSubsystem::GetInputDevices() const { |
| 427 | return impl->GetInputDevices(); | 333 | return impl->GetInputDevices(); |
| 428 | } | 334 | } |
diff --git a/src/input_common/main.h b/src/input_common/main.h index 6218c37f6..1207d786c 100644 --- a/src/input_common/main.h +++ b/src/input_common/main.h | |||
| @@ -34,6 +34,7 @@ class Keyboard; | |||
| 34 | class Mouse; | 34 | class Mouse; |
| 35 | class TouchScreen; | 35 | class TouchScreen; |
| 36 | class VirtualAmiibo; | 36 | class VirtualAmiibo; |
| 37 | class VirtualGamepad; | ||
| 37 | struct MappingData; | 38 | struct MappingData; |
| 38 | } // namespace InputCommon | 39 | } // namespace InputCommon |
| 39 | 40 | ||
| @@ -108,6 +109,12 @@ public: | |||
| 108 | /// Retrieves the underlying virtual amiibo input device. | 109 | /// Retrieves the underlying virtual amiibo input device. |
| 109 | [[nodiscard]] const VirtualAmiibo* GetVirtualAmiibo() const; | 110 | [[nodiscard]] const VirtualAmiibo* GetVirtualAmiibo() const; |
| 110 | 111 | ||
| 112 | /// Retrieves the underlying virtual gamepad input device. | ||
| 113 | [[nodiscard]] VirtualGamepad* GetVirtualGamepad(); | ||
| 114 | |||
| 115 | /// Retrieves the underlying virtual gamepad input device. | ||
| 116 | [[nodiscard]] const VirtualGamepad* GetVirtualGamepad() const; | ||
| 117 | |||
| 111 | /** | 118 | /** |
| 112 | * Returns all available input devices that this Factory can create a new device with. | 119 | * Returns all available input devices that this Factory can create a new device with. |
| 113 | * Each returned ParamPackage should have a `display` field used for display, a `engine` field | 120 | * Each returned ParamPackage should have a `display` field used for display, a `engine` field |
diff --git a/src/video_core/vulkan_common/vulkan_wrapper.cpp b/src/video_core/vulkan_common/vulkan_wrapper.cpp index 483b534a0..7dca7341c 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.cpp +++ b/src/video_core/vulkan_common/vulkan_wrapper.cpp | |||
| @@ -314,6 +314,18 @@ const char* ToString(VkResult result) noexcept { | |||
| 314 | return "VK_ERROR_VALIDATION_FAILED_EXT"; | 314 | return "VK_ERROR_VALIDATION_FAILED_EXT"; |
| 315 | case VkResult::VK_ERROR_INVALID_SHADER_NV: | 315 | case VkResult::VK_ERROR_INVALID_SHADER_NV: |
| 316 | return "VK_ERROR_INVALID_SHADER_NV"; | 316 | return "VK_ERROR_INVALID_SHADER_NV"; |
| 317 | case VkResult::VK_ERROR_IMAGE_USAGE_NOT_SUPPORTED_KHR: | ||
| 318 | return "VK_ERROR_IMAGE_USAGE_NOT_SUPPORTED_KHR"; | ||
| 319 | case VkResult::VK_ERROR_VIDEO_PICTURE_LAYOUT_NOT_SUPPORTED_KHR: | ||
| 320 | return "VK_ERROR_VIDEO_PICTURE_LAYOUT_NOT_SUPPORTED_KHR"; | ||
| 321 | case VkResult::VK_ERROR_VIDEO_PROFILE_OPERATION_NOT_SUPPORTED_KHR: | ||
| 322 | return "VK_ERROR_VIDEO_PROFILE_OPERATION_NOT_SUPPORTED_KHR"; | ||
| 323 | case VkResult::VK_ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR: | ||
| 324 | return "VK_ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR"; | ||
| 325 | case VkResult::VK_ERROR_VIDEO_PROFILE_CODEC_NOT_SUPPORTED_KHR: | ||
| 326 | return "VK_ERROR_VIDEO_PROFILE_CODEC_NOT_SUPPORTED_KHR"; | ||
| 327 | case VkResult::VK_ERROR_VIDEO_STD_VERSION_NOT_SUPPORTED_KHR: | ||
| 328 | return "VK_ERROR_VIDEO_STD_VERSION_NOT_SUPPORTED_KHR"; | ||
| 317 | case VkResult::VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT: | 329 | case VkResult::VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT: |
| 318 | return "VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT"; | 330 | return "VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT"; |
| 319 | case VkResult::VK_ERROR_FRAGMENTATION_EXT: | 331 | case VkResult::VK_ERROR_FRAGMENTATION_EXT: |
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 40b3d91fc..13782869d 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp | |||
| @@ -740,7 +740,9 @@ void GRenderWindow::InitializeCamera() { | |||
| 740 | return; | 740 | return; |
| 741 | } | 741 | } |
| 742 | 742 | ||
| 743 | camera_data.resize(CAMERA_WIDTH * CAMERA_HEIGHT); | 743 | const auto camera_width = input_subsystem->GetCamera()->getImageWidth(); |
| 744 | const auto camera_height = input_subsystem->GetCamera()->getImageHeight(); | ||
| 745 | camera_data.resize(camera_width * camera_height); | ||
| 744 | camera_capture->setCaptureDestination(QCameraImageCapture::CaptureDestination::CaptureToBuffer); | 746 | camera_capture->setCaptureDestination(QCameraImageCapture::CaptureDestination::CaptureToBuffer); |
| 745 | connect(camera_capture.get(), &QCameraImageCapture::imageCaptured, this, | 747 | connect(camera_capture.get(), &QCameraImageCapture::imageCaptured, this, |
| 746 | &GRenderWindow::OnCameraCapture); | 748 | &GRenderWindow::OnCameraCapture); |
| @@ -796,14 +798,22 @@ void GRenderWindow::RequestCameraCapture() { | |||
| 796 | } | 798 | } |
| 797 | 799 | ||
| 798 | void GRenderWindow::OnCameraCapture(int requestId, const QImage& img) { | 800 | void GRenderWindow::OnCameraCapture(int requestId, const QImage& img) { |
| 801 | #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) && YUZU_USE_QT_MULTIMEDIA | ||
| 799 | // TODO: Capture directly in the format and resolution needed | 802 | // TODO: Capture directly in the format and resolution needed |
| 803 | const auto camera_width = input_subsystem->GetCamera()->getImageWidth(); | ||
| 804 | const auto camera_height = input_subsystem->GetCamera()->getImageHeight(); | ||
| 800 | const auto converted = | 805 | const auto converted = |
| 801 | img.scaled(CAMERA_WIDTH, CAMERA_HEIGHT, Qt::AspectRatioMode::IgnoreAspectRatio, | 806 | img.scaled(static_cast<int>(camera_width), static_cast<int>(camera_height), |
| 807 | Qt::AspectRatioMode::IgnoreAspectRatio, | ||
| 802 | Qt::TransformationMode::SmoothTransformation) | 808 | Qt::TransformationMode::SmoothTransformation) |
| 803 | .mirrored(false, true); | 809 | .mirrored(false, true); |
| 804 | std::memcpy(camera_data.data(), converted.bits(), CAMERA_WIDTH * CAMERA_HEIGHT * sizeof(u32)); | 810 | if (camera_data.size() != camera_width * camera_height) { |
| 805 | input_subsystem->GetCamera()->SetCameraData(CAMERA_WIDTH, CAMERA_HEIGHT, camera_data); | 811 | camera_data.resize(camera_width * camera_height); |
| 812 | } | ||
| 813 | std::memcpy(camera_data.data(), converted.bits(), camera_width * camera_height * sizeof(u32)); | ||
| 814 | input_subsystem->GetCamera()->SetCameraData(camera_width, camera_height, camera_data); | ||
| 806 | pending_camera_snapshots = 0; | 815 | pending_camera_snapshots = 0; |
| 816 | #endif | ||
| 807 | } | 817 | } |
| 808 | 818 | ||
| 809 | bool GRenderWindow::event(QEvent* event) { | 819 | bool GRenderWindow::event(QEvent* event) { |
diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index 52867d628..1c2e76369 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h | |||
| @@ -239,16 +239,14 @@ private: | |||
| 239 | bool first_frame = false; | 239 | bool first_frame = false; |
| 240 | InputCommon::TasInput::TasState last_tas_state; | 240 | InputCommon::TasInput::TasState last_tas_state; |
| 241 | 241 | ||
| 242 | #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) && YUZU_USE_QT_MULTIMEDIA | ||
| 242 | bool is_virtual_camera; | 243 | bool is_virtual_camera; |
| 243 | int pending_camera_snapshots; | 244 | int pending_camera_snapshots; |
| 244 | #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) && YUZU_USE_QT_MULTIMEDIA | 245 | std::vector<u32> camera_data; |
| 245 | std::unique_ptr<QCamera> camera; | 246 | std::unique_ptr<QCamera> camera; |
| 246 | std::unique_ptr<QCameraImageCapture> camera_capture; | 247 | std::unique_ptr<QCameraImageCapture> camera_capture; |
| 247 | static constexpr std::size_t CAMERA_WIDTH = 320; | ||
| 248 | static constexpr std::size_t CAMERA_HEIGHT = 240; | ||
| 249 | std::vector<u32> camera_data; | ||
| 250 | #endif | ||
| 251 | std::unique_ptr<QTimer> camera_timer; | 248 | std::unique_ptr<QTimer> camera_timer; |
| 249 | #endif | ||
| 252 | 250 | ||
| 253 | Core::System& system; | 251 | Core::System& system; |
| 254 | 252 | ||
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index a8d47a2f9..2ea4f367b 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp | |||
| @@ -783,8 +783,6 @@ void Config::ReadSystemValues() { | |||
| 783 | } | 783 | } |
| 784 | } | 784 | } |
| 785 | 785 | ||
| 786 | ReadBasicSetting(Settings::values.device_name); | ||
| 787 | |||
| 788 | if (global) { | 786 | if (global) { |
| 789 | ReadBasicSetting(Settings::values.current_user); | 787 | ReadBasicSetting(Settings::values.current_user); |
| 790 | Settings::values.current_user = std::clamp<int>(Settings::values.current_user.GetValue(), 0, | 788 | Settings::values.current_user = std::clamp<int>(Settings::values.current_user.GetValue(), 0, |
| @@ -797,6 +795,7 @@ void Config::ReadSystemValues() { | |||
| 797 | } else { | 795 | } else { |
| 798 | Settings::values.custom_rtc = std::nullopt; | 796 | Settings::values.custom_rtc = std::nullopt; |
| 799 | } | 797 | } |
| 798 | ReadBasicSetting(Settings::values.device_name); | ||
| 800 | } | 799 | } |
| 801 | 800 | ||
| 802 | ReadGlobalSetting(Settings::values.sound_index); | 801 | ReadGlobalSetting(Settings::values.sound_index); |
| @@ -1407,7 +1406,6 @@ void Config::SaveSystemValues() { | |||
| 1407 | Settings::values.rng_seed.UsingGlobal()); | 1406 | Settings::values.rng_seed.UsingGlobal()); |
| 1408 | WriteSetting(QStringLiteral("rng_seed"), Settings::values.rng_seed.GetValue(global).value_or(0), | 1407 | WriteSetting(QStringLiteral("rng_seed"), Settings::values.rng_seed.GetValue(global).value_or(0), |
| 1409 | 0, Settings::values.rng_seed.UsingGlobal()); | 1408 | 0, Settings::values.rng_seed.UsingGlobal()); |
| 1410 | WriteBasicSetting(Settings::values.device_name); | ||
| 1411 | 1409 | ||
| 1412 | if (global) { | 1410 | if (global) { |
| 1413 | WriteBasicSetting(Settings::values.current_user); | 1411 | WriteBasicSetting(Settings::values.current_user); |
| @@ -1416,6 +1414,7 @@ void Config::SaveSystemValues() { | |||
| 1416 | false); | 1414 | false); |
| 1417 | WriteSetting(QStringLiteral("custom_rtc"), | 1415 | WriteSetting(QStringLiteral("custom_rtc"), |
| 1418 | QVariant::fromValue<long long>(Settings::values.custom_rtc.value_or(0)), 0); | 1416 | QVariant::fromValue<long long>(Settings::values.custom_rtc.value_or(0)), 0); |
| 1417 | WriteBasicSetting(Settings::values.device_name); | ||
| 1419 | } | 1418 | } |
| 1420 | 1419 | ||
| 1421 | WriteGlobalSetting(Settings::values.sound_index); | 1420 | WriteGlobalSetting(Settings::values.sound_index); |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index c6f285dc2..820f60e61 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -2662,6 +2662,9 @@ void GMainWindow::OnMenuInstallToNAND() { | |||
| 2662 | return; | 2662 | return; |
| 2663 | } | 2663 | } |
| 2664 | 2664 | ||
| 2665 | // Save folder location of the first selected file | ||
| 2666 | UISettings::values.roms_path = QFileInfo(filenames[0]).path(); | ||
| 2667 | |||
| 2665 | int remaining = filenames.size(); | 2668 | int remaining = filenames.size(); |
| 2666 | 2669 | ||
| 2667 | // This would only overflow above 2^43 bytes (8.796 TB) | 2670 | // This would only overflow above 2^43 bytes (8.796 TB) |
diff --git a/src/yuzu/startup_checks.cpp b/src/yuzu/startup_checks.cpp index 563818362..9f702fe95 100644 --- a/src/yuzu/startup_checks.cpp +++ b/src/yuzu/startup_checks.cpp | |||
| @@ -186,7 +186,7 @@ pid_t SpawnChild(const char* arg0) { | |||
| 186 | return pid; | 186 | return pid; |
| 187 | } else if (pid == 0) { | 187 | } else if (pid == 0) { |
| 188 | // child | 188 | // child |
| 189 | execl(arg0, arg0, nullptr); | 189 | execlp(arg0, arg0, nullptr); |
| 190 | const int err = errno; | 190 | const int err = errno; |
| 191 | fmt::print(stderr, "execl failed with error {}\n", err); | 191 | fmt::print(stderr, "execl failed with error {}\n", err); |
| 192 | _exit(0); | 192 | _exit(0); |
diff --git a/src/yuzu/util/overlay_dialog.cpp b/src/yuzu/util/overlay_dialog.cpp index b27954512..3fa3d0afb 100644 --- a/src/yuzu/util/overlay_dialog.cpp +++ b/src/yuzu/util/overlay_dialog.cpp | |||
| @@ -42,7 +42,7 @@ OverlayDialog::OverlayDialog(QWidget* parent, Core::System& system, const QStrin | |||
| 42 | MoveAndResizeWindow(); | 42 | MoveAndResizeWindow(); |
| 43 | 43 | ||
| 44 | // TODO (Morph): Remove this when InputInterpreter no longer relies on the HID backend | 44 | // TODO (Morph): Remove this when InputInterpreter no longer relies on the HID backend |
| 45 | if (system.IsPoweredOn()) { | 45 | if (system.IsPoweredOn() && !ui->buttonsDialog->isHidden()) { |
| 46 | input_interpreter = std::make_unique<InputInterpreter>(system); | 46 | input_interpreter = std::make_unique<InputInterpreter>(system); |
| 47 | 47 | ||
| 48 | StartInputThread(); | 48 | StartInputThread(); |
| @@ -83,6 +83,11 @@ void OverlayDialog::InitializeRegularTextDialog(const QString& title_text, const | |||
| 83 | ui->button_ok_label->setEnabled(false); | 83 | ui->button_ok_label->setEnabled(false); |
| 84 | } | 84 | } |
| 85 | 85 | ||
| 86 | if (ui->button_cancel->isHidden() && ui->button_ok_label->isHidden()) { | ||
| 87 | ui->buttonsDialog->hide(); | ||
| 88 | return; | ||
| 89 | } | ||
| 90 | |||
| 86 | connect( | 91 | connect( |
| 87 | ui->button_cancel, &QPushButton::clicked, this, | 92 | ui->button_cancel, &QPushButton::clicked, this, |
| 88 | [this](bool) { | 93 | [this](bool) { |
| @@ -130,6 +135,11 @@ void OverlayDialog::InitializeRichTextDialog(const QString& title_text, const QS | |||
| 130 | ui->button_ok_rich->setEnabled(false); | 135 | ui->button_ok_rich->setEnabled(false); |
| 131 | } | 136 | } |
| 132 | 137 | ||
| 138 | if (ui->button_cancel_rich->isHidden() && ui->button_ok_rich->isHidden()) { | ||
| 139 | ui->buttonsRichDialog->hide(); | ||
| 140 | return; | ||
| 141 | } | ||
| 142 | |||
| 133 | connect( | 143 | connect( |
| 134 | ui->button_cancel_rich, &QPushButton::clicked, this, | 144 | ui->button_cancel_rich, &QPushButton::clicked, this, |
| 135 | [this](bool) { | 145 | [this](bool) { |