diff options
66 files changed, 1422 insertions, 1125 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index c834e9396..a810e11c2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -131,7 +131,7 @@ add_definitions(-DBOOST_ASIO_DISABLE_CONCEPTS)  if (MSVC)      add_compile_options($<$<COMPILE_LANGUAGE:CXX>:/std:c++latest>) -    # cubeb and boost still make use of deprecated result_of. +    # boost still makes use of deprecated result_of.      add_definitions(-D_HAS_DEPRECATED_RESULT_OF)  else()      set(CMAKE_CXX_STANDARD 20) diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index a76a3d800..64d1e6aec 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -44,10 +44,6 @@ target_include_directories(mbedtls PUBLIC ./mbedtls/include)  add_library(microprofile INTERFACE)  target_include_directories(microprofile INTERFACE ./microprofile) -# Unicorn -add_library(unicorn-headers INTERFACE) -target_include_directories(unicorn-headers INTERFACE ./unicorn/include) -  # libusb  if (NOT LIBUSB_FOUND OR YUZU_USE_BUNDLED_LIBUSB)      add_subdirectory(libusb) diff --git a/externals/cubeb b/externals/cubeb -Subproject 1d66483ad2b93f0e00e175f9480c771af90003a +Subproject 75d9d125ee655ef80f3bfcd97ae5a805931042b diff --git a/externals/find-modules/FindUnicorn.cmake b/externals/find-modules/FindUnicorn.cmake deleted file mode 100644 index a0f2a71f6..000000000 --- a/externals/find-modules/FindUnicorn.cmake +++ /dev/null @@ -1,18 +0,0 @@ -# Exports: -#  LIBUNICORN_FOUND -#  LIBUNICORN_INCLUDE_DIR -#  LIBUNICORN_LIBRARY - -find_path(LIBUNICORN_INCLUDE_DIR -          unicorn/unicorn.h -          HINTS $ENV{UNICORNDIR} -          PATH_SUFFIXES include) - -find_library(LIBUNICORN_LIBRARY -             NAMES unicorn -             HINTS $ENV{UNICORNDIR}) - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(unicorn DEFAULT_MSG -                                  LIBUNICORN_LIBRARY LIBUNICORN_INCLUDE_DIR) -mark_as_advanced(LIBUNICORN_INCLUDE_DIR LIBUNICORN_LIBRARY) diff --git a/src/common/input.h b/src/common/input.h index eaee0bdea..f775a4c01 100644 --- a/src/common/input.h +++ b/src/common/input.h @@ -227,7 +227,7 @@ struct CallbackStatus {  // Triggered once every input change  struct InputCallback { -    std::function<void(CallbackStatus)> on_change; +    std::function<void(const CallbackStatus&)> on_change;  };  /// An abstract class template for an input device (a button, an analog input, etc.). @@ -236,14 +236,10 @@ public:      virtual ~InputDevice() = default;      // Request input device to update if necessary -    virtual void SoftUpdate() { -        return; -    } +    virtual void SoftUpdate() {}      // Force input device to update data regardless of the current state -    virtual void ForceUpdate() { -        return; -    } +    virtual void ForceUpdate() {}      // Sets the function to be triggered when input changes      void SetCallback(InputCallback callback_) { @@ -251,7 +247,7 @@ public:      }      // Triggers the function set in the callback -    void TriggerOnChange(CallbackStatus status) { +    void TriggerOnChange(const CallbackStatus& status) {          if (callback.on_change) {              callback.on_change(status);          } @@ -266,11 +262,9 @@ class OutputDevice {  public:      virtual ~OutputDevice() = default; -    virtual void SetLED([[maybe_unused]] LedStatus led_status) { -        return; -    } +    virtual void SetLED([[maybe_unused]] const LedStatus& led_status) {} -    virtual VibrationError SetVibration([[maybe_unused]] VibrationStatus vibration_status) { +    virtual VibrationError SetVibration([[maybe_unused]] const VibrationStatus& vibration_status) {          return VibrationError::NotSupported;      } diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 506885659..49bed614a 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -187,6 +187,7 @@ add_library(core STATIC      hle/kernel/k_event.h      hle/kernel/k_handle_table.cpp      hle/kernel/k_handle_table.h +    hle/kernel/k_light_condition_variable.cpp      hle/kernel/k_light_condition_variable.h      hle/kernel/k_light_lock.cpp      hle/kernel/k_light_lock.h @@ -239,6 +240,7 @@ add_library(core STATIC      hle/kernel/k_system_control.h      hle/kernel/k_thread.cpp      hle/kernel/k_thread.h +    hle/kernel/k_thread_queue.cpp      hle/kernel/k_thread_queue.h      hle/kernel/k_trace.h      hle/kernel/k_transfer_memory.cpp diff --git a/src/core/core.cpp b/src/core/core.cpp index 473ab9f81..aa96f709b 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -521,12 +521,6 @@ const ARM_Interface& System::CurrentArmInterface() const {      return impl->kernel.CurrentPhysicalCore().ArmInterface();  } -std::size_t System::CurrentCoreIndex() const { -    std::size_t core = impl->kernel.GetCurrentHostThreadID(); -    ASSERT(core < Core::Hardware::NUM_CPU_CORES); -    return core; -} -  Kernel::PhysicalCore& System::CurrentPhysicalCore() {      return impl->kernel.CurrentPhysicalCore();  } diff --git a/src/core/core.h b/src/core/core.h index 645e5c241..52ff90359 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -208,9 +208,6 @@ public:      /// Gets an ARM interface to the CPU core that is currently running      [[nodiscard]] const ARM_Interface& CurrentArmInterface() const; -    /// Gets the index of the currently running CPU core -    [[nodiscard]] std::size_t CurrentCoreIndex() const; -      /// Gets the physical core for the CPU core that is currently running      [[nodiscard]] Kernel::PhysicalCore& CurrentPhysicalCore(); diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp index 5d43c6e5d..cbcc54891 100644 --- a/src/core/cpu_manager.cpp +++ b/src/core/cpu_manager.cpp @@ -117,17 +117,18 @@ void CpuManager::MultiCoreRunGuestLoop() {              physical_core = &kernel.CurrentPhysicalCore();          }          system.ExitDynarmicProfile(); -        physical_core->ArmInterface().ClearExclusiveState(); -        kernel.CurrentScheduler()->RescheduleCurrentCore(); +        { +            Kernel::KScopedDisableDispatch dd(kernel); +            physical_core->ArmInterface().ClearExclusiveState(); +        }      }  }  void CpuManager::MultiCoreRunIdleThread() {      auto& kernel = system.Kernel();      while (true) { -        auto& physical_core = kernel.CurrentPhysicalCore(); -        physical_core.Idle(); -        kernel.CurrentScheduler()->RescheduleCurrentCore(); +        Kernel::KScopedDisableDispatch dd(kernel); +        kernel.CurrentPhysicalCore().Idle();      }  } @@ -135,12 +136,12 @@ void CpuManager::MultiCoreRunSuspendThread() {      auto& kernel = system.Kernel();      kernel.CurrentScheduler()->OnThreadStart();      while (true) { -        auto core = kernel.GetCurrentHostThreadID(); +        auto core = kernel.CurrentPhysicalCoreIndex();          auto& scheduler = *kernel.CurrentScheduler();          Kernel::KThread* current_thread = scheduler.GetCurrentThread();          Common::Fiber::YieldTo(current_thread->GetHostContext(), *core_data[core].host_context);          ASSERT(scheduler.ContextSwitchPending()); -        ASSERT(core == kernel.GetCurrentHostThreadID()); +        ASSERT(core == kernel.CurrentPhysicalCoreIndex());          scheduler.RescheduleCurrentCore();      }  } @@ -346,13 +347,9 @@ void CpuManager::RunThread(std::stop_token stop_token, std::size_t core) {              sc_sync_first_use = false;          } -        // Abort if emulation was killed before the session really starts -        if (!system.IsPoweredOn()) { -            return; -        } - +        // Emulation was stopped          if (stop_token.stop_requested()) { -            break; +            return;          }          auto current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread(); diff --git a/src/core/hid/emulated_console.cpp b/src/core/hid/emulated_console.cpp index 80db8e9c6..685ec080c 100644 --- a/src/core/hid/emulated_console.cpp +++ b/src/core/hid/emulated_console.cpp @@ -66,9 +66,10 @@ void EmulatedConsole::ReloadInput() {      motion_devices = Common::Input::CreateDevice<Common::Input::InputDevice>(motion_params);      if (motion_devices) { -        Common::Input::InputCallback motion_callback{ -            [this](Common::Input::CallbackStatus callback) { SetMotion(callback); }}; -        motion_devices->SetCallback(motion_callback); +        motion_devices->SetCallback({ +            .on_change = +                [this](const Common::Input::CallbackStatus& callback) { SetMotion(callback); }, +        });      }      // Unique index for identifying touch device source @@ -78,9 +79,12 @@ void EmulatedConsole::ReloadInput() {          if (!touch_device) {              continue;          } -        Common::Input::InputCallback touch_callback{ -            [this, index](Common::Input::CallbackStatus callback) { SetTouch(callback, index); }}; -        touch_device->SetCallback(touch_callback); +        touch_device->SetCallback({ +            .on_change = +                [this, index](const Common::Input::CallbackStatus& callback) { +                    SetTouch(callback, index); +                }, +        });          index++;      }  } @@ -127,7 +131,7 @@ void EmulatedConsole::SetMotionParam(Common::ParamPackage param) {      ReloadInput();  } -void EmulatedConsole::SetMotion(Common::Input::CallbackStatus callback) { +void EmulatedConsole::SetMotion(const Common::Input::CallbackStatus& callback) {      std::lock_guard lock{mutex};      auto& raw_status = console.motion_values.raw_status;      auto& emulated = console.motion_values.emulated; @@ -162,8 +166,7 @@ void EmulatedConsole::SetMotion(Common::Input::CallbackStatus callback) {      TriggerOnChange(ConsoleTriggerType::Motion);  } -void EmulatedConsole::SetTouch(Common::Input::CallbackStatus callback, -                               [[maybe_unused]] std::size_t index) { +void EmulatedConsole::SetTouch(const Common::Input::CallbackStatus& callback, std::size_t index) {      if (index >= console.touch_values.size()) {          return;      } diff --git a/src/core/hid/emulated_console.h b/src/core/hid/emulated_console.h index bb3d7ab90..3afd284d5 100644 --- a/src/core/hid/emulated_console.h +++ b/src/core/hid/emulated_console.h @@ -155,14 +155,14 @@ private:       * Updates the motion status of the console       * @param callback A CallbackStatus containing gyro and accelerometer data       */ -    void SetMotion(Common::Input::CallbackStatus callback); +    void SetMotion(const Common::Input::CallbackStatus& callback);      /**       * Updates the touch status of the console       * @param callback A CallbackStatus containing the touch position       * @param index Finger ID to be updated       */ -    void SetTouch(Common::Input::CallbackStatus callback, std::size_t index); +    void SetTouch(const Common::Input::CallbackStatus& callback, std::size_t index);      /**       * Triggers a callback that something has changed on the console status diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index fbb19f230..93372445b 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -205,11 +205,12 @@ void EmulatedController::ReloadInput() {              continue;          }          const auto uuid = Common::UUID{button_params[index].Get("guid", "")}; -        Common::Input::InputCallback button_callback{ -            [this, index, uuid](Common::Input::CallbackStatus callback) { -                SetButton(callback, index, uuid); -            }}; -        button_devices[index]->SetCallback(button_callback); +        button_devices[index]->SetCallback({ +            .on_change = +                [this, index, uuid](const Common::Input::CallbackStatus& callback) { +                    SetButton(callback, index, uuid); +                }, +        });          button_devices[index]->ForceUpdate();      } @@ -218,11 +219,12 @@ void EmulatedController::ReloadInput() {              continue;          }          const auto uuid = Common::UUID{stick_params[index].Get("guid", "")}; -        Common::Input::InputCallback stick_callback{ -            [this, index, uuid](Common::Input::CallbackStatus callback) { -                SetStick(callback, index, uuid); -            }}; -        stick_devices[index]->SetCallback(stick_callback); +        stick_devices[index]->SetCallback({ +            .on_change = +                [this, index, uuid](const Common::Input::CallbackStatus& callback) { +                    SetStick(callback, index, uuid); +                }, +        });          stick_devices[index]->ForceUpdate();      } @@ -231,11 +233,12 @@ void EmulatedController::ReloadInput() {              continue;          }          const auto uuid = Common::UUID{trigger_params[index].Get("guid", "")}; -        Common::Input::InputCallback trigger_callback{ -            [this, index, uuid](Common::Input::CallbackStatus callback) { -                SetTrigger(callback, index, uuid); -            }}; -        trigger_devices[index]->SetCallback(trigger_callback); +        trigger_devices[index]->SetCallback({ +            .on_change = +                [this, index, uuid](const Common::Input::CallbackStatus& callback) { +                    SetTrigger(callback, index, uuid); +                }, +        });          trigger_devices[index]->ForceUpdate();      } @@ -243,9 +246,12 @@ void EmulatedController::ReloadInput() {          if (!battery_devices[index]) {              continue;          } -        Common::Input::InputCallback battery_callback{ -            [this, index](Common::Input::CallbackStatus callback) { SetBattery(callback, index); }}; -        battery_devices[index]->SetCallback(battery_callback); +        battery_devices[index]->SetCallback({ +            .on_change = +                [this, index](const Common::Input::CallbackStatus& callback) { +                    SetBattery(callback, index); +                }, +        });          battery_devices[index]->ForceUpdate();      } @@ -253,9 +259,12 @@ void EmulatedController::ReloadInput() {          if (!motion_devices[index]) {              continue;          } -        Common::Input::InputCallback motion_callback{ -            [this, index](Common::Input::CallbackStatus callback) { SetMotion(callback, index); }}; -        motion_devices[index]->SetCallback(motion_callback); +        motion_devices[index]->SetCallback({ +            .on_change = +                [this, index](const Common::Input::CallbackStatus& callback) { +                    SetMotion(callback, index); +                }, +        });          motion_devices[index]->ForceUpdate();      } @@ -267,22 +276,24 @@ void EmulatedController::ReloadInput() {          if (!tas_button_devices[index]) {              continue;          } -        Common::Input::InputCallback button_callback{ -            [this, index, tas_uuid](Common::Input::CallbackStatus callback) { -                SetButton(callback, index, tas_uuid); -            }}; -        tas_button_devices[index]->SetCallback(button_callback); +        tas_button_devices[index]->SetCallback({ +            .on_change = +                [this, index, tas_uuid](const Common::Input::CallbackStatus& callback) { +                    SetButton(callback, index, tas_uuid); +                }, +        });      }      for (std::size_t index = 0; index < tas_stick_devices.size(); ++index) {          if (!tas_stick_devices[index]) {              continue;          } -        Common::Input::InputCallback stick_callback{ -            [this, index, tas_uuid](Common::Input::CallbackStatus callback) { -                SetStick(callback, index, tas_uuid); -            }}; -        tas_stick_devices[index]->SetCallback(stick_callback); +        tas_stick_devices[index]->SetCallback({ +            .on_change = +                [this, index, tas_uuid](const Common::Input::CallbackStatus& callback) { +                    SetStick(callback, index, tas_uuid); +                }, +        });      }  } @@ -440,7 +451,7 @@ void EmulatedController::SetButtonParam(std::size_t index, Common::ParamPackage      if (index >= button_params.size()) {          return;      } -    button_params[index] = param; +    button_params[index] = std::move(param);      ReloadInput();  } @@ -448,7 +459,7 @@ void EmulatedController::SetStickParam(std::size_t index, Common::ParamPackage p      if (index >= stick_params.size()) {          return;      } -    stick_params[index] = param; +    stick_params[index] = std::move(param);      ReloadInput();  } @@ -456,11 +467,11 @@ void EmulatedController::SetMotionParam(std::size_t index, Common::ParamPackage      if (index >= motion_params.size()) {          return;      } -    motion_params[index] = param; +    motion_params[index] = std::move(param);      ReloadInput();  } -void EmulatedController::SetButton(Common::Input::CallbackStatus callback, std::size_t index, +void EmulatedController::SetButton(const Common::Input::CallbackStatus& callback, std::size_t index,                                     Common::UUID uuid) {      if (index >= controller.button_values.size()) {          return; @@ -600,7 +611,7 @@ void EmulatedController::SetButton(Common::Input::CallbackStatus callback, std::      TriggerOnChange(ControllerTriggerType::Button, true);  } -void EmulatedController::SetStick(Common::Input::CallbackStatus callback, std::size_t index, +void EmulatedController::SetStick(const Common::Input::CallbackStatus& callback, std::size_t index,                                    Common::UUID uuid) {      if (index >= controller.stick_values.size()) {          return; @@ -650,8 +661,8 @@ void EmulatedController::SetStick(Common::Input::CallbackStatus callback, std::s      TriggerOnChange(ControllerTriggerType::Stick, true);  } -void EmulatedController::SetTrigger(Common::Input::CallbackStatus callback, std::size_t index, -                                    Common::UUID uuid) { +void EmulatedController::SetTrigger(const Common::Input::CallbackStatus& callback, +                                    std::size_t index, Common::UUID uuid) {      if (index >= controller.trigger_values.size()) {          return;      } @@ -659,7 +670,7 @@ void EmulatedController::SetTrigger(Common::Input::CallbackStatus callback, std:      const auto trigger_value = TransformToTrigger(callback);      // Only read trigger values that have the same uuid or are pressed once -    if (controller.stick_values[index].uuid != uuid) { +    if (controller.trigger_values[index].uuid != uuid) {          if (!trigger_value.pressed.value) {              return;          } @@ -675,7 +686,7 @@ void EmulatedController::SetTrigger(Common::Input::CallbackStatus callback, std:          return;      } -    const auto trigger = controller.trigger_values[index]; +    const auto& trigger = controller.trigger_values[index];      switch (index) {      case Settings::NativeTrigger::LTrigger: @@ -692,7 +703,8 @@ void EmulatedController::SetTrigger(Common::Input::CallbackStatus callback, std:      TriggerOnChange(ControllerTriggerType::Trigger, true);  } -void EmulatedController::SetMotion(Common::Input::CallbackStatus callback, std::size_t index) { +void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback, +                                   std::size_t index) {      if (index >= controller.motion_values.size()) {          return;      } @@ -730,7 +742,8 @@ void EmulatedController::SetMotion(Common::Input::CallbackStatus callback, std::      TriggerOnChange(ControllerTriggerType::Motion, true);  } -void EmulatedController::SetBattery(Common::Input::CallbackStatus callback, std::size_t index) { +void EmulatedController::SetBattery(const Common::Input::CallbackStatus& callback, +                                    std::size_t index) {      if (index >= controller.battery_values.size()) {          return;      } @@ -1110,7 +1123,7 @@ void EmulatedController::TriggerOnChange(ControllerTriggerType type, bool is_npa  int EmulatedController::SetCallback(ControllerUpdateCallback update_callback) {      std::lock_guard lock{mutex}; -    callback_list.insert_or_assign(last_callback_key, update_callback); +    callback_list.insert_or_assign(last_callback_key, std::move(update_callback));      return last_callback_key++;  } diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index 425b3e7c4..e42aafebc 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h @@ -328,35 +328,38 @@ private:       * @param callback A CallbackStatus containing the button status       * @param index Button ID of the to be updated       */ -    void SetButton(Common::Input::CallbackStatus callback, std::size_t index, Common::UUID uuid); +    void SetButton(const Common::Input::CallbackStatus& callback, std::size_t index, +                   Common::UUID uuid);      /**       * Updates the analog stick status of the controller       * @param callback A CallbackStatus containing the analog stick status       * @param index stick ID of the to be updated       */ -    void SetStick(Common::Input::CallbackStatus callback, std::size_t index, Common::UUID uuid); +    void SetStick(const Common::Input::CallbackStatus& callback, std::size_t index, +                  Common::UUID uuid);      /**       * Updates the trigger status of the controller       * @param callback A CallbackStatus containing the trigger status       * @param index trigger ID of the to be updated       */ -    void SetTrigger(Common::Input::CallbackStatus callback, std::size_t index, Common::UUID uuid); +    void SetTrigger(const Common::Input::CallbackStatus& callback, std::size_t index, +                    Common::UUID uuid);      /**       * Updates the motion status of the controller       * @param callback A CallbackStatus containing gyro and accelerometer data       * @param index motion ID of the to be updated       */ -    void SetMotion(Common::Input::CallbackStatus callback, std::size_t index); +    void SetMotion(const Common::Input::CallbackStatus& callback, std::size_t index);      /**       * Updates the battery status of the controller       * @param callback A CallbackStatus containing the battery status       * @param index Button ID of the to be updated       */ -    void SetBattery(Common::Input::CallbackStatus callback, std::size_t index); +    void SetBattery(const Common::Input::CallbackStatus& callback, std::size_t index);      /**       * Triggers a callback that something has changed on the controller status diff --git a/src/core/hid/emulated_devices.cpp b/src/core/hid/emulated_devices.cpp index 874780ec2..708480f2d 100644 --- a/src/core/hid/emulated_devices.cpp +++ b/src/core/hid/emulated_devices.cpp @@ -70,50 +70,55 @@ void EmulatedDevices::ReloadInput() {          if (!mouse_button_devices[index]) {              continue;          } -        Common::Input::InputCallback button_callback{ -            [this, index](Common::Input::CallbackStatus callback) { -                SetMouseButton(callback, index); -            }}; -        mouse_button_devices[index]->SetCallback(button_callback); +        mouse_button_devices[index]->SetCallback({ +            .on_change = +                [this, index](const Common::Input::CallbackStatus& callback) { +                    SetMouseButton(callback, index); +                }, +        });      }      for (std::size_t index = 0; index < mouse_analog_devices.size(); ++index) {          if (!mouse_analog_devices[index]) {              continue;          } -        Common::Input::InputCallback button_callback{ -            [this, index](Common::Input::CallbackStatus callback) { -                SetMouseAnalog(callback, index); -            }}; -        mouse_analog_devices[index]->SetCallback(button_callback); +        mouse_analog_devices[index]->SetCallback({ +            .on_change = +                [this, index](const Common::Input::CallbackStatus& callback) { +                    SetMouseAnalog(callback, index); +                }, +        });      }      if (mouse_stick_device) { -        Common::Input::InputCallback button_callback{ -            [this](Common::Input::CallbackStatus callback) { SetMouseStick(callback); }}; -        mouse_stick_device->SetCallback(button_callback); +        mouse_stick_device->SetCallback({ +            .on_change = +                [this](const Common::Input::CallbackStatus& callback) { SetMouseStick(callback); }, +        });      }      for (std::size_t index = 0; index < keyboard_devices.size(); ++index) {          if (!keyboard_devices[index]) {              continue;          } -        Common::Input::InputCallback button_callback{ -            [this, index](Common::Input::CallbackStatus callback) { -                SetKeyboardButton(callback, index); -            }}; -        keyboard_devices[index]->SetCallback(button_callback); +        keyboard_devices[index]->SetCallback({ +            .on_change = +                [this, index](const Common::Input::CallbackStatus& callback) { +                    SetKeyboardButton(callback, index); +                }, +        });      }      for (std::size_t index = 0; index < keyboard_modifier_devices.size(); ++index) {          if (!keyboard_modifier_devices[index]) {              continue;          } -        Common::Input::InputCallback button_callback{ -            [this, index](Common::Input::CallbackStatus callback) { -                SetKeyboardModifier(callback, index); -            }}; -        keyboard_modifier_devices[index]->SetCallback(button_callback); +        keyboard_modifier_devices[index]->SetCallback({ +            .on_change = +                [this, index](const Common::Input::CallbackStatus& callback) { +                    SetKeyboardModifier(callback, index); +                }, +        });      }  } @@ -159,7 +164,8 @@ void EmulatedDevices::RestoreConfig() {      ReloadFromSettings();  } -void EmulatedDevices::SetKeyboardButton(Common::Input::CallbackStatus callback, std::size_t index) { +void EmulatedDevices::SetKeyboardButton(const Common::Input::CallbackStatus& callback, +                                        std::size_t index) {      if (index >= device_status.keyboard_values.size()) {          return;      } @@ -216,7 +222,7 @@ void EmulatedDevices::UpdateKey(std::size_t key_index, bool status) {      }  } -void EmulatedDevices::SetKeyboardModifier(Common::Input::CallbackStatus callback, +void EmulatedDevices::SetKeyboardModifier(const Common::Input::CallbackStatus& callback,                                            std::size_t index) {      if (index >= device_status.keyboard_moddifier_values.size()) {          return; @@ -286,7 +292,8 @@ void EmulatedDevices::SetKeyboardModifier(Common::Input::CallbackStatus callback      TriggerOnChange(DeviceTriggerType::KeyboardModdifier);  } -void EmulatedDevices::SetMouseButton(Common::Input::CallbackStatus callback, std::size_t index) { +void EmulatedDevices::SetMouseButton(const Common::Input::CallbackStatus& callback, +                                     std::size_t index) {      if (index >= device_status.mouse_button_values.size()) {          return;      } @@ -347,7 +354,8 @@ void EmulatedDevices::SetMouseButton(Common::Input::CallbackStatus callback, std      TriggerOnChange(DeviceTriggerType::Mouse);  } -void EmulatedDevices::SetMouseAnalog(Common::Input::CallbackStatus callback, std::size_t index) { +void EmulatedDevices::SetMouseAnalog(const Common::Input::CallbackStatus& callback, +                                     std::size_t index) {      if (index >= device_status.mouse_analog_values.size()) {          return;      } @@ -374,7 +382,7 @@ void EmulatedDevices::SetMouseAnalog(Common::Input::CallbackStatus callback, std      TriggerOnChange(DeviceTriggerType::Mouse);  } -void EmulatedDevices::SetMouseStick(Common::Input::CallbackStatus callback) { +void EmulatedDevices::SetMouseStick(const Common::Input::CallbackStatus& callback) {      std::lock_guard lock{mutex};      const auto touch_value = TransformToTouch(callback); @@ -435,7 +443,7 @@ void EmulatedDevices::TriggerOnChange(DeviceTriggerType type) {  int EmulatedDevices::SetCallback(InterfaceUpdateCallback update_callback) {      std::lock_guard lock{mutex}; -    callback_list.insert_or_assign(last_callback_key, update_callback); +    callback_list.insert_or_assign(last_callback_key, std::move(update_callback));      return last_callback_key++;  } diff --git a/src/core/hid/emulated_devices.h b/src/core/hid/emulated_devices.h index c72327681..790d3b411 100644 --- a/src/core/hid/emulated_devices.h +++ b/src/core/hid/emulated_devices.h @@ -156,35 +156,34 @@ private:       * @param callback A CallbackStatus containing the key status       * @param index key ID to be updated       */ -    void SetKeyboardButton(Common::Input::CallbackStatus callback, std::size_t index); +    void SetKeyboardButton(const Common::Input::CallbackStatus& callback, std::size_t index);      /**       * Updates the keyboard status of the keyboard device       * @param callback A CallbackStatus containing the modifier key status       * @param index modifier key ID to be updated       */ -    void SetKeyboardModifier(Common::Input::CallbackStatus callback, std::size_t index); +    void SetKeyboardModifier(const Common::Input::CallbackStatus& callback, std::size_t index);      /**       * Updates the mouse button status of the mouse device       * @param callback A CallbackStatus containing the button status       * @param index Button ID to be updated       */ -    void SetMouseButton(Common::Input::CallbackStatus callback, std::size_t index); +    void SetMouseButton(const Common::Input::CallbackStatus& callback, std::size_t index);      /**       * Updates the mouse wheel status of the mouse device       * @param callback A CallbackStatus containing the wheel status       * @param index wheel ID to be updated       */ -    void SetMouseAnalog(Common::Input::CallbackStatus callback, std::size_t index); +    void SetMouseAnalog(const Common::Input::CallbackStatus& callback, std::size_t index);      /**       * Updates the mouse position status of the mouse device       * @param callback A CallbackStatus containing the position status -     * @param index stick ID to be updated       */ -    void SetMouseStick(Common::Input::CallbackStatus callback); +    void SetMouseStick(const Common::Input::CallbackStatus& callback);      /**       * Triggers a callback that something has changed on the device status diff --git a/src/core/hle/kernel/k_address_arbiter.cpp b/src/core/hle/kernel/k_address_arbiter.cpp index 1b429bc1e..783c69858 100644 --- a/src/core/hle/kernel/k_address_arbiter.cpp +++ b/src/core/hle/kernel/k_address_arbiter.cpp @@ -8,6 +8,7 @@  #include "core/hle/kernel/k_scheduler.h"  #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"  #include "core/hle/kernel/k_thread.h" +#include "core/hle/kernel/k_thread_queue.h"  #include "core/hle/kernel/kernel.h"  #include "core/hle/kernel/svc_results.h"  #include "core/hle/kernel/time_manager.h" @@ -28,7 +29,7 @@ bool ReadFromUser(Core::System& system, s32* out, VAddr address) {  bool DecrementIfLessThan(Core::System& system, s32* out, VAddr address, s32 value) {      auto& monitor = system.Monitor(); -    const auto current_core = system.CurrentCoreIndex(); +    const auto current_core = system.Kernel().CurrentPhysicalCoreIndex();      // TODO(bunnei): We should disable interrupts here via KScopedInterruptDisable.      // TODO(bunnei): We should call CanAccessAtomic(..) here. @@ -58,7 +59,7 @@ bool DecrementIfLessThan(Core::System& system, s32* out, VAddr address, s32 valu  bool UpdateIfEqual(Core::System& system, s32* out, VAddr address, s32 value, s32 new_value) {      auto& monitor = system.Monitor(); -    const auto current_core = system.CurrentCoreIndex(); +    const auto current_core = system.Kernel().CurrentPhysicalCoreIndex();      // TODO(bunnei): We should disable interrupts here via KScopedInterruptDisable.      // TODO(bunnei): We should call CanAccessAtomic(..) here. @@ -85,6 +86,27 @@ bool UpdateIfEqual(Core::System& system, s32* out, VAddr address, s32 value, s32      return true;  } +class ThreadQueueImplForKAddressArbiter final : public KThreadQueue { +public: +    explicit ThreadQueueImplForKAddressArbiter(KernelCore& kernel_, KAddressArbiter::ThreadTree* t) +        : KThreadQueue(kernel_), m_tree(t) {} + +    void CancelWait(KThread* waiting_thread, ResultCode wait_result, +                    bool cancel_timer_task) override { +        // If the thread is waiting on an address arbiter, remove it from the tree. +        if (waiting_thread->IsWaitingForAddressArbiter()) { +            m_tree->erase(m_tree->iterator_to(*waiting_thread)); +            waiting_thread->ClearAddressArbiter(); +        } + +        // Invoke the base cancel wait handler. +        KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task); +    } + +private: +    KAddressArbiter::ThreadTree* m_tree; +}; +  } // namespace  ResultCode KAddressArbiter::Signal(VAddr addr, s32 count) { @@ -96,14 +118,14 @@ ResultCode KAddressArbiter::Signal(VAddr addr, s32 count) {          auto it = thread_tree.nfind_light({addr, -1});          while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) &&                 (it->GetAddressArbiterKey() == addr)) { +            // End the thread's wait.              KThread* target_thread = std::addressof(*it); -            target_thread->SetSyncedObject(nullptr, ResultSuccess); +            target_thread->EndWait(ResultSuccess);              ASSERT(target_thread->IsWaitingForAddressArbiter()); -            target_thread->Wakeup(); +            target_thread->ClearAddressArbiter();              it = thread_tree.erase(it); -            target_thread->ClearAddressArbiter();              ++num_waiters;          }      } @@ -129,14 +151,14 @@ ResultCode KAddressArbiter::SignalAndIncrementIfEqual(VAddr addr, s32 value, s32          auto it = thread_tree.nfind_light({addr, -1});          while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) &&                 (it->GetAddressArbiterKey() == addr)) { +            // End the thread's wait.              KThread* target_thread = std::addressof(*it); -            target_thread->SetSyncedObject(nullptr, ResultSuccess); +            target_thread->EndWait(ResultSuccess);              ASSERT(target_thread->IsWaitingForAddressArbiter()); -            target_thread->Wakeup(); +            target_thread->ClearAddressArbiter();              it = thread_tree.erase(it); -            target_thread->ClearAddressArbiter();              ++num_waiters;          }      } @@ -197,14 +219,14 @@ ResultCode KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(VAddr addr, s32          while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) &&                 (it->GetAddressArbiterKey() == addr)) { +            // End the thread's wait.              KThread* target_thread = std::addressof(*it); -            target_thread->SetSyncedObject(nullptr, ResultSuccess); +            target_thread->EndWait(ResultSuccess);              ASSERT(target_thread->IsWaitingForAddressArbiter()); -            target_thread->Wakeup(); +            target_thread->ClearAddressArbiter();              it = thread_tree.erase(it); -            target_thread->ClearAddressArbiter();              ++num_waiters;          }      } @@ -214,6 +236,7 @@ ResultCode KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(VAddr addr, s32  ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement, s64 timeout) {      // Prepare to wait.      KThread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread(); +    ThreadQueueImplForKAddressArbiter wait_queue(kernel, std::addressof(thread_tree));      {          KScopedSchedulerLockAndSleep slp{kernel, cur_thread, timeout}; @@ -224,9 +247,6 @@ ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement              return ResultTerminationRequested;          } -        // Set the synced object. -        cur_thread->SetSyncedObject(nullptr, ResultTimedOut); -          // Read the value from userspace.          s32 user_value{};          bool succeeded{}; @@ -256,31 +276,20 @@ ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement          // Set the arbiter.          cur_thread->SetAddressArbiter(&thread_tree, addr);          thread_tree.insert(*cur_thread); -        cur_thread->SetState(ThreadState::Waiting); -        cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Arbitration); -    } - -    // Cancel the timer wait. -    kernel.TimeManager().UnscheduleTimeEvent(cur_thread); -    // Remove from the address arbiter. -    { -        KScopedSchedulerLock sl(kernel); - -        if (cur_thread->IsWaitingForAddressArbiter()) { -            thread_tree.erase(thread_tree.iterator_to(*cur_thread)); -            cur_thread->ClearAddressArbiter(); -        } +        // Wait for the thread to finish. +        cur_thread->BeginWait(std::addressof(wait_queue)); +        cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Arbitration);      }      // Get the result. -    KSynchronizationObject* dummy{}; -    return cur_thread->GetWaitResult(&dummy); +    return cur_thread->GetWaitResult();  }  ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) {      // Prepare to wait.      KThread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread(); +    ThreadQueueImplForKAddressArbiter wait_queue(kernel, std::addressof(thread_tree));      {          KScopedSchedulerLockAndSleep slp{kernel, cur_thread, timeout}; @@ -291,9 +300,6 @@ ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) {              return ResultTerminationRequested;          } -        // Set the synced object. -        cur_thread->SetSyncedObject(nullptr, ResultTimedOut); -          // Read the value from userspace.          s32 user_value{};          if (!ReadFromUser(system, &user_value, addr)) { @@ -316,26 +322,14 @@ ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) {          // Set the arbiter.          cur_thread->SetAddressArbiter(&thread_tree, addr);          thread_tree.insert(*cur_thread); -        cur_thread->SetState(ThreadState::Waiting); -        cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Arbitration); -    } - -    // Cancel the timer wait. -    kernel.TimeManager().UnscheduleTimeEvent(cur_thread); -    // Remove from the address arbiter. -    { -        KScopedSchedulerLock sl(kernel); - -        if (cur_thread->IsWaitingForAddressArbiter()) { -            thread_tree.erase(thread_tree.iterator_to(*cur_thread)); -            cur_thread->ClearAddressArbiter(); -        } +        // Wait for the thread to finish. +        cur_thread->BeginWait(std::addressof(wait_queue)); +        cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Arbitration);      }      // Get the result. -    KSynchronizationObject* dummy{}; -    return cur_thread->GetWaitResult(&dummy); +    return cur_thread->GetWaitResult();  }  } // namespace Kernel diff --git a/src/core/hle/kernel/k_auto_object.h b/src/core/hle/kernel/k_auto_object.h index e4fcdbc67..165b76747 100644 --- a/src/core/hle/kernel/k_auto_object.h +++ b/src/core/hle/kernel/k_auto_object.h @@ -170,6 +170,10 @@ public:          }      } +    const std::string& GetName() const { +        return name; +    } +  private:      void RegisterWithKernel();      void UnregisterWithKernel(); diff --git a/src/core/hle/kernel/k_condition_variable.cpp b/src/core/hle/kernel/k_condition_variable.cpp index 7fa9b8cc3..aadcc297a 100644 --- a/src/core/hle/kernel/k_condition_variable.cpp +++ b/src/core/hle/kernel/k_condition_variable.cpp @@ -11,6 +11,7 @@  #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"  #include "core/hle/kernel/k_synchronization_object.h"  #include "core/hle/kernel/k_thread.h" +#include "core/hle/kernel/k_thread_queue.h"  #include "core/hle/kernel/kernel.h"  #include "core/hle/kernel/svc_common.h"  #include "core/hle/kernel/svc_results.h" @@ -33,7 +34,7 @@ bool WriteToUser(Core::System& system, VAddr address, const u32* p) {  bool UpdateLockAtomic(Core::System& system, u32* out, VAddr address, u32 if_zero,                        u32 new_orr_mask) {      auto& monitor = system.Monitor(); -    const auto current_core = system.CurrentCoreIndex(); +    const auto current_core = system.Kernel().CurrentPhysicalCoreIndex();      // Load the value from the address.      const auto expected = monitor.ExclusiveRead32(current_core, address); @@ -57,6 +58,48 @@ bool UpdateLockAtomic(Core::System& system, u32* out, VAddr address, u32 if_zero      return true;  } +class ThreadQueueImplForKConditionVariableWaitForAddress final : public KThreadQueue { +public: +    explicit ThreadQueueImplForKConditionVariableWaitForAddress(KernelCore& kernel_) +        : KThreadQueue(kernel_) {} + +    void CancelWait(KThread* waiting_thread, ResultCode wait_result, +                    bool cancel_timer_task) override { +        // Remove the thread as a waiter from its owner. +        waiting_thread->GetLockOwner()->RemoveWaiter(waiting_thread); + +        // Invoke the base cancel wait handler. +        KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task); +    } +}; + +class ThreadQueueImplForKConditionVariableWaitConditionVariable final : public KThreadQueue { +private: +    KConditionVariable::ThreadTree* m_tree; + +public: +    explicit ThreadQueueImplForKConditionVariableWaitConditionVariable( +        KernelCore& kernel_, KConditionVariable::ThreadTree* t) +        : KThreadQueue(kernel_), m_tree(t) {} + +    void CancelWait(KThread* waiting_thread, ResultCode wait_result, +                    bool cancel_timer_task) override { +        // Remove the thread as a waiter from its owner. +        if (KThread* owner = waiting_thread->GetLockOwner(); owner != nullptr) { +            owner->RemoveWaiter(waiting_thread); +        } + +        // If the thread is waiting on a condvar, remove it from the tree. +        if (waiting_thread->IsWaitingForConditionVariable()) { +            m_tree->erase(m_tree->iterator_to(*waiting_thread)); +            waiting_thread->ClearConditionVariable(); +        } + +        // Invoke the base cancel wait handler. +        KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task); +    } +}; +  } // namespace  KConditionVariable::KConditionVariable(Core::System& system_) @@ -78,84 +121,77 @@ ResultCode KConditionVariable::SignalToAddress(VAddr addr) {          // Determine the next tag.          u32 next_value{}; -        if (next_owner_thread) { +        if (next_owner_thread != nullptr) {              next_value = next_owner_thread->GetAddressKeyValue();              if (num_waiters > 1) {                  next_value |= Svc::HandleWaitMask;              } -            next_owner_thread->SetSyncedObject(nullptr, ResultSuccess); -            next_owner_thread->Wakeup(); -        } - -        // Write the value to userspace. -        if (!WriteToUser(system, addr, std::addressof(next_value))) { -            if (next_owner_thread) { -                next_owner_thread->SetSyncedObject(nullptr, ResultInvalidCurrentMemory); +            // Write the value to userspace. +            ResultCode result{ResultSuccess}; +            if (WriteToUser(system, addr, std::addressof(next_value))) [[likely]] { +                result = ResultSuccess; +            } else { +                result = ResultInvalidCurrentMemory;              } -            return ResultInvalidCurrentMemory; +            // Signal the next owner thread. +            next_owner_thread->EndWait(result); +            return result; +        } else { +            // Just write the value to userspace. +            R_UNLESS(WriteToUser(system, addr, std::addressof(next_value)), +                     ResultInvalidCurrentMemory); + +            return ResultSuccess;          }      } - -    return ResultSuccess;  }  ResultCode KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 value) {      KThread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread(); +    ThreadQueueImplForKConditionVariableWaitForAddress wait_queue(kernel);      // Wait for the address. +    KThread* owner_thread{};      { -        KScopedAutoObject<KThread> owner_thread; -        ASSERT(owner_thread.IsNull()); -        { -            KScopedSchedulerLock sl(kernel); -            cur_thread->SetSyncedObject(nullptr, ResultSuccess); +        KScopedSchedulerLock sl(kernel); -            // Check if the thread should terminate. -            R_UNLESS(!cur_thread->IsTerminationRequested(), ResultTerminationRequested); +        // Check if the thread should terminate. +        R_UNLESS(!cur_thread->IsTerminationRequested(), ResultTerminationRequested); -            { -                // Read the tag from userspace. -                u32 test_tag{}; -                R_UNLESS(ReadFromUser(system, std::addressof(test_tag), addr), -                         ResultInvalidCurrentMemory); - -                // If the tag isn't the handle (with wait mask), we're done. -                R_UNLESS(test_tag == (handle | Svc::HandleWaitMask), ResultSuccess); - -                // Get the lock owner thread. -                owner_thread = -                    kernel.CurrentProcess()->GetHandleTable().GetObjectWithoutPseudoHandle<KThread>( -                        handle); -                R_UNLESS(owner_thread.IsNotNull(), ResultInvalidHandle); - -                // Update the lock. -                cur_thread->SetAddressKey(addr, value); -                owner_thread->AddWaiter(cur_thread); -                cur_thread->SetState(ThreadState::Waiting); -                cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::ConditionVar); -                cur_thread->SetMutexWaitAddressForDebugging(addr); -            } -        } -        ASSERT(owner_thread.IsNotNull()); -    } +        // Read the tag from userspace. +        u32 test_tag{}; +        R_UNLESS(ReadFromUser(system, std::addressof(test_tag), addr), ResultInvalidCurrentMemory); -    // Remove the thread as a waiter from the lock owner. -    { -        KScopedSchedulerLock sl(kernel); -        KThread* owner_thread = cur_thread->GetLockOwner(); -        if (owner_thread != nullptr) { -            owner_thread->RemoveWaiter(cur_thread); -        } +        // If the tag isn't the handle (with wait mask), we're done. +        R_SUCCEED_IF(test_tag != (handle | Svc::HandleWaitMask)); + +        // Get the lock owner thread. +        owner_thread = kernel.CurrentProcess() +                           ->GetHandleTable() +                           .GetObjectWithoutPseudoHandle<KThread>(handle) +                           .ReleasePointerUnsafe(); +        R_UNLESS(owner_thread != nullptr, ResultInvalidHandle); + +        // Update the lock. +        cur_thread->SetAddressKey(addr, value); +        owner_thread->AddWaiter(cur_thread); + +        // Begin waiting. +        cur_thread->BeginWait(std::addressof(wait_queue)); +        cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::ConditionVar); +        cur_thread->SetMutexWaitAddressForDebugging(addr);      } +    // Close our reference to the owner thread, now that the wait is over. +    owner_thread->Close(); +      // Get the wait result. -    KSynchronizationObject* dummy{}; -    return cur_thread->GetWaitResult(std::addressof(dummy)); +    return cur_thread->GetWaitResult();  } -KThread* KConditionVariable::SignalImpl(KThread* thread) { +void KConditionVariable::SignalImpl(KThread* thread) {      // Check pre-conditions.      ASSERT(kernel.GlobalSchedulerContext().IsLocked()); @@ -169,18 +205,16 @@ KThread* KConditionVariable::SignalImpl(KThread* thread) {          // TODO(bunnei): We should disable interrupts here via KScopedInterruptDisable.          // TODO(bunnei): We should call CanAccessAtomic(..) here.          can_access = true; -        if (can_access) { +        if (can_access) [[likely]] {              UpdateLockAtomic(system, std::addressof(prev_tag), address, own_tag,                               Svc::HandleWaitMask);          }      } -    KThread* thread_to_close = nullptr; -    if (can_access) { +    if (can_access) [[likely]] {          if (prev_tag == Svc::InvalidHandle) {              // If nobody held the lock previously, we're all good. -            thread->SetSyncedObject(nullptr, ResultSuccess); -            thread->Wakeup(); +            thread->EndWait(ResultSuccess);          } else {              // Get the previous owner.              KThread* owner_thread = kernel.CurrentProcess() @@ -189,33 +223,22 @@ KThread* KConditionVariable::SignalImpl(KThread* thread) {                                              static_cast<Handle>(prev_tag & ~Svc::HandleWaitMask))                                          .ReleasePointerUnsafe(); -            if (owner_thread) { +            if (owner_thread) [[likely]] {                  // Add the thread as a waiter on the owner.                  owner_thread->AddWaiter(thread); -                thread_to_close = owner_thread; +                owner_thread->Close();              } else {                  // The lock was tagged with a thread that doesn't exist. -                thread->SetSyncedObject(nullptr, ResultInvalidState); -                thread->Wakeup(); +                thread->EndWait(ResultInvalidState);              }          }      } else {          // If the address wasn't accessible, note so. -        thread->SetSyncedObject(nullptr, ResultInvalidCurrentMemory); -        thread->Wakeup(); +        thread->EndWait(ResultInvalidCurrentMemory);      } - -    return thread_to_close;  }  void KConditionVariable::Signal(u64 cv_key, s32 count) { -    // Prepare for signaling. -    constexpr int MaxThreads = 16; - -    KLinkedList<KThread> thread_list{kernel}; -    std::array<KThread*, MaxThreads> thread_array; -    s32 num_to_close{}; -      // Perform signaling.      s32 num_waiters{};      { @@ -226,14 +249,7 @@ void KConditionVariable::Signal(u64 cv_key, s32 count) {                 (it->GetConditionVariableKey() == cv_key)) {              KThread* target_thread = std::addressof(*it); -            if (KThread* thread = SignalImpl(target_thread); thread != nullptr) { -                if (num_to_close < MaxThreads) { -                    thread_array[num_to_close++] = thread; -                } else { -                    thread_list.push_back(*thread); -                } -            } - +            this->SignalImpl(target_thread);              it = thread_tree.erase(it);              target_thread->ClearConditionVariable();              ++num_waiters; @@ -245,27 +261,16 @@ void KConditionVariable::Signal(u64 cv_key, s32 count) {              WriteToUser(system, cv_key, std::addressof(has_waiter_flag));          }      } - -    // Close threads in the array. -    for (auto i = 0; i < num_to_close; ++i) { -        thread_array[i]->Close(); -    } - -    // Close threads in the list. -    for (auto it = thread_list.begin(); it != thread_list.end(); it = thread_list.erase(it)) { -        (*it).Close(); -    }  }  ResultCode KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout) {      // Prepare to wait. -    KThread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread(); +    KThread* cur_thread = GetCurrentThreadPointer(kernel); +    ThreadQueueImplForKConditionVariableWaitConditionVariable wait_queue( +        kernel, std::addressof(thread_tree));      { -        KScopedSchedulerLockAndSleep slp{kernel, cur_thread, timeout}; - -        // Set the synced object. -        cur_thread->SetSyncedObject(nullptr, ResultTimedOut); +        KScopedSchedulerLockAndSleep slp(kernel, cur_thread, timeout);          // Check that the thread isn't terminating.          if (cur_thread->IsTerminationRequested()) { @@ -290,8 +295,7 @@ ResultCode KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout)                  }                  // Wake up the next owner. -                next_owner_thread->SetSyncedObject(nullptr, ResultSuccess); -                next_owner_thread->Wakeup(); +                next_owner_thread->EndWait(ResultSuccess);              }              // Write to the cv key. @@ -308,40 +312,21 @@ ResultCode KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout)              }          } -        // Update condition variable tracking. -        { -            cur_thread->SetConditionVariable(std::addressof(thread_tree), addr, key, value); -            thread_tree.insert(*cur_thread); -        } +        // If timeout is zero, time out. +        R_UNLESS(timeout != 0, ResultTimedOut); -        // If the timeout is non-zero, set the thread as waiting. -        if (timeout != 0) { -            cur_thread->SetState(ThreadState::Waiting); -            cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::ConditionVar); -            cur_thread->SetMutexWaitAddressForDebugging(addr); -        } -    } - -    // Cancel the timer wait. -    kernel.TimeManager().UnscheduleTimeEvent(cur_thread); - -    // Remove from the condition variable. -    { -        KScopedSchedulerLock sl(kernel); - -        if (KThread* owner = cur_thread->GetLockOwner(); owner != nullptr) { -            owner->RemoveWaiter(cur_thread); -        } +        // Update condition variable tracking. +        cur_thread->SetConditionVariable(std::addressof(thread_tree), addr, key, value); +        thread_tree.insert(*cur_thread); -        if (cur_thread->IsWaitingForConditionVariable()) { -            thread_tree.erase(thread_tree.iterator_to(*cur_thread)); -            cur_thread->ClearConditionVariable(); -        } +        // Begin waiting. +        cur_thread->BeginWait(std::addressof(wait_queue)); +        cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::ConditionVar); +        cur_thread->SetMutexWaitAddressForDebugging(addr);      } -    // Get the result. -    KSynchronizationObject* dummy{}; -    return cur_thread->GetWaitResult(std::addressof(dummy)); +    // Get the wait result. +    return cur_thread->GetWaitResult();  }  } // namespace Kernel diff --git a/src/core/hle/kernel/k_condition_variable.h b/src/core/hle/kernel/k_condition_variable.h index 861dbd420..5e4815d08 100644 --- a/src/core/hle/kernel/k_condition_variable.h +++ b/src/core/hle/kernel/k_condition_variable.h @@ -34,7 +34,7 @@ public:      [[nodiscard]] ResultCode Wait(VAddr addr, u64 key, u32 value, s64 timeout);  private: -    [[nodiscard]] KThread* SignalImpl(KThread* thread); +    void SignalImpl(KThread* thread);      ThreadTree thread_tree; diff --git a/src/core/hle/kernel/k_handle_table.cpp b/src/core/hle/kernel/k_handle_table.cpp index e90fc0628..cf95f0852 100644 --- a/src/core/hle/kernel/k_handle_table.cpp +++ b/src/core/hle/kernel/k_handle_table.cpp @@ -13,6 +13,7 @@ ResultCode KHandleTable::Finalize() {      // Get the table and clear our record of it.      u16 saved_table_size = 0;      { +        KScopedDisableDispatch dd(kernel);          KScopedSpinLock lk(m_lock);          std::swap(m_table_size, saved_table_size); @@ -43,6 +44,7 @@ bool KHandleTable::Remove(Handle handle) {      // Find the object and free the entry.      KAutoObject* obj = nullptr;      { +        KScopedDisableDispatch dd(kernel);          KScopedSpinLock lk(m_lock);          if (this->IsValidHandle(handle)) { @@ -62,6 +64,7 @@ bool KHandleTable::Remove(Handle handle) {  }  ResultCode KHandleTable::Add(Handle* out_handle, KAutoObject* obj, u16 type) { +    KScopedDisableDispatch dd(kernel);      KScopedSpinLock lk(m_lock);      // Never exceed our capacity. @@ -84,6 +87,7 @@ ResultCode KHandleTable::Add(Handle* out_handle, KAutoObject* obj, u16 type) {  }  ResultCode KHandleTable::Reserve(Handle* out_handle) { +    KScopedDisableDispatch dd(kernel);      KScopedSpinLock lk(m_lock);      // Never exceed our capacity. @@ -94,6 +98,7 @@ ResultCode KHandleTable::Reserve(Handle* out_handle) {  }  void KHandleTable::Unreserve(Handle handle) { +    KScopedDisableDispatch dd(kernel);      KScopedSpinLock lk(m_lock);      // Unpack the handle. @@ -112,6 +117,7 @@ void KHandleTable::Unreserve(Handle handle) {  }  void KHandleTable::Register(Handle handle, KAutoObject* obj, u16 type) { +    KScopedDisableDispatch dd(kernel);      KScopedSpinLock lk(m_lock);      // Unpack the handle. diff --git a/src/core/hle/kernel/k_handle_table.h b/src/core/hle/kernel/k_handle_table.h index 95ec905ae..4b114ec2f 100644 --- a/src/core/hle/kernel/k_handle_table.h +++ b/src/core/hle/kernel/k_handle_table.h @@ -68,6 +68,7 @@ public:      template <typename T = KAutoObject>      KScopedAutoObject<T> GetObjectWithoutPseudoHandle(Handle handle) const {          // Lock and look up in table. +        KScopedDisableDispatch dd(kernel);          KScopedSpinLock lk(m_lock);          if constexpr (std::is_same_v<T, KAutoObject>) { @@ -122,6 +123,7 @@ public:          size_t num_opened;          {              // Lock the table. +            KScopedDisableDispatch dd(kernel);              KScopedSpinLock lk(m_lock);              for (num_opened = 0; num_opened < num_handles; num_opened++) {                  // Get the current handle. diff --git a/src/core/hle/kernel/k_light_condition_variable.cpp b/src/core/hle/kernel/k_light_condition_variable.cpp new file mode 100644 index 000000000..a8001fffc --- /dev/null +++ b/src/core/hle/kernel/k_light_condition_variable.cpp @@ -0,0 +1,80 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/kernel/k_light_condition_variable.h" +#include "core/hle/kernel/k_scheduler.h" +#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" +#include "core/hle/kernel/k_thread_queue.h" +#include "core/hle/kernel/svc_results.h" + +namespace Kernel { + +namespace { + +class ThreadQueueImplForKLightConditionVariable final : public KThreadQueue { +public: +    ThreadQueueImplForKLightConditionVariable(KernelCore& kernel_, KThread::WaiterList* wl, +                                              bool term) +        : KThreadQueue(kernel_), m_wait_list(wl), m_allow_terminating_thread(term) {} + +    void CancelWait(KThread* waiting_thread, ResultCode wait_result, +                    bool cancel_timer_task) override { +        // Only process waits if we're allowed to. +        if (ResultTerminationRequested == wait_result && m_allow_terminating_thread) { +            return; +        } + +        // Remove the thread from the waiting thread from the light condition variable. +        m_wait_list->erase(m_wait_list->iterator_to(*waiting_thread)); + +        // Invoke the base cancel wait handler. +        KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task); +    } + +private: +    KThread::WaiterList* m_wait_list; +    bool m_allow_terminating_thread; +}; + +} // namespace + +void KLightConditionVariable::Wait(KLightLock* lock, s64 timeout, bool allow_terminating_thread) { +    // Create thread queue. +    KThread* owner = GetCurrentThreadPointer(kernel); + +    ThreadQueueImplForKLightConditionVariable wait_queue(kernel, std::addressof(wait_list), +                                                         allow_terminating_thread); + +    // Sleep the thread. +    { +        KScopedSchedulerLockAndSleep lk(kernel, owner, timeout); + +        if (!allow_terminating_thread && owner->IsTerminationRequested()) { +            lk.CancelSleep(); +            return; +        } + +        lock->Unlock(); + +        // Add the thread to the queue. +        wait_list.push_back(*owner); + +        // Begin waiting. +        owner->BeginWait(std::addressof(wait_queue)); +    } + +    // Re-acquire the lock. +    lock->Lock(); +} + +void KLightConditionVariable::Broadcast() { +    KScopedSchedulerLock lk(kernel); + +    // Signal all threads. +    for (auto it = wait_list.begin(); it != wait_list.end(); it = wait_list.erase(it)) { +        it->EndWait(ResultSuccess); +    } +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_light_condition_variable.h b/src/core/hle/kernel/k_light_condition_variable.h index fb0ad783a..5d6d7f128 100644 --- a/src/core/hle/kernel/k_light_condition_variable.h +++ b/src/core/hle/kernel/k_light_condition_variable.h @@ -2,72 +2,24 @@  // Licensed under GPLv2 or any later version  // Refer to the license.txt file included. -// This file references various implementation details from Atmosphere, an open-source firmware for -// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX. -  #pragma once  #include "common/common_types.h" -#include "core/hle/kernel/k_scheduler.h" -#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" -#include "core/hle/kernel/time_manager.h" +#include "core/hle/kernel/k_thread.h"  namespace Kernel { +  class KernelCore; +class KLightLock;  class KLightConditionVariable {  public:      explicit KLightConditionVariable(KernelCore& kernel_) : kernel{kernel_} {} -    void Wait(KLightLock* lock, s64 timeout = -1, bool allow_terminating_thread = true) { -        WaitImpl(lock, timeout, allow_terminating_thread); -    } - -    void Broadcast() { -        KScopedSchedulerLock lk{kernel}; - -        // Signal all threads. -        for (auto& thread : wait_list) { -            thread.SetState(ThreadState::Runnable); -        } -    } +    void Wait(KLightLock* lock, s64 timeout = -1, bool allow_terminating_thread = true); +    void Broadcast();  private: -    void WaitImpl(KLightLock* lock, s64 timeout, bool allow_terminating_thread) { -        KThread* owner = GetCurrentThreadPointer(kernel); - -        // Sleep the thread. -        { -            KScopedSchedulerLockAndSleep lk{kernel, owner, timeout}; - -            if (!allow_terminating_thread && owner->IsTerminationRequested()) { -                lk.CancelSleep(); -                return; -            } - -            lock->Unlock(); - -            // Set the thread as waiting. -            GetCurrentThread(kernel).SetState(ThreadState::Waiting); - -            // Add the thread to the queue. -            wait_list.push_back(GetCurrentThread(kernel)); -        } - -        // Remove the thread from the wait list. -        { -            KScopedSchedulerLock sl{kernel}; - -            wait_list.erase(wait_list.iterator_to(GetCurrentThread(kernel))); -        } - -        // Cancel the task that the sleep setup. -        kernel.TimeManager().UnscheduleTimeEvent(owner); - -        // Re-acquire the lock. -        lock->Lock(); -    } -      KernelCore& kernel;      KThread::WaiterList wait_list{};  }; diff --git a/src/core/hle/kernel/k_light_lock.cpp b/src/core/hle/kernel/k_light_lock.cpp index 0896e705f..4620342eb 100644 --- a/src/core/hle/kernel/k_light_lock.cpp +++ b/src/core/hle/kernel/k_light_lock.cpp @@ -5,44 +5,59 @@  #include "core/hle/kernel/k_light_lock.h"  #include "core/hle/kernel/k_scheduler.h"  #include "core/hle/kernel/k_thread.h" +#include "core/hle/kernel/k_thread_queue.h"  #include "core/hle/kernel/kernel.h"  namespace Kernel { +namespace { + +class ThreadQueueImplForKLightLock final : public KThreadQueue { +public: +    explicit ThreadQueueImplForKLightLock(KernelCore& kernel_) : KThreadQueue(kernel_) {} + +    void CancelWait(KThread* waiting_thread, ResultCode wait_result, +                    bool cancel_timer_task) override { +        // Remove the thread as a waiter from its owner. +        if (KThread* owner = waiting_thread->GetLockOwner(); owner != nullptr) { +            owner->RemoveWaiter(waiting_thread); +        } + +        // Invoke the base cancel wait handler. +        KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task); +    } +}; + +} // namespace +  void KLightLock::Lock() {      const uintptr_t cur_thread = reinterpret_cast<uintptr_t>(GetCurrentThreadPointer(kernel)); -    const uintptr_t cur_thread_tag = (cur_thread | 1);      while (true) {          uintptr_t old_tag = tag.load(std::memory_order_relaxed); -        while (!tag.compare_exchange_weak(old_tag, (old_tag == 0) ? cur_thread : old_tag | 1, +        while (!tag.compare_exchange_weak(old_tag, (old_tag == 0) ? cur_thread : (old_tag | 1),                                            std::memory_order_acquire)) { -            if ((old_tag | 1) == cur_thread_tag) { -                return; -            }          } -        if ((old_tag == 0) || ((old_tag | 1) == cur_thread_tag)) { +        if (old_tag == 0 || this->LockSlowPath(old_tag | 1, cur_thread)) {              break;          } - -        LockSlowPath(old_tag | 1, cur_thread);      }  }  void KLightLock::Unlock() {      const uintptr_t cur_thread = reinterpret_cast<uintptr_t>(GetCurrentThreadPointer(kernel)); +      uintptr_t expected = cur_thread; -    do { -        if (expected != cur_thread) { -            return UnlockSlowPath(cur_thread); -        } -    } while (!tag.compare_exchange_weak(expected, 0, std::memory_order_release)); +    if (!tag.compare_exchange_strong(expected, 0, std::memory_order_release)) { +        this->UnlockSlowPath(cur_thread); +    }  } -void KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) { +bool KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) {      KThread* cur_thread = reinterpret_cast<KThread*>(_cur_thread); +    ThreadQueueImplForKLightLock wait_queue(kernel);      // Pend the current thread waiting on the owner thread.      { @@ -50,7 +65,7 @@ void KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) {          // Ensure we actually have locking to do.          if (tag.load(std::memory_order_relaxed) != _owner) { -            return; +            return false;          }          // Add the current thread as a waiter on the owner. @@ -58,22 +73,15 @@ void KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) {          cur_thread->SetAddressKey(reinterpret_cast<uintptr_t>(std::addressof(tag)));          owner_thread->AddWaiter(cur_thread); -        // Set thread states. -        cur_thread->SetState(ThreadState::Waiting); +        // Begin waiting to hold the lock. +        cur_thread->BeginWait(std::addressof(wait_queue));          if (owner_thread->IsSuspended()) {              owner_thread->ContinueIfHasKernelWaiters();          }      } -    // We're no longer waiting on the lock owner. -    { -        KScopedSchedulerLock sl{kernel}; - -        if (KThread* owner_thread = cur_thread->GetLockOwner(); owner_thread != nullptr) { -            owner_thread->RemoveWaiter(cur_thread); -        } -    } +    return true;  }  void KLightLock::UnlockSlowPath(uintptr_t _cur_thread) { @@ -81,22 +89,20 @@ void KLightLock::UnlockSlowPath(uintptr_t _cur_thread) {      // Unlock.      { -        KScopedSchedulerLock sl{kernel}; +        KScopedSchedulerLock sl(kernel);          // Get the next owner. -        s32 num_waiters = 0; +        s32 num_waiters;          KThread* next_owner = owner_thread->RemoveWaiterByKey(              std::addressof(num_waiters), reinterpret_cast<uintptr_t>(std::addressof(tag)));          // Pass the lock to the next owner.          uintptr_t next_tag = 0;          if (next_owner != nullptr) { -            next_tag = reinterpret_cast<uintptr_t>(next_owner); -            if (num_waiters > 1) { -                next_tag |= 0x1; -            } +            next_tag = +                reinterpret_cast<uintptr_t>(next_owner) | static_cast<uintptr_t>(num_waiters > 1); -            next_owner->SetState(ThreadState::Runnable); +            next_owner->EndWait(ResultSuccess);              if (next_owner->IsSuspended()) {                  next_owner->ContinueIfHasKernelWaiters(); @@ -110,7 +116,7 @@ void KLightLock::UnlockSlowPath(uintptr_t _cur_thread) {          }          // Write the new tag value. -        tag.store(next_tag); +        tag.store(next_tag, std::memory_order_release);      }  } diff --git a/src/core/hle/kernel/k_light_lock.h b/src/core/hle/kernel/k_light_lock.h index ad853661d..4163b8a85 100644 --- a/src/core/hle/kernel/k_light_lock.h +++ b/src/core/hle/kernel/k_light_lock.h @@ -20,7 +20,7 @@ public:      void Unlock(); -    void LockSlowPath(uintptr_t owner, uintptr_t cur_thread); +    bool LockSlowPath(uintptr_t owner, uintptr_t cur_thread);      void UnlockSlowPath(uintptr_t cur_thread); diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp index 1aad061e1..90dda40dc 100644 --- a/src/core/hle/kernel/k_process.cpp +++ b/src/core/hle/kernel/k_process.cpp @@ -60,6 +60,7 @@ void SetupMainThread(Core::System& system, KProcess& owner_process, u32 priority      thread->GetContext64().cpu_registers[0] = 0;      thread->GetContext32().cpu_registers[1] = thread_handle;      thread->GetContext64().cpu_registers[1] = thread_handle; +    thread->DisableDispatch();      auto& kernel = system.Kernel();      // Threads by default are dormant, wake up the main thread so it runs when the scheduler fires @@ -227,12 +228,15 @@ void KProcess::PinCurrentThread() {      const s32 core_id = GetCurrentCoreId(kernel);      KThread* cur_thread = GetCurrentThreadPointer(kernel); -    // Pin it. -    PinThread(core_id, cur_thread); -    cur_thread->Pin(); +    // If the thread isn't terminated, pin it. +    if (!cur_thread->IsTerminationRequested()) { +        // Pin it. +        PinThread(core_id, cur_thread); +        cur_thread->Pin(); -    // An update is needed. -    KScheduler::SetSchedulerUpdateNeeded(kernel); +        // An update is needed. +        KScheduler::SetSchedulerUpdateNeeded(kernel); +    }  }  void KProcess::UnpinCurrentThread() { @@ -250,6 +254,20 @@ void KProcess::UnpinCurrentThread() {      KScheduler::SetSchedulerUpdateNeeded(kernel);  } +void KProcess::UnpinThread(KThread* thread) { +    ASSERT(kernel.GlobalSchedulerContext().IsLocked()); + +    // Get the thread's core id. +    const auto core_id = thread->GetActiveCore(); + +    // Unpin it. +    UnpinThread(core_id, thread); +    thread->Unpin(); + +    // An update is needed. +    KScheduler::SetSchedulerUpdateNeeded(kernel); +} +  ResultCode KProcess::AddSharedMemory(KSharedMemory* shmem, [[maybe_unused]] VAddr address,                                       [[maybe_unused]] size_t size) {      // Lock ourselves, to prevent concurrent access. diff --git a/src/core/hle/kernel/k_process.h b/src/core/hle/kernel/k_process.h index 8a8c1fcbb..cb93c7e24 100644 --- a/src/core/hle/kernel/k_process.h +++ b/src/core/hle/kernel/k_process.h @@ -347,6 +347,7 @@ public:      void PinCurrentThread();      void UnpinCurrentThread(); +    void UnpinThread(KThread* thread);      KLightLock& GetStateLock() {          return state_lock; diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index 6a7d80d03..277201de4 100644 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp @@ -240,8 +240,8 @@ void KScheduler::OnThreadPriorityChanged(KernelCore& kernel, KThread* thread, s3      // If the thread is runnable, we want to change its priority in the queue.      if (thread->GetRawState() == ThreadState::Runnable) { -        GetPriorityQueue(kernel).ChangePriority( -            old_priority, thread == kernel.CurrentScheduler()->GetCurrentThread(), thread); +        GetPriorityQueue(kernel).ChangePriority(old_priority, +                                                thread == kernel.GetCurrentEmuThread(), thread);          IncrementScheduledCount(thread);          SetSchedulerUpdateNeeded(kernel);      } @@ -360,7 +360,7 @@ void KScheduler::RotateScheduledQueue(s32 cpu_core_id, s32 priority) {  }  bool KScheduler::CanSchedule(KernelCore& kernel) { -    return kernel.CurrentScheduler()->GetCurrentThread()->GetDisableDispatchCount() <= 1; +    return kernel.GetCurrentEmuThread()->GetDisableDispatchCount() <= 1;  }  bool KScheduler::IsSchedulerUpdateNeeded(const KernelCore& kernel) { @@ -376,20 +376,30 @@ void KScheduler::ClearSchedulerUpdateNeeded(KernelCore& kernel) {  }  void KScheduler::DisableScheduling(KernelCore& kernel) { -    if (auto* scheduler = kernel.CurrentScheduler(); scheduler) { -        ASSERT(scheduler->GetCurrentThread()->GetDisableDispatchCount() >= 0); -        scheduler->GetCurrentThread()->DisableDispatch(); +    // If we are shutting down the kernel, none of this is relevant anymore. +    if (kernel.IsShuttingDown()) { +        return;      } + +    ASSERT(GetCurrentThreadPointer(kernel)->GetDisableDispatchCount() >= 0); +    GetCurrentThreadPointer(kernel)->DisableDispatch();  }  void KScheduler::EnableScheduling(KernelCore& kernel, u64 cores_needing_scheduling) { -    if (auto* scheduler = kernel.CurrentScheduler(); scheduler) { -        ASSERT(scheduler->GetCurrentThread()->GetDisableDispatchCount() >= 1); -        if (scheduler->GetCurrentThread()->GetDisableDispatchCount() >= 1) { -            scheduler->GetCurrentThread()->EnableDispatch(); -        } +    // If we are shutting down the kernel, none of this is relevant anymore. +    if (kernel.IsShuttingDown()) { +        return; +    } + +    auto* current_thread = GetCurrentThreadPointer(kernel); + +    ASSERT(current_thread->GetDisableDispatchCount() >= 1); + +    if (current_thread->GetDisableDispatchCount() > 1) { +        current_thread->EnableDispatch(); +    } else { +        RescheduleCores(kernel, cores_needing_scheduling);      } -    RescheduleCores(kernel, cores_needing_scheduling);  }  u64 KScheduler::UpdateHighestPriorityThreads(KernelCore& kernel) { @@ -617,13 +627,17 @@ KScheduler::KScheduler(Core::System& system_, s32 core_id_) : system{system_}, c      state.highest_priority_thread = nullptr;  } -KScheduler::~KScheduler() { +void KScheduler::Finalize() {      if (idle_thread) {          idle_thread->Close();          idle_thread = nullptr;      }  } +KScheduler::~KScheduler() { +    ASSERT(!idle_thread); +} +  KThread* KScheduler::GetCurrentThread() const {      if (auto result = current_thread.load(); result) {          return result; @@ -642,10 +656,12 @@ void KScheduler::RescheduleCurrentCore() {      if (phys_core.IsInterrupted()) {          phys_core.ClearInterrupt();      } +      guard.Lock();      if (state.needs_scheduling.load()) {          Schedule();      } else { +        GetCurrentThread()->EnableDispatch();          guard.Unlock();      }  } @@ -655,26 +671,33 @@ void KScheduler::OnThreadStart() {  }  void KScheduler::Unload(KThread* thread) { +    ASSERT(thread); +      LOG_TRACE(Kernel, "core {}, unload thread {}", core_id, thread ? thread->GetName() : "nullptr"); -    if (thread) { -        if (thread->IsCallingSvc()) { -            thread->ClearIsCallingSvc(); -        } -        if (!thread->IsTerminationRequested()) { -            prev_thread = thread; - -            Core::ARM_Interface& cpu_core = system.ArmInterface(core_id); -            cpu_core.SaveContext(thread->GetContext32()); -            cpu_core.SaveContext(thread->GetContext64()); -            // Save the TPIDR_EL0 system register in case it was modified. -            thread->SetTPIDR_EL0(cpu_core.GetTPIDR_EL0()); -            cpu_core.ClearExclusiveState(); -        } else { -            prev_thread = nullptr; -        } -        thread->context_guard.Unlock(); +    if (thread->IsCallingSvc()) { +        thread->ClearIsCallingSvc(); +    } + +    auto& physical_core = system.Kernel().PhysicalCore(core_id); +    if (!physical_core.IsInitialized()) { +        return; +    } + +    Core::ARM_Interface& cpu_core = physical_core.ArmInterface(); +    cpu_core.SaveContext(thread->GetContext32()); +    cpu_core.SaveContext(thread->GetContext64()); +    // Save the TPIDR_EL0 system register in case it was modified. +    thread->SetTPIDR_EL0(cpu_core.GetTPIDR_EL0()); +    cpu_core.ClearExclusiveState(); + +    if (!thread->IsTerminationRequested() && thread->GetActiveCore() == core_id) { +        prev_thread = thread; +    } else { +        prev_thread = nullptr;      } + +    thread->context_guard.Unlock();  }  void KScheduler::Reload(KThread* thread) { @@ -683,11 +706,6 @@ void KScheduler::Reload(KThread* thread) {      if (thread) {          ASSERT_MSG(thread->GetState() == ThreadState::Runnable, "Thread must be runnable."); -        auto* const thread_owner_process = thread->GetOwnerProcess(); -        if (thread_owner_process != nullptr) { -            system.Kernel().MakeCurrentProcess(thread_owner_process); -        } -          Core::ARM_Interface& cpu_core = system.ArmInterface(core_id);          cpu_core.LoadContext(thread->GetContext32());          cpu_core.LoadContext(thread->GetContext64()); @@ -705,7 +723,7 @@ void KScheduler::SwitchContextStep2() {  }  void KScheduler::ScheduleImpl() { -    KThread* previous_thread = current_thread.load(); +    KThread* previous_thread = GetCurrentThread();      KThread* next_thread = state.highest_priority_thread;      state.needs_scheduling = false; @@ -717,10 +735,15 @@ void KScheduler::ScheduleImpl() {      // If we're not actually switching thread, there's nothing to do.      if (next_thread == current_thread.load()) { +        previous_thread->EnableDispatch();          guard.Unlock();          return;      } +    if (next_thread->GetCurrentCore() != core_id) { +        next_thread->SetCurrentCore(core_id); +    } +      current_thread.store(next_thread);      KProcess* const previous_process = system.Kernel().CurrentProcess(); @@ -731,11 +754,7 @@ void KScheduler::ScheduleImpl() {      Unload(previous_thread);      std::shared_ptr<Common::Fiber>* old_context; -    if (previous_thread != nullptr) { -        old_context = &previous_thread->GetHostContext(); -    } else { -        old_context = &idle_thread->GetHostContext(); -    } +    old_context = &previous_thread->GetHostContext();      guard.Unlock();      Common::Fiber::YieldTo(*old_context, *switch_fiber); diff --git a/src/core/hle/kernel/k_scheduler.h b/src/core/hle/kernel/k_scheduler.h index 7df288438..82fcd99e7 100644 --- a/src/core/hle/kernel/k_scheduler.h +++ b/src/core/hle/kernel/k_scheduler.h @@ -33,6 +33,8 @@ public:      explicit KScheduler(Core::System& system_, s32 core_id_);      ~KScheduler(); +    void Finalize(); +      /// Reschedules to the next available thread (call after current thread is suspended)      void RescheduleCurrentCore(); diff --git a/src/core/hle/kernel/k_scheduler_lock.h b/src/core/hle/kernel/k_scheduler_lock.h index c571f2992..93c47f1b1 100644 --- a/src/core/hle/kernel/k_scheduler_lock.h +++ b/src/core/hle/kernel/k_scheduler_lock.h @@ -23,6 +23,11 @@ public:      }      void Lock() { +        // If we are shutting down the kernel, none of this is relevant anymore. +        if (kernel.IsShuttingDown()) { +            return; +        } +          if (IsLockedByCurrentThread()) {              // If we already own the lock, we can just increment the count.              ASSERT(lock_count > 0); @@ -43,6 +48,11 @@ public:      }      void Unlock() { +        // If we are shutting down the kernel, none of this is relevant anymore. +        if (kernel.IsShuttingDown()) { +            return; +        } +          ASSERT(IsLockedByCurrentThread());          ASSERT(lock_count > 0); 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 61dc2858f..2995c492d 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 @@ -8,6 +8,7 @@  #pragma once  #include "common/common_types.h" +#include "core/hle/kernel/global_scheduler_context.h"  #include "core/hle/kernel/k_thread.h"  #include "core/hle/kernel/kernel.h"  #include "core/hle/kernel/time_manager.h" diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp index 2bd53ccbd..d4e4a6b06 100644 --- a/src/core/hle/kernel/k_server_session.cpp +++ b/src/core/hle/kernel/k_server_session.cpp @@ -175,8 +175,7 @@ ResultCode KServerSession::CompleteSyncRequest(HLERequestContext& context) {      {          KScopedSchedulerLock lock(kernel);          if (!context.IsThreadWaiting()) { -            context.GetThread().Wakeup(); -            context.GetThread().SetSyncedObject(nullptr, result); +            context.GetThread().EndWait(result);          }      } diff --git a/src/core/hle/kernel/k_synchronization_object.cpp b/src/core/hle/kernel/k_synchronization_object.cpp index f168b4f21..e4c5eb74f 100644 --- a/src/core/hle/kernel/k_synchronization_object.cpp +++ b/src/core/hle/kernel/k_synchronization_object.cpp @@ -8,11 +8,66 @@  #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"  #include "core/hle/kernel/k_synchronization_object.h"  #include "core/hle/kernel/k_thread.h" +#include "core/hle/kernel/k_thread_queue.h"  #include "core/hle/kernel/kernel.h"  #include "core/hle/kernel/svc_results.h"  namespace Kernel { +namespace { + +class ThreadQueueImplForKSynchronizationObjectWait final : public KThreadQueueWithoutEndWait { +public: +    ThreadQueueImplForKSynchronizationObjectWait(KernelCore& kernel_, KSynchronizationObject** o, +                                                 KSynchronizationObject::ThreadListNode* n, s32 c) +        : KThreadQueueWithoutEndWait(kernel_), m_objects(o), m_nodes(n), m_count(c) {} + +    void NotifyAvailable(KThread* waiting_thread, KSynchronizationObject* signaled_object, +                         ResultCode wait_result) override { +        // Determine the sync index, and unlink all nodes. +        s32 sync_index = -1; +        for (auto i = 0; i < m_count; ++i) { +            // Check if this is the signaled object. +            if (m_objects[i] == signaled_object && sync_index == -1) { +                sync_index = i; +            } + +            // Unlink the current node from the current object. +            m_objects[i]->UnlinkNode(std::addressof(m_nodes[i])); +        } + +        // Set the waiting thread's sync index. +        waiting_thread->SetSyncedIndex(sync_index); + +        // Set the waiting thread as not cancellable. +        waiting_thread->ClearCancellable(); + +        // Invoke the base end wait handler. +        KThreadQueue::EndWait(waiting_thread, wait_result); +    } + +    void CancelWait(KThread* waiting_thread, ResultCode wait_result, +                    bool cancel_timer_task) override { +        // Remove all nodes from our list. +        for (auto i = 0; i < m_count; ++i) { +            m_objects[i]->UnlinkNode(std::addressof(m_nodes[i])); +        } + +        // Set the waiting thread as not cancellable. +        waiting_thread->ClearCancellable(); + +        // Invoke the base cancel wait handler. +        KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task); +    } + +private: +    KSynchronizationObject** m_objects; +    KSynchronizationObject::ThreadListNode* m_nodes; +    s32 m_count; +}; + +} // namespace +  void KSynchronizationObject::Finalize() {      this->OnFinalizeSynchronizationObject();      KAutoObject::Finalize(); @@ -25,11 +80,19 @@ ResultCode KSynchronizationObject::Wait(KernelCore& kernel_ctx, s32* out_index,      std::vector<ThreadListNode> thread_nodes(num_objects);      // Prepare for wait. -    KThread* thread = kernel_ctx.CurrentScheduler()->GetCurrentThread(); +    KThread* thread = GetCurrentThreadPointer(kernel_ctx); +    ThreadQueueImplForKSynchronizationObjectWait wait_queue(kernel_ctx, objects, +                                                            thread_nodes.data(), num_objects);      {          // Setup the scheduling lock and sleep. -        KScopedSchedulerLockAndSleep slp{kernel_ctx, thread, timeout}; +        KScopedSchedulerLockAndSleep slp(kernel_ctx, thread, timeout); + +        // Check if the thread should terminate. +        if (thread->IsTerminationRequested()) { +            slp.CancelSleep(); +            return ResultTerminationRequested; +        }          // Check if any of the objects are already signaled.          for (auto i = 0; i < num_objects; ++i) { @@ -48,12 +111,6 @@ ResultCode KSynchronizationObject::Wait(KernelCore& kernel_ctx, s32* out_index,              return ResultTimedOut;          } -        // Check if the thread should terminate. -        if (thread->IsTerminationRequested()) { -            slp.CancelSleep(); -            return ResultTerminationRequested; -        } -          // Check if waiting was canceled.          if (thread->IsWaitCancelled()) {              slp.CancelSleep(); @@ -66,73 +123,25 @@ ResultCode KSynchronizationObject::Wait(KernelCore& kernel_ctx, s32* out_index,              thread_nodes[i].thread = thread;              thread_nodes[i].next = nullptr; -            if (objects[i]->thread_list_tail == nullptr) { -                objects[i]->thread_list_head = std::addressof(thread_nodes[i]); -            } else { -                objects[i]->thread_list_tail->next = std::addressof(thread_nodes[i]); -            } - -            objects[i]->thread_list_tail = std::addressof(thread_nodes[i]); +            objects[i]->LinkNode(std::addressof(thread_nodes[i]));          } -        // For debugging only -        thread->SetWaitObjectsForDebugging({objects, static_cast<std::size_t>(num_objects)}); - -        // Mark the thread as waiting. +        // Mark the thread as cancellable.          thread->SetCancellable(); -        thread->SetSyncedObject(nullptr, ResultTimedOut); -        thread->SetState(ThreadState::Waiting); -        thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Synchronization); -    } -    // The lock/sleep is done, so we should be able to get our result. +        // Clear the thread's synced index. +        thread->SetSyncedIndex(-1); -    // Thread is no longer cancellable. -    thread->ClearCancellable(); - -    // For debugging only -    thread->SetWaitObjectsForDebugging({}); +        // Wait for an object to be signaled. +        thread->BeginWait(std::addressof(wait_queue)); +        thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Synchronization); +    } -    // Cancel the timer as needed. -    kernel_ctx.TimeManager().UnscheduleTimeEvent(thread); +    // Set the output index. +    *out_index = thread->GetSyncedIndex();      // Get the wait result. -    ResultCode wait_result{ResultSuccess}; -    s32 sync_index = -1; -    { -        KScopedSchedulerLock lock(kernel_ctx); -        KSynchronizationObject* synced_obj; -        wait_result = thread->GetWaitResult(std::addressof(synced_obj)); - -        for (auto i = 0; i < num_objects; ++i) { -            // Unlink the object from the list. -            ThreadListNode* prev_ptr = -                reinterpret_cast<ThreadListNode*>(std::addressof(objects[i]->thread_list_head)); -            ThreadListNode* prev_val = nullptr; -            ThreadListNode *prev, *tail_prev; - -            do { -                prev = prev_ptr; -                prev_ptr = prev_ptr->next; -                tail_prev = prev_val; -                prev_val = prev_ptr; -            } while (prev_ptr != std::addressof(thread_nodes[i])); - -            if (objects[i]->thread_list_tail == std::addressof(thread_nodes[i])) { -                objects[i]->thread_list_tail = tail_prev; -            } - -            prev->next = thread_nodes[i].next; - -            if (objects[i] == synced_obj) { -                sync_index = i; -            } -        } -    } - -    // Set output. -    *out_index = sync_index; -    return wait_result; +    return thread->GetWaitResult();  }  KSynchronizationObject::KSynchronizationObject(KernelCore& kernel_) @@ -141,7 +150,7 @@ KSynchronizationObject::KSynchronizationObject(KernelCore& kernel_)  KSynchronizationObject::~KSynchronizationObject() = default;  void KSynchronizationObject::NotifyAvailable(ResultCode result) { -    KScopedSchedulerLock lock(kernel); +    KScopedSchedulerLock sl(kernel);      // If we're not signaled, we've nothing to notify.      if (!this->IsSignaled()) { @@ -150,11 +159,7 @@ void KSynchronizationObject::NotifyAvailable(ResultCode result) {      // Iterate over each thread.      for (auto* cur_node = thread_list_head; cur_node != nullptr; cur_node = cur_node->next) { -        KThread* thread = cur_node->thread; -        if (thread->GetState() == ThreadState::Waiting) { -            thread->SetSyncedObject(this, result); -            thread->SetState(ThreadState::Runnable); -        } +        cur_node->thread->NotifyAvailable(this, result);      }  } diff --git a/src/core/hle/kernel/k_synchronization_object.h b/src/core/hle/kernel/k_synchronization_object.h index 898e58e16..ec235437b 100644 --- a/src/core/hle/kernel/k_synchronization_object.h +++ b/src/core/hle/kernel/k_synchronization_object.h @@ -35,6 +35,38 @@ public:      [[nodiscard]] std::vector<KThread*> GetWaitingThreadsForDebugging() const; +    void LinkNode(ThreadListNode* node_) { +        // Link the node to the list. +        if (thread_list_tail == nullptr) { +            thread_list_head = node_; +        } else { +            thread_list_tail->next = node_; +        } + +        thread_list_tail = node_; +    } + +    void UnlinkNode(ThreadListNode* node_) { +        // Unlink the node from the list. +        ThreadListNode* prev_ptr = +            reinterpret_cast<ThreadListNode*>(std::addressof(thread_list_head)); +        ThreadListNode* prev_val = nullptr; +        ThreadListNode *prev, *tail_prev; + +        do { +            prev = prev_ptr; +            prev_ptr = prev_ptr->next; +            tail_prev = prev_val; +            prev_val = prev_ptr; +        } while (prev_ptr != node_); + +        if (thread_list_tail == node_) { +            thread_list_tail = tail_prev; +        } + +        prev->next = node_->next; +    } +  protected:      explicit KSynchronizationObject(KernelCore& kernel);      ~KSynchronizationObject() override; diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index db65ce79a..752592e2e 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp @@ -13,6 +13,9 @@  #include "common/common_types.h"  #include "common/fiber.h"  #include "common/logging/log.h" +#include "common/scope_exit.h" +#include "common/settings.h" +#include "common/thread_queue_list.h"  #include "core/core.h"  #include "core/cpu_manager.h"  #include "core/hardware_properties.h" @@ -56,6 +59,34 @@ static void ResetThreadContext64(Core::ARM_Interface::ThreadContext64& context,  namespace Kernel { +namespace { + +class ThreadQueueImplForKThreadSleep final : public KThreadQueueWithoutEndWait { +public: +    explicit ThreadQueueImplForKThreadSleep(KernelCore& kernel_) +        : KThreadQueueWithoutEndWait(kernel_) {} +}; + +class ThreadQueueImplForKThreadSetProperty final : public KThreadQueue { +public: +    explicit ThreadQueueImplForKThreadSetProperty(KernelCore& kernel_, KThread::WaiterList* wl) +        : KThreadQueue(kernel_), m_wait_list(wl) {} + +    void CancelWait(KThread* waiting_thread, ResultCode wait_result, +                    bool cancel_timer_task) override { +        // Remove the thread from the wait list. +        m_wait_list->erase(m_wait_list->iterator_to(*waiting_thread)); + +        // Invoke the base cancel wait handler. +        KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task); +    } + +private: +    KThread::WaiterList* m_wait_list; +}; + +} // namespace +  KThread::KThread(KernelCore& kernel_)      : KAutoObjectWithSlabHeapAndContainer{kernel_}, activity_pause_lock{kernel_} {}  KThread::~KThread() = default; @@ -82,6 +113,8 @@ ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_s          [[fallthrough]];      case ThreadType::HighPriority:          [[fallthrough]]; +    case ThreadType::Dummy: +        [[fallthrough]];      case ThreadType::User:          ASSERT(((owner == nullptr) ||                  (owner->GetCoreMask() | (1ULL << virt_core)) == owner->GetCoreMask())); @@ -127,11 +160,8 @@ ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_s      priority = prio;      base_priority = prio; -    // Set sync object and waiting lock to null. -    synced_object = nullptr; -      // Initialize sleeping queue. -    sleeping_queue = nullptr; +    wait_queue = nullptr;      // Set suspend flags.      suspend_request_flags = 0; @@ -184,7 +214,7 @@ ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_s      // Setup the stack parameters.      StackParameters& sp = GetStackParameters();      sp.cur_thread = this; -    sp.disable_count = 1; +    sp.disable_count = 0;      SetInExceptionHandler();      // Set thread ID. @@ -211,15 +241,16 @@ ResultCode KThread::InitializeThread(KThread* thread, KThreadFunction func, uint      // Initialize the thread.      R_TRY(thread->Initialize(func, arg, user_stack_top, prio, core, owner, type)); -    // Initialize host context. +    // Initialize emulation parameters.      thread->host_context =          std::make_shared<Common::Fiber>(std::move(init_func), init_func_parameter); +    thread->is_single_core = !Settings::values.use_multi_core.GetValue();      return ResultSuccess;  }  ResultCode KThread::InitializeDummyThread(KThread* thread) { -    return thread->Initialize({}, {}, {}, DefaultThreadPriority, 3, {}, ThreadType::Main); +    return thread->Initialize({}, {}, {}, DefaultThreadPriority, 3, {}, ThreadType::Dummy);  }  ResultCode KThread::InitializeIdleThread(Core::System& system, KThread* thread, s32 virt_core) { @@ -273,11 +304,14 @@ void KThread::Finalize() {          auto it = waiter_list.begin();          while (it != waiter_list.end()) { -            // The thread shouldn't be a kernel waiter. +            // Clear the lock owner              it->SetLockOwner(nullptr); -            it->SetSyncedObject(nullptr, ResultInvalidState); -            it->Wakeup(); + +            // Erase the waiter from our list.              it = waiter_list.erase(it); + +            // Cancel the thread's wait. +            it->CancelWait(ResultInvalidState, true);          }      } @@ -294,15 +328,12 @@ bool KThread::IsSignaled() const {      return signaled;  } -void KThread::Wakeup() { -    KScopedSchedulerLock sl{kernel}; +void KThread::OnTimer() { +    ASSERT(kernel.GlobalSchedulerContext().IsLocked()); +    // If we're waiting, cancel the wait.      if (GetState() == ThreadState::Waiting) { -        if (sleeping_queue != nullptr) { -            sleeping_queue->WakeupThread(this); -        } else { -            SetState(ThreadState::Runnable); -        } +        wait_queue->CancelWait(this, ResultTimedOut, false);      }  } @@ -327,7 +358,7 @@ void KThread::StartTermination() {      // Signal.      signaled = true; -    NotifyAvailable(); +    KSynchronizationObject::NotifyAvailable();      // Clear previous thread in KScheduler.      KScheduler::ClearPreviousThread(kernel, this); @@ -475,30 +506,32 @@ ResultCode KThread::GetPhysicalCoreMask(s32* out_ideal_core, u64* out_affinity_m      return ResultSuccess;  } -ResultCode KThread::SetCoreMask(s32 cpu_core_id, u64 v_affinity_mask) { +ResultCode KThread::SetCoreMask(s32 core_id_, u64 v_affinity_mask) {      ASSERT(parent != nullptr);      ASSERT(v_affinity_mask != 0); -    KScopedLightLock lk{activity_pause_lock}; +    KScopedLightLock lk(activity_pause_lock);      // Set the core mask.      u64 p_affinity_mask = 0;      { -        KScopedSchedulerLock sl{kernel}; +        KScopedSchedulerLock sl(kernel);          ASSERT(num_core_migration_disables >= 0); -        // If the core id is no-update magic, preserve the ideal core id. -        if (cpu_core_id == Svc::IdealCoreNoUpdate) { -            cpu_core_id = virtual_ideal_core_id; -            R_UNLESS(((1ULL << cpu_core_id) & v_affinity_mask) != 0, ResultInvalidCombination); +        // If we're updating, set our ideal virtual core. +        if (core_id_ != Svc::IdealCoreNoUpdate) { +            virtual_ideal_core_id = core_id_; +        } else { +            // Preserve our ideal core id. +            core_id_ = virtual_ideal_core_id; +            R_UNLESS(((1ULL << core_id_) & v_affinity_mask) != 0, ResultInvalidCombination);          } -        // Set the virtual core/affinity mask. -        virtual_ideal_core_id = cpu_core_id; +        // Set our affinity mask.          virtual_affinity_mask = v_affinity_mask;          // Translate the virtual core to a physical core. -        if (cpu_core_id >= 0) { -            cpu_core_id = Core::Hardware::VirtualToPhysicalCoreMap[cpu_core_id]; +        if (core_id_ >= 0) { +            core_id_ = Core::Hardware::VirtualToPhysicalCoreMap[core_id_];          }          // Translate the virtual affinity mask to a physical one. @@ -513,7 +546,7 @@ ResultCode KThread::SetCoreMask(s32 cpu_core_id, u64 v_affinity_mask) {              const KAffinityMask old_mask = physical_affinity_mask;              // Set our new ideals. -            physical_ideal_core_id = cpu_core_id; +            physical_ideal_core_id = core_id_;              physical_affinity_mask.SetAffinityMask(p_affinity_mask);              if (physical_affinity_mask.GetAffinityMask() != old_mask.GetAffinityMask()) { @@ -531,18 +564,18 @@ ResultCode KThread::SetCoreMask(s32 cpu_core_id, u64 v_affinity_mask) {              }          } else {              // Otherwise, we edit the original affinity for restoration later. -            original_physical_ideal_core_id = cpu_core_id; +            original_physical_ideal_core_id = core_id_;              original_physical_affinity_mask.SetAffinityMask(p_affinity_mask);          }      }      // Update the pinned waiter list. +    ThreadQueueImplForKThreadSetProperty wait_queue_(kernel, std::addressof(pinned_waiter_list));      {          bool retry_update{}; -        bool thread_is_pinned{};          do {              // Lock the scheduler. -            KScopedSchedulerLock sl{kernel}; +            KScopedSchedulerLock sl(kernel);              // Don't do any further management if our termination has been requested.              R_SUCCEED_IF(IsTerminationRequested()); @@ -570,12 +603,9 @@ ResultCode KThread::SetCoreMask(s32 cpu_core_id, u64 v_affinity_mask) {                      R_UNLESS(!GetCurrentThread(kernel).IsTerminationRequested(),                               ResultTerminationRequested); -                    // Note that the thread was pinned. -                    thread_is_pinned = true; -                      // Wait until the thread isn't pinned any more.                      pinned_waiter_list.push_back(GetCurrentThread(kernel)); -                    GetCurrentThread(kernel).SetState(ThreadState::Waiting); +                    GetCurrentThread(kernel).BeginWait(std::addressof(wait_queue_));                  } else {                      // If the thread isn't pinned, release the scheduler lock and retry until it's                      // not current. @@ -583,16 +613,6 @@ ResultCode KThread::SetCoreMask(s32 cpu_core_id, u64 v_affinity_mask) {                  }              }          } while (retry_update); - -        // If the thread was pinned, it no longer is, and we should remove the current thread from -        // our waiter list. -        if (thread_is_pinned) { -            // Lock the scheduler. -            KScopedSchedulerLock sl{kernel}; - -            // Remove from the list. -            pinned_waiter_list.erase(pinned_waiter_list.iterator_to(GetCurrentThread(kernel))); -        }      }      return ResultSuccess; @@ -641,15 +661,9 @@ void KThread::WaitCancel() {      KScopedSchedulerLock sl{kernel};      // Check if we're waiting and cancellable. -    if (GetState() == ThreadState::Waiting && cancellable) { -        if (sleeping_queue != nullptr) { -            sleeping_queue->WakeupThread(this); -            wait_cancelled = true; -        } else { -            SetSyncedObject(nullptr, ResultCancelled); -            SetState(ThreadState::Runnable); -            wait_cancelled = false; -        } +    if (this->GetState() == ThreadState::Waiting && cancellable) { +        wait_cancelled = false; +        wait_queue->CancelWait(this, ResultCancelled, true);      } else {          // Otherwise, note that we cancelled a wait.          wait_cancelled = true; @@ -700,60 +714,59 @@ ResultCode KThread::SetActivity(Svc::ThreadActivity activity) {      // Set the activity.      {          // Lock the scheduler. -        KScopedSchedulerLock sl{kernel}; +        KScopedSchedulerLock sl(kernel);          // Verify our state. -        const auto cur_state = GetState(); +        const auto cur_state = this->GetState();          R_UNLESS((cur_state == ThreadState::Waiting || cur_state == ThreadState::Runnable),                   ResultInvalidState);          // Either pause or resume.          if (activity == Svc::ThreadActivity::Paused) {              // Verify that we're not suspended. -            R_UNLESS(!IsSuspendRequested(SuspendType::Thread), ResultInvalidState); +            R_UNLESS(!this->IsSuspendRequested(SuspendType::Thread), ResultInvalidState);              // Suspend. -            RequestSuspend(SuspendType::Thread); +            this->RequestSuspend(SuspendType::Thread);          } else {              ASSERT(activity == Svc::ThreadActivity::Runnable);              // Verify that we're suspended. -            R_UNLESS(IsSuspendRequested(SuspendType::Thread), ResultInvalidState); +            R_UNLESS(this->IsSuspendRequested(SuspendType::Thread), ResultInvalidState);              // Resume. -            Resume(SuspendType::Thread); +            this->Resume(SuspendType::Thread);          }      }      // If the thread is now paused, update the pinned waiter list.      if (activity == Svc::ThreadActivity::Paused) { -        bool thread_is_pinned{}; -        bool thread_is_current{}; +        ThreadQueueImplForKThreadSetProperty wait_queue_(kernel, +                                                         std::addressof(pinned_waiter_list)); + +        bool thread_is_current;          do {              // Lock the scheduler. -            KScopedSchedulerLock sl{kernel}; +            KScopedSchedulerLock sl(kernel);              // Don't do any further management if our termination has been requested. -            R_SUCCEED_IF(IsTerminationRequested()); +            R_SUCCEED_IF(this->IsTerminationRequested()); + +            // By default, treat the thread as not current. +            thread_is_current = false;              // Check whether the thread is pinned. -            if (GetStackParameters().is_pinned) { +            if (this->GetStackParameters().is_pinned) {                  // Verify that the current thread isn't terminating.                  R_UNLESS(!GetCurrentThread(kernel).IsTerminationRequested(),                           ResultTerminationRequested); -                // Note that the thread was pinned and not current. -                thread_is_pinned = true; -                thread_is_current = false; -                  // Wait until the thread isn't pinned any more.                  pinned_waiter_list.push_back(GetCurrentThread(kernel)); -                GetCurrentThread(kernel).SetState(ThreadState::Waiting); +                GetCurrentThread(kernel).BeginWait(std::addressof(wait_queue_));              } else {                  // Check if the thread is currently running.                  // If it is, we'll need to retry. -                thread_is_current = false; -                  for (auto i = 0; i < static_cast<s32>(Core::Hardware::NUM_CPU_CORES); ++i) {                      if (kernel.Scheduler(i).GetCurrentThread() == this) {                          thread_is_current = true; @@ -762,16 +775,6 @@ ResultCode KThread::SetActivity(Svc::ThreadActivity activity) {                  }              }          } while (thread_is_current); - -        // If the thread was pinned, it no longer is, and we should remove the current thread from -        // our waiter list. -        if (thread_is_pinned) { -            // Lock the scheduler. -            KScopedSchedulerLock sl{kernel}; - -            // Remove from the list. -            pinned_waiter_list.erase(pinned_waiter_list.iterator_to(GetCurrentThread(kernel))); -        }      }      return ResultSuccess; @@ -966,6 +969,9 @@ ResultCode KThread::Run() {          // Set our state and finish.          SetState(ThreadState::Runnable); + +        DisableDispatch(); +          return ResultSuccess;      }  } @@ -996,27 +1002,61 @@ ResultCode KThread::Sleep(s64 timeout) {      ASSERT(this == GetCurrentThreadPointer(kernel));      ASSERT(timeout > 0); +    ThreadQueueImplForKThreadSleep wait_queue_(kernel);      {          // Setup the scheduling lock and sleep. -        KScopedSchedulerLockAndSleep slp{kernel, this, timeout}; +        KScopedSchedulerLockAndSleep slp(kernel, this, timeout);          // Check if the thread should terminate. -        if (IsTerminationRequested()) { +        if (this->IsTerminationRequested()) {              slp.CancelSleep();              return ResultTerminationRequested;          } -        // Mark the thread as waiting. -        SetState(ThreadState::Waiting); +        // Wait for the sleep to end. +        this->BeginWait(std::addressof(wait_queue_));          SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Sleep);      } -    // The lock/sleep is done. +    return ResultSuccess; +} -    // Cancel the timer. -    kernel.TimeManager().UnscheduleTimeEvent(this); +void KThread::BeginWait(KThreadQueue* queue) { +    // Set our state as waiting. +    SetState(ThreadState::Waiting); -    return ResultSuccess; +    // Set our wait queue. +    wait_queue = queue; +} + +void KThread::NotifyAvailable(KSynchronizationObject* signaled_object, ResultCode wait_result_) { +    // Lock the scheduler. +    KScopedSchedulerLock sl(kernel); + +    // If we're waiting, notify our queue that we're available. +    if (GetState() == ThreadState::Waiting) { +        wait_queue->NotifyAvailable(this, signaled_object, wait_result_); +    } +} + +void KThread::EndWait(ResultCode wait_result_) { +    // Lock the scheduler. +    KScopedSchedulerLock sl(kernel); + +    // If we're waiting, notify our queue that we're available. +    if (GetState() == ThreadState::Waiting) { +        wait_queue->EndWait(this, wait_result_); +    } +} + +void KThread::CancelWait(ResultCode wait_result_, bool cancel_timer_task) { +    // Lock the scheduler. +    KScopedSchedulerLock sl(kernel); + +    // If we're waiting, notify our queue that we're available. +    if (GetState() == ThreadState::Waiting) { +        wait_queue->CancelWait(this, wait_result_, cancel_timer_task); +    }  }  void KThread::SetState(ThreadState state) { @@ -1050,4 +1090,26 @@ s32 GetCurrentCoreId(KernelCore& kernel) {      return GetCurrentThread(kernel).GetCurrentCore();  } +KScopedDisableDispatch::~KScopedDisableDispatch() { +    // If we are shutting down the kernel, none of this is relevant anymore. +    if (kernel.IsShuttingDown()) { +        return; +    } + +    // Skip the reschedule if single-core, as dispatch tracking is disabled here. +    if (!Settings::values.use_multi_core.GetValue()) { +        return; +    } + +    if (GetCurrentThread(kernel).GetDisableDispatchCount() <= 1) { +        auto scheduler = kernel.CurrentScheduler(); + +        if (scheduler) { +            scheduler->RescheduleCurrentCore(); +        } +    } else { +        GetCurrentThread(kernel).EnableDispatch(); +    } +} +  } // namespace Kernel diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index c77f44ad4..c8a08bd71 100644 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h @@ -48,6 +48,7 @@ enum class ThreadType : u32 {      Kernel = 1,      HighPriority = 2,      User = 3, +    Dummy = 100, // Special thread type for emulation purposes only  };  DECLARE_ENUM_FLAG_OPERATORS(ThreadType); @@ -161,8 +162,6 @@ public:          }      } -    void Wakeup(); -      void SetBasePriority(s32 value);      [[nodiscard]] ResultCode Run(); @@ -197,13 +196,19 @@ public:      void Suspend(); -    void SetSyncedObject(KSynchronizationObject* obj, ResultCode wait_res) { -        synced_object = obj; +    constexpr void SetSyncedIndex(s32 index) { +        synced_index = index; +    } + +    [[nodiscard]] constexpr s32 GetSyncedIndex() const { +        return synced_index; +    } + +    constexpr void SetWaitResult(ResultCode wait_res) {          wait_result = wait_res;      } -    [[nodiscard]] ResultCode GetWaitResult(KSynchronizationObject** out) const { -        *out = synced_object; +    [[nodiscard]] constexpr ResultCode GetWaitResult() const {          return wait_result;      } @@ -374,6 +379,8 @@ public:      [[nodiscard]] bool IsSignaled() const override; +    void OnTimer(); +      static void PostDestroy(uintptr_t arg);      [[nodiscard]] static ResultCode InitializeDummyThread(KThread* thread); @@ -446,20 +453,39 @@ public:          return per_core_priority_queue_entry[core];      } -    void SetSleepingQueue(KThreadQueue* q) { -        sleeping_queue = q; +    [[nodiscard]] bool IsKernelThread() const { +        return GetActiveCore() == 3; +    } + +    [[nodiscard]] bool IsDispatchTrackingDisabled() const { +        return is_single_core || IsKernelThread();      }      [[nodiscard]] s32 GetDisableDispatchCount() const { +        if (IsDispatchTrackingDisabled()) { +            // TODO(bunnei): Until kernel threads are emulated, we cannot enable/disable dispatch. +            return 1; +        } +          return this->GetStackParameters().disable_count;      }      void DisableDispatch() { +        if (IsDispatchTrackingDisabled()) { +            // TODO(bunnei): Until kernel threads are emulated, we cannot enable/disable dispatch. +            return; +        } +          ASSERT(GetCurrentThread(kernel).GetDisableDispatchCount() >= 0);          this->GetStackParameters().disable_count++;      }      void EnableDispatch() { +        if (IsDispatchTrackingDisabled()) { +            // TODO(bunnei): Until kernel threads are emulated, we cannot enable/disable dispatch. +            return; +        } +          ASSERT(GetCurrentThread(kernel).GetDisableDispatchCount() > 0);          this->GetStackParameters().disable_count--;      } @@ -573,6 +599,15 @@ public:          address_key_value = val;      } +    void ClearWaitQueue() { +        wait_queue = nullptr; +    } + +    void BeginWait(KThreadQueue* queue); +    void NotifyAvailable(KSynchronizationObject* signaled_object, ResultCode wait_result_); +    void EndWait(ResultCode wait_result_); +    void CancelWait(ResultCode wait_result_, bool cancel_timer_task); +      [[nodiscard]] bool HasWaiters() const {          return !waiter_list.empty();      } @@ -667,7 +702,6 @@ private:      KAffinityMask physical_affinity_mask{};      u64 thread_id{};      std::atomic<s64> cpu_time{}; -    KSynchronizationObject* synced_object{};      VAddr address_key{};      KProcess* parent{};      VAddr kernel_stack_top{}; @@ -677,13 +711,14 @@ private:      s64 schedule_count{};      s64 last_scheduled_tick{};      std::array<QueueEntry, Core::Hardware::NUM_CPU_CORES> per_core_priority_queue_entry{}; -    KThreadQueue* sleeping_queue{}; +    KThreadQueue* wait_queue{};      WaiterList waiter_list{};      WaiterList pinned_waiter_list{};      KThread* lock_owner{};      u32 address_key_value{};      u32 suspend_request_flags{};      u32 suspend_allowed_flags{}; +    s32 synced_index{};      ResultCode wait_result{ResultSuccess};      s32 base_priority{};      s32 physical_ideal_core_id{}; @@ -708,6 +743,7 @@ private:      // For emulation      std::shared_ptr<Common::Fiber> host_context{}; +    bool is_single_core{};      // For debugging      std::vector<KSynchronizationObject*> wait_objects_for_debugging; @@ -752,4 +788,20 @@ public:      }  }; +class KScopedDisableDispatch { +public: +    [[nodiscard]] explicit KScopedDisableDispatch(KernelCore& kernel_) : kernel{kernel_} { +        // If we are shutting down the kernel, none of this is relevant anymore. +        if (kernel.IsShuttingDown()) { +            return; +        } +        GetCurrentThread(kernel).DisableDispatch(); +    } + +    ~KScopedDisableDispatch(); + +private: +    KernelCore& kernel; +}; +  } // namespace Kernel diff --git a/src/core/hle/kernel/k_thread_queue.cpp b/src/core/hle/kernel/k_thread_queue.cpp new file mode 100644 index 000000000..d5248b547 --- /dev/null +++ b/src/core/hle/kernel/k_thread_queue.cpp @@ -0,0 +1,49 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/kernel/k_thread_queue.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/time_manager.h" + +namespace Kernel { + +void KThreadQueue::NotifyAvailable([[maybe_unused]] KThread* waiting_thread, +                                   [[maybe_unused]] KSynchronizationObject* signaled_object, +                                   [[maybe_unused]] ResultCode wait_result) {} + +void KThreadQueue::EndWait(KThread* waiting_thread, ResultCode wait_result) { +    // Set the thread's wait result. +    waiting_thread->SetWaitResult(wait_result); + +    // Set the thread as runnable. +    waiting_thread->SetState(ThreadState::Runnable); + +    // Clear the thread's wait queue. +    waiting_thread->ClearWaitQueue(); + +    // Cancel the thread task. +    kernel.TimeManager().UnscheduleTimeEvent(waiting_thread); +} + +void KThreadQueue::CancelWait(KThread* waiting_thread, ResultCode wait_result, +                              bool cancel_timer_task) { +    // Set the thread's wait result. +    waiting_thread->SetWaitResult(wait_result); + +    // Set the thread as runnable. +    waiting_thread->SetState(ThreadState::Runnable); + +    // Clear the thread's wait queue. +    waiting_thread->ClearWaitQueue(); + +    // Cancel the thread task. +    if (cancel_timer_task) { +        kernel.TimeManager().UnscheduleTimeEvent(waiting_thread); +    } +} + +void KThreadQueueWithoutEndWait::EndWait([[maybe_unused]] KThread* waiting_thread, +                                         [[maybe_unused]] ResultCode wait_result) {} + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_thread_queue.h b/src/core/hle/kernel/k_thread_queue.h index 35d471dc5..ccb718e49 100644 --- a/src/core/hle/kernel/k_thread_queue.h +++ b/src/core/hle/kernel/k_thread_queue.h @@ -4,6 +4,7 @@  #pragma once +#include "core/hle/kernel/k_scheduler.h"  #include "core/hle/kernel/k_thread.h"  namespace Kernel { @@ -11,71 +12,24 @@ namespace Kernel {  class KThreadQueue {  public:      explicit KThreadQueue(KernelCore& kernel_) : kernel{kernel_} {} +    virtual ~KThreadQueue() = default; -    bool IsEmpty() const { -        return wait_list.empty(); -    } - -    KThread::WaiterList::iterator begin() { -        return wait_list.begin(); -    } -    KThread::WaiterList::iterator end() { -        return wait_list.end(); -    } - -    bool SleepThread(KThread* t) { -        KScopedSchedulerLock sl{kernel}; - -        // If the thread needs terminating, don't enqueue it. -        if (t->IsTerminationRequested()) { -            return false; -        } - -        // Set the thread's queue and mark it as waiting. -        t->SetSleepingQueue(this); -        t->SetState(ThreadState::Waiting); - -        // Add the thread to the queue. -        wait_list.push_back(*t); - -        return true; -    } - -    void WakeupThread(KThread* t) { -        KScopedSchedulerLock sl{kernel}; - -        // Remove the thread from the queue. -        wait_list.erase(wait_list.iterator_to(*t)); - -        // Mark the thread as no longer sleeping. -        t->SetState(ThreadState::Runnable); -        t->SetSleepingQueue(nullptr); -    } - -    KThread* WakeupFrontThread() { -        KScopedSchedulerLock sl{kernel}; - -        if (wait_list.empty()) { -            return nullptr; -        } else { -            // Remove the thread from the queue. -            auto it = wait_list.begin(); -            KThread* thread = std::addressof(*it); -            wait_list.erase(it); - -            ASSERT(thread->GetState() == ThreadState::Waiting); - -            // Mark the thread as no longer sleeping. -            thread->SetState(ThreadState::Runnable); -            thread->SetSleepingQueue(nullptr); - -            return thread; -        } -    } +    virtual void NotifyAvailable(KThread* waiting_thread, KSynchronizationObject* signaled_object, +                                 ResultCode wait_result); +    virtual void EndWait(KThread* waiting_thread, ResultCode wait_result); +    virtual void CancelWait(KThread* waiting_thread, ResultCode wait_result, +                            bool cancel_timer_task);  private:      KernelCore& kernel;      KThread::WaiterList wait_list{};  }; +class KThreadQueueWithoutEndWait : public KThreadQueue { +public: +    explicit KThreadQueueWithoutEndWait(KernelCore& kernel_) : KThreadQueue(kernel_) {} + +    void EndWait(KThread* waiting_thread, ResultCode wait_result) override final; +}; +  } // namespace Kernel diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 45e86a677..2e4e4cb1c 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -14,6 +14,7 @@  #include "common/assert.h"  #include "common/logging/log.h"  #include "common/microprofile.h" +#include "common/scope_exit.h"  #include "common/thread.h"  #include "common/thread_worker.h"  #include "core/arm/arm_interface.h" @@ -83,12 +84,16 @@ struct KernelCore::Impl {      }      void InitializeCores() { -        for (auto& core : cores) { -            core.Initialize(current_process->Is64BitProcess()); +        for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { +            cores[core_id].Initialize(current_process->Is64BitProcess()); +            system.Memory().SetCurrentPageTable(*current_process, core_id);          }      }      void Shutdown() { +        is_shutting_down.store(true, std::memory_order_relaxed); +        SCOPE_EXIT({ is_shutting_down.store(false, std::memory_order_relaxed); }); +          process_list.clear();          // Close all open server ports. @@ -123,15 +128,6 @@ struct KernelCore::Impl {          next_user_process_id = KProcess::ProcessIDMin;          next_thread_id = 1; -        for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { -            if (suspend_threads[core_id]) { -                suspend_threads[core_id]->Close(); -                suspend_threads[core_id] = nullptr; -            } - -            schedulers[core_id].reset(); -        } -          cores.clear();          global_handle_table->Finalize(); @@ -159,6 +155,16 @@ struct KernelCore::Impl {          CleanupObject(time_shared_mem);          CleanupObject(system_resource_limit); +        for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { +            if (suspend_threads[core_id]) { +                suspend_threads[core_id]->Close(); +                suspend_threads[core_id] = nullptr; +            } + +            schedulers[core_id]->Finalize(); +            schedulers[core_id].reset(); +        } +          // Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others          next_host_thread_id = Core::Hardware::NUM_CPU_CORES; @@ -245,13 +251,11 @@ struct KernelCore::Impl {                      KScopedSchedulerLock lock(kernel);                      global_scheduler_context->PreemptThreads();                  } -                const auto time_interval = std::chrono::nanoseconds{ -                    Core::Timing::msToCycles(std::chrono::milliseconds(10))}; +                const auto time_interval = std::chrono::nanoseconds{std::chrono::milliseconds(10)};                  system.CoreTiming().ScheduleEvent(time_interval, preemption_event);              }); -        const auto time_interval = -            std::chrono::nanoseconds{Core::Timing::msToCycles(std::chrono::milliseconds(10))}; +        const auto time_interval = std::chrono::nanoseconds{std::chrono::milliseconds(10)};          system.CoreTiming().ScheduleEvent(time_interval, preemption_event);      } @@ -267,14 +271,6 @@ struct KernelCore::Impl {      void MakeCurrentProcess(KProcess* process) {          current_process = process; -        if (process == nullptr) { -            return; -        } - -        const u32 core_id = GetCurrentHostThreadID(); -        if (core_id < Core::Hardware::NUM_CPU_CORES) { -            system.Memory().SetCurrentPageTable(*process, core_id); -        }      }      static inline thread_local u32 host_thread_id = UINT32_MAX; @@ -344,7 +340,16 @@ struct KernelCore::Impl {          is_phantom_mode_for_singlecore = value;      } +    bool IsShuttingDown() const { +        return is_shutting_down.load(std::memory_order_relaxed); +    } +      KThread* GetCurrentEmuThread() { +        // If we are shutting down the kernel, none of this is relevant anymore. +        if (IsShuttingDown()) { +            return {}; +        } +          const auto thread_id = GetCurrentHostThreadID();          if (thread_id >= Core::Hardware::NUM_CPU_CORES) {              return GetHostDummyThread(); @@ -760,6 +765,7 @@ struct KernelCore::Impl {      std::vector<std::unique_ptr<KThread>> dummy_threads;      bool is_multicore{}; +    std::atomic_bool is_shutting_down{};      bool is_phantom_mode_for_singlecore{};      u32 single_core_thread_id{}; @@ -845,16 +851,20 @@ const Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) const {      return impl->cores[id];  } +size_t KernelCore::CurrentPhysicalCoreIndex() const { +    const u32 core_id = impl->GetCurrentHostThreadID(); +    if (core_id >= Core::Hardware::NUM_CPU_CORES) { +        return Core::Hardware::NUM_CPU_CORES - 1; +    } +    return core_id; +} +  Kernel::PhysicalCore& KernelCore::CurrentPhysicalCore() { -    u32 core_id = impl->GetCurrentHostThreadID(); -    ASSERT(core_id < Core::Hardware::NUM_CPU_CORES); -    return impl->cores[core_id]; +    return impl->cores[CurrentPhysicalCoreIndex()];  }  const Kernel::PhysicalCore& KernelCore::CurrentPhysicalCore() const { -    u32 core_id = impl->GetCurrentHostThreadID(); -    ASSERT(core_id < Core::Hardware::NUM_CPU_CORES); -    return impl->cores[core_id]; +    return impl->cores[CurrentPhysicalCoreIndex()];  }  Kernel::KScheduler* KernelCore::CurrentScheduler() { @@ -1057,6 +1067,9 @@ void KernelCore::Suspend(bool in_suspention) {              impl->suspend_threads[core_id]->SetState(state);              impl->suspend_threads[core_id]->SetWaitReasonForDebugging(                  ThreadWaitReasonForDebugging::Suspended); +            if (!should_suspend) { +                impl->suspend_threads[core_id]->DisableDispatch(); +            }          }      }  } @@ -1065,19 +1078,21 @@ bool KernelCore::IsMulticore() const {      return impl->is_multicore;  } +bool KernelCore::IsShuttingDown() const { +    return impl->IsShuttingDown(); +} +  void KernelCore::ExceptionalExit() {      exception_exited = true;      Suspend(true);  }  void KernelCore::EnterSVCProfile() { -    std::size_t core = impl->GetCurrentHostThreadID(); -    impl->svc_ticks[core] = MicroProfileEnter(MICROPROFILE_TOKEN(Kernel_SVC)); +    impl->svc_ticks[CurrentPhysicalCoreIndex()] = MicroProfileEnter(MICROPROFILE_TOKEN(Kernel_SVC));  }  void KernelCore::ExitSVCProfile() { -    std::size_t core = impl->GetCurrentHostThreadID(); -    MicroProfileLeave(MICROPROFILE_TOKEN(Kernel_SVC), impl->svc_ticks[core]); +    MicroProfileLeave(MICROPROFILE_TOKEN(Kernel_SVC), impl->svc_ticks[CurrentPhysicalCoreIndex()]);  }  std::weak_ptr<Kernel::ServiceThread> KernelCore::CreateServiceThread(const std::string& name) { diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index d847fd0c5..b9b423908 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -149,6 +149,9 @@ public:      /// Gets the an instance of the respective physical CPU core.      const Kernel::PhysicalCore& PhysicalCore(std::size_t id) const; +    /// Gets the current physical core index for the running host thread. +    std::size_t CurrentPhysicalCoreIndex() const; +      /// Gets the sole instance of the Scheduler at the current running core.      Kernel::KScheduler* CurrentScheduler(); @@ -272,6 +275,8 @@ public:      bool IsMulticore() const; +    bool IsShuttingDown() const; +      void EnterSVCProfile();      void ExitSVCProfile(); diff --git a/src/core/hle/kernel/service_thread.cpp b/src/core/hle/kernel/service_thread.cpp index 6721b6276..03f3dec10 100644 --- a/src/core/hle/kernel/service_thread.cpp +++ b/src/core/hle/kernel/service_thread.cpp @@ -25,24 +25,27 @@ public:      void QueueSyncRequest(KSession& session, std::shared_ptr<HLERequestContext>&& context);  private: -    std::vector<std::thread> threads; +    std::vector<std::jthread> threads;      std::queue<std::function<void()>> requests;      std::mutex queue_mutex; -    std::condition_variable condition; +    std::condition_variable_any condition;      const std::string service_name; -    bool stop{};  };  ServiceThread::Impl::Impl(KernelCore& kernel, std::size_t num_threads, const std::string& name)      : service_name{name} { -    for (std::size_t i = 0; i < num_threads; ++i) -        threads.emplace_back([this, &kernel] { +    for (std::size_t i = 0; i < num_threads; ++i) { +        threads.emplace_back([this, &kernel](std::stop_token stop_token) {              Common::SetCurrentThreadName(std::string{"yuzu:HleService:" + service_name}.c_str());              // Wait for first request before trying to acquire a render context              {                  std::unique_lock lock{queue_mutex}; -                condition.wait(lock, [this] { return stop || !requests.empty(); }); +                condition.wait(lock, stop_token, [this] { return !requests.empty(); }); +            } + +            if (stop_token.stop_requested()) { +                return;              }              kernel.RegisterHostThread(); @@ -52,10 +55,16 @@ ServiceThread::Impl::Impl(KernelCore& kernel, std::size_t num_threads, const std                  {                      std::unique_lock lock{queue_mutex}; -                    condition.wait(lock, [this] { return stop || !requests.empty(); }); -                    if (stop || requests.empty()) { +                    condition.wait(lock, stop_token, [this] { return !requests.empty(); }); + +                    if (stop_token.stop_requested()) {                          return;                      } + +                    if (requests.empty()) { +                        continue; +                    } +                      task = std::move(requests.front());                      requests.pop();                  } @@ -63,6 +72,7 @@ ServiceThread::Impl::Impl(KernelCore& kernel, std::size_t num_threads, const std                  task();              }          }); +    }  }  void ServiceThread::Impl::QueueSyncRequest(KSession& session, @@ -88,12 +98,9 @@ void ServiceThread::Impl::QueueSyncRequest(KSession& session,  }  ServiceThread::Impl::~Impl() { -    { -        std::unique_lock lock{queue_mutex}; -        stop = true; -    }      condition.notify_all(); -    for (std::thread& thread : threads) { +    for (auto& thread : threads) { +        thread.request_stop();          thread.join();      }  } diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index b37db918e..a9f7438ea 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -32,6 +32,7 @@  #include "core/hle/kernel/k_shared_memory.h"  #include "core/hle/kernel/k_synchronization_object.h"  #include "core/hle/kernel/k_thread.h" +#include "core/hle/kernel/k_thread_queue.h"  #include "core/hle/kernel/k_transfer_memory.h"  #include "core/hle/kernel/k_writable_event.h"  #include "core/hle/kernel/kernel.h" @@ -308,26 +309,29 @@ static ResultCode ConnectToNamedPort32(Core::System& system, Handle* out_handle,  /// Makes a blocking IPC call to an OS service.  static ResultCode SendSyncRequest(Core::System& system, Handle handle) { -      auto& kernel = system.Kernel(); +    // Create the wait queue. +    KThreadQueue wait_queue(kernel); + +    // Get the client session from its handle. +    KScopedAutoObject session = +        kernel.CurrentProcess()->GetHandleTable().GetObject<KClientSession>(handle); +    R_UNLESS(session.IsNotNull(), ResultInvalidHandle); + +    LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName()); +      auto thread = kernel.CurrentScheduler()->GetCurrentThread();      {          KScopedSchedulerLock lock(kernel); -        thread->SetState(ThreadState::Waiting); -        thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::IPC); - -        { -            KScopedAutoObject session = -                kernel.CurrentProcess()->GetHandleTable().GetObject<KClientSession>(handle); -            R_UNLESS(session.IsNotNull(), ResultInvalidHandle); -            LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName()); -            session->SendSyncRequest(thread, system.Memory(), system.CoreTiming()); -        } + +        // This is a synchronous request, so we should wait for our request to complete. +        GetCurrentThread(kernel).BeginWait(std::addressof(wait_queue)); +        GetCurrentThread(kernel).SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::IPC); +        session->SendSyncRequest(&GetCurrentThread(kernel), system.Memory(), system.CoreTiming());      } -    KSynchronizationObject* dummy{}; -    return thread->GetWaitResult(std::addressof(dummy)); +    return thread->GetWaitResult();  }  static ResultCode SendSyncRequest32(Core::System& system, Handle handle) { @@ -874,7 +878,7 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, Handle              const u64 thread_ticks = current_thread->GetCpuTime();              out_ticks = thread_ticks + (core_timing.GetCPUTicks() - prev_ctx_ticks); -        } else if (same_thread && info_sub_id == system.CurrentCoreIndex()) { +        } else if (same_thread && info_sub_id == system.Kernel().CurrentPhysicalCoreIndex()) {              out_ticks = core_timing.GetCPUTicks() - prev_ctx_ticks;          } @@ -888,7 +892,8 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, Handle              return ResultInvalidHandle;          } -        if (info_sub_id != 0xFFFFFFFFFFFFFFFF && info_sub_id != system.CurrentCoreIndex()) { +        if (info_sub_id != 0xFFFFFFFFFFFFFFFF && +            info_sub_id != system.Kernel().CurrentPhysicalCoreIndex()) {              LOG_ERROR(Kernel_SVC, "Core is not the current core, got {}", info_sub_id);              return ResultInvalidCombination;          } diff --git a/src/core/hle/kernel/time_manager.cpp b/src/core/hle/kernel/time_manager.cpp index 8cd7279a3..aa985d820 100644 --- a/src/core/hle/kernel/time_manager.cpp +++ b/src/core/hle/kernel/time_manager.cpp @@ -5,6 +5,7 @@  #include "common/assert.h"  #include "core/core.h"  #include "core/core_timing.h" +#include "core/hle/kernel/k_scheduler.h"  #include "core/hle/kernel/k_thread.h"  #include "core/hle/kernel/time_manager.h" @@ -15,7 +16,10 @@ TimeManager::TimeManager(Core::System& system_) : system{system_} {          Core::Timing::CreateEvent("Kernel::TimeManagerCallback",                                    [this](std::uintptr_t thread_handle, std::chrono::nanoseconds) {                                        KThread* thread = reinterpret_cast<KThread*>(thread_handle); -                                      thread->Wakeup(); +                                      { +                                          KScopedSchedulerLock sl(system.Kernel()); +                                          thread->OnTimer(); +                                      }                                    });  } diff --git a/src/input_common/drivers/gc_adapter.cpp b/src/input_common/drivers/gc_adapter.cpp index 8b6574223..7ab4540a8 100644 --- a/src/input_common/drivers/gc_adapter.cpp +++ b/src/input_common/drivers/gc_adapter.cpp @@ -69,7 +69,7 @@ private:      libusb_device_handle* handle{};  }; -GCAdapter::GCAdapter(const std::string& input_engine_) : InputEngine(input_engine_) { +GCAdapter::GCAdapter(std::string input_engine_) : InputEngine(std::move(input_engine_)) {      if (usb_adapter_handle) {          return;      } @@ -325,8 +325,8 @@ bool GCAdapter::GetGCEndpoint(libusb_device* device) {      return true;  } -Common::Input::VibrationError GCAdapter::SetRumble(const PadIdentifier& identifier, -                                                   const Common::Input::VibrationStatus vibration) { +Common::Input::VibrationError GCAdapter::SetRumble( +    const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) {      const auto mean_amplitude = (vibration.low_amplitude + vibration.high_amplitude) * 0.5f;      const auto processed_amplitude =          static_cast<u8>((mean_amplitude + std::pow(mean_amplitude, 0.3f)) * 0.5f * 0x8); diff --git a/src/input_common/drivers/gc_adapter.h b/src/input_common/drivers/gc_adapter.h index 8dc51d2e5..7ce1912a3 100644 --- a/src/input_common/drivers/gc_adapter.h +++ b/src/input_common/drivers/gc_adapter.h @@ -22,13 +22,13 @@ namespace InputCommon {  class LibUSBContext;  class LibUSBDeviceHandle; -class GCAdapter : public InputCommon::InputEngine { +class GCAdapter : public InputEngine {  public: -    explicit GCAdapter(const std::string& input_engine_); -    ~GCAdapter(); +    explicit GCAdapter(std::string input_engine_); +    ~GCAdapter() override;      Common::Input::VibrationError SetRumble( -        const PadIdentifier& identifier, const Common::Input::VibrationStatus vibration) override; +        const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) override;      /// Used for automapping features      std::vector<Common::ParamPackage> GetInputDevices() const override; diff --git a/src/input_common/drivers/keyboard.cpp b/src/input_common/drivers/keyboard.cpp index 23b0c0ccf..4c1e5bbec 100644 --- a/src/input_common/drivers/keyboard.cpp +++ b/src/input_common/drivers/keyboard.cpp @@ -24,7 +24,7 @@ constexpr PadIdentifier keyboard_modifier_identifier = {      .pad = 1,  }; -Keyboard::Keyboard(const std::string& input_engine_) : InputEngine(input_engine_) { +Keyboard::Keyboard(std::string input_engine_) : InputEngine(std::move(input_engine_)) {      // Keyboard is broken into 3 diferent sets:      // key: Unfiltered intended for controllers.      // keyboard_key: Allows only Settings::NativeKeyboard::Keys intended for keyboard emulation. diff --git a/src/input_common/drivers/keyboard.h b/src/input_common/drivers/keyboard.h index ad123b136..3856c882c 100644 --- a/src/input_common/drivers/keyboard.h +++ b/src/input_common/drivers/keyboard.h @@ -12,9 +12,9 @@ namespace InputCommon {   * A button device factory representing a keyboard. It receives keyboard events and forward them   * to all button devices it created.   */ -class Keyboard final : public InputCommon::InputEngine { +class Keyboard final : public InputEngine {  public: -    explicit Keyboard(const std::string& input_engine_); +    explicit Keyboard(std::string input_engine_);      /**       * Sets the status of all buttons bound with the key to pressed diff --git a/src/input_common/drivers/mouse.cpp b/src/input_common/drivers/mouse.cpp index 752118e97..aa69216c8 100644 --- a/src/input_common/drivers/mouse.cpp +++ b/src/input_common/drivers/mouse.cpp @@ -24,7 +24,7 @@ constexpr PadIdentifier identifier = {      .pad = 0,  }; -Mouse::Mouse(const std::string& input_engine_) : InputEngine(input_engine_) { +Mouse::Mouse(std::string input_engine_) : InputEngine(std::move(input_engine_)) {      PreSetController(identifier);      PreSetAxis(identifier, mouse_axis_x);      PreSetAxis(identifier, mouse_axis_y); diff --git a/src/input_common/drivers/mouse.h b/src/input_common/drivers/mouse.h index 4a1fd2fd9..040446178 100644 --- a/src/input_common/drivers/mouse.h +++ b/src/input_common/drivers/mouse.h @@ -27,9 +27,9 @@ enum class MouseButton {   * A button device factory representing a keyboard. It receives keyboard events and forward them   * to all button devices it created.   */ -class Mouse final : public InputCommon::InputEngine { +class Mouse final : public InputEngine {  public: -    explicit Mouse(const std::string& input_engine_); +    explicit Mouse(std::string input_engine_);      /**       * Signals that mouse has moved. diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp index 1052ed394..0cda9df62 100644 --- a/src/input_common/drivers/sdl_driver.cpp +++ b/src/input_common/drivers/sdl_driver.cpp @@ -88,7 +88,7 @@ public:          return true;      } -    BasicMotion GetMotion() { +    const BasicMotion& GetMotion() const {          return motion;      } @@ -367,7 +367,7 @@ void SDLDriver::HandleGameControllerEvent(const SDL_Event& event) {              if (joystick->UpdateMotion(event.csensor)) {                  const PadIdentifier identifier = joystick->GetPadIdentifier();                  SetMotion(identifier, 0, joystick->GetMotion()); -            }; +            }          }          break;      } @@ -387,7 +387,7 @@ void SDLDriver::CloseJoysticks() {      joystick_map.clear();  } -SDLDriver::SDLDriver(const std::string& input_engine_) : InputEngine(input_engine_) { +SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_engine_)) {      if (!Settings::values.enable_raw_input) {          // Disable raw input. When enabled this setting causes SDL to die when a web applet opens          SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT, "0"); @@ -403,10 +403,11 @@ SDLDriver::SDLDriver(const std::string& input_engine_) : InputEngine(input_engin      // Use hidapi driver for joycons. This will allow joycons to be detected as a GameController and      // not a generic one -    SDL_SetHint("SDL_JOYSTICK_HIDAPI_JOY_CONS", "1"); +    SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "1"); -    // Turn off Pro controller home led -    SDL_SetHint("SDL_JOYSTICK_HIDAPI_SWITCH_HOME_LED", "0"); +    // Disable hidapi driver for xbox. Already default on Windows, this causes conflict with native +    // driver on Linux. +    SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_XBOX, "0");      // If the frontend is going to manage the event loop, then we don't start one here      start_thread = SDL_WasInit(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) == 0; @@ -491,8 +492,9 @@ std::vector<Common::ParamPackage> SDLDriver::GetInputDevices() const {      }      return devices;  } -Common::Input::VibrationError SDLDriver::SetRumble(const PadIdentifier& identifier, -                                                   const Common::Input::VibrationStatus vibration) { + +Common::Input::VibrationError SDLDriver::SetRumble( +    const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) {      const auto joystick =          GetSDLJoystickByGUID(identifier.guid.Format(), static_cast<int>(identifier.port));      const auto process_amplitude_exp = [](f32 amplitude, f32 factor) { @@ -526,6 +528,7 @@ Common::Input::VibrationError SDLDriver::SetRumble(const PadIdentifier& identifi      return Common::Input::VibrationError::None;  } +  Common::ParamPackage SDLDriver::BuildAnalogParamPackageForButton(int port, std::string guid,                                                                   s32 axis, float value) const {      Common::ParamPackage params{}; diff --git a/src/input_common/drivers/sdl_driver.h b/src/input_common/drivers/sdl_driver.h index d03ff4b84..e9a5d2e26 100644 --- a/src/input_common/drivers/sdl_driver.h +++ b/src/input_common/drivers/sdl_driver.h @@ -19,19 +19,19 @@ using SDL_GameController = struct _SDL_GameController;  using SDL_Joystick = struct _SDL_Joystick;  using SDL_JoystickID = s32; +namespace InputCommon { + +class SDLJoystick; +  using ButtonBindings =      std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerButton>, 17>;  using ZButtonBindings =      std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerAxis>, 2>; -namespace InputCommon { - -class SDLJoystick; - -class SDLDriver : public InputCommon::InputEngine { +class SDLDriver : public InputEngine {  public:      /// Initializes and registers SDL device factories -    SDLDriver(const std::string& input_engine_); +    explicit SDLDriver(std::string input_engine_);      /// Unregisters SDL device factories and shut them down.      ~SDLDriver() override; @@ -59,7 +59,7 @@ public:      u8 GetHatButtonId(const std::string& direction_name) const override;      Common::Input::VibrationError SetRumble( -        const PadIdentifier& identifier, const Common::Input::VibrationStatus vibration) override; +        const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) override;  private:      void InitJoystick(int joystick_index); diff --git a/src/input_common/drivers/tas_input.cpp b/src/input_common/drivers/tas_input.cpp index 0e01fb0d9..5bdd5dac3 100644 --- a/src/input_common/drivers/tas_input.cpp +++ b/src/input_common/drivers/tas_input.cpp @@ -3,7 +3,6 @@  // Refer to the license.txt file included.  #include <cstring> -#include <regex>  #include <fmt/format.h>  #include "common/fs/file.h" @@ -15,7 +14,7 @@  namespace InputCommon::TasInput { -enum TasAxes : u8 { +enum class Tas::TasAxis : u8 {      StickX,      StickY,      SubstickX, @@ -47,7 +46,7 @@ constexpr std::array<std::pair<std::string_view, TasButton>, 20> text_to_tas_but      {"KEY_ZR", TasButton::TRIGGER_ZR},  }; -Tas::Tas(const std::string& input_engine_) : InputCommon::InputEngine(input_engine_) { +Tas::Tas(std::string input_engine_) : InputEngine(std::move(input_engine_)) {      for (size_t player_index = 0; player_index < PLAYER_NUMBER; player_index++) {          PadIdentifier identifier{              .guid = Common::UUID{}, @@ -66,7 +65,7 @@ Tas::Tas(const std::string& input_engine_) : InputCommon::InputEngine(input_engi  Tas::~Tas() {      Stop(); -}; +}  void Tas::LoadTasFiles() {      script_length = 0; @@ -79,43 +78,43 @@ void Tas::LoadTasFiles() {  }  void Tas::LoadTasFile(size_t player_index, size_t file_index) { -    if (!commands[player_index].empty()) { -        commands[player_index].clear(); -    } +    commands[player_index].clear(); +      std::string file = Common::FS::ReadStringFromFile(          Common::FS::GetYuzuPath(Common::FS::YuzuPath::TASDir) /              fmt::format("script{}-{}.txt", file_index, player_index + 1),          Common::FS::FileType::BinaryFile); -    std::stringstream command_line(file); +    std::istringstream command_line(file);      std::string line;      int frame_no = 0;      while (std::getline(command_line, line, '\n')) {          if (line.empty()) {              continue;          } -        std::smatch m; -        std::stringstream linestream(line); -        std::string segment; -        std::vector<std::string> seglist; - -        while (std::getline(linestream, segment, ' ')) { -            seglist.push_back(segment); +        std::vector<std::string> seg_list; +        { +            std::istringstream line_stream(line); +            std::string segment; +            while (std::getline(line_stream, segment, ' ')) { +                seg_list.push_back(std::move(segment)); +            }          } -        if (seglist.size() < 4) { +        if (seg_list.size() < 4) {              continue;          } -        while (frame_no < std::stoi(seglist.at(0))) { -            commands[player_index].push_back({}); +        const auto num_frames = std::stoi(seg_list[0]); +        while (frame_no < num_frames) { +            commands[player_index].emplace_back();              frame_no++;          }          TASCommand command = { -            .buttons = ReadCommandButtons(seglist.at(1)), -            .l_axis = ReadCommandAxis(seglist.at(2)), -            .r_axis = ReadCommandAxis(seglist.at(3)), +            .buttons = ReadCommandButtons(seg_list[1]), +            .l_axis = ReadCommandAxis(seg_list[2]), +            .r_axis = ReadCommandAxis(seg_list[3]),          };          commands[player_index].push_back(command);          frame_no++; @@ -123,16 +122,17 @@ void Tas::LoadTasFile(size_t player_index, size_t file_index) {      LOG_INFO(Input, "TAS file loaded! {} frames", frame_no);  } -void Tas::WriteTasFile(std::u8string file_name) { +void Tas::WriteTasFile(std::u8string_view file_name) {      std::string output_text;      for (size_t frame = 0; frame < record_commands.size(); frame++) {          const TASCommand& line = record_commands[frame];          output_text += fmt::format("{} {} {} {}\n", frame, WriteCommandButtons(line.buttons),                                     WriteCommandAxis(line.l_axis), WriteCommandAxis(line.r_axis));      } -    const auto bytes_written = Common::FS::WriteStringToFile( -        Common::FS::GetYuzuPath(Common::FS::YuzuPath::TASDir) / file_name, -        Common::FS::FileType::TextFile, output_text); + +    const auto tas_file_name = Common::FS::GetYuzuPath(Common::FS::YuzuPath::TASDir) / file_name; +    const auto bytes_written = +        Common::FS::WriteStringToFile(tas_file_name, Common::FS::FileType::TextFile, output_text);      if (bytes_written == output_text.size()) {          LOG_INFO(Input, "TAS file written to file!");      } else { @@ -205,10 +205,10 @@ void Tas::UpdateThread() {                  const int button = static_cast<int>(i);                  SetButton(identifier, button, button_status);              } -            SetAxis(identifier, TasAxes::StickX, command.l_axis.x); -            SetAxis(identifier, TasAxes::StickY, command.l_axis.y); -            SetAxis(identifier, TasAxes::SubstickX, command.r_axis.x); -            SetAxis(identifier, TasAxes::SubstickY, command.r_axis.y); +            SetTasAxis(identifier, TasAxis::StickX, command.l_axis.x); +            SetTasAxis(identifier, TasAxis::StickY, command.l_axis.y); +            SetTasAxis(identifier, TasAxis::SubstickX, command.r_axis.x); +            SetTasAxis(identifier, TasAxis::SubstickY, command.r_axis.y);          }      } else {          is_running = Settings::values.tas_loop.GetValue(); @@ -224,27 +224,28 @@ void Tas::ClearInput() {  }  TasAnalog Tas::ReadCommandAxis(const std::string& line) const { -    std::stringstream linestream(line); -    std::string segment; -    std::vector<std::string> seglist; - -    while (std::getline(linestream, segment, ';')) { -        seglist.push_back(segment); +    std::vector<std::string> seg_list; +    { +        std::istringstream line_stream(line); +        std::string segment; +        while (std::getline(line_stream, segment, ';')) { +            seg_list.push_back(std::move(segment)); +        }      } -    const float x = std::stof(seglist.at(0)) / 32767.0f; -    const float y = std::stof(seglist.at(1)) / 32767.0f; +    const float x = std::stof(seg_list.at(0)) / 32767.0f; +    const float y = std::stof(seg_list.at(1)) / 32767.0f;      return {x, y};  } -u64 Tas::ReadCommandButtons(const std::string& data) const { -    std::stringstream button_text(data); -    std::string line; +u64 Tas::ReadCommandButtons(const std::string& line) const { +    std::istringstream button_text(line); +    std::string button_line;      u64 buttons = 0; -    while (std::getline(button_text, line, ';')) { -        for (auto [text, tas_button] : text_to_tas_button) { -            if (text == line) { +    while (std::getline(button_text, button_line, ';')) { +        for (const auto& [text, tas_button] : text_to_tas_button) { +            if (text == button_line) {                  buttons |= static_cast<u64>(tas_button);                  break;              } @@ -254,8 +255,8 @@ u64 Tas::ReadCommandButtons(const std::string& data) const {  }  std::string Tas::WriteCommandButtons(u64 buttons) const { -    std::string returns = ""; -    for (auto [text_button, tas_button] : text_to_tas_button) { +    std::string returns; +    for (const auto& [text_button, tas_button] : text_to_tas_button) {          if ((buttons & static_cast<u64>(tas_button)) != 0) {              returns += fmt::format("{};", text_button);          } @@ -267,6 +268,10 @@ std::string Tas::WriteCommandAxis(TasAnalog analog) const {      return fmt::format("{};{}", analog.x * 32767, analog.y * 32767);  } +void Tas::SetTasAxis(const PadIdentifier& identifier, TasAxis axis, f32 value) { +    SetAxis(identifier, static_cast<int>(axis), value); +} +  void Tas::StartStop() {      if (!Settings::values.tas_enable) {          return; diff --git a/src/input_common/drivers/tas_input.h b/src/input_common/drivers/tas_input.h index c95a130fc..4b4e6c417 100644 --- a/src/input_common/drivers/tas_input.h +++ b/src/input_common/drivers/tas_input.h @@ -5,11 +5,11 @@  #pragma once  #include <array> +#include <string> +#include <vector>  #include "common/common_types.h" -#include "common/settings_input.h"  #include "input_common/input_engine.h" -#include "input_common/main.h"  /*  To play back TAS scripts on Yuzu, select the folder with scripts in the configuration menu below @@ -81,46 +81,46 @@ enum class TasState {      Stopped,  }; -class Tas final : public InputCommon::InputEngine { +class Tas final : public InputEngine {  public: -    explicit Tas(const std::string& input_engine_); -    ~Tas(); +    explicit Tas(std::string input_engine_); +    ~Tas() override;      /**       * Changes the input status that will be stored in each frame -     * @param buttons: bitfield with the status of the buttons -     * @param left_axis: value of the left axis -     * @param right_axis: value of the right axis +     * @param buttons    Bitfield with the status of the buttons +     * @param left_axis  Value of the left axis +     * @param right_axis Value of the right axis       */      void RecordInput(u64 buttons, TasAnalog left_axis, TasAnalog right_axis);      // Main loop that records or executes input      void UpdateThread(); -    //  Sets the flag to start or stop the TAS command excecution and swaps controllers profiles +    // Sets the flag to start or stop the TAS command execution and swaps controllers profiles      void StartStop(); -    //  Stop the TAS and reverts any controller profile +    // Stop the TAS and reverts any controller profile      void Stop(); -    // Sets the flag to reload the file and start from the begining in the next update +    // Sets the flag to reload the file and start from the beginning in the next update      void Reset();      /**       * Sets the flag to enable or disable recording of inputs -     * @return Returns true if the current recording status is enabled +     * @returns true if the current recording status is enabled       */      bool Record();      /**       * Saves contents of record_commands on a file -     * @param overwrite_file: Indicates if player 1 should be overwritten +     * @param overwrite_file Indicates if player 1 should be overwritten       */      void SaveRecording(bool overwrite_file);      /**       * Returns the current status values of TAS playback/recording -     * @return Tuple of +     * @returns A Tuple of       * TasState indicating the current state out of Running ;       * Current playback progress ;       * Total length of script file currently loaded or being recorded @@ -128,6 +128,8 @@ public:      std::tuple<TasState, size_t, size_t> GetStatus() const;  private: +    enum class TasAxis : u8; +      struct TASCommand {          u64 buttons{};          TasAnalog l_axis{}; @@ -137,29 +139,31 @@ private:      /// Loads TAS files from all players      void LoadTasFiles(); -    /** Loads TAS file from the specified player -     * @param player_index: player number to save the script -     * @param file_index: script number of the file +    /** +     * Loads TAS file from the specified player +     * @param player_index Player number to save the script +     * @param file_index   Script number of the file       */      void LoadTasFile(size_t player_index, size_t file_index); -    /** Writes a TAS file from the recorded commands -     * @param file_name: name of the file to be written +    /** +     * Writes a TAS file from the recorded commands +     * @param file_name Name of the file to be written       */ -    void WriteTasFile(std::u8string file_name); +    void WriteTasFile(std::u8string_view file_name);      /**       * Parses a string containing the axis values. X and Y have a range from -32767 to 32767 -     * @param line: string containing axis values with the following format "x;y" -     * @return Returns a TAS analog object with axis values with range from -1.0 to 1.0 +     * @param line String containing axis values with the following format "x;y" +     * @returns A TAS analog object with axis values with range from -1.0 to 1.0       */      TasAnalog ReadCommandAxis(const std::string& line) const;      /**       * Parses a string containing the button values. Each button is represented by it's text format       * specified in text_to_tas_button array -     * @param line: string containing button name with the following format "a;b;c;d..." -     * @return Returns a u64 with each bit representing the status of a button +     * @param line string containing button name with the following format "a;b;c;d..." +     * @returns A u64 with each bit representing the status of a button       */      u64 ReadCommandButtons(const std::string& line) const; @@ -170,17 +174,20 @@ private:      /**       * Converts an u64 containing the button status into the text equivalent -     * @param buttons: bitfield with the status of the buttons -     * @return Returns a string with the name of the buttons to be written to the file +     * @param buttons Bitfield with the status of the buttons +     * @returns A string with the name of the buttons to be written to the file       */      std::string WriteCommandButtons(u64 buttons) const;      /**       * Converts an TAS analog object containing the axis status into the text equivalent -     * @param data: value of the axis -     * @return A string with the value of the axis to be written to the file +     * @param analog Value of the axis +     * @returns A string with the value of the axis to be written to the file       */ -    std::string WriteCommandAxis(TasAnalog data) const; +    std::string WriteCommandAxis(TasAnalog analog) const; + +    /// Sets an axis for a particular pad to the given value. +    void SetTasAxis(const PadIdentifier& identifier, TasAxis axis, f32 value);      size_t script_length{0};      bool is_recording{false}; diff --git a/src/input_common/drivers/touch_screen.cpp b/src/input_common/drivers/touch_screen.cpp index 45b3086f6..880781825 100644 --- a/src/input_common/drivers/touch_screen.cpp +++ b/src/input_common/drivers/touch_screen.cpp @@ -13,7 +13,7 @@ constexpr PadIdentifier identifier = {      .pad = 0,  }; -TouchScreen::TouchScreen(const std::string& input_engine_) : InputEngine(input_engine_) { +TouchScreen::TouchScreen(std::string input_engine_) : InputEngine(std::move(input_engine_)) {      PreSetController(identifier);  } diff --git a/src/input_common/drivers/touch_screen.h b/src/input_common/drivers/touch_screen.h index 25c11e8bf..bf395c40b 100644 --- a/src/input_common/drivers/touch_screen.h +++ b/src/input_common/drivers/touch_screen.h @@ -12,9 +12,9 @@ namespace InputCommon {   * A button device factory representing a keyboard. It receives keyboard events and forward them   * to all button devices it created.   */ -class TouchScreen final : public InputCommon::InputEngine { +class TouchScreen final : public InputEngine {  public: -    explicit TouchScreen(const std::string& input_engine_); +    explicit TouchScreen(std::string input_engine_);      /**       * Signals that mouse has moved. diff --git a/src/input_common/drivers/udp_client.cpp b/src/input_common/drivers/udp_client.cpp index fdee0f2d5..4ab991a7d 100644 --- a/src/input_common/drivers/udp_client.cpp +++ b/src/input_common/drivers/udp_client.cpp @@ -136,7 +136,7 @@ static void SocketLoop(Socket* socket) {      socket->Loop();  } -UDPClient::UDPClient(const std::string& input_engine_) : InputEngine(input_engine_) { +UDPClient::UDPClient(std::string input_engine_) : InputEngine(std::move(input_engine_)) {      LOG_INFO(Input, "Udp Initialization started");      ReloadSockets();  } diff --git a/src/input_common/drivers/udp_client.h b/src/input_common/drivers/udp_client.h index 5d483f26b..1adc947c4 100644 --- a/src/input_common/drivers/udp_client.h +++ b/src/input_common/drivers/udp_client.h @@ -49,10 +49,10 @@ struct DeviceStatus {   * A button device factory representing a keyboard. It receives keyboard events and forward them   * to all button devices it created.   */ -class UDPClient final : public InputCommon::InputEngine { +class UDPClient final : public InputEngine {  public: -    explicit UDPClient(const std::string& input_engine_); -    ~UDPClient(); +    explicit UDPClient(std::string input_engine_); +    ~UDPClient() override;      void ReloadSockets(); diff --git a/src/input_common/helpers/stick_from_buttons.cpp b/src/input_common/helpers/stick_from_buttons.cpp index 77fcd655e..e23394f5f 100644 --- a/src/input_common/helpers/stick_from_buttons.cpp +++ b/src/input_common/helpers/stick_from_buttons.cpp @@ -19,23 +19,36 @@ public:          : up(std::move(up_)), down(std::move(down_)), left(std::move(left_)),            right(std::move(right_)), modifier(std::move(modifier_)), modifier_scale(modifier_scale_),            modifier_angle(modifier_angle_) { -        Common::Input::InputCallback button_up_callback{ -            [this](Common::Input::CallbackStatus callback_) { UpdateUpButtonStatus(callback_); }}; -        Common::Input::InputCallback button_down_callback{ -            [this](Common::Input::CallbackStatus callback_) { UpdateDownButtonStatus(callback_); }}; -        Common::Input::InputCallback button_left_callback{ -            [this](Common::Input::CallbackStatus callback_) { UpdateLeftButtonStatus(callback_); }}; -        Common::Input::InputCallback button_right_callback{ -            [this](Common::Input::CallbackStatus callback_) { -                UpdateRightButtonStatus(callback_); -            }}; -        Common::Input::InputCallback button_modifier_callback{ -            [this](Common::Input::CallbackStatus callback_) { UpdateModButtonStatus(callback_); }}; -        up->SetCallback(button_up_callback); -        down->SetCallback(button_down_callback); -        left->SetCallback(button_left_callback); -        right->SetCallback(button_right_callback); -        modifier->SetCallback(button_modifier_callback); +        up->SetCallback({ +            .on_change = +                [this](const Common::Input::CallbackStatus& callback_) { +                    UpdateUpButtonStatus(callback_); +                }, +        }); +        down->SetCallback({ +            .on_change = +                [this](const Common::Input::CallbackStatus& callback_) { +                    UpdateDownButtonStatus(callback_); +                }, +        }); +        left->SetCallback({ +            .on_change = +                [this](const Common::Input::CallbackStatus& callback_) { +                    UpdateLeftButtonStatus(callback_); +                }, +        }); +        right->SetCallback({ +            .on_change = +                [this](const Common::Input::CallbackStatus& callback_) { +                    UpdateRightButtonStatus(callback_); +                }, +        }); +        modifier->SetCallback({ +            .on_change = +                [this](const Common::Input::CallbackStatus& callback_) { +                    UpdateModButtonStatus(callback_); +                }, +        });          last_x_axis_value = 0.0f;          last_y_axis_value = 0.0f;      } @@ -133,27 +146,27 @@ public:          }      } -    void UpdateUpButtonStatus(Common::Input::CallbackStatus button_callback) { +    void UpdateUpButtonStatus(const Common::Input::CallbackStatus& button_callback) {          up_status = button_callback.button_status.value;          UpdateStatus();      } -    void UpdateDownButtonStatus(Common::Input::CallbackStatus button_callback) { +    void UpdateDownButtonStatus(const Common::Input::CallbackStatus& button_callback) {          down_status = button_callback.button_status.value;          UpdateStatus();      } -    void UpdateLeftButtonStatus(Common::Input::CallbackStatus button_callback) { +    void UpdateLeftButtonStatus(const Common::Input::CallbackStatus& button_callback) {          left_status = button_callback.button_status.value;          UpdateStatus();      } -    void UpdateRightButtonStatus(Common::Input::CallbackStatus button_callback) { +    void UpdateRightButtonStatus(const Common::Input::CallbackStatus& button_callback) {          right_status = button_callback.button_status.value;          UpdateStatus();      } -    void UpdateModButtonStatus(Common::Input::CallbackStatus button_callback) { +    void UpdateModButtonStatus(const Common::Input::CallbackStatus& button_callback) {          modifier_status = button_callback.button_status.value;          UpdateStatus();      } @@ -265,18 +278,18 @@ private:      Button left;      Button right;      Button modifier; -    float modifier_scale; -    float modifier_angle; +    float modifier_scale{}; +    float modifier_angle{};      float angle{};      float goal_angle{};      float amplitude{}; -    bool up_status; -    bool down_status; -    bool left_status; -    bool right_status; -    bool modifier_status; -    float last_x_axis_value; -    float last_y_axis_value; +    bool up_status{}; +    bool down_status{}; +    bool left_status{}; +    bool right_status{}; +    bool modifier_status{}; +    float last_x_axis_value{}; +    float last_y_axis_value{};      const Common::Input::AnalogProperties properties{0.0f, 1.0f, 0.5f, 0.0f, false};      std::chrono::time_point<std::chrono::steady_clock> last_update;  }; diff --git a/src/input_common/helpers/touch_from_buttons.cpp b/src/input_common/helpers/touch_from_buttons.cpp index 35d60bc90..ece1e3b32 100644 --- a/src/input_common/helpers/touch_from_buttons.cpp +++ b/src/input_common/helpers/touch_from_buttons.cpp @@ -14,10 +14,13 @@ public:      using Button = std::unique_ptr<Common::Input::InputDevice>;      TouchFromButtonDevice(Button button_, int touch_id_, float x_, float y_)          : button(std::move(button_)), touch_id(touch_id_), x(x_), y(y_) { -        Common::Input::InputCallback button_up_callback{ -            [this](Common::Input::CallbackStatus callback_) { UpdateButtonStatus(callback_); }};          last_button_value = false; -        button->SetCallback(button_up_callback); +        button->SetCallback({ +            .on_change = +                [this](const Common::Input::CallbackStatus& callback_) { +                    UpdateButtonStatus(callback_); +                }, +        });          button->ForceUpdate();      } @@ -47,7 +50,7 @@ public:          return status;      } -    void UpdateButtonStatus(Common::Input::CallbackStatus button_callback) { +    void UpdateButtonStatus(const Common::Input::CallbackStatus& button_callback) {          const Common::Input::CallbackStatus status{              .type = Common::Input::InputType::Touch,              .touch_status = GetStatus(button_callback.button_status.value), diff --git a/src/input_common/input_engine.cpp b/src/input_common/input_engine.cpp index 2b2105376..9c17ca4f7 100644 --- a/src/input_common/input_engine.cpp +++ b/src/input_common/input_engine.cpp @@ -10,41 +10,31 @@ namespace InputCommon {  void InputEngine::PreSetController(const PadIdentifier& identifier) {      std::lock_guard lock{mutex}; -    if (!controller_list.contains(identifier)) { -        controller_list.insert_or_assign(identifier, ControllerData{}); -    } +    controller_list.try_emplace(identifier);  }  void InputEngine::PreSetButton(const PadIdentifier& identifier, int button) {      std::lock_guard lock{mutex};      ControllerData& controller = controller_list.at(identifier); -    if (!controller.buttons.contains(button)) { -        controller.buttons.insert_or_assign(button, false); -    } +    controller.buttons.try_emplace(button, false);  }  void InputEngine::PreSetHatButton(const PadIdentifier& identifier, int button) {      std::lock_guard lock{mutex};      ControllerData& controller = controller_list.at(identifier); -    if (!controller.hat_buttons.contains(button)) { -        controller.hat_buttons.insert_or_assign(button, u8{0}); -    } +    controller.hat_buttons.try_emplace(button, u8{0});  }  void InputEngine::PreSetAxis(const PadIdentifier& identifier, int axis) {      std::lock_guard lock{mutex};      ControllerData& controller = controller_list.at(identifier); -    if (!controller.axes.contains(axis)) { -        controller.axes.insert_or_assign(axis, 0.0f); -    } +    controller.axes.try_emplace(axis, 0.0f);  }  void InputEngine::PreSetMotion(const PadIdentifier& identifier, int motion) {      std::lock_guard lock{mutex};      ControllerData& controller = controller_list.at(identifier); -    if (!controller.motions.contains(motion)) { -        controller.motions.insert_or_assign(motion, BasicMotion{}); -    } +    controller.motions.try_emplace(motion);  }  void InputEngine::SetButton(const PadIdentifier& identifier, int button, bool value) { @@ -91,7 +81,7 @@ void InputEngine::SetBattery(const PadIdentifier& identifier, BatteryLevel value      TriggerOnBatteryChange(identifier, value);  } -void InputEngine::SetMotion(const PadIdentifier& identifier, int motion, BasicMotion value) { +void InputEngine::SetMotion(const PadIdentifier& identifier, int motion, const BasicMotion& value) {      {          std::lock_guard lock{mutex};          ControllerData& controller = controller_list.at(identifier); @@ -104,85 +94,93 @@ void InputEngine::SetMotion(const PadIdentifier& identifier, int motion, BasicMo  bool InputEngine::GetButton(const PadIdentifier& identifier, int button) const {      std::lock_guard lock{mutex}; -    if (!controller_list.contains(identifier)) { +    const auto controller_iter = controller_list.find(identifier); +    if (controller_iter == controller_list.cend()) {          LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.Format(),                    identifier.pad, identifier.port);          return false;      } -    ControllerData controller = controller_list.at(identifier); -    if (!controller.buttons.contains(button)) { +    const ControllerData& controller = controller_iter->second; +    const auto button_iter = controller.buttons.find(button); +    if (button_iter == controller.buttons.cend()) {          LOG_ERROR(Input, "Invalid button {}", button);          return false;      } -    return controller.buttons.at(button); +    return button_iter->second;  }  bool InputEngine::GetHatButton(const PadIdentifier& identifier, int button, u8 direction) const {      std::lock_guard lock{mutex}; -    if (!controller_list.contains(identifier)) { +    const auto controller_iter = controller_list.find(identifier); +    if (controller_iter == controller_list.cend()) {          LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.Format(),                    identifier.pad, identifier.port);          return false;      } -    ControllerData controller = controller_list.at(identifier); -    if (!controller.hat_buttons.contains(button)) { +    const ControllerData& controller = controller_iter->second; +    const auto hat_iter = controller.hat_buttons.find(button); +    if (hat_iter == controller.hat_buttons.cend()) {          LOG_ERROR(Input, "Invalid hat button {}", button);          return false;      } -    return (controller.hat_buttons.at(button) & direction) != 0; +    return (hat_iter->second & direction) != 0;  }  f32 InputEngine::GetAxis(const PadIdentifier& identifier, int axis) const {      std::lock_guard lock{mutex}; -    if (!controller_list.contains(identifier)) { +    const auto controller_iter = controller_list.find(identifier); +    if (controller_iter == controller_list.cend()) {          LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.Format(),                    identifier.pad, identifier.port);          return 0.0f;      } -    ControllerData controller = controller_list.at(identifier); -    if (!controller.axes.contains(axis)) { +    const ControllerData& controller = controller_iter->second; +    const auto axis_iter = controller.axes.find(axis); +    if (axis_iter == controller.axes.cend()) {          LOG_ERROR(Input, "Invalid axis {}", axis);          return 0.0f;      } -    return controller.axes.at(axis); +    return axis_iter->second;  }  BatteryLevel InputEngine::GetBattery(const PadIdentifier& identifier) const {      std::lock_guard lock{mutex}; -    if (!controller_list.contains(identifier)) { +    const auto controller_iter = controller_list.find(identifier); +    if (controller_iter == controller_list.cend()) {          LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.Format(),                    identifier.pad, identifier.port);          return BatteryLevel::Charging;      } -    ControllerData controller = controller_list.at(identifier); +    const ControllerData& controller = controller_iter->second;      return controller.battery;  }  BasicMotion InputEngine::GetMotion(const PadIdentifier& identifier, int motion) const {      std::lock_guard lock{mutex}; -    if (!controller_list.contains(identifier)) { +    const auto controller_iter = controller_list.find(identifier); +    if (controller_iter == controller_list.cend()) {          LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.Format(),                    identifier.pad, identifier.port);          return {};      } -    ControllerData controller = controller_list.at(identifier); +    const ControllerData& controller = controller_iter->second;      return controller.motions.at(motion);  }  void InputEngine::ResetButtonState() { -    for (std::pair<PadIdentifier, ControllerData> controller : controller_list) { -        for (std::pair<int, bool> button : controller.second.buttons) { +    for (const auto& controller : controller_list) { +        for (const auto& button : controller.second.buttons) {              SetButton(controller.first, button.first, false);          } -        for (std::pair<int, bool> button : controller.second.hat_buttons) { +        for (const auto& button : controller.second.hat_buttons) {              SetHatButton(controller.first, button.first, false);          }      }  }  void InputEngine::ResetAnalogState() { -    for (std::pair<PadIdentifier, ControllerData> controller : controller_list) { -        for (std::pair<int, float> axis : controller.second.axes) { +    for (const auto& controller : controller_list) { +        for (const auto& axis : controller.second.axes) {              SetAxis(controller.first, axis.first, 0.0);          }      } @@ -190,7 +188,7 @@ void InputEngine::ResetAnalogState() {  void InputEngine::TriggerOnButtonChange(const PadIdentifier& identifier, int button, bool value) {      std::lock_guard lock{mutex_callback}; -    for (const std::pair<int, InputIdentifier> poller_pair : callback_list) { +    for (const auto& poller_pair : callback_list) {          const InputIdentifier& poller = poller_pair.second;          if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::Button, button)) {              continue; @@ -218,7 +216,7 @@ void InputEngine::TriggerOnButtonChange(const PadIdentifier& identifier, int but  void InputEngine::TriggerOnHatButtonChange(const PadIdentifier& identifier, int button, u8 value) {      std::lock_guard lock{mutex_callback}; -    for (const std::pair<int, InputIdentifier> poller_pair : callback_list) { +    for (const auto& poller_pair : callback_list) {          const InputIdentifier& poller = poller_pair.second;          if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::HatButton, button)) {              continue; @@ -247,7 +245,7 @@ void InputEngine::TriggerOnHatButtonChange(const PadIdentifier& identifier, int  void InputEngine::TriggerOnAxisChange(const PadIdentifier& identifier, int axis, f32 value) {      std::lock_guard lock{mutex_callback}; -    for (const std::pair<int, InputIdentifier> poller_pair : callback_list) { +    for (const auto& poller_pair : callback_list) {          const InputIdentifier& poller = poller_pair.second;          if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::Analog, axis)) {              continue; @@ -274,7 +272,7 @@ void InputEngine::TriggerOnAxisChange(const PadIdentifier& identifier, int axis,  void InputEngine::TriggerOnBatteryChange(const PadIdentifier& identifier,                                           [[maybe_unused]] BatteryLevel value) {      std::lock_guard lock{mutex_callback}; -    for (const std::pair<int, InputIdentifier> poller_pair : callback_list) { +    for (const auto& poller_pair : callback_list) {          const InputIdentifier& poller = poller_pair.second;          if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::Battery, 0)) {              continue; @@ -286,9 +284,9 @@ void InputEngine::TriggerOnBatteryChange(const PadIdentifier& identifier,  }  void InputEngine::TriggerOnMotionChange(const PadIdentifier& identifier, int motion, -                                        BasicMotion value) { +                                        const BasicMotion& value) {      std::lock_guard lock{mutex_callback}; -    for (const std::pair<int, InputIdentifier> poller_pair : callback_list) { +    for (const auto& poller_pair : callback_list) {          const InputIdentifier& poller = poller_pair.second;          if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::Motion, motion)) {              continue; @@ -342,7 +340,7 @@ const std::string& InputEngine::GetEngineName() const {  int InputEngine::SetCallback(InputIdentifier input_identifier) {      std::lock_guard lock{mutex_callback}; -    callback_list.insert_or_assign(last_callback_key, input_identifier); +    callback_list.insert_or_assign(last_callback_key, std::move(input_identifier));      return last_callback_key++;  } diff --git a/src/input_common/input_engine.h b/src/input_common/input_engine.h index 02272b3f8..390581c94 100644 --- a/src/input_common/input_engine.h +++ b/src/input_common/input_engine.h @@ -23,15 +23,15 @@ struct PadIdentifier {      friend constexpr bool operator==(const PadIdentifier&, const PadIdentifier&) = default;  }; -// Basic motion data containing data from the sensors and a timestamp in microsecons +// Basic motion data containing data from the sensors and a timestamp in microseconds  struct BasicMotion { -    float gyro_x; -    float gyro_y; -    float gyro_z; -    float accel_x; -    float accel_y; -    float accel_z; -    u64 delta_timestamp; +    float gyro_x{}; +    float gyro_y{}; +    float gyro_z{}; +    float accel_x{}; +    float accel_y{}; +    float accel_z{}; +    u64 delta_timestamp{};  };  // Stages of a battery charge @@ -102,9 +102,7 @@ struct InputIdentifier {  class InputEngine {  public: -    explicit InputEngine(const std::string& input_engine_) : input_engine(input_engine_) { -        callback_list.clear(); -    } +    explicit InputEngine(std::string input_engine_) : input_engine{std::move(input_engine_)} {}      virtual ~InputEngine() = default; @@ -116,14 +114,12 @@ public:      // Sets a led pattern for a controller      virtual void SetLeds([[maybe_unused]] const PadIdentifier& identifier, -                         [[maybe_unused]] const Common::Input::LedStatus led_status) { -        return; -    } +                         [[maybe_unused]] const Common::Input::LedStatus& led_status) {}      // Sets rumble to a controller      virtual Common::Input::VibrationError SetRumble(          [[maybe_unused]] const PadIdentifier& identifier, -        [[maybe_unused]] const Common::Input::VibrationStatus vibration) { +        [[maybe_unused]] const Common::Input::VibrationStatus& vibration) {          return Common::Input::VibrationError::NotSupported;      } @@ -140,36 +136,36 @@ public:      /// Used for automapping features      virtual std::vector<Common::ParamPackage> GetInputDevices() const {          return {}; -    }; +    }      /// Retrieves the button mappings for the given device -    virtual InputCommon::ButtonMapping GetButtonMappingForDevice( +    virtual ButtonMapping GetButtonMappingForDevice(          [[maybe_unused]] const Common::ParamPackage& params) {          return {}; -    }; +    }      /// Retrieves the analog mappings for the given device -    virtual InputCommon::AnalogMapping GetAnalogMappingForDevice( +    virtual AnalogMapping GetAnalogMappingForDevice(          [[maybe_unused]] const Common::ParamPackage& params) {          return {}; -    }; +    }      /// Retrieves the motion mappings for the given device -    virtual InputCommon::MotionMapping GetMotionMappingForDevice( +    virtual MotionMapping GetMotionMappingForDevice(          [[maybe_unused]] const Common::ParamPackage& params) {          return {}; -    }; +    }      /// Retrieves the name of the given input.      virtual Common::Input::ButtonNames GetUIName(          [[maybe_unused]] const Common::ParamPackage& params) const {          return Common::Input::ButtonNames::Engine; -    }; +    }      /// Retrieves the index number of the given hat button direction      virtual u8 GetHatButtonId([[maybe_unused]] const std::string& direction_name) const {          return 0; -    }; +    }      void PreSetController(const PadIdentifier& identifier);      void PreSetButton(const PadIdentifier& identifier, int button); @@ -194,7 +190,7 @@ protected:      void SetHatButton(const PadIdentifier& identifier, int button, u8 value);      void SetAxis(const PadIdentifier& identifier, int axis, f32 value);      void SetBattery(const PadIdentifier& identifier, BatteryLevel value); -    void SetMotion(const PadIdentifier& identifier, int motion, BasicMotion value); +    void SetMotion(const PadIdentifier& identifier, int motion, const BasicMotion& value);      virtual std::string GetHatButtonName([[maybe_unused]] u8 direction_value) const {          return "Unknown"; @@ -206,14 +202,15 @@ private:          std::unordered_map<int, u8> hat_buttons;          std::unordered_map<int, float> axes;          std::unordered_map<int, BasicMotion> motions; -        BatteryLevel battery; +        BatteryLevel battery{};      };      void TriggerOnButtonChange(const PadIdentifier& identifier, int button, bool value);      void TriggerOnHatButtonChange(const PadIdentifier& identifier, int button, u8 value); -    void TriggerOnAxisChange(const PadIdentifier& identifier, int button, f32 value); +    void TriggerOnAxisChange(const PadIdentifier& identifier, int axis, f32 value);      void TriggerOnBatteryChange(const PadIdentifier& identifier, BatteryLevel value); -    void TriggerOnMotionChange(const PadIdentifier& identifier, int motion, BasicMotion value); +    void TriggerOnMotionChange(const PadIdentifier& identifier, int motion, +                               const BasicMotion& value);      bool IsInputIdentifierEqual(const InputIdentifier& input_identifier,                                  const PadIdentifier& identifier, EngineInputType type, diff --git a/src/input_common/input_mapping.h b/src/input_common/input_mapping.h index 44eb8ad9a..93564b5f8 100644 --- a/src/input_common/input_mapping.h +++ b/src/input_common/input_mapping.h @@ -14,8 +14,8 @@ public:      MappingFactory();      /** -     * Resets all varables to beggin the mapping process -     * @param "type": type of input desired to be returned +     * Resets all variables to begin the mapping process +     * @param type type of input desired to be returned       */      void BeginMapping(Polling::InputType type); @@ -24,8 +24,8 @@ public:      /**       * Registers mapping input data from the driver -     * @param "data": An struct containing all the information needed to create a proper -     * ParamPackage +     * @param data A struct containing all the information needed to create a proper +     *             ParamPackage       */      void RegisterInput(const MappingData& data); @@ -34,42 +34,42 @@ public:  private:      /** -     * If provided data satisfies the requeriments it will push an element to the input_queue +     * If provided data satisfies the requirements it will push an element to the input_queue       * Supported input:       *     - Button: Creates a basic button ParamPackage       *     - HatButton: Creates a basic hat button ParamPackage       *     - Analog: Creates a basic analog ParamPackage -     * @param "data": An struct containing all the information needed to create a proper +     * @param data A struct containing all the information needed to create a proper       * ParamPackage       */      void RegisterButton(const MappingData& data);      /** -     * If provided data satisfies the requeriments it will push an element to the input_queue +     * If provided data satisfies the requirements it will push an element to the input_queue       * Supported input:       *     - Button, HatButton: Pass the data to RegisterButton       *     - Analog: Stores the first axis and on the second axis creates a basic stick ParamPackage -     * @param "data": An struct containing all the information needed to create a proper -     * ParamPackage +     * @param data A struct containing all the information needed to create a proper +     *             ParamPackage       */      void RegisterStick(const MappingData& data);      /** -     * If provided data satisfies the requeriments it will push an element to the input_queue +     * If provided data satisfies the requirements it will push an element to the input_queue       * Supported input:       *     - Button, HatButton: Pass the data to RegisterButton       *     - Analog: Stores the first two axis and on the third axis creates a basic Motion       * ParamPackage       *     - Motion: Creates a basic Motion ParamPackage -     * @param "data": An struct containing all the information needed to create a proper -     * ParamPackage +     * @param data A struct containing all the information needed to create a proper +     *             ParamPackage       */      void RegisterMotion(const MappingData& data);      /**       * Returns true if driver can be mapped -     * @param "data": An struct containing all the information needed to create a proper -     * ParamPackage +     * @param data A struct containing all the information needed to create a proper +     *             ParamPackage       */      bool IsDriverValid(const MappingData& data) const; diff --git a/src/input_common/input_poller.cpp b/src/input_common/input_poller.cpp index 7e4eafded..7b370335f 100644 --- a/src/input_common/input_poller.cpp +++ b/src/input_common/input_poller.cpp @@ -12,8 +12,7 @@ namespace InputCommon {  class DummyInput final : public Common::Input::InputDevice {  public: -    explicit DummyInput() {} -    ~DummyInput() {} +    explicit DummyInput() = default;  };  class InputFromButton final : public Common::Input::InputDevice { @@ -33,7 +32,7 @@ public:          callback_key = input_engine->SetCallback(input_identifier);      } -    ~InputFromButton() { +    ~InputFromButton() override {          input_engine->DeleteCallback(callback_key);      } @@ -45,7 +44,7 @@ public:          };      } -    void ForceUpdate() { +    void ForceUpdate() override {          const Common::Input::CallbackStatus status{              .type = Common::Input::InputType::Button,              .button_status = GetStatus(), @@ -94,7 +93,7 @@ public:          callback_key = input_engine->SetCallback(input_identifier);      } -    ~InputFromHatButton() { +    ~InputFromHatButton() override {          input_engine->DeleteCallback(callback_key);      } @@ -106,7 +105,7 @@ public:          };      } -    void ForceUpdate() { +    void ForceUpdate() override {          const Common::Input::CallbackStatus status{              .type = Common::Input::InputType::Button,              .button_status = GetStatus(), @@ -167,7 +166,7 @@ public:          callback_key_y = input_engine->SetCallback(y_input_identifier);      } -    ~InputFromStick() { +    ~InputFromStick() override {          input_engine->DeleteCallback(callback_key_x);          input_engine->DeleteCallback(callback_key_y);      } @@ -190,7 +189,7 @@ public:          return status;      } -    void ForceUpdate() { +    void ForceUpdate() override {          const Common::Input::CallbackStatus status{              .type = Common::Input::InputType::Stick,              .stick_status = GetStatus(), @@ -266,7 +265,7 @@ public:          callback_key_y = input_engine->SetCallback(y_input_identifier);      } -    ~InputFromTouch() { +    ~InputFromTouch() override {          input_engine->DeleteCallback(callback_key_button);          input_engine->DeleteCallback(callback_key_x);          input_engine->DeleteCallback(callback_key_y); @@ -352,7 +351,7 @@ public:          axis_callback_key = input_engine->SetCallback(axis_input_identifier);      } -    ~InputFromTrigger() { +    ~InputFromTrigger() override {          input_engine->DeleteCallback(callback_key_button);          input_engine->DeleteCallback(axis_callback_key);      } @@ -419,7 +418,7 @@ public:          callback_key = input_engine->SetCallback(input_identifier);      } -    ~InputFromAnalog() { +    ~InputFromAnalog() override {          input_engine->DeleteCallback(callback_key);      } @@ -466,7 +465,7 @@ public:          callback_key = input_engine->SetCallback(input_identifier);      } -    ~InputFromBattery() { +    ~InputFromBattery() override {          input_engine->DeleteCallback(callback_key);      } @@ -474,7 +473,7 @@ public:          return static_cast<Common::Input::BatteryLevel>(input_engine->GetBattery(identifier));      } -    void ForceUpdate() { +    void ForceUpdate() override {          const Common::Input::CallbackStatus status{              .type = Common::Input::InputType::Battery,              .battery_status = GetStatus(), @@ -518,7 +517,7 @@ public:          callback_key = input_engine->SetCallback(input_identifier);      } -    ~InputFromMotion() { +    ~InputFromMotion() override {          input_engine->DeleteCallback(callback_key);      } @@ -593,7 +592,7 @@ public:          callback_key_z = input_engine->SetCallback(z_input_identifier);      } -    ~InputFromAxisMotion() { +    ~InputFromAxisMotion() override {          input_engine->DeleteCallback(callback_key_x);          input_engine->DeleteCallback(callback_key_y);          input_engine->DeleteCallback(callback_key_z); @@ -618,7 +617,7 @@ public:          return status;      } -    void ForceUpdate() { +    void ForceUpdate() override {          const Common::Input::CallbackStatus status{              .type = Common::Input::InputType::Motion,              .motion_status = GetStatus(), @@ -668,16 +667,16 @@ public:      explicit OutputFromIdentifier(PadIdentifier identifier_, InputEngine* input_engine_)          : identifier(identifier_), input_engine(input_engine_) {} -    virtual void SetLED(Common::Input::LedStatus led_status) { +    void SetLED(const Common::Input::LedStatus& led_status) override {          input_engine->SetLeds(identifier, led_status);      } -    virtual Common::Input::VibrationError SetVibration( -        Common::Input::VibrationStatus vibration_status) { +    Common::Input::VibrationError SetVibration( +        const Common::Input::VibrationStatus& vibration_status) override {          return input_engine->SetRumble(identifier, vibration_status);      } -    virtual Common::Input::PollingError SetPollingMode(Common::Input::PollingMode polling_mode) { +    Common::Input::PollingError SetPollingMode(Common::Input::PollingMode polling_mode) override {          return input_engine->SetPollingMode(identifier, polling_mode);      } diff --git a/src/input_common/input_poller.h b/src/input_common/input_poller.h index 573f09fde..8a0977d58 100644 --- a/src/input_common/input_poller.h +++ b/src/input_common/input_poller.h @@ -13,9 +13,6 @@ class Factory;  namespace InputCommon {  class InputEngine; -/** - * An Input factory. It receives input events and forward them to all input devices it created. - */  class OutputFactory final : public Common::Input::Factory<Common::Input::OutputDevice> {  public: @@ -24,10 +21,10 @@ public:      /**       * Creates an output device from the parameters given.       * @param params contains parameters for creating the device: -     * @param    - "guid": text string for identifing controllers -     * @param    - "port": port of the connected device -     * @param    - "pad": slot of the connected controller -     * @return an unique ouput device with the parameters specified +     *               - "guid" text string for identifying controllers +     *               - "port": port of the connected device +     *               - "pad": slot of the connected controller +     * @returns a unique output device with the parameters specified       */      std::unique_ptr<Common::Input::OutputDevice> Create(          const Common::ParamPackage& params) override; @@ -36,6 +33,9 @@ private:      std::shared_ptr<InputEngine> input_engine;  }; +/** + * An Input factory. It receives input events and forward them to all input devices it created. + */  class InputFactory final : public Common::Input::Factory<Common::Input::InputDevice> {  public:      explicit InputFactory(std::shared_ptr<InputEngine> input_engine_); @@ -54,16 +54,16 @@ public:       * - battery: Contains "battery"       * - output: Contains "output"       * @param params contains parameters for creating the device: -     * @param    - "code": the code of the keyboard key to bind with the input -     * @param    - "button": same as "code" but for controller buttons -     * @param    - "hat": similar as "button" but it's a group of hat buttons from SDL -     * @param    - "axis": the axis number of the axis to bind with the input -     * @param    - "motion": the motion number of the motion to bind with the input -     * @param    - "axis_x": same as axis but specifing horizontal direction -     * @param    - "axis_y": same as axis but specifing vertical direction -     * @param    - "axis_z": same as axis but specifing forward direction -     * @param    - "battery": Only used as a placeholder to set the input type -     * @return an unique input device with the parameters specified +     *               - "code": the code of the keyboard key to bind with the input +     *               - "button": same as "code" but for controller buttons +     *               - "hat": similar as "button" but it's a group of hat buttons from SDL +     *               - "axis": the axis number of the axis to bind with the input +     *               - "motion": the motion number of the motion to bind with the input +     *               - "axis_x": same as axis but specifying horizontal direction +     *               - "axis_y": same as axis but specifying vertical direction +     *               - "axis_z": same as axis but specifying forward direction +     *               - "battery": Only used as a placeholder to set the input type +     * @returns a unique input device with the parameters specified       */      std::unique_ptr<Common::Input::InputDevice> Create(const Common::ParamPackage& params) override; @@ -71,14 +71,14 @@ private:      /**       * Creates a button device from the parameters given.       * @param params contains parameters for creating the device: -     * @param    - "code": the code of the keyboard key to bind with the input -     * @param    - "button": same as "code" but for controller buttons -     * @param    - "toggle": press once to enable, press again to disable -     * @param    - "inverted": inverts the output of the button -     * @param    - "guid": text string for identifing controllers -     * @param    - "port": port of the connected device -     * @param    - "pad": slot of the connected controller -     * @return an unique input device with the parameters specified +     *               - "code": the code of the keyboard key to bind with the input +     *               - "button": same as "code" but for controller buttons +     *               - "toggle": press once to enable, press again to disable +     *               - "inverted": inverts the output of the button +     *               - "guid": text string for identifying controllers +     *               - "port": port of the connected device +     *               - "pad": slot of the connected controller +     * @returns a unique input device with the parameters specified       */      std::unique_ptr<Common::Input::InputDevice> CreateButtonDevice(          const Common::ParamPackage& params); @@ -86,14 +86,14 @@ private:      /**       * Creates a hat button device from the parameters given.       * @param params contains parameters for creating the device: -     * @param    - "button": the controller hat id to bind with the input -     * @param    - "direction": the direction id to be detected -     * @param    - "toggle": press once to enable, press again to disable -     * @param    - "inverted": inverts the output of the button -     * @param    - "guid": text string for identifing controllers -     * @param    - "port": port of the connected device -     * @param    - "pad": slot of the connected controller -     * @return an unique input device with the parameters specified +     *               - "button": the controller hat id to bind with the input +     *               - "direction": the direction id to be detected +     *               - "toggle": press once to enable, press again to disable +     *               - "inverted": inverts the output of the button +     *               - "guid": text string for identifying controllers +     *               - "port": port of the connected device +     *               - "pad": slot of the connected controller +     * @returns a unique input device with the parameters specified       */      std::unique_ptr<Common::Input::InputDevice> CreateHatButtonDevice(          const Common::ParamPackage& params); @@ -101,19 +101,19 @@ private:      /**       * Creates a stick device from the parameters given.       * @param params contains parameters for creating the device: -     * @param    - "axis_x": the controller horizontal axis id to bind with the input -     * @param    - "axis_y": the controller vertical axis id to bind with the input -     * @param    - "deadzone": the mimimum required value to be detected -     * @param    - "range": the maximum value required to reach 100% -     * @param    - "threshold": the mimimum required value to considered pressed -     * @param    - "offset_x": the amount of offset in the x axis -     * @param    - "offset_y": the amount of offset in the y axis -     * @param    - "invert_x": inverts the sign of the horizontal axis -     * @param    - "invert_y": inverts the sign of the vertical axis -     * @param    - "guid": text string for identifing controllers -     * @param    - "port": port of the connected device -     * @param    - "pad": slot of the connected controller -     * @return an unique input device with the parameters specified +     *               - "axis_x": the controller horizontal axis id to bind with the input +     *               - "axis_y": the controller vertical axis id to bind with the input +     *               - "deadzone": the minimum required value to be detected +     *               - "range": the maximum value required to reach 100% +     *               - "threshold": the minimum required value to considered pressed +     *               - "offset_x": the amount of offset in the x axis +     *               - "offset_y": the amount of offset in the y axis +     *               - "invert_x": inverts the sign of the horizontal axis +     *               - "invert_y": inverts the sign of the vertical axis +     *               - "guid": text string for identifying controllers +     *               - "port": port of the connected device +     *               - "pad": slot of the connected controller +     * @returns a unique input device with the parameters specified       */      std::unique_ptr<Common::Input::InputDevice> CreateStickDevice(          const Common::ParamPackage& params); @@ -121,16 +121,16 @@ private:      /**       * Creates an analog device from the parameters given.       * @param params contains parameters for creating the device: -     * @param    - "axis": the controller axis id to bind with the input -     * @param    - "deadzone": the mimimum required value to be detected -     * @param    - "range": the maximum value required to reach 100% -     * @param    - "threshold": the mimimum required value to considered pressed -     * @param    - "offset": the amount of offset in the axis -     * @param    - "invert": inverts the sign of the axis -     * @param    - "guid": text string for identifing controllers -     * @param    - "port": port of the connected device -     * @param    - "pad": slot of the connected controller -     * @return an unique input device with the parameters specified +     *               - "axis": the controller axis id to bind with the input +     *               - "deadzone": the minimum required value to be detected +     *               - "range": the maximum value required to reach 100% +     *               - "threshold": the minimum required value to considered pressed +     *               - "offset": the amount of offset in the axis +     *               - "invert": inverts the sign of the axis +     *               - "guid": text string for identifying controllers +     *               - "port": port of the connected device +     *               - "pad": slot of the connected controller +     * @returns a unique input device with the parameters specified       */      std::unique_ptr<Common::Input::InputDevice> CreateAnalogDevice(          const Common::ParamPackage& params); @@ -138,20 +138,20 @@ private:      /**       * Creates a trigger device from the parameters given.       * @param params contains parameters for creating the device: -     * @param    - "button": the controller hat id to bind with the input -     * @param    - "direction": the direction id to be detected -     * @param    - "toggle": press once to enable, press again to disable -     * @param    - "inverted": inverts the output of the button -     * @param    - "axis": the controller axis id to bind with the input -     * @param    - "deadzone": the mimimum required value to be detected -     * @param    - "range": the maximum value required to reach 100% -     * @param    - "threshold": the mimimum required value to considered pressed -     * @param    - "offset": the amount of offset in the axis -     * @param    - "invert": inverts the sign of the axis -     * @param    - "guid": text string for identifing controllers -     * @param    - "port": port of the connected device -     * @param    - "pad": slot of the connected controller -     * @return an unique input device with the parameters specified +     *               - "button": the controller hat id to bind with the input +     *               - "direction": the direction id to be detected +     *               - "toggle": press once to enable, press again to disable +     *               - "inverted": inverts the output of the button +     *               - "axis": the controller axis id to bind with the input +     *               - "deadzone": the minimum required value to be detected +     *               - "range": the maximum value required to reach 100% +     *               - "threshold": the minimum required value to considered pressed +     *               - "offset": the amount of offset in the axis +     *               - "invert": inverts the sign of the axis +     *               - "guid": text string for identifying controllers +     *               - "port": port of the connected device +     *               - "pad": slot of the connected controller +     * @returns a unique input device with the parameters specified       */      std::unique_ptr<Common::Input::InputDevice> CreateTriggerDevice(          const Common::ParamPackage& params); @@ -159,23 +159,23 @@ private:      /**       * Creates a touch device from the parameters given.       * @param params contains parameters for creating the device: -     * @param    - "button": the controller hat id to bind with the input -     * @param    - "direction": the direction id to be detected -     * @param    - "toggle": press once to enable, press again to disable -     * @param    - "inverted": inverts the output of the button -     * @param    - "axis_x": the controller horizontal axis id to bind with the input -     * @param    - "axis_y": the controller vertical axis id to bind with the input -     * @param    - "deadzone": the mimimum required value to be detected -     * @param    - "range": the maximum value required to reach 100% -     * @param    - "threshold": the mimimum required value to considered pressed -     * @param    - "offset_x": the amount of offset in the x axis -     * @param    - "offset_y": the amount of offset in the y axis -     * @param    - "invert_x": inverts the sign of the horizontal axis -     * @param    - "invert_y": inverts the sign of the vertical axis -     * @param    - "guid": text string for identifing controllers -     * @param    - "port": port of the connected device -     * @param    - "pad": slot of the connected controller -     * @return an unique input device with the parameters specified +     *               - "button": the controller hat id to bind with the input +     *               - "direction": the direction id to be detected +     *               - "toggle": press once to enable, press again to disable +     *               - "inverted": inverts the output of the button +     *               - "axis_x": the controller horizontal axis id to bind with the input +     *               - "axis_y": the controller vertical axis id to bind with the input +     *               - "deadzone": the minimum required value to be detected +     *               - "range": the maximum value required to reach 100% +     *               - "threshold": the minimum required value to considered pressed +     *               - "offset_x": the amount of offset in the x axis +     *               - "offset_y": the amount of offset in the y axis +     *               - "invert_x": inverts the sign of the horizontal axis +     *               - "invert_y": inverts the sign of the vertical axis +     *               - "guid": text string for identifying controllers +     *               - "port": port of the connected device +     *               - "pad": slot of the connected controller +     * @returns a unique input device with the parameters specified       */      std::unique_ptr<Common::Input::InputDevice> CreateTouchDevice(          const Common::ParamPackage& params); @@ -183,10 +183,10 @@ private:      /**       * Creates a battery device from the parameters given.       * @param params contains parameters for creating the device: -     * @param    - "guid": text string for identifing controllers -     * @param    - "port": port of the connected device -     * @param    - "pad": slot of the connected controller -     * @return an unique input device with the parameters specified +     *               - "guid": text string for identifying controllers +     *               - "port": port of the connected device +     *               - "pad": slot of the connected controller +     * @returns a unique input device with the parameters specified       */      std::unique_ptr<Common::Input::InputDevice> CreateBatteryDevice(          const Common::ParamPackage& params); @@ -194,21 +194,21 @@ private:      /**       * Creates a motion device from the parameters given.       * @param params contains parameters for creating the device: -     * @param    - "axis_x": the controller horizontal axis id to bind with the input -     * @param    - "axis_y": the controller vertical axis id to bind with the input -     * @param    - "axis_z": the controller fordward axis id to bind with the input -     * @param    - "deadzone": the mimimum required value to be detected -     * @param    - "range": the maximum value required to reach 100% -     * @param    - "offset_x": the amount of offset in the x axis -     * @param    - "offset_y": the amount of offset in the y axis -     * @param    - "offset_z": the amount of offset in the z axis -     * @param    - "invert_x": inverts the sign of the horizontal axis -     * @param    - "invert_y": inverts the sign of the vertical axis -     * @param    - "invert_z": inverts the sign of the fordward axis -     * @param    - "guid": text string for identifing controllers -     * @param    - "port": port of the connected device -     * @param    - "pad": slot of the connected controller -     * @return an unique input device with the parameters specified +     *               - "axis_x": the controller horizontal axis id to bind with the input +     *               - "axis_y": the controller vertical axis id to bind with the input +     *               - "axis_z": the controller forward axis id to bind with the input +     *               - "deadzone": the minimum required value to be detected +     *               - "range": the maximum value required to reach 100% +     *               - "offset_x": the amount of offset in the x axis +     *               - "offset_y": the amount of offset in the y axis +     *               - "offset_z": the amount of offset in the z axis +     *               - "invert_x": inverts the sign of the horizontal axis +     *               - "invert_y": inverts the sign of the vertical axis +     *               - "invert_z": inverts the sign of the forward axis +     *               - "guid": text string for identifying controllers +     *               - "port": port of the connected device +     *               - "pad": slot of the connected controller +     * @returns a unique input device with the parameters specified       */      std::unique_ptr<Common::Input::InputDevice> CreateMotionDevice(Common::ParamPackage params); diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp index e38cfbc6c..751e4792b 100644 --- a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp +++ b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp @@ -176,8 +176,8 @@ struct FormatTuple {      {VK_FORMAT_R32_UINT, Attachable | Storage},                // R32_UINT      {VK_FORMAT_R32_SINT, Attachable | Storage},                // R32_SINT      {VK_FORMAT_ASTC_8x8_UNORM_BLOCK},                          // ASTC_2D_8X8_UNORM -    {VK_FORMAT_UNDEFINED},                                     // ASTC_2D_8X5_UNORM -    {VK_FORMAT_UNDEFINED},                                     // ASTC_2D_5X4_UNORM +    {VK_FORMAT_ASTC_8x5_UNORM_BLOCK},                          // ASTC_2D_8X5_UNORM +    {VK_FORMAT_ASTC_5x4_UNORM_BLOCK},                          // ASTC_2D_5X4_UNORM      {VK_FORMAT_B8G8R8A8_SRGB, Attachable},                     // B8G8R8A8_SRGB      {VK_FORMAT_BC1_RGBA_SRGB_BLOCK},                           // BC1_RGBA_SRGB      {VK_FORMAT_BC2_SRGB_BLOCK},                                // BC2_SRGB diff --git a/src/yuzu/applets/qt_software_keyboard.cpp b/src/yuzu/applets/qt_software_keyboard.cpp index de7f98c4f..c3857fc98 100644 --- a/src/yuzu/applets/qt_software_keyboard.cpp +++ b/src/yuzu/applets/qt_software_keyboard.cpp @@ -475,11 +475,26 @@ void QtSoftwareKeyboardDialog::open() {      row = 0;      column = 0; -    const auto* const curr_button = -        keyboard_buttons[static_cast<int>(bottom_osk_index)][row][column]; +    switch (bottom_osk_index) { +    case BottomOSKIndex::LowerCase: +    case BottomOSKIndex::UpperCase: { +        const auto* const curr_button = +            keyboard_buttons[static_cast<std::size_t>(bottom_osk_index)][row][column]; + +        // This is a workaround for setFocus() randomly not showing focus in the UI +        QCursor::setPos(curr_button->mapToGlobal(curr_button->rect().center())); +        break; +    } +    case BottomOSKIndex::NumberPad: { +        const auto* const curr_button = numberpad_buttons[row][column]; -    // This is a workaround for setFocus() randomly not showing focus in the UI -    QCursor::setPos(curr_button->mapToGlobal(curr_button->rect().center())); +        // This is a workaround for setFocus() randomly not showing focus in the UI +        QCursor::setPos(curr_button->mapToGlobal(curr_button->rect().center())); +        break; +    } +    default: +        break; +    }      StartInputThread();  }  | 
