diff options
80 files changed, 732 insertions, 403 deletions
diff --git a/externals/dynarmic b/externals/dynarmic -Subproject af2d50288fc537201014c4230bb55ab9018a743 +Subproject 644172477eaf0d822178cb7e96c62b75caa9657 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3ad2c0950..9182dbfd4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -65,12 +65,14 @@ if (MSVC)          /we4305 # 'context': truncation from 'type1' to 'type2'          /we4388 # 'expression': signed/unsigned mismatch          /we4389 # 'operator': signed/unsigned mismatch +        /we4505 # 'function': unreferenced local function has been removed          /we4547 # 'operator': operator before comma has no effect; expected operator with side-effect          /we4549 # 'operator1': operator before comma has no effect; did you intend 'operator2'?          /we4555 # Expression has no effect; expected expression with side-effect          /we4715 # 'function': not all control paths return a value          /we4834 # Discarding return value of function with 'nodiscard' attribute          /we5038 # data member 'member1' will be initialized after data member 'member2' +        /we5245 # 'function': unreferenced function with internal linkage has been removed      )      if (ARCHITECTURE_x86_64) diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp index e829af1ac..802943eb7 100644 --- a/src/common/host_memory.cpp +++ b/src/common/host_memory.cpp @@ -149,7 +149,7 @@ public:      }      void Unmap(size_t virtual_offset, size_t length) { -        std::lock_guard lock{placeholder_mutex}; +        std::scoped_lock lock{placeholder_mutex};          // Unmap until there are no more placeholders          while (UnmapOnePlaceholder(virtual_offset, length)) { @@ -169,7 +169,7 @@ public:          }          const size_t virtual_end = virtual_offset + length; -        std::lock_guard lock{placeholder_mutex}; +        std::scoped_lock lock{placeholder_mutex};          auto [it, end] = placeholders.equal_range({virtual_offset, virtual_end});          while (it != end) {              const size_t offset = std::max(it->lower(), virtual_offset); diff --git a/src/common/logging/filter.cpp b/src/common/logging/filter.cpp index 9120cc178..4acbff649 100644 --- a/src/common/logging/filter.cpp +++ b/src/common/logging/filter.cpp @@ -101,6 +101,7 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {      SUB(Service, GRC)                                                                              \      SUB(Service, HID)                                                                              \      SUB(Service, IRS)                                                                              \ +    SUB(Service, JIT)                                                                              \      SUB(Service, LBL)                                                                              \      SUB(Service, LDN)                                                                              \      SUB(Service, LDR)                                                                              \ diff --git a/src/common/logging/types.h b/src/common/logging/types.h index f803ab796..99c15fa96 100644 --- a/src/common/logging/types.h +++ b/src/common/logging/types.h @@ -69,6 +69,7 @@ enum class Class : u8 {      Service_GRC,       ///< The game recording service      Service_HID,       ///< The HID (Human interface device) service      Service_IRS,       ///< The IRS service +    Service_JIT,       ///< The JIT service      Service_LBL,       ///< The LBL (LCD backlight) service      Service_LDN,       ///< The LDN (Local domain network) service      Service_LDR,       ///< The loader service diff --git a/src/common/thread.h b/src/common/thread.h index a8c17c71a..626609372 100644 --- a/src/common/thread.h +++ b/src/common/thread.h @@ -17,7 +17,7 @@ namespace Common {  class Event {  public:      void Set() { -        std::lock_guard lk{mutex}; +        std::scoped_lock lk{mutex};          if (!is_set) {              is_set = true;              condvar.notify_one(); diff --git a/src/common/threadsafe_queue.h b/src/common/threadsafe_queue.h index 2c8c2b90e..7272ac6e8 100644 --- a/src/common/threadsafe_queue.h +++ b/src/common/threadsafe_queue.h @@ -52,7 +52,7 @@ public:          // line before cv.wait          // TODO(bunnei): This can be replaced with C++20 waitable atomics when properly supported.          // See discussion on https://github.com/yuzu-emu/yuzu/pull/3173 for details. -        std::lock_guard lock{cv_mutex}; +        std::scoped_lock lock{cv_mutex};          cv.notify_one();      } @@ -159,7 +159,7 @@ public:      template <typename Arg>      void Push(Arg&& t) { -        std::lock_guard lock{write_lock}; +        std::scoped_lock lock{write_lock};          spsc_queue.Push(t);      } diff --git a/src/common/x64/native_clock.cpp b/src/common/x64/native_clock.cpp index 7a3f21dcf..7fd9d22f8 100644 --- a/src/common/x64/native_clock.cpp +++ b/src/common/x64/native_clock.cpp @@ -10,25 +10,49 @@  #include "common/uint128.h"  #include "common/x64/native_clock.h" +#ifdef _MSC_VER +#include <intrin.h> +#endif +  namespace Common { +#ifdef _MSC_VER +__forceinline static u64 FencedRDTSC() { +    _mm_lfence(); +    _ReadWriteBarrier(); +    const u64 result = __rdtsc(); +    _mm_lfence(); +    _ReadWriteBarrier(); +    return result; +} +#else +static u64 FencedRDTSC() { +    u64 result; +    asm volatile("lfence\n\t" +                 "rdtsc\n\t" +                 "shl $32, %%rdx\n\t" +                 "or %%rdx, %0\n\t" +                 "lfence" +                 : "=a"(result) +                 : +                 : "rdx", "memory", "cc"); +    return result; +} +#endif +  u64 EstimateRDTSCFrequency() {      // Discard the first result measuring the rdtsc. -    _mm_mfence(); -    __rdtsc(); +    FencedRDTSC();      std::this_thread::sleep_for(std::chrono::milliseconds{1}); -    _mm_mfence(); -    __rdtsc(); +    FencedRDTSC();      // Get the current time.      const auto start_time = std::chrono::steady_clock::now(); -    _mm_mfence(); -    const u64 tsc_start = __rdtsc(); +    const u64 tsc_start = FencedRDTSC();      // Wait for 200 milliseconds.      std::this_thread::sleep_for(std::chrono::milliseconds{200});      const auto end_time = std::chrono::steady_clock::now(); -    _mm_mfence(); -    const u64 tsc_end = __rdtsc(); +    const u64 tsc_end = FencedRDTSC();      // Calculate differences.      const u64 timer_diff = static_cast<u64>(          std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - start_time).count()); @@ -42,8 +66,7 @@ NativeClock::NativeClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequen                           u64 rtsc_frequency_)      : WallClock(emulated_cpu_frequency_, emulated_clock_frequency_, true), rtsc_frequency{                                                                                 rtsc_frequency_} { -    _mm_mfence(); -    time_point.inner.last_measure = __rdtsc(); +    time_point.inner.last_measure = FencedRDTSC();      time_point.inner.accumulated_ticks = 0U;      ns_rtsc_factor = GetFixedPoint64Factor(NS_RATIO, rtsc_frequency);      us_rtsc_factor = GetFixedPoint64Factor(US_RATIO, rtsc_frequency); @@ -58,8 +81,7 @@ u64 NativeClock::GetRTSC() {      current_time_point.pack = Common::AtomicLoad128(time_point.pack.data());      do { -        _mm_mfence(); -        const u64 current_measure = __rdtsc(); +        const u64 current_measure = FencedRDTSC();          u64 diff = current_measure - current_time_point.inner.last_measure;          diff = diff & ~static_cast<u64>(static_cast<s64>(diff) >> 63); // max(diff, 0)          new_time_point.inner.last_measure = current_measure > current_time_point.inner.last_measure @@ -80,8 +102,7 @@ void NativeClock::Pause(bool is_paused) {          current_time_point.pack = Common::AtomicLoad128(time_point.pack.data());          do {              new_time_point.pack = current_time_point.pack; -            _mm_mfence(); -            new_time_point.inner.last_measure = __rdtsc(); +            new_time_point.inner.last_measure = FencedRDTSC();          } while (!Common::AtomicCompareAndSwap(time_point.pack.data(), new_time_point.pack,                                                 current_time_point.pack, current_time_point.pack));      } diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 6536d0544..81eaf0942 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -458,6 +458,8 @@ add_library(core STATIC      hle/service/hid/controllers/touchscreen.h      hle/service/hid/controllers/xpad.cpp      hle/service/hid/controllers/xpad.h +    hle/service/jit/jit.cpp +    hle/service/jit/jit.h      hle/service/lbl/lbl.cpp      hle/service/lbl/lbl.h      hle/service/ldn/errors.h diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index c60322442..dce2f4195 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h @@ -171,6 +171,9 @@ public:      /// Prepare core for thread reschedule (if needed to correctly handle state)      virtual void PrepareReschedule() = 0; +    /// Signal an interrupt and ask the core to halt as soon as possible. +    virtual void SignalInterrupt() = 0; +      struct BacktraceEntry {          std::string module;          u64 address; diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index 054572445..ab3210d84 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -25,6 +25,9 @@ namespace Core {  using namespace Common::Literals; +constexpr Dynarmic::HaltReason break_loop = Dynarmic::HaltReason::UserDefined2; +constexpr Dynarmic::HaltReason svc_call = Dynarmic::HaltReason::UserDefined3; +  class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks {  public:      explicit DynarmicCallbacks32(ARM_Dynarmic_32& parent_) @@ -84,15 +87,13 @@ public:      }      void CallSVC(u32 swi) override { -        parent.svc_called = true;          parent.svc_swi = swi; -        parent.jit->HaltExecution(); +        parent.jit->HaltExecution(svc_call);      }      void AddTicks(u64 ticks) override { -        if (parent.uses_wall_clock) { -            return; -        } +        ASSERT_MSG(!parent.uses_wall_clock, "This should never happen - dynarmic ticking disabled"); +          // Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a          // rough approximation of the amount of executed ticks in the system, it may be thrown off          // if not all cores are doing a similar amount of work. Instead of doing this, we should @@ -108,12 +109,8 @@ public:      }      u64 GetTicksRemaining() override { -        if (parent.uses_wall_clock) { -            if (!parent.interrupt_handlers[parent.core_index].IsInterrupted()) { -                return minimum_run_cycles; -            } -            return 0U; -        } +        ASSERT_MSG(!parent.uses_wall_clock, "This should never happen - dynarmic ticking disabled"); +          return std::max<s64>(parent.system.CoreTiming().GetDowncount(), 0);      } @@ -148,6 +145,7 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*      // Timing      config.wall_clock_cntpct = uses_wall_clock; +    config.enable_cycle_counting = !uses_wall_clock;      // Code cache size      config.code_cache_size = 512_MiB; @@ -230,13 +228,11 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*  void ARM_Dynarmic_32::Run() {      while (true) { -        jit->Run(); -        if (!svc_called) { -            break; +        const auto hr = jit->Run(); +        if (Has(hr, svc_call)) { +            Kernel::Svc::Call(system, svc_swi);          } -        svc_called = false; -        Kernel::Svc::Call(system, svc_swi); -        if (shutdown) { +        if (Has(hr, break_loop)) {              break;          }      } @@ -322,8 +318,11 @@ void ARM_Dynarmic_32::LoadContext(const ThreadContext32& ctx) {  }  void ARM_Dynarmic_32::PrepareReschedule() { -    jit->HaltExecution(); -    shutdown = true; +    jit->HaltExecution(break_loop); +} + +void ARM_Dynarmic_32::SignalInterrupt() { +    jit->HaltExecution(break_loop);  }  void ARM_Dynarmic_32::ClearInstructionCache() { diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.h b/src/core/arm/dynarmic/arm_dynarmic_32.h index 5d47b600d..3f68a4ff1 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.h +++ b/src/core/arm/dynarmic/arm_dynarmic_32.h @@ -57,6 +57,7 @@ public:      void LoadContext(const ThreadContext64& ctx) override {}      void PrepareReschedule() override; +    void SignalInterrupt() override;      void ClearExclusiveState() override;      void ClearInstructionCache() override; @@ -83,9 +84,6 @@ private:      // SVC callback      u32 svc_swi{}; -    bool svc_called{}; - -    bool shutdown{};  };  } // namespace Core diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index 7ff8f9495..68822a1fc 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -26,6 +26,9 @@ namespace Core {  using Vector = Dynarmic::A64::Vector;  using namespace Common::Literals; +constexpr Dynarmic::HaltReason break_loop = Dynarmic::HaltReason::UserDefined2; +constexpr Dynarmic::HaltReason svc_call = Dynarmic::HaltReason::UserDefined3; +  class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks {  public:      explicit DynarmicCallbacks64(ARM_Dynarmic_64& parent_) @@ -106,7 +109,7 @@ public:              break;          } -        parent.jit->HaltExecution(); +        parent.jit->HaltExecution(Dynarmic::HaltReason::CacheInvalidation);      }      void ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) override { @@ -126,15 +129,12 @@ public:      }      void CallSVC(u32 swi) override { -        parent.svc_called = true;          parent.svc_swi = swi; -        parent.jit->HaltExecution(); +        parent.jit->HaltExecution(svc_call);      }      void AddTicks(u64 ticks) override { -        if (parent.uses_wall_clock) { -            return; -        } +        ASSERT_MSG(!parent.uses_wall_clock, "This should never happen - dynarmic ticking disabled");          // Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a          // rough approximation of the amount of executed ticks in the system, it may be thrown off @@ -149,12 +149,8 @@ public:      }      u64 GetTicksRemaining() override { -        if (parent.uses_wall_clock) { -            if (!parent.interrupt_handlers[parent.core_index].IsInterrupted()) { -                return minimum_run_cycles; -            } -            return 0U; -        } +        ASSERT_MSG(!parent.uses_wall_clock, "This should never happen - dynarmic ticking disabled"); +          return std::max<s64>(parent.system.CoreTiming().GetDowncount(), 0);      } @@ -210,6 +206,7 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*      // Timing      config.wall_clock_cntpct = uses_wall_clock; +    config.enable_cycle_counting = !uses_wall_clock;      // Code cache size      config.code_cache_size = 512_MiB; @@ -292,13 +289,11 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*  void ARM_Dynarmic_64::Run() {      while (true) { -        jit->Run(); -        if (!svc_called) { -            break; +        const auto hr = jit->Run(); +        if (Has(hr, svc_call)) { +            Kernel::Svc::Call(system, svc_swi);          } -        svc_called = false; -        Kernel::Svc::Call(system, svc_swi); -        if (shutdown) { +        if (Has(hr, break_loop)) {              break;          }      } @@ -389,8 +384,11 @@ void ARM_Dynarmic_64::LoadContext(const ThreadContext64& ctx) {  }  void ARM_Dynarmic_64::PrepareReschedule() { -    jit->HaltExecution(); -    shutdown = true; +    jit->HaltExecution(break_loop); +} + +void ARM_Dynarmic_64::SignalInterrupt() { +    jit->HaltExecution(break_loop);  }  void ARM_Dynarmic_64::ClearInstructionCache() { diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.h b/src/core/arm/dynarmic/arm_dynarmic_64.h index 0c4e46c64..58bc7fbec 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.h +++ b/src/core/arm/dynarmic/arm_dynarmic_64.h @@ -51,6 +51,7 @@ public:      void LoadContext(const ThreadContext64& ctx) override;      void PrepareReschedule() override; +    void SignalInterrupt() override;      void ClearExclusiveState() override;      void ClearInstructionCache() override; @@ -77,9 +78,6 @@ private:      // SVC callback      u32 svc_swi{}; -    bool svc_called{}; - -    bool shutdown{};  };  } // namespace Core diff --git a/src/core/hid/emulated_console.cpp b/src/core/hid/emulated_console.cpp index eef0ff493..de565048b 100644 --- a/src/core/hid/emulated_console.cpp +++ b/src/core/hid/emulated_console.cpp @@ -132,7 +132,7 @@ void EmulatedConsole::SetMotionParam(Common::ParamPackage param) {  }  void EmulatedConsole::SetMotion(const Common::Input::CallbackStatus& callback) { -    std::lock_guard lock{mutex}; +    std::unique_lock lock{mutex};      auto& raw_status = console.motion_values.raw_status;      auto& emulated = console.motion_values.emulated; @@ -151,6 +151,7 @@ void EmulatedConsole::SetMotion(const Common::Input::CallbackStatus& callback) {      emulated.UpdateOrientation(raw_status.delta_timestamp);      if (is_configuring) { +        lock.unlock();          TriggerOnChange(ConsoleTriggerType::Motion);          return;      } @@ -166,6 +167,7 @@ void EmulatedConsole::SetMotion(const Common::Input::CallbackStatus& callback) {      // Find what is this value      motion.verticalization_error = 0.0f; +    lock.unlock();      TriggerOnChange(ConsoleTriggerType::Motion);  } @@ -173,11 +175,12 @@ void EmulatedConsole::SetTouch(const Common::Input::CallbackStatus& callback, st      if (index >= console.touch_values.size()) {          return;      } -    std::lock_guard lock{mutex}; +    std::unique_lock lock{mutex};      console.touch_values[index] = TransformToTouch(callback);      if (is_configuring) { +        lock.unlock();          TriggerOnChange(ConsoleTriggerType::Touch);          return;      } @@ -189,26 +192,32 @@ void EmulatedConsole::SetTouch(const Common::Input::CallbackStatus& callback, st          .pressed = console.touch_values[index].pressed.value,      }; +    lock.unlock();      TriggerOnChange(ConsoleTriggerType::Touch);  }  ConsoleMotionValues EmulatedConsole::GetMotionValues() const { +    std::scoped_lock lock{mutex};      return console.motion_values;  }  TouchValues EmulatedConsole::GetTouchValues() const { +    std::scoped_lock lock{mutex};      return console.touch_values;  }  ConsoleMotion EmulatedConsole::GetMotion() const { +    std::scoped_lock lock{mutex};      return console.motion_state;  }  TouchFingerState EmulatedConsole::GetTouch() const { +    std::scoped_lock lock{mutex};      return console.touch_state;  }  void EmulatedConsole::TriggerOnChange(ConsoleTriggerType type) { +    std::scoped_lock lock{callback_mutex};      for (const auto& poller_pair : callback_list) {          const ConsoleUpdateCallback& poller = poller_pair.second;          if (poller.on_change) { @@ -218,13 +227,13 @@ void EmulatedConsole::TriggerOnChange(ConsoleTriggerType type) {  }  int EmulatedConsole::SetCallback(ConsoleUpdateCallback update_callback) { -    std::lock_guard lock{mutex}; +    std::scoped_lock lock{callback_mutex};      callback_list.insert_or_assign(last_callback_key, update_callback);      return last_callback_key++;  }  void EmulatedConsole::DeleteCallback(int key) { -    std::lock_guard lock{mutex}; +    std::scoped_lock lock{callback_mutex};      const auto& iterator = callback_list.find(key);      if (iterator == callback_list.end()) {          LOG_ERROR(Input, "Tried to delete non-existent callback {}", key); diff --git a/src/core/hid/emulated_console.h b/src/core/hid/emulated_console.h index 5eb170823..53677bdc5 100644 --- a/src/core/hid/emulated_console.h +++ b/src/core/hid/emulated_console.h @@ -183,6 +183,7 @@ private:      TouchDevices touch_devices;      mutable std::mutex mutex; +    mutable std::mutex callback_mutex;      std::unordered_map<int, ConsoleUpdateCallback> callback_list;      int last_callback_key = 0; diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 7e05666d6..c3f21066c 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -353,14 +353,17 @@ void EmulatedController::DisableConfiguration() {  }  void EmulatedController::EnableSystemButtons() { +    std::scoped_lock lock{mutex};      system_buttons_enabled = true;  }  void EmulatedController::DisableSystemButtons() { +    std::scoped_lock lock{mutex};      system_buttons_enabled = false;  }  void EmulatedController::ResetSystemButtons() { +    std::scoped_lock lock{mutex};      controller.home_button_state.home.Assign(false);      controller.capture_button_state.capture.Assign(false);  } @@ -494,139 +497,141 @@ void EmulatedController::SetButton(const Common::Input::CallbackStatus& callback      if (index >= controller.button_values.size()) {          return;      } -    { -        std::lock_guard lock{mutex}; -        bool value_changed = false; -        const auto new_status = TransformToButton(callback); -        auto& current_status = controller.button_values[index]; +    std::unique_lock lock{mutex}; +    bool value_changed = false; +    const auto new_status = TransformToButton(callback); +    auto& current_status = controller.button_values[index]; -        // Only read button values that have the same uuid or are pressed once -        if (current_status.uuid != uuid) { -            if (!new_status.value) { -                return; -            } +    // Only read button values that have the same uuid or are pressed once +    if (current_status.uuid != uuid) { +        if (!new_status.value) { +            return;          } +    } -        current_status.toggle = new_status.toggle; -        current_status.uuid = uuid; - -        // Update button status with current -        if (!current_status.toggle) { -            current_status.locked = false; -            if (current_status.value != new_status.value) { -                current_status.value = new_status.value; -                value_changed = true; -            } -        } else { -            // Toggle button and lock status -            if (new_status.value && !current_status.locked) { -                current_status.locked = true; -                current_status.value = !current_status.value; -                value_changed = true; -            } +    current_status.toggle = new_status.toggle; +    current_status.uuid = uuid; -            // Unlock button ready for next press -            if (!new_status.value && current_status.locked) { -                current_status.locked = false; -            } +    // Update button status with current +    if (!current_status.toggle) { +        current_status.locked = false; +        if (current_status.value != new_status.value) { +            current_status.value = new_status.value; +            value_changed = true;          } - -        if (!value_changed) { -            return; +    } else { +        // Toggle button and lock status +        if (new_status.value && !current_status.locked) { +            current_status.locked = true; +            current_status.value = !current_status.value; +            value_changed = true;          } -        if (is_configuring) { -            controller.npad_button_state.raw = NpadButton::None; -            controller.debug_pad_button_state.raw = 0; -            TriggerOnChange(ControllerTriggerType::Button, false); -            return; +        // Unlock button ready for next press +        if (!new_status.value && current_status.locked) { +            current_status.locked = false;          } +    } -        switch (index) { -        case Settings::NativeButton::A: -            controller.npad_button_state.a.Assign(current_status.value); -            controller.debug_pad_button_state.a.Assign(current_status.value); -            break; -        case Settings::NativeButton::B: -            controller.npad_button_state.b.Assign(current_status.value); -            controller.debug_pad_button_state.b.Assign(current_status.value); -            break; -        case Settings::NativeButton::X: -            controller.npad_button_state.x.Assign(current_status.value); -            controller.debug_pad_button_state.x.Assign(current_status.value); -            break; -        case Settings::NativeButton::Y: -            controller.npad_button_state.y.Assign(current_status.value); -            controller.debug_pad_button_state.y.Assign(current_status.value); -            break; -        case Settings::NativeButton::LStick: -            controller.npad_button_state.stick_l.Assign(current_status.value); -            break; -        case Settings::NativeButton::RStick: -            controller.npad_button_state.stick_r.Assign(current_status.value); -            break; -        case Settings::NativeButton::L: -            controller.npad_button_state.l.Assign(current_status.value); -            controller.debug_pad_button_state.l.Assign(current_status.value); -            break; -        case Settings::NativeButton::R: -            controller.npad_button_state.r.Assign(current_status.value); -            controller.debug_pad_button_state.r.Assign(current_status.value); -            break; -        case Settings::NativeButton::ZL: -            controller.npad_button_state.zl.Assign(current_status.value); -            controller.debug_pad_button_state.zl.Assign(current_status.value); -            break; -        case Settings::NativeButton::ZR: -            controller.npad_button_state.zr.Assign(current_status.value); -            controller.debug_pad_button_state.zr.Assign(current_status.value); -            break; -        case Settings::NativeButton::Plus: -            controller.npad_button_state.plus.Assign(current_status.value); -            controller.debug_pad_button_state.plus.Assign(current_status.value); -            break; -        case Settings::NativeButton::Minus: -            controller.npad_button_state.minus.Assign(current_status.value); -            controller.debug_pad_button_state.minus.Assign(current_status.value); -            break; -        case Settings::NativeButton::DLeft: -            controller.npad_button_state.left.Assign(current_status.value); -            controller.debug_pad_button_state.d_left.Assign(current_status.value); -            break; -        case Settings::NativeButton::DUp: -            controller.npad_button_state.up.Assign(current_status.value); -            controller.debug_pad_button_state.d_up.Assign(current_status.value); -            break; -        case Settings::NativeButton::DRight: -            controller.npad_button_state.right.Assign(current_status.value); -            controller.debug_pad_button_state.d_right.Assign(current_status.value); -            break; -        case Settings::NativeButton::DDown: -            controller.npad_button_state.down.Assign(current_status.value); -            controller.debug_pad_button_state.d_down.Assign(current_status.value); -            break; -        case Settings::NativeButton::SL: -            controller.npad_button_state.left_sl.Assign(current_status.value); -            controller.npad_button_state.right_sl.Assign(current_status.value); -            break; -        case Settings::NativeButton::SR: -            controller.npad_button_state.left_sr.Assign(current_status.value); -            controller.npad_button_state.right_sr.Assign(current_status.value); -            break; -        case Settings::NativeButton::Home: -            if (!system_buttons_enabled) { -                break; -            } -            controller.home_button_state.home.Assign(current_status.value); +    if (!value_changed) { +        return; +    } + +    if (is_configuring) { +        controller.npad_button_state.raw = NpadButton::None; +        controller.debug_pad_button_state.raw = 0; +        lock.unlock(); +        TriggerOnChange(ControllerTriggerType::Button, false); +        return; +    } + +    switch (index) { +    case Settings::NativeButton::A: +        controller.npad_button_state.a.Assign(current_status.value); +        controller.debug_pad_button_state.a.Assign(current_status.value); +        break; +    case Settings::NativeButton::B: +        controller.npad_button_state.b.Assign(current_status.value); +        controller.debug_pad_button_state.b.Assign(current_status.value); +        break; +    case Settings::NativeButton::X: +        controller.npad_button_state.x.Assign(current_status.value); +        controller.debug_pad_button_state.x.Assign(current_status.value); +        break; +    case Settings::NativeButton::Y: +        controller.npad_button_state.y.Assign(current_status.value); +        controller.debug_pad_button_state.y.Assign(current_status.value); +        break; +    case Settings::NativeButton::LStick: +        controller.npad_button_state.stick_l.Assign(current_status.value); +        break; +    case Settings::NativeButton::RStick: +        controller.npad_button_state.stick_r.Assign(current_status.value); +        break; +    case Settings::NativeButton::L: +        controller.npad_button_state.l.Assign(current_status.value); +        controller.debug_pad_button_state.l.Assign(current_status.value); +        break; +    case Settings::NativeButton::R: +        controller.npad_button_state.r.Assign(current_status.value); +        controller.debug_pad_button_state.r.Assign(current_status.value); +        break; +    case Settings::NativeButton::ZL: +        controller.npad_button_state.zl.Assign(current_status.value); +        controller.debug_pad_button_state.zl.Assign(current_status.value); +        break; +    case Settings::NativeButton::ZR: +        controller.npad_button_state.zr.Assign(current_status.value); +        controller.debug_pad_button_state.zr.Assign(current_status.value); +        break; +    case Settings::NativeButton::Plus: +        controller.npad_button_state.plus.Assign(current_status.value); +        controller.debug_pad_button_state.plus.Assign(current_status.value); +        break; +    case Settings::NativeButton::Minus: +        controller.npad_button_state.minus.Assign(current_status.value); +        controller.debug_pad_button_state.minus.Assign(current_status.value); +        break; +    case Settings::NativeButton::DLeft: +        controller.npad_button_state.left.Assign(current_status.value); +        controller.debug_pad_button_state.d_left.Assign(current_status.value); +        break; +    case Settings::NativeButton::DUp: +        controller.npad_button_state.up.Assign(current_status.value); +        controller.debug_pad_button_state.d_up.Assign(current_status.value); +        break; +    case Settings::NativeButton::DRight: +        controller.npad_button_state.right.Assign(current_status.value); +        controller.debug_pad_button_state.d_right.Assign(current_status.value); +        break; +    case Settings::NativeButton::DDown: +        controller.npad_button_state.down.Assign(current_status.value); +        controller.debug_pad_button_state.d_down.Assign(current_status.value); +        break; +    case Settings::NativeButton::SL: +        controller.npad_button_state.left_sl.Assign(current_status.value); +        controller.npad_button_state.right_sl.Assign(current_status.value); +        break; +    case Settings::NativeButton::SR: +        controller.npad_button_state.left_sr.Assign(current_status.value); +        controller.npad_button_state.right_sr.Assign(current_status.value); +        break; +    case Settings::NativeButton::Home: +        if (!system_buttons_enabled) {              break; -        case Settings::NativeButton::Screenshot: -            if (!system_buttons_enabled) { -                break; -            } -            controller.capture_button_state.capture.Assign(current_status.value); +        } +        controller.home_button_state.home.Assign(current_status.value); +        break; +    case Settings::NativeButton::Screenshot: +        if (!system_buttons_enabled) {              break;          } +        controller.capture_button_state.capture.Assign(current_status.value); +        break;      } + +    lock.unlock(); +      if (!is_connected) {          if (npad_id_type == NpadIdType::Player1 && npad_type != NpadStyleIndex::Handheld) {              Connect(); @@ -643,7 +648,7 @@ void EmulatedController::SetStick(const Common::Input::CallbackStatus& callback,      if (index >= controller.stick_values.size()) {          return;      } -    std::lock_guard lock{mutex}; +    std::unique_lock lock{mutex};      const auto stick_value = TransformToStick(callback);      // Only read stick values that have the same uuid or are over the threshold to avoid flapping @@ -659,6 +664,7 @@ void EmulatedController::SetStick(const Common::Input::CallbackStatus& callback,      if (is_configuring) {          controller.analog_stick_state.left = {};          controller.analog_stick_state.right = {}; +        lock.unlock();          TriggerOnChange(ControllerTriggerType::Stick, false);          return;      } @@ -685,6 +691,7 @@ void EmulatedController::SetStick(const Common::Input::CallbackStatus& callback,          break;      } +    lock.unlock();      TriggerOnChange(ControllerTriggerType::Stick, true);  } @@ -693,7 +700,7 @@ void EmulatedController::SetTrigger(const Common::Input::CallbackStatus& callbac      if (index >= controller.trigger_values.size()) {          return;      } -    std::lock_guard lock{mutex}; +    std::unique_lock lock{mutex};      const auto trigger_value = TransformToTrigger(callback);      // Only read trigger values that have the same uuid or are pressed once @@ -709,6 +716,7 @@ void EmulatedController::SetTrigger(const Common::Input::CallbackStatus& callbac      if (is_configuring) {          controller.gc_trigger_state.left = 0;          controller.gc_trigger_state.right = 0; +        lock.unlock();          TriggerOnChange(ControllerTriggerType::Trigger, false);          return;      } @@ -727,6 +735,7 @@ void EmulatedController::SetTrigger(const Common::Input::CallbackStatus& callbac          break;      } +    lock.unlock();      TriggerOnChange(ControllerTriggerType::Trigger, true);  } @@ -735,7 +744,7 @@ void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback      if (index >= controller.motion_values.size()) {          return;      } -    std::lock_guard lock{mutex}; +    std::unique_lock lock{mutex};      auto& raw_status = controller.motion_values[index].raw_status;      auto& emulated = controller.motion_values[index].emulated; @@ -756,6 +765,7 @@ void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback      force_update_motion = raw_status.force_update;      if (is_configuring) { +        lock.unlock();          TriggerOnChange(ControllerTriggerType::Motion, false);          return;      } @@ -767,6 +777,7 @@ void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback      motion.orientation = emulated.GetOrientation();      motion.is_at_rest = !emulated.IsMoving(motion_sensitivity); +    lock.unlock();      TriggerOnChange(ControllerTriggerType::Motion, true);  } @@ -775,10 +786,11 @@ void EmulatedController::SetBattery(const Common::Input::CallbackStatus& callbac      if (index >= controller.battery_values.size()) {          return;      } -    std::lock_guard lock{mutex}; +    std::unique_lock lock{mutex};      controller.battery_values[index] = TransformToBattery(callback);      if (is_configuring) { +        lock.unlock();          TriggerOnChange(ControllerTriggerType::Battery, false);          return;      } @@ -835,6 +847,8 @@ void EmulatedController::SetBattery(const Common::Input::CallbackStatus& callbac          };          break;      } + +    lock.unlock();      TriggerOnChange(ControllerTriggerType::Battery, true);  } @@ -932,6 +946,7 @@ void EmulatedController::SetSupportedNpadStyleTag(NpadStyleTag supported_styles)  }  bool EmulatedController::IsControllerFullkey(bool use_temporary_value) const { +    std::scoped_lock lock{mutex};      const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type;      switch (type) {      case NpadStyleIndex::ProController: @@ -947,6 +962,7 @@ bool EmulatedController::IsControllerFullkey(bool use_temporary_value) const {  }  bool EmulatedController::IsControllerSupported(bool use_temporary_value) const { +    std::scoped_lock lock{mutex};      const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type;      switch (type) {      case NpadStyleIndex::ProController: @@ -982,40 +998,44 @@ void EmulatedController::Connect(bool use_temporary_value) {          LOG_ERROR(Service_HID, "Controller type {} is not supported", type);          return;      } -    { -        std::lock_guard lock{mutex}; -        if (is_configuring) { -            tmp_is_connected = true; -            TriggerOnChange(ControllerTriggerType::Connected, false); -            return; -        } -        if (is_connected) { -            return; -        } -        is_connected = true; +    std::unique_lock lock{mutex}; +    if (is_configuring) { +        tmp_is_connected = true; +        lock.unlock(); +        TriggerOnChange(ControllerTriggerType::Connected, false); +        return; +    } + +    if (is_connected) { +        return;      } +    is_connected = true; + +    lock.unlock();      TriggerOnChange(ControllerTriggerType::Connected, true);  }  void EmulatedController::Disconnect() { -    { -        std::lock_guard lock{mutex}; -        if (is_configuring) { -            tmp_is_connected = false; -            TriggerOnChange(ControllerTriggerType::Disconnected, false); -            return; -        } +    std::unique_lock lock{mutex}; +    if (is_configuring) { +        tmp_is_connected = false; +        lock.unlock(); +        TriggerOnChange(ControllerTriggerType::Disconnected, false); +        return; +    } -        if (!is_connected) { -            return; -        } -        is_connected = false; +    if (!is_connected) { +        return;      } +    is_connected = false; + +    lock.unlock();      TriggerOnChange(ControllerTriggerType::Disconnected, true);  }  bool EmulatedController::IsConnected(bool get_temporary_value) const { +    std::scoped_lock lock{mutex};      if (get_temporary_value && is_configuring) {          return tmp_is_connected;      } @@ -1029,10 +1049,12 @@ bool EmulatedController::IsVibrationEnabled() const {  }  NpadIdType EmulatedController::GetNpadIdType() const { +    std::scoped_lock lock{mutex};      return npad_id_type;  }  NpadStyleIndex EmulatedController::GetNpadStyleIndex(bool get_temporary_value) const { +    std::scoped_lock lock{mutex};      if (get_temporary_value && is_configuring) {          return tmp_npad_type;      } @@ -1040,27 +1062,28 @@ NpadStyleIndex EmulatedController::GetNpadStyleIndex(bool get_temporary_value) c  }  void EmulatedController::SetNpadStyleIndex(NpadStyleIndex npad_type_) { -    { -        std::lock_guard lock{mutex}; +    std::unique_lock lock{mutex}; -        if (is_configuring) { -            if (tmp_npad_type == npad_type_) { -                return; -            } -            tmp_npad_type = npad_type_; -            TriggerOnChange(ControllerTriggerType::Type, false); +    if (is_configuring) { +        if (tmp_npad_type == npad_type_) {              return;          } +        tmp_npad_type = npad_type_; +        lock.unlock(); +        TriggerOnChange(ControllerTriggerType::Type, false); +        return; +    } -        if (npad_type == npad_type_) { -            return; -        } -        if (is_connected) { -            LOG_WARNING(Service_HID, "Controller {} type changed while it's connected", -                        NpadIdTypeToIndex(npad_id_type)); -        } -        npad_type = npad_type_; +    if (npad_type == npad_type_) { +        return; +    } +    if (is_connected) { +        LOG_WARNING(Service_HID, "Controller {} type changed while it's connected", +                    NpadIdTypeToIndex(npad_id_type));      } +    npad_type = npad_type_; + +    lock.unlock();      TriggerOnChange(ControllerTriggerType::Type, true);  } @@ -1088,30 +1111,37 @@ LedPattern EmulatedController::GetLedPattern() const {  }  ButtonValues EmulatedController::GetButtonsValues() const { +    std::scoped_lock lock{mutex};      return controller.button_values;  }  SticksValues EmulatedController::GetSticksValues() const { +    std::scoped_lock lock{mutex};      return controller.stick_values;  }  TriggerValues EmulatedController::GetTriggersValues() const { +    std::scoped_lock lock{mutex};      return controller.trigger_values;  }  ControllerMotionValues EmulatedController::GetMotionValues() const { +    std::scoped_lock lock{mutex};      return controller.motion_values;  }  ColorValues EmulatedController::GetColorsValues() const { +    std::scoped_lock lock{mutex};      return controller.color_values;  }  BatteryValues EmulatedController::GetBatteryValues() const { +    std::scoped_lock lock{mutex};      return controller.battery_values;  }  HomeButtonState EmulatedController::GetHomeButtons() const { +    std::scoped_lock lock{mutex};      if (is_configuring) {          return {};      } @@ -1119,6 +1149,7 @@ HomeButtonState EmulatedController::GetHomeButtons() const {  }  CaptureButtonState EmulatedController::GetCaptureButtons() const { +    std::scoped_lock lock{mutex};      if (is_configuring) {          return {};      } @@ -1126,6 +1157,7 @@ CaptureButtonState EmulatedController::GetCaptureButtons() const {  }  NpadButtonState EmulatedController::GetNpadButtons() const { +    std::scoped_lock lock{mutex};      if (is_configuring) {          return {};      } @@ -1133,6 +1165,7 @@ NpadButtonState EmulatedController::GetNpadButtons() const {  }  DebugPadButton EmulatedController::GetDebugPadButtons() const { +    std::scoped_lock lock{mutex};      if (is_configuring) {          return {};      } @@ -1140,20 +1173,27 @@ DebugPadButton EmulatedController::GetDebugPadButtons() const {  }  AnalogSticks EmulatedController::GetSticks() const { +    std::unique_lock lock{mutex}; +      if (is_configuring) {          return {};      } +      // Some drivers like stick from buttons need constant refreshing      for (auto& device : stick_devices) {          if (!device) {              continue;          } +        lock.unlock();          device->SoftUpdate(); +        lock.lock();      } +      return controller.analog_stick_state;  }  NpadGcTriggerState EmulatedController::GetTriggers() const { +    std::scoped_lock lock{mutex};      if (is_configuring) {          return {};      } @@ -1161,26 +1201,35 @@ NpadGcTriggerState EmulatedController::GetTriggers() const {  }  MotionState EmulatedController::GetMotions() const { +    std::unique_lock lock{mutex}; + +    // Some drivers like mouse motion need constant refreshing      if (force_update_motion) {          for (auto& device : motion_devices) {              if (!device) {                  continue;              } +            lock.unlock();              device->ForceUpdate(); +            lock.lock();          }      } +      return controller.motion_state;  }  ControllerColors EmulatedController::GetColors() const { +    std::scoped_lock lock{mutex};      return controller.colors_state;  }  BatteryLevelState EmulatedController::GetBattery() const { +    std::scoped_lock lock{mutex};      return controller.battery_state;  }  void EmulatedController::TriggerOnChange(ControllerTriggerType type, bool is_npad_service_update) { +    std::scoped_lock lock{callback_mutex};      for (const auto& poller_pair : callback_list) {          const ControllerUpdateCallback& poller = poller_pair.second;          if (!is_npad_service_update && poller.is_npad_service) { @@ -1193,13 +1242,13 @@ void EmulatedController::TriggerOnChange(ControllerTriggerType type, bool is_npa  }  int EmulatedController::SetCallback(ControllerUpdateCallback update_callback) { -    std::lock_guard lock{mutex}; +    std::scoped_lock lock{callback_mutex};      callback_list.insert_or_assign(last_callback_key, std::move(update_callback));      return last_callback_key++;  }  void EmulatedController::DeleteCallback(int key) { -    std::lock_guard lock{mutex}; +    std::scoped_lock lock{callback_mutex};      const auto& iterator = callback_list.find(key);      if (iterator == callback_list.end()) {          LOG_ERROR(Input, "Tried to delete non-existent callback {}", key); diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index aa52f9572..1e224685d 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h @@ -400,7 +400,7 @@ private:       */      void TriggerOnChange(ControllerTriggerType type, bool is_service_update); -    NpadIdType npad_id_type; +    const NpadIdType npad_id_type;      NpadStyleIndex npad_type{NpadStyleIndex::None};      NpadStyleTag supported_style_tag{NpadStyleSet::All};      bool is_connected{false}; @@ -434,6 +434,7 @@ private:      StickDevices tas_stick_devices;      mutable std::mutex mutex; +    mutable std::mutex callback_mutex;      std::unordered_map<int, ControllerUpdateCallback> callback_list;      int last_callback_key = 0; diff --git a/src/core/hid/emulated_devices.cpp b/src/core/hid/emulated_devices.cpp index 708480f2d..cc0dcd931 100644 --- a/src/core/hid/emulated_devices.cpp +++ b/src/core/hid/emulated_devices.cpp @@ -169,7 +169,7 @@ void EmulatedDevices::SetKeyboardButton(const Common::Input::CallbackStatus& cal      if (index >= device_status.keyboard_values.size()) {          return;      } -    std::lock_guard lock{mutex}; +    std::unique_lock lock{mutex};      bool value_changed = false;      const auto new_status = TransformToButton(callback);      auto& current_status = device_status.keyboard_values[index]; @@ -201,6 +201,7 @@ void EmulatedDevices::SetKeyboardButton(const Common::Input::CallbackStatus& cal      }      if (is_configuring) { +        lock.unlock();          TriggerOnChange(DeviceTriggerType::Keyboard);          return;      } @@ -208,6 +209,7 @@ void EmulatedDevices::SetKeyboardButton(const Common::Input::CallbackStatus& cal      // Index should be converted from NativeKeyboard to KeyboardKeyIndex      UpdateKey(index, current_status.value); +    lock.unlock();      TriggerOnChange(DeviceTriggerType::Keyboard);  } @@ -227,7 +229,7 @@ void EmulatedDevices::SetKeyboardModifier(const Common::Input::CallbackStatus& c      if (index >= device_status.keyboard_moddifier_values.size()) {          return;      } -    std::lock_guard lock{mutex}; +    std::unique_lock lock{mutex};      bool value_changed = false;      const auto new_status = TransformToButton(callback);      auto& current_status = device_status.keyboard_moddifier_values[index]; @@ -259,6 +261,7 @@ void EmulatedDevices::SetKeyboardModifier(const Common::Input::CallbackStatus& c      }      if (is_configuring) { +        lock.unlock();          TriggerOnChange(DeviceTriggerType::KeyboardModdifier);          return;      } @@ -289,6 +292,7 @@ void EmulatedDevices::SetKeyboardModifier(const Common::Input::CallbackStatus& c          break;      } +    lock.unlock();      TriggerOnChange(DeviceTriggerType::KeyboardModdifier);  } @@ -297,7 +301,7 @@ void EmulatedDevices::SetMouseButton(const Common::Input::CallbackStatus& callba      if (index >= device_status.mouse_button_values.size()) {          return;      } -    std::lock_guard lock{mutex}; +    std::unique_lock lock{mutex};      bool value_changed = false;      const auto new_status = TransformToButton(callback);      auto& current_status = device_status.mouse_button_values[index]; @@ -329,6 +333,7 @@ void EmulatedDevices::SetMouseButton(const Common::Input::CallbackStatus& callba      }      if (is_configuring) { +        lock.unlock();          TriggerOnChange(DeviceTriggerType::Mouse);          return;      } @@ -351,6 +356,7 @@ void EmulatedDevices::SetMouseButton(const Common::Input::CallbackStatus& callba          break;      } +    lock.unlock();      TriggerOnChange(DeviceTriggerType::Mouse);  } @@ -359,13 +365,14 @@ void EmulatedDevices::SetMouseAnalog(const Common::Input::CallbackStatus& callba      if (index >= device_status.mouse_analog_values.size()) {          return;      } -    std::lock_guard lock{mutex}; +    std::unique_lock lock{mutex};      const auto analog_value = TransformToAnalog(callback);      device_status.mouse_analog_values[index] = analog_value;      if (is_configuring) {          device_status.mouse_position_state = {}; +        lock.unlock();          TriggerOnChange(DeviceTriggerType::Mouse);          return;      } @@ -379,17 +386,19 @@ void EmulatedDevices::SetMouseAnalog(const Common::Input::CallbackStatus& callba          break;      } +    lock.unlock();      TriggerOnChange(DeviceTriggerType::Mouse);  }  void EmulatedDevices::SetMouseStick(const Common::Input::CallbackStatus& callback) { -    std::lock_guard lock{mutex}; +    std::unique_lock lock{mutex};      const auto touch_value = TransformToTouch(callback);      device_status.mouse_stick_value = touch_value;      if (is_configuring) {          device_status.mouse_position_state = {}; +        lock.unlock();          TriggerOnChange(DeviceTriggerType::Mouse);          return;      } @@ -397,42 +406,52 @@ void EmulatedDevices::SetMouseStick(const Common::Input::CallbackStatus& callbac      device_status.mouse_position_state.x = touch_value.x.value;      device_status.mouse_position_state.y = touch_value.y.value; +    lock.unlock();      TriggerOnChange(DeviceTriggerType::Mouse);  }  KeyboardValues EmulatedDevices::GetKeyboardValues() const { +    std::scoped_lock lock{mutex};      return device_status.keyboard_values;  }  KeyboardModifierValues EmulatedDevices::GetKeyboardModdifierValues() const { +    std::scoped_lock lock{mutex};      return device_status.keyboard_moddifier_values;  }  MouseButtonValues EmulatedDevices::GetMouseButtonsValues() const { +    std::scoped_lock lock{mutex};      return device_status.mouse_button_values;  }  KeyboardKey EmulatedDevices::GetKeyboard() const { +    std::scoped_lock lock{mutex};      return device_status.keyboard_state;  }  KeyboardModifier EmulatedDevices::GetKeyboardModifier() const { +    std::scoped_lock lock{mutex};      return device_status.keyboard_moddifier_state;  }  MouseButton EmulatedDevices::GetMouseButtons() const { +    std::scoped_lock lock{mutex};      return device_status.mouse_button_state;  }  MousePosition EmulatedDevices::GetMousePosition() const { +    std::scoped_lock lock{mutex};      return device_status.mouse_position_state;  }  AnalogStickState EmulatedDevices::GetMouseWheel() const { +    std::scoped_lock lock{mutex};      return device_status.mouse_wheel_state;  }  void EmulatedDevices::TriggerOnChange(DeviceTriggerType type) { +    std::scoped_lock lock{callback_mutex};      for (const auto& poller_pair : callback_list) {          const InterfaceUpdateCallback& poller = poller_pair.second;          if (poller.on_change) { @@ -442,13 +461,13 @@ void EmulatedDevices::TriggerOnChange(DeviceTriggerType type) {  }  int EmulatedDevices::SetCallback(InterfaceUpdateCallback update_callback) { -    std::lock_guard lock{mutex}; +    std::scoped_lock lock{callback_mutex};      callback_list.insert_or_assign(last_callback_key, std::move(update_callback));      return last_callback_key++;  }  void EmulatedDevices::DeleteCallback(int key) { -    std::lock_guard lock{mutex}; +    std::scoped_lock lock{callback_mutex};      const auto& iterator = callback_list.find(key);      if (iterator == callback_list.end()) {          LOG_ERROR(Input, "Tried to delete non-existent callback {}", key); diff --git a/src/core/hid/emulated_devices.h b/src/core/hid/emulated_devices.h index 790d3b411..73e9f0293 100644 --- a/src/core/hid/emulated_devices.h +++ b/src/core/hid/emulated_devices.h @@ -200,6 +200,7 @@ private:      MouseStickDevice mouse_stick_device;      mutable std::mutex mutex; +    mutable std::mutex callback_mutex;      std::unordered_map<int, InterfaceUpdateCallback> callback_list;      int last_callback_key = 0; diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 42d1b0e31..b547a3463 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -24,8 +24,15 @@  namespace Kernel { -SessionRequestHandler::SessionRequestHandler(KernelCore& kernel_, const char* service_name_) -    : kernel{kernel_}, service_thread{kernel.CreateServiceThread(service_name_)} {} +SessionRequestHandler::SessionRequestHandler(KernelCore& kernel_, const char* service_name_, +                                             ServiceThreadType thread_type) +    : kernel{kernel_} { +    if (thread_type == ServiceThreadType::CreateNew) { +        service_thread = kernel.CreateServiceThread(service_name_); +    } else { +        service_thread = kernel.GetDefaultServiceThread(); +    } +}  SessionRequestHandler::~SessionRequestHandler() {      kernel.ReleaseServiceThread(service_thread); diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index 670cc741c..640146137 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -33,6 +33,11 @@ namespace Service {  class ServiceFrameworkBase;  } +enum class ServiceThreadType { +    Default, +    CreateNew, +}; +  namespace Kernel {  class Domain; @@ -57,7 +62,8 @@ enum class ThreadWakeupReason;   */  class SessionRequestHandler : public std::enable_shared_from_this<SessionRequestHandler> {  public: -    SessionRequestHandler(KernelCore& kernel, const char* service_name_); +    SessionRequestHandler(KernelCore& kernel_, const char* service_name_, +                          ServiceThreadType thread_type);      virtual ~SessionRequestHandler();      /** diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 34da7c23b..134a0b8e9 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -61,6 +61,7 @@ struct KernelCore::Impl {          global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel);          global_handle_table = std::make_unique<Kernel::KHandleTable>(kernel);          global_handle_table->Initialize(KHandleTable::MaxTableSize); +        default_service_thread = CreateServiceThread(kernel, "DefaultServiceThread");          is_phantom_mode_for_singlecore = false; @@ -98,7 +99,7 @@ struct KernelCore::Impl {          // Close all open server ports.          std::unordered_set<KServerPort*> server_ports_;          { -            std::lock_guard lk(server_ports_lock); +            std::scoped_lock lk{server_ports_lock};              server_ports_ = server_ports;              server_ports.clear();          } @@ -156,7 +157,7 @@ struct KernelCore::Impl {          // Close kernel objects that were not freed on shutdown          { -            std::lock_guard lk(registered_in_use_objects_lock); +            std::scoped_lock lk{registered_in_use_objects_lock};              if (registered_in_use_objects.size()) {                  for (auto& object : registered_in_use_objects) {                      object->Close(); @@ -177,7 +178,7 @@ struct KernelCore::Impl {          // Track kernel objects that were not freed on shutdown          { -            std::lock_guard lk(registered_objects_lock); +            std::scoped_lock lk{registered_objects_lock};              if (registered_objects.size()) {                  LOG_DEBUG(Kernel, "{} kernel objects were dangling on shutdown!",                            registered_objects.size()); @@ -659,7 +660,7 @@ struct KernelCore::Impl {          KClientPort* port = &search->second(system.ServiceManager(), system);          { -            std::lock_guard lk(server_ports_lock); +            std::scoped_lock lk{server_ports_lock};              server_ports.insert(&port->GetParent()->GetServerPort());          }          return port; @@ -677,6 +678,12 @@ struct KernelCore::Impl {      void ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread) {          if (auto strong_ptr = service_thread.lock()) { +            if (strong_ptr == default_service_thread.lock()) { +                // Nothing to do here, the service is using default_service_thread, which will be +                // released on shutdown. +                return; +            } +              service_threads_manager.QueueWork(                  [this, strong_ptr{std::move(strong_ptr)}]() { service_threads.erase(strong_ptr); });          } @@ -739,7 +746,8 @@ struct KernelCore::Impl {      std::unique_ptr<KMemoryLayout> memory_layout;      // Threads used for services -    std::unordered_set<std::shared_ptr<Kernel::ServiceThread>> service_threads; +    std::unordered_set<std::shared_ptr<ServiceThread>> service_threads; +    std::weak_ptr<ServiceThread> default_service_thread;      Common::ThreadWorker service_threads_manager;      std::array<KThread*, Core::Hardware::NUM_CPU_CORES> suspend_threads; @@ -921,22 +929,22 @@ KClientPort* KernelCore::CreateNamedServicePort(std::string name) {  }  void KernelCore::RegisterKernelObject(KAutoObject* object) { -    std::lock_guard lk(impl->registered_objects_lock); +    std::scoped_lock lk{impl->registered_objects_lock};      impl->registered_objects.insert(object);  }  void KernelCore::UnregisterKernelObject(KAutoObject* object) { -    std::lock_guard lk(impl->registered_objects_lock); +    std::scoped_lock lk{impl->registered_objects_lock};      impl->registered_objects.erase(object);  }  void KernelCore::RegisterInUseObject(KAutoObject* object) { -    std::lock_guard lk(impl->registered_in_use_objects_lock); +    std::scoped_lock lk{impl->registered_in_use_objects_lock};      impl->registered_in_use_objects.insert(object);  }  void KernelCore::UnregisterInUseObject(KAutoObject* object) { -    std::lock_guard lk(impl->registered_in_use_objects_lock); +    std::scoped_lock lk{impl->registered_in_use_objects_lock};      impl->registered_in_use_objects.erase(object);  } @@ -1065,6 +1073,10 @@ std::weak_ptr<Kernel::ServiceThread> KernelCore::CreateServiceThread(const std::      return impl->CreateServiceThread(*this, name);  } +std::weak_ptr<Kernel::ServiceThread> KernelCore::GetDefaultServiceThread() const { +    return impl->default_service_thread; +} +  void KernelCore::ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread) {      impl->ReleaseServiceThread(service_thread);  } diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 4c68e96df..24e26fa44 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -271,9 +271,11 @@ public:      void ExitSVCProfile();      /** -     * Creates an HLE service thread, which are used to execute service routines asynchronously. -     * While these are allocated per ServerSession, these need to be owned and managed outside -     * of ServerSession to avoid a circular dependency. +     * Creates a host thread to execute HLE service requests, which are used to execute service +     * routines asynchronously. While these are allocated per ServerSession, these need to be owned +     * and managed outside of ServerSession to avoid a circular dependency. In general, most +     * services can just use the default service thread, and not need their own host service thread. +     * See GetDefaultServiceThread.       * @param name String name for the ServerSession creating this thread, used for debug       * purposes.       * @returns The a weak pointer newly created service thread. @@ -281,6 +283,14 @@ public:      std::weak_ptr<Kernel::ServiceThread> CreateServiceThread(const std::string& name);      /** +     * Gets the default host service thread, which executes HLE service requests. Unless service +     * requests need to block on the host, the default service thread should be used in favor of +     * creating a new service thread. +     * @returns The a weak pointer for the default service thread. +     */ +    std::weak_ptr<Kernel::ServiceThread> GetDefaultServiceThread() const; + +    /**       * Releases a HLE service thread, instructing KernelCore to free it. This should be called when       * the ServerSession associated with the thread is destroyed.       * @param service_thread Service thread to release. diff --git a/src/core/hle/kernel/physical_core.cpp b/src/core/hle/kernel/physical_core.cpp index 7477668e4..18a5f40f8 100644 --- a/src/core/hle/kernel/physical_core.cpp +++ b/src/core/hle/kernel/physical_core.cpp @@ -58,6 +58,7 @@ bool PhysicalCore::IsInterrupted() const {  void PhysicalCore::Interrupt() {      guard->lock();      interrupts[core_index].SetInterrupt(true); +    arm_interface->SignalInterrupt();      guard->unlock();  } diff --git a/src/core/hle/kernel/time_manager.cpp b/src/core/hle/kernel/time_manager.cpp index aa985d820..5b8fe8eae 100644 --- a/src/core/hle/kernel/time_manager.cpp +++ b/src/core/hle/kernel/time_manager.cpp @@ -24,7 +24,7 @@ TimeManager::TimeManager(Core::System& system_) : system{system_} {  }  void TimeManager::ScheduleTimeEvent(KThread* thread, s64 nanoseconds) { -    std::lock_guard lock{mutex}; +    std::scoped_lock lock{mutex};      if (nanoseconds > 0) {          ASSERT(thread);          ASSERT(thread->GetState() != ThreadState::Runnable); @@ -35,7 +35,7 @@ void TimeManager::ScheduleTimeEvent(KThread* thread, s64 nanoseconds) {  }  void TimeManager::UnscheduleTimeEvent(KThread* thread) { -    std::lock_guard lock{mutex}; +    std::scoped_lock lock{mutex};      system.CoreTiming().UnscheduleEvent(time_manager_event_type,                                          reinterpret_cast<uintptr_t>(thread));  } diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 420de3c54..4d7e5ecd3 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -1337,7 +1337,7 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_)          {200, nullptr, "GetLastApplicationExitReason"},          {500, nullptr, "StartContinuousRecordingFlushForDebug"},          {1000, nullptr, "CreateMovieMaker"}, -        {1001, nullptr, "PrepareForJit"}, +        {1001, &IApplicationFunctions::PrepareForJit, "PrepareForJit"},      };      // clang-format on @@ -1787,6 +1787,13 @@ void IApplicationFunctions::GetHealthWarningDisappearedSystemEvent(Kernel::HLERe      rb.PushCopyObjects(health_warning_disappeared_system_event->GetReadableEvent());  } +void IApplicationFunctions::PrepareForJit(Kernel::HLERequestContext& ctx) { +    LOG_WARNING(Service_AM, "(STUBBED) called"); + +    IPC::ResponseBuilder rb{ctx, 2}; +    rb.Push(ResultSuccess); +} +  void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger,                         Core::System& system) {      auto message_queue = std::make_shared<AppletMessageQueue>(system); diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index fdd937b82..11a3c0459 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h @@ -336,6 +336,7 @@ private:      void TryPopFromFriendInvitationStorageChannel(Kernel::HLERequestContext& ctx);      void GetNotificationStorageChannelEvent(Kernel::HLERequestContext& ctx);      void GetHealthWarningDisappearedSystemEvent(Kernel::HLERequestContext& ctx); +    void PrepareForJit(Kernel::HLERequestContext& ctx);      KernelHelpers::ServiceContext service_context; diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp index affa7971c..a72956a28 100644 --- a/src/core/hle/service/audio/audout_u.cpp +++ b/src/core/hle/service/audio/audout_u.cpp @@ -41,9 +41,10 @@ public:      explicit IAudioOut(Core::System& system_, AudoutParams audio_params_,                         AudioCore::AudioOut& audio_core_, std::string&& device_name_,                         std::string&& unique_name) -        : ServiceFramework{system_, "IAudioOut"}, audio_core{audio_core_}, -          device_name{std::move(device_name_)}, audio_params{audio_params_}, -          main_memory{system.Memory()}, service_context{system_, "IAudioOut"} { +        : ServiceFramework{system_, "IAudioOut", ServiceThreadType::CreateNew}, +          audio_core{audio_core_}, device_name{std::move(device_name_)}, +          audio_params{audio_params_}, main_memory{system.Memory()}, service_context{system_, +                                                                                     "IAudioOut"} {          // clang-format off          static const FunctionInfo functions[] = {              {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"}, diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp index f45e5cecc..d4ffeb21d 100644 --- a/src/core/hle/service/audio/audren_u.cpp +++ b/src/core/hle/service/audio/audren_u.cpp @@ -24,7 +24,8 @@ public:      explicit IAudioRenderer(Core::System& system_,                              const AudioCommon::AudioRendererParameter& audren_params,                              const std::size_t instance_number) -        : ServiceFramework{system_, "IAudioRenderer"}, service_context{system_, "IAudioRenderer"} { +        : ServiceFramework{system_, "IAudioRenderer", ServiceThreadType::CreateNew}, +          service_context{system_, "IAudioRenderer"} {          // clang-format off          static const FunctionInfo functions[] = {              {0, &IAudioRenderer::GetSampleRate, "GetSampleRate"}, diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index b087e7bba..c07929ab8 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp @@ -58,7 +58,8 @@ enum class FileSystemType : u8 {  class IStorage final : public ServiceFramework<IStorage> {  public:      explicit IStorage(Core::System& system_, FileSys::VirtualFile backend_) -        : ServiceFramework{system_, "IStorage"}, backend(std::move(backend_)) { +        : ServiceFramework{system_, "IStorage", ServiceThreadType::CreateNew}, +          backend(std::move(backend_)) {          static const FunctionInfo functions[] = {              {0, &IStorage::Read, "Read"},              {1, nullptr, "Write"}, @@ -116,7 +117,8 @@ private:  class IFile final : public ServiceFramework<IFile> {  public:      explicit IFile(Core::System& system_, FileSys::VirtualFile backend_) -        : ServiceFramework{system_, "IFile"}, backend(std::move(backend_)) { +        : ServiceFramework{system_, "IFile", ServiceThreadType::CreateNew}, +          backend(std::move(backend_)) {          static const FunctionInfo functions[] = {              {0, &IFile::Read, "Read"},              {1, &IFile::Write, "Write"}, @@ -252,7 +254,8 @@ static void BuildEntryIndex(std::vector<FileSys::Entry>& entries, const std::vec  class IDirectory final : public ServiceFramework<IDirectory> {  public:      explicit IDirectory(Core::System& system_, FileSys::VirtualDir backend_) -        : ServiceFramework{system_, "IDirectory"}, backend(std::move(backend_)) { +        : ServiceFramework{system_, "IDirectory", ServiceThreadType::CreateNew}, +          backend(std::move(backend_)) {          static const FunctionInfo functions[] = {              {0, &IDirectory::Read, "Read"},              {1, &IDirectory::GetEntryCount, "GetEntryCount"}, @@ -308,8 +311,8 @@ private:  class IFileSystem final : public ServiceFramework<IFileSystem> {  public:      explicit IFileSystem(Core::System& system_, FileSys::VirtualDir backend_, SizeGetter size_) -        : ServiceFramework{system_, "IFileSystem"}, backend{std::move(backend_)}, size{std::move( -                                                                                      size_)} { +        : ServiceFramework{system_, "IFileSystem", ServiceThreadType::CreateNew}, +          backend{std::move(backend_)}, size{std::move(size_)} {          static const FunctionInfo functions[] = {              {0, &IFileSystem::CreateFile, "CreateFile"},              {1, &IFileSystem::DeleteFile, "DeleteFile"}, diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index aa6cb34b7..4e17a952e 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -318,7 +318,7 @@ void Controller_NPad::OnRelease() {  }  void Controller_NPad::RequestPadStateUpdate(Core::HID::NpadIdType npad_id) { -    std::lock_guard lock{mutex}; +    std::scoped_lock lock{mutex};      auto& controller = GetControllerFromNpadIdType(npad_id);      const auto controller_type = controller.device->GetNpadStyleIndex();      if (!controller.device->IsConnected()) { diff --git a/src/core/hle/service/jit/jit.cpp b/src/core/hle/service/jit/jit.cpp new file mode 100644 index 000000000..c8ebd2e3f --- /dev/null +++ b/src/core/hle/service/jit/jit.cpp @@ -0,0 +1,53 @@ +// Copyright 2022 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/ipc_helpers.h" +#include "core/hle/result.h" +#include "core/hle/service/jit/jit.h" +#include "core/hle/service/service.h" + +namespace Service::JIT { + +class IJitEnvironment final : public ServiceFramework<IJitEnvironment> { +public: +    explicit IJitEnvironment(Core::System& system_) : ServiceFramework{system_, "IJitEnvironment"} { +        // clang-format off +        static const FunctionInfo functions[] = { +            {0, nullptr, "GenerateCode"}, +            {1, nullptr, "Control"}, +            {1000, nullptr, "LoadPlugin"}, +            {1001, nullptr, "GetCodeAddress"}, +        }; +        // clang-format on + +        RegisterHandlers(functions); +    } +}; + +class JITU final : public ServiceFramework<JITU> { +public: +    explicit JITU(Core::System& system_) : ServiceFramework{system_, "jit:u"} { +        // clang-format off +        static const FunctionInfo functions[] = { +            {0, &JITU::CreateJitEnvironment, "CreateJitEnvironment"}, +        }; +        // clang-format on + +        RegisterHandlers(functions); +    } + +    void CreateJitEnvironment(Kernel::HLERequestContext& ctx) { +        LOG_DEBUG(Service_JIT, "called"); + +        IPC::ResponseBuilder rb{ctx, 2, 0, 1}; +        rb.Push(ResultSuccess); +        rb.PushIpcInterface<IJitEnvironment>(system); +    } +}; + +void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) { +    std::make_shared<JITU>(system)->InstallAsService(sm); +} + +} // namespace Service::JIT diff --git a/src/core/hle/service/jit/jit.h b/src/core/hle/service/jit/jit.h new file mode 100644 index 000000000..8fbf504a1 --- /dev/null +++ b/src/core/hle/service/jit/jit.h @@ -0,0 +1,20 @@ +// Copyright 2022 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +namespace Core { +class System; +} + +namespace Service::SM { +class ServiceManager; +} + +namespace Service::JIT { + +/// Registers all JIT services with the specified service manager. +void InstallInterfaces(SM::ServiceManager& sm, Core::System& system); + +} // namespace Service::JIT diff --git a/src/core/hle/service/nvdrv/nvdrv_interface.cpp b/src/core/hle/service/nvdrv/nvdrv_interface.cpp index 1ce2a856b..8467b50e4 100644 --- a/src/core/hle/service/nvdrv/nvdrv_interface.cpp +++ b/src/core/hle/service/nvdrv/nvdrv_interface.cpp @@ -230,7 +230,7 @@ void NVDRV::DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx) {  }  NVDRV::NVDRV(Core::System& system_, std::shared_ptr<Module> nvdrv_, const char* name) -    : ServiceFramework{system_, name}, nvdrv{std::move(nvdrv_)} { +    : ServiceFramework{system_, name, ServiceThreadType::CreateNew}, nvdrv{std::move(nvdrv_)} {      static const FunctionInfo functions[] = {          {0, &NVDRV::Open, "Open"},          {1, &NVDRV::Ioctl1, "Ioctl"}, diff --git a/src/core/hle/service/nvflinger/buffer_item_consumer.cpp b/src/core/hle/service/nvflinger/buffer_item_consumer.cpp index 93fa1ec10..d7ee5362b 100644 --- a/src/core/hle/service/nvflinger/buffer_item_consumer.cpp +++ b/src/core/hle/service/nvflinger/buffer_item_consumer.cpp @@ -21,7 +21,7 @@ Status BufferItemConsumer::AcquireBuffer(BufferItem* item, std::chrono::nanoseco          return Status::BadValue;      } -    std::scoped_lock lock(mutex); +    std::scoped_lock lock{mutex};      if (const auto status = AcquireBufferLocked(item, present_when); status != Status::NoError) {          if (status != Status::NoBufferAvailable) { @@ -40,7 +40,7 @@ Status BufferItemConsumer::AcquireBuffer(BufferItem* item, std::chrono::nanoseco  }  Status BufferItemConsumer::ReleaseBuffer(const BufferItem& item, Fence& release_fence) { -    std::scoped_lock lock(mutex); +    std::scoped_lock lock{mutex};      if (const auto status = AddReleaseFenceLocked(item.buf, item.graphic_buffer, release_fence);          status != Status::NoError) { diff --git a/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp b/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp index c527c577e..3ab9a8c05 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp @@ -19,7 +19,7 @@ BufferQueueConsumer::~BufferQueueConsumer() = default;  Status BufferQueueConsumer::AcquireBuffer(BufferItem* out_buffer,                                            std::chrono::nanoseconds expected_present) { -    std::scoped_lock lock(core->mutex); +    std::scoped_lock lock{core->mutex};      // Check that the consumer doesn't currently have the maximum number of buffers acquired.      const s32 num_acquired_buffers{ @@ -120,7 +120,7 @@ Status BufferQueueConsumer::ReleaseBuffer(s32 slot, u64 frame_number, const Fenc      std::shared_ptr<IProducerListener> listener;      { -        std::scoped_lock lock(core->mutex); +        std::scoped_lock lock{core->mutex};          // If the frame number has changed because the buffer has been reallocated, we can ignore          // this ReleaseBuffer for the old buffer. @@ -180,7 +180,7 @@ Status BufferQueueConsumer::Connect(std::shared_ptr<IConsumerListener> consumer_      LOG_DEBUG(Service_NVFlinger, "controlled_by_app={}", controlled_by_app); -    std::scoped_lock lock(core->mutex); +    std::scoped_lock lock{core->mutex};      if (core->is_abandoned) {          LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned"); @@ -199,7 +199,7 @@ Status BufferQueueConsumer::GetReleasedBuffers(u64* out_slot_mask) {          return Status::BadValue;      } -    std::scoped_lock lock(core->mutex); +    std::scoped_lock lock{core->mutex};      if (core->is_abandoned) {          LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned"); diff --git a/src/core/hle/service/nvflinger/buffer_queue_core.cpp b/src/core/hle/service/nvflinger/buffer_queue_core.cpp index 3a0481786..ec5aabaeb 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_core.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue_core.cpp @@ -15,7 +15,7 @@ BufferQueueCore::BufferQueueCore() = default;  BufferQueueCore::~BufferQueueCore() = default;  void BufferQueueCore::NotifyShutdown() { -    std::scoped_lock lock(mutex); +    std::scoped_lock lock{mutex};      is_shutting_down = true; diff --git a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp index 3d6e990c3..6f604a88e 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp @@ -38,7 +38,7 @@ BufferQueueProducer::~BufferQueueProducer() {  Status BufferQueueProducer::RequestBuffer(s32 slot, std::shared_ptr<GraphicBuffer>* buf) {      LOG_DEBUG(Service_NVFlinger, "slot {}", slot); -    std::scoped_lock lock(core->mutex); +    std::scoped_lock lock{core->mutex};      if (core->is_abandoned) {          LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned"); @@ -65,7 +65,7 @@ Status BufferQueueProducer::SetBufferCount(s32 buffer_count) {      std::shared_ptr<IConsumerListener> listener;      { -        std::scoped_lock lock(core->mutex); +        std::scoped_lock lock{core->mutex};          core->WaitWhileAllocatingLocked();          if (core->is_abandoned) { @@ -236,7 +236,7 @@ Status BufferQueueProducer::DequeueBuffer(s32* out_slot, Fence* out_fence, bool      Status return_flags = Status::NoError;      bool attached_by_consumer = false;      { -        std::scoped_lock lock(core->mutex); +        std::scoped_lock lock{core->mutex};          core->WaitWhileAllocatingLocked();          if (format == PixelFormat::NoFormat) { @@ -295,7 +295,7 @@ Status BufferQueueProducer::DequeueBuffer(s32* out_slot, Fence* out_fence, bool          }          { -            std::scoped_lock lock(core->mutex); +            std::scoped_lock lock{core->mutex};              if (core->is_abandoned) {                  LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned"); @@ -320,7 +320,7 @@ Status BufferQueueProducer::DequeueBuffer(s32* out_slot, Fence* out_fence, bool  Status BufferQueueProducer::DetachBuffer(s32 slot) {      LOG_DEBUG(Service_NVFlinger, "slot {}", slot); -    std::scoped_lock lock(core->mutex); +    std::scoped_lock lock{core->mutex};      if (core->is_abandoned) {          LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned"); @@ -356,7 +356,7 @@ Status BufferQueueProducer::DetachNextBuffer(std::shared_ptr<GraphicBuffer>* out          return Status::BadValue;      } -    std::scoped_lock lock(core->mutex); +    std::scoped_lock lock{core->mutex};      core->WaitWhileAllocatingLocked();      if (core->is_abandoned) { @@ -399,7 +399,7 @@ Status BufferQueueProducer::AttachBuffer(s32* out_slot,          return Status::BadValue;      } -    std::scoped_lock lock(core->mutex); +    std::scoped_lock lock{core->mutex};      core->WaitWhileAllocatingLocked();      Status return_flags = Status::NoError; @@ -460,7 +460,7 @@ Status BufferQueueProducer::QueueBuffer(s32 slot, const QueueBufferInput& input,      BufferItem item;      { -        std::scoped_lock lock(core->mutex); +        std::scoped_lock lock{core->mutex};          if (core->is_abandoned) {              LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned"); @@ -576,7 +576,7 @@ Status BufferQueueProducer::QueueBuffer(s32 slot, const QueueBufferInput& input,      // Call back without the main BufferQueue lock held, but with the callback lock held so we can      // ensure that callbacks occur in order      { -        std::scoped_lock lock(callback_mutex); +        std::scoped_lock lock{callback_mutex};          while (callback_ticket != current_callback_ticket) {              callback_condition.wait(callback_mutex);          } @@ -597,7 +597,7 @@ Status BufferQueueProducer::QueueBuffer(s32 slot, const QueueBufferInput& input,  void BufferQueueProducer::CancelBuffer(s32 slot, const Fence& fence) {      LOG_DEBUG(Service_NVFlinger, "slot {}", slot); -    std::scoped_lock lock(core->mutex); +    std::scoped_lock lock{core->mutex};      if (core->is_abandoned) {          LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned"); @@ -623,7 +623,7 @@ void BufferQueueProducer::CancelBuffer(s32 slot, const Fence& fence) {  }  Status BufferQueueProducer::Query(NativeWindow what, s32* out_value) { -    std::scoped_lock lock(core->mutex); +    std::scoped_lock lock{core->mutex};      if (out_value == nullptr) {          LOG_ERROR(Service_NVFlinger, "outValue was nullptr"); @@ -673,7 +673,7 @@ Status BufferQueueProducer::Query(NativeWindow what, s32* out_value) {  Status BufferQueueProducer::Connect(const std::shared_ptr<IProducerListener>& listener,                                      NativeWindowApi api, bool producer_controlled_by_app,                                      QueueBufferOutput* output) { -    std::scoped_lock lock(core->mutex); +    std::scoped_lock lock{core->mutex};      LOG_DEBUG(Service_NVFlinger, "api = {} producer_controlled_by_app = {}", api,                producer_controlled_by_app); @@ -730,7 +730,7 @@ Status BufferQueueProducer::Disconnect(NativeWindowApi api) {      std::shared_ptr<IConsumerListener> listener;      { -        std::scoped_lock lock(core->mutex); +        std::scoped_lock lock{core->mutex};          core->WaitWhileAllocatingLocked(); @@ -780,7 +780,7 @@ Status BufferQueueProducer::SetPreallocatedBuffer(s32 slot,          return Status::BadValue;      } -    std::scoped_lock lock(core->mutex); +    std::scoped_lock lock{core->mutex};      slots[slot] = {};      slots[slot].graphic_buffer = buffer; diff --git a/src/core/hle/service/nvflinger/consumer_base.cpp b/src/core/hle/service/nvflinger/consumer_base.cpp index c2c80832c..30fc21acc 100644 --- a/src/core/hle/service/nvflinger/consumer_base.cpp +++ b/src/core/hle/service/nvflinger/consumer_base.cpp @@ -18,7 +18,7 @@ ConsumerBase::ConsumerBase(std::unique_ptr<BufferQueueConsumer> consumer_)      : consumer{std::move(consumer_)} {}  ConsumerBase::~ConsumerBase() { -    std::scoped_lock lock(mutex); +    std::scoped_lock lock{mutex};      ASSERT_MSG(is_abandoned, "consumer is not abandoned!");  } @@ -44,7 +44,7 @@ void ConsumerBase::OnFrameReplaced(const BufferItem& item) {  }  void ConsumerBase::OnBuffersReleased() { -    std::scoped_lock lock(mutex); +    std::scoped_lock lock{mutex};      LOG_DEBUG(Service_NVFlinger, "called"); diff --git a/src/core/hle/service/nvflinger/graphic_buffer_producer.cpp b/src/core/hle/service/nvflinger/graphic_buffer_producer.cpp index d4da98ddb..04068827e 100644 --- a/src/core/hle/service/nvflinger/graphic_buffer_producer.cpp +++ b/src/core/hle/service/nvflinger/graphic_buffer_producer.cpp @@ -4,8 +4,6 @@  // Parts of this implementation were base on:  // https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/libs/gui/IGraphicBufferProducer.cpp -#pragma once -  #include "core/hle/service/nvflinger/graphic_buffer_producer.h"  #include "core/hle/service/nvflinger/parcel.h" diff --git a/src/core/hle/service/nvflinger/hos_binder_driver_server.cpp b/src/core/hle/service/nvflinger/hos_binder_driver_server.cpp index 0c937d682..094ba2542 100644 --- a/src/core/hle/service/nvflinger/hos_binder_driver_server.cpp +++ b/src/core/hle/service/nvflinger/hos_binder_driver_server.cpp @@ -14,7 +14,7 @@ HosBinderDriverServer::HosBinderDriverServer(Core::System& system_)  HosBinderDriverServer::~HosBinderDriverServer() {}  u64 HosBinderDriverServer::RegisterProducer(std::unique_ptr<android::IBinder>&& binder) { -    std::lock_guard lk{lock}; +    std::scoped_lock lk{lock};      last_id++; @@ -24,7 +24,7 @@ u64 HosBinderDriverServer::RegisterProducer(std::unique_ptr<android::IBinder>&&  }  android::IBinder* HosBinderDriverServer::TryGetProducer(u64 id) { -    std::lock_guard lk{lock}; +    std::scoped_lock lk{lock};      if (auto search = producers.find(id); search != producers.end()) {          return search->second.get(); diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index ab3286db9..0f59a03c5 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -32,6 +32,7 @@  #include "core/hle/service/glue/glue.h"  #include "core/hle/service/grc/grc.h"  #include "core/hle/service/hid/hid.h" +#include "core/hle/service/jit/jit.h"  #include "core/hle/service/lbl/lbl.h"  #include "core/hle/service/ldn/ldn.h"  #include "core/hle/service/ldr/ldr.h" @@ -91,8 +92,9 @@ namespace Service {  }  ServiceFrameworkBase::ServiceFrameworkBase(Core::System& system_, const char* service_name_, -                                           u32 max_sessions_, InvokerFn* handler_invoker_) -    : SessionRequestHandler(system_.Kernel(), service_name_), system{system_}, +                                           ServiceThreadType thread_type, u32 max_sessions_, +                                           InvokerFn* handler_invoker_) +    : SessionRequestHandler(system_.Kernel(), service_name_, thread_type), system{system_},        service_name{service_name_}, max_sessions{max_sessions_}, handler_invoker{handler_invoker_} {}  ServiceFrameworkBase::~ServiceFrameworkBase() { @@ -261,6 +263,7 @@ Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system      Glue::InstallInterfaces(system);      GRC::InstallInterfaces(*sm, system);      HID::InstallInterfaces(*sm, system); +    JIT::InstallInterfaces(*sm, system);      LBL::InstallInterfaces(*sm, system);      LDN::InstallInterfaces(*sm, system);      LDR::InstallInterfaces(*sm, system); diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index b9ab2c465..c78b2baeb 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -114,7 +114,8 @@ private:                             Kernel::HLERequestContext& ctx);      explicit ServiceFrameworkBase(Core::System& system_, const char* service_name_, -                                  u32 max_sessions_, InvokerFn* handler_invoker_); +                                  ServiceThreadType thread_type, u32 max_sessions_, +                                  InvokerFn* handler_invoker_);      ~ServiceFrameworkBase() override;      void RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n); @@ -176,14 +177,17 @@ protected:      /**       * Initializes the handler with no functions installed.       * -     * @param system_       The system context to construct this service under. +     * @param system_ The system context to construct this service under.       * @param service_name_ Name of the service. -     * @param max_sessions_ Maximum number of sessions that can be -     *                      connected to this service at the same time. +     * @param thread_type Specifies the thread type for this service. If this is set to CreateNew, +     *                    it creates a new thread for it, otherwise this uses the default thread. +     * @param max_sessions_ Maximum number of sessions that can be connected to this service at the +     * same time.       */      explicit ServiceFramework(Core::System& system_, const char* service_name_, +                              ServiceThreadType thread_type = ServiceThreadType::Default,                                u32 max_sessions_ = ServerSessionCountMax) -        : ServiceFrameworkBase(system_, service_name_, max_sessions_, Invoker) {} +        : ServiceFrameworkBase(system_, service_name_, thread_type, max_sessions_, Invoker) {}      /// Registers handlers in the service.      template <std::size_t N> diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp index 695a1faa6..97f895852 100644 --- a/src/core/hle/service/sm/sm.cpp +++ b/src/core/hle/service/sm/sm.cpp @@ -206,7 +206,7 @@ void SM::UnregisterService(Kernel::HLERequestContext& ctx) {  }  SM::SM(ServiceManager& service_manager_, Core::System& system_) -    : ServiceFramework{system_, "sm:", 4}, +    : ServiceFramework{system_, "sm:", ServiceThreadType::Default, 4},        service_manager{service_manager_}, kernel{system_.Kernel()} {      RegisterHandlers({          {0, &SM::Initialize, "Initialize"}, diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp index e5631c27e..d25b050e2 100644 --- a/src/core/hle/service/sockets/bsd.cpp +++ b/src/core/hle/service/sockets/bsd.cpp @@ -840,7 +840,8 @@ void BSD::BuildErrnoResponse(Kernel::HLERequestContext& ctx, Errno bsd_errno) co      rb.PushEnum(bsd_errno);  } -BSD::BSD(Core::System& system_, const char* name) : ServiceFramework{system_, name} { +BSD::BSD(Core::System& system_, const char* name) +    : ServiceFramework{system_, name, ServiceThreadType::CreateNew} {      // clang-format off      static const FunctionInfo functions[] = {          {0, &BSD::RegisterClient, "RegisterClient"}, diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index 430cbc546..a3436c8ea 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp @@ -77,7 +77,8 @@ static_assert(sizeof(NativeWindow) == 0x28, "NativeWindow has wrong size");  class IHOSBinderDriver final : public ServiceFramework<IHOSBinderDriver> {  public:      explicit IHOSBinderDriver(Core::System& system_, NVFlinger::HosBinderDriverServer& server_) -        : ServiceFramework{system_, "IHOSBinderDriver"}, server(server_) { +        : ServiceFramework{system_, "IHOSBinderDriver", ServiceThreadType::CreateNew}, +          server(server_) {          static const FunctionInfo functions[] = {              {0, &IHOSBinderDriver::TransactParcel, "TransactParcel"},              {1, &IHOSBinderDriver::AdjustRefcount, "AdjustRefcount"}, diff --git a/src/core/perf_stats.cpp b/src/core/perf_stats.cpp index 52c43c857..6ef459b7a 100644 --- a/src/core/perf_stats.cpp +++ b/src/core/perf_stats.cpp @@ -53,13 +53,13 @@ PerfStats::~PerfStats() {  }  void PerfStats::BeginSystemFrame() { -    std::lock_guard lock{object_mutex}; +    std::scoped_lock lock{object_mutex};      frame_begin = Clock::now();  }  void PerfStats::EndSystemFrame() { -    std::lock_guard lock{object_mutex}; +    std::scoped_lock lock{object_mutex};      auto frame_end = Clock::now();      const auto frame_time = frame_end - frame_begin; @@ -79,7 +79,7 @@ void PerfStats::EndGameFrame() {  }  double PerfStats::GetMeanFrametime() const { -    std::lock_guard lock{object_mutex}; +    std::scoped_lock lock{object_mutex};      if (current_index <= IgnoreFrames) {          return 0; @@ -91,7 +91,7 @@ double PerfStats::GetMeanFrametime() const {  }  PerfStatsResults PerfStats::GetAndResetStats(microseconds current_system_time_us) { -    std::lock_guard lock{object_mutex}; +    std::scoped_lock lock{object_mutex};      const auto now = Clock::now();      // Walltime elapsed since stats were reset @@ -120,7 +120,7 @@ PerfStatsResults PerfStats::GetAndResetStats(microseconds current_system_time_us  }  double PerfStats::GetLastFrameTimeScale() const { -    std::lock_guard lock{object_mutex}; +    std::scoped_lock lock{object_mutex};      constexpr double FRAME_LENGTH = 1.0 / 60;      return duration_cast<DoubleSecs>(previous_frame_length).count() / FRAME_LENGTH; diff --git a/src/core/tools/freezer.cpp b/src/core/tools/freezer.cpp index 032c71aff..c81dc0e52 100644 --- a/src/core/tools/freezer.cpp +++ b/src/core/tools/freezer.cpp @@ -80,7 +80,7 @@ bool Freezer::IsActive() const {  }  void Freezer::Clear() { -    std::lock_guard lock{entries_mutex}; +    std::scoped_lock lock{entries_mutex};      LOG_DEBUG(Common_Memory, "Clearing all frozen memory values."); @@ -88,7 +88,7 @@ void Freezer::Clear() {  }  u64 Freezer::Freeze(VAddr address, u32 width) { -    std::lock_guard lock{entries_mutex}; +    std::scoped_lock lock{entries_mutex};      const auto current_value = MemoryReadWidth(memory, width, address);      entries.push_back({address, width, current_value}); @@ -101,7 +101,7 @@ u64 Freezer::Freeze(VAddr address, u32 width) {  }  void Freezer::Unfreeze(VAddr address) { -    std::lock_guard lock{entries_mutex}; +    std::scoped_lock lock{entries_mutex};      LOG_DEBUG(Common_Memory, "Unfreezing memory for address={:016X}", address); @@ -109,13 +109,13 @@ void Freezer::Unfreeze(VAddr address) {  }  bool Freezer::IsFrozen(VAddr address) const { -    std::lock_guard lock{entries_mutex}; +    std::scoped_lock lock{entries_mutex};      return FindEntry(address) != entries.cend();  }  void Freezer::SetFrozenValue(VAddr address, u64 value) { -    std::lock_guard lock{entries_mutex}; +    std::scoped_lock lock{entries_mutex};      const auto iter = FindEntry(address); @@ -132,7 +132,7 @@ void Freezer::SetFrozenValue(VAddr address, u64 value) {  }  std::optional<Freezer::Entry> Freezer::GetEntry(VAddr address) const { -    std::lock_guard lock{entries_mutex}; +    std::scoped_lock lock{entries_mutex};      const auto iter = FindEntry(address); @@ -144,7 +144,7 @@ std::optional<Freezer::Entry> Freezer::GetEntry(VAddr address) const {  }  std::vector<Freezer::Entry> Freezer::GetEntries() const { -    std::lock_guard lock{entries_mutex}; +    std::scoped_lock lock{entries_mutex};      return entries;  } @@ -165,7 +165,7 @@ void Freezer::FrameCallback(std::uintptr_t, std::chrono::nanoseconds ns_late) {          return;      } -    std::lock_guard lock{entries_mutex}; +    std::scoped_lock lock{entries_mutex};      for (const auto& entry : entries) {          LOG_DEBUG(Common_Memory, @@ -178,7 +178,7 @@ void Freezer::FrameCallback(std::uintptr_t, std::chrono::nanoseconds ns_late) {  }  void Freezer::FillEntryReads() { -    std::lock_guard lock{entries_mutex}; +    std::scoped_lock lock{entries_mutex};      LOG_DEBUG(Common_Memory, "Updating memory freeze entries to current values."); diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp index c17ea305e..b3e4c3f64 100644 --- a/src/input_common/drivers/sdl_driver.cpp +++ b/src/input_common/drivers/sdl_driver.cpp @@ -62,7 +62,7 @@ public:      bool UpdateMotion(SDL_ControllerSensorEvent event) {          constexpr float gravity_constant = 9.80665f; -        std::lock_guard lock{mutex}; +        std::scoped_lock lock{mutex};          const u64 time_difference = event.timestamp - last_motion_update;          last_motion_update = event.timestamp;          switch (event.sensor) { @@ -241,7 +241,7 @@ private:  };  std::shared_ptr<SDLJoystick> SDLDriver::GetSDLJoystickByGUID(const std::string& guid, int port) { -    std::lock_guard lock{joystick_map_mutex}; +    std::scoped_lock lock{joystick_map_mutex};      const auto it = joystick_map.find(guid);      if (it != joystick_map.end()) { @@ -263,7 +263,7 @@ std::shared_ptr<SDLJoystick> SDLDriver::GetSDLJoystickBySDLID(SDL_JoystickID sdl      auto sdl_joystick = SDL_JoystickFromInstanceID(sdl_id);      const std::string guid = GetGUID(sdl_joystick); -    std::lock_guard lock{joystick_map_mutex}; +    std::scoped_lock lock{joystick_map_mutex};      const auto map_it = joystick_map.find(guid);      if (map_it == joystick_map.end()) { @@ -297,7 +297,7 @@ void SDLDriver::InitJoystick(int joystick_index) {      const std::string guid = GetGUID(sdl_joystick); -    std::lock_guard lock{joystick_map_mutex}; +    std::scoped_lock lock{joystick_map_mutex};      if (joystick_map.find(guid) == joystick_map.end()) {          auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick, sdl_gamecontroller);          PreSetController(joystick->GetPadIdentifier()); @@ -326,7 +326,7 @@ void SDLDriver::InitJoystick(int joystick_index) {  void SDLDriver::CloseJoystick(SDL_Joystick* sdl_joystick) {      const std::string guid = GetGUID(sdl_joystick); -    std::lock_guard lock{joystick_map_mutex}; +    std::scoped_lock lock{joystick_map_mutex};      // This call to guid is safe since the joystick is guaranteed to be in the map      const auto& joystick_guid_list = joystick_map[guid];      const auto joystick_it = std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(), @@ -392,7 +392,7 @@ void SDLDriver::HandleGameControllerEvent(const SDL_Event& event) {  }  void SDLDriver::CloseJoysticks() { -    std::lock_guard lock{joystick_map_mutex}; +    std::scoped_lock lock{joystick_map_mutex};      joystick_map.clear();  } diff --git a/src/input_common/input_engine.cpp b/src/input_common/input_engine.cpp index 738022ece..a16cca33d 100644 --- a/src/input_common/input_engine.cpp +++ b/src/input_common/input_engine.cpp @@ -8,37 +8,37 @@  namespace InputCommon {  void InputEngine::PreSetController(const PadIdentifier& identifier) { -    std::lock_guard lock{mutex}; +    std::scoped_lock lock{mutex};      controller_list.try_emplace(identifier);  }  void InputEngine::PreSetButton(const PadIdentifier& identifier, int button) { -    std::lock_guard lock{mutex}; +    std::scoped_lock lock{mutex};      ControllerData& controller = controller_list.at(identifier);      controller.buttons.try_emplace(button, false);  }  void InputEngine::PreSetHatButton(const PadIdentifier& identifier, int button) { -    std::lock_guard lock{mutex}; +    std::scoped_lock lock{mutex};      ControllerData& controller = controller_list.at(identifier);      controller.hat_buttons.try_emplace(button, u8{0});  }  void InputEngine::PreSetAxis(const PadIdentifier& identifier, int axis) { -    std::lock_guard lock{mutex}; +    std::scoped_lock lock{mutex};      ControllerData& controller = controller_list.at(identifier);      controller.axes.try_emplace(axis, 0.0f);  }  void InputEngine::PreSetMotion(const PadIdentifier& identifier, int motion) { -    std::lock_guard lock{mutex}; +    std::scoped_lock lock{mutex};      ControllerData& controller = controller_list.at(identifier);      controller.motions.try_emplace(motion);  }  void InputEngine::SetButton(const PadIdentifier& identifier, int button, bool value) {      { -        std::lock_guard lock{mutex}; +        std::scoped_lock lock{mutex};          ControllerData& controller = controller_list.at(identifier);          if (!configuring) {              controller.buttons.insert_or_assign(button, value); @@ -49,7 +49,7 @@ void InputEngine::SetButton(const PadIdentifier& identifier, int button, bool va  void InputEngine::SetHatButton(const PadIdentifier& identifier, int button, u8 value) {      { -        std::lock_guard lock{mutex}; +        std::scoped_lock lock{mutex};          ControllerData& controller = controller_list.at(identifier);          if (!configuring) {              controller.hat_buttons.insert_or_assign(button, value); @@ -60,7 +60,7 @@ void InputEngine::SetHatButton(const PadIdentifier& identifier, int button, u8 v  void InputEngine::SetAxis(const PadIdentifier& identifier, int axis, f32 value) {      { -        std::lock_guard lock{mutex}; +        std::scoped_lock lock{mutex};          ControllerData& controller = controller_list.at(identifier);          if (!configuring) {              controller.axes.insert_or_assign(axis, value); @@ -71,7 +71,7 @@ void InputEngine::SetAxis(const PadIdentifier& identifier, int axis, f32 value)  void InputEngine::SetBattery(const PadIdentifier& identifier, Common::Input::BatteryLevel value) {      { -        std::lock_guard lock{mutex}; +        std::scoped_lock lock{mutex};          ControllerData& controller = controller_list.at(identifier);          if (!configuring) {              controller.battery = value; @@ -82,7 +82,7 @@ void InputEngine::SetBattery(const PadIdentifier& identifier, Common::Input::Bat  void InputEngine::SetMotion(const PadIdentifier& identifier, int motion, const BasicMotion& value) {      { -        std::lock_guard lock{mutex}; +        std::scoped_lock lock{mutex};          ControllerData& controller = controller_list.at(identifier);          if (!configuring) {              controller.motions.insert_or_assign(motion, value); @@ -92,7 +92,7 @@ void InputEngine::SetMotion(const PadIdentifier& identifier, int motion, const B  }  bool InputEngine::GetButton(const PadIdentifier& identifier, int button) const { -    std::lock_guard lock{mutex}; +    std::scoped_lock lock{mutex};      const auto controller_iter = controller_list.find(identifier);      if (controller_iter == controller_list.cend()) {          LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.RawString(), @@ -109,7 +109,7 @@ bool InputEngine::GetButton(const PadIdentifier& identifier, int button) const {  }  bool InputEngine::GetHatButton(const PadIdentifier& identifier, int button, u8 direction) const { -    std::lock_guard lock{mutex}; +    std::scoped_lock lock{mutex};      const auto controller_iter = controller_list.find(identifier);      if (controller_iter == controller_list.cend()) {          LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.RawString(), @@ -126,7 +126,7 @@ bool InputEngine::GetHatButton(const PadIdentifier& identifier, int button, u8 d  }  f32 InputEngine::GetAxis(const PadIdentifier& identifier, int axis) const { -    std::lock_guard lock{mutex}; +    std::scoped_lock lock{mutex};      const auto controller_iter = controller_list.find(identifier);      if (controller_iter == controller_list.cend()) {          LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.RawString(), @@ -143,7 +143,7 @@ f32 InputEngine::GetAxis(const PadIdentifier& identifier, int axis) const {  }  Common::Input::BatteryLevel InputEngine::GetBattery(const PadIdentifier& identifier) const { -    std::lock_guard lock{mutex}; +    std::scoped_lock lock{mutex};      const auto controller_iter = controller_list.find(identifier);      if (controller_iter == controller_list.cend()) {          LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.RawString(), @@ -155,7 +155,7 @@ Common::Input::BatteryLevel InputEngine::GetBattery(const PadIdentifier& identif  }  BasicMotion InputEngine::GetMotion(const PadIdentifier& identifier, int motion) const { -    std::lock_guard lock{mutex}; +    std::scoped_lock lock{mutex};      const auto controller_iter = controller_list.find(identifier);      if (controller_iter == controller_list.cend()) {          LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.RawString(), @@ -186,7 +186,7 @@ void InputEngine::ResetAnalogState() {  }  void InputEngine::TriggerOnButtonChange(const PadIdentifier& identifier, int button, bool value) { -    std::lock_guard lock{mutex_callback}; +    std::scoped_lock lock{mutex_callback};      for (const auto& poller_pair : callback_list) {          const InputIdentifier& poller = poller_pair.second;          if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::Button, button)) { @@ -214,7 +214,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}; +    std::scoped_lock lock{mutex_callback};      for (const auto& poller_pair : callback_list) {          const InputIdentifier& poller = poller_pair.second;          if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::HatButton, button)) { @@ -243,7 +243,7 @@ void InputEngine::TriggerOnHatButtonChange(const PadIdentifier& identifier, int  }  void InputEngine::TriggerOnAxisChange(const PadIdentifier& identifier, int axis, f32 value) { -    std::lock_guard lock{mutex_callback}; +    std::scoped_lock lock{mutex_callback};      for (const auto& poller_pair : callback_list) {          const InputIdentifier& poller = poller_pair.second;          if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::Analog, axis)) { @@ -270,7 +270,7 @@ void InputEngine::TriggerOnAxisChange(const PadIdentifier& identifier, int axis,  void InputEngine::TriggerOnBatteryChange(const PadIdentifier& identifier,                                           [[maybe_unused]] Common::Input::BatteryLevel value) { -    std::lock_guard lock{mutex_callback}; +    std::scoped_lock lock{mutex_callback};      for (const auto& poller_pair : callback_list) {          const InputIdentifier& poller = poller_pair.second;          if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::Battery, 0)) { @@ -284,7 +284,7 @@ void InputEngine::TriggerOnBatteryChange(const PadIdentifier& identifier,  void InputEngine::TriggerOnMotionChange(const PadIdentifier& identifier, int motion,                                          const BasicMotion& value) { -    std::lock_guard lock{mutex_callback}; +    std::scoped_lock lock{mutex_callback};      for (const auto& poller_pair : callback_list) {          const InputIdentifier& poller = poller_pair.second;          if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::Motion, motion)) { @@ -346,18 +346,18 @@ const std::string& InputEngine::GetEngineName() const {  }  int InputEngine::SetCallback(InputIdentifier input_identifier) { -    std::lock_guard lock{mutex_callback}; +    std::scoped_lock lock{mutex_callback};      callback_list.insert_or_assign(last_callback_key, std::move(input_identifier));      return last_callback_key++;  }  void InputEngine::SetMappingCallback(MappingCallback callback) { -    std::lock_guard lock{mutex_callback}; +    std::scoped_lock lock{mutex_callback};      mapping_callback = std::move(callback);  }  void InputEngine::DeleteCallback(int key) { -    std::lock_guard lock{mutex_callback}; +    std::scoped_lock lock{mutex_callback};      const auto& iterator = callback_list.find(key);      if (iterator == callback_list.end()) {          LOG_ERROR(Input, "Tried to delete non-existent callback {}", key); diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp index 0c1fbc7b1..282668b36 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp +++ b/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp @@ -35,6 +35,15 @@ std::string_view OutputVertexIndex(EmitContext& ctx) {      return ctx.stage == Stage::TessellationControl ? "[gl_InvocationID]" : "";  } +std::string ChooseCbuf(EmitContext& ctx, const IR::Value& binding, std::string_view index) { +    if (binding.IsImmediate()) { +        return fmt::format("{}_cbuf{}[{}]", ctx.stage_name, binding.U32(), index); +    } else { +        const auto binding_var{ctx.var_alloc.Consume(binding)}; +        return fmt::format("GetCbufIndirect({},{})", binding_var, index); +    } +} +  void GetCbuf(EmitContext& ctx, std::string_view ret, const IR::Value& binding,               const IR::Value& offset, u32 num_bits, std::string_view cast = {},               std::string_view bit_offset = {}) { @@ -55,8 +64,8 @@ void GetCbuf(EmitContext& ctx, std::string_view ret, const IR::Value& binding,      const auto swizzle{is_immediate ? fmt::format(".{}", OffsetSwizzle(offset.U32()))                                      : fmt::format("[({}>>2)%4]", offset_var)}; -    const auto cbuf{fmt::format("{}_cbuf{}", ctx.stage_name, binding.U32())}; -    const auto cbuf_cast{fmt::format("{}({}[{}]{{}})", cast, cbuf, index)}; +    const auto cbuf{ChooseCbuf(ctx, binding, index)}; +    const auto cbuf_cast{fmt::format("{}({}{{}})", cast, cbuf)};      const auto extraction{num_bits == 32 ? cbuf_cast                                           : fmt::format("bitfieldExtract({},int({}),{})", cbuf_cast,                                                         bit_offset, num_bits)}; @@ -140,9 +149,9 @@ void EmitGetCbufF32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,  void EmitGetCbufU32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,                        const IR::Value& offset) { -    const auto cbuf{fmt::format("{}_cbuf{}", ctx.stage_name, binding.U32())};      const auto cast{ctx.profile.has_gl_cbuf_ftou_bug ? "" : "ftou"};      if (offset.IsImmediate()) { +        const auto cbuf{fmt::format("{}_cbuf{}", ctx.stage_name, binding.U32())};          static constexpr u32 cbuf_size{0x10000};          const u32 u32_offset{offset.U32()};          const s32 signed_offset{static_cast<s32>(offset.U32())}; @@ -162,17 +171,17 @@ void EmitGetCbufU32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding          return;      }      const auto offset_var{ctx.var_alloc.Consume(offset)}; +    const auto cbuf{ChooseCbuf(ctx, binding, fmt::format("{}>>4", offset_var))};      if (!ctx.profile.has_gl_component_indexing_bug) { -        ctx.AddU32x2("{}=uvec2({}({}[{}>>4][({}>>2)%4]),{}({}[({}+4)>>4][(({}+4)>>2)%4]));", inst, -                     cast, cbuf, offset_var, offset_var, cast, cbuf, offset_var, offset_var); +        ctx.AddU32x2("{}=uvec2({}({}[({}>>2)%4]),{}({}[(({}+4)>>2)%4]));", inst, cast, cbuf, +                     offset_var, cast, cbuf, offset_var);          return;      }      const auto ret{ctx.var_alloc.Define(inst, GlslVarType::U32x2)};      const auto cbuf_offset{fmt::format("{}>>2", offset_var)};      for (u32 swizzle = 0; swizzle < 4; ++swizzle) { -        ctx.Add("if(({}&3)=={}){}=uvec2({}({}[{}>>4].{}),{}({}[({}+4)>>4].{}));", cbuf_offset, -                swizzle, ret, cast, cbuf, offset_var, "xyzw"[swizzle], cast, cbuf, offset_var, -                "xyzw"[(swizzle + 1) % 4]); +        ctx.Add("if(({}&3)=={}){}=uvec2({}({}.{}),{}({}.{}));", cbuf_offset, swizzle, ret, cast, +                cbuf, "xyzw"[swizzle], cast, cbuf, "xyzw"[(swizzle + 1) % 4]);      }  } diff --git a/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp b/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp index e816a93ec..17266f40d 100644 --- a/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp +++ b/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp @@ -359,6 +359,7 @@ EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile          header += "layout(location=0) uniform vec4 scaling;";      }      DefineConstantBuffers(bindings); +    DefineConstantBufferIndirect();      DefineStorageBuffers(bindings);      SetupImages(bindings);      SetupTextures(bindings); @@ -436,6 +437,24 @@ void EmitContext::DefineConstantBuffers(Bindings& bindings) {      }  } +void EmitContext::DefineConstantBufferIndirect() { +    if (!info.uses_cbuf_indirect) { +        return; +    } + +    header += profile.has_gl_cbuf_ftou_bug ? "uvec4 " : "vec4 "; +    header += "GetCbufIndirect(uint binding, uint offset){" +              "switch(binding){" +              "default:"; + +    for (const auto& desc : info.constant_buffer_descriptors) { +        header += +            fmt::format("case {}:return {}_cbuf{}[offset];", desc.index, stage_name, desc.index); +    } + +    header += "}}"; +} +  void EmitContext::DefineStorageBuffers(Bindings& bindings) {      if (info.storage_buffers_descriptors.empty()) {          return; diff --git a/src/shader_recompiler/backend/glsl/glsl_emit_context.h b/src/shader_recompiler/backend/glsl/glsl_emit_context.h index d9b639d29..2b13db6e6 100644 --- a/src/shader_recompiler/backend/glsl/glsl_emit_context.h +++ b/src/shader_recompiler/backend/glsl/glsl_emit_context.h @@ -162,6 +162,7 @@ public:  private:      void SetupExtensions();      void DefineConstantBuffers(Bindings& bindings); +    void DefineConstantBufferIndirect();      void DefineStorageBuffers(Bindings& bindings);      void DefineGenericOutput(size_t index, u32 invocations);      void DefineHelperFunctions(); diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp index 28f6a6184..9c83cd2e4 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp @@ -1043,15 +1043,15 @@ void EmitContext::DefineConstantBufferIndirectFunctions(const Info& info) {          const Id merge_label{OpLabel()};          const Id uniform_type{uniform_types.*member_ptr}; -        std::array<Id, Info::MAX_CBUFS> buf_labels; -        std::array<Sirit::Literal, Info::MAX_CBUFS> buf_literals; -        for (u32 i = 0; i < Info::MAX_CBUFS; i++) { +        std::array<Id, Info::MAX_INDIRECT_CBUFS> buf_labels; +        std::array<Sirit::Literal, Info::MAX_INDIRECT_CBUFS> buf_literals; +        for (u32 i = 0; i < Info::MAX_INDIRECT_CBUFS; i++) {              buf_labels[i] = OpLabel();              buf_literals[i] = Sirit::Literal{i};          }          OpSelectionMerge(merge_label, spv::SelectionControlMask::MaskNone);          OpSwitch(binding, buf_labels[0], buf_literals, buf_labels); -        for (u32 i = 0; i < Info::MAX_CBUFS; i++) { +        for (u32 i = 0; i < Info::MAX_INDIRECT_CBUFS; i++) {              AddLabel(buf_labels[i]);              const Id cbuf{cbufs[i].*member_ptr};              const Id access_chain{OpAccessChain(uniform_type, cbuf, u32_zero_value, offset)}; @@ -1064,22 +1064,23 @@ void EmitContext::DefineConstantBufferIndirectFunctions(const Info& info) {          return func;      }};      IR::Type types{info.used_indirect_cbuf_types}; -    if (True(types & IR::Type::U8)) { +    bool supports_aliasing = profile.support_descriptor_aliasing; +    if (supports_aliasing && True(types & IR::Type::U8)) {          load_const_func_u8 = make_accessor(U8, &UniformDefinitions::U8);      } -    if (True(types & IR::Type::U16)) { +    if (supports_aliasing && True(types & IR::Type::U16)) {          load_const_func_u16 = make_accessor(U16, &UniformDefinitions::U16);      } -    if (True(types & IR::Type::F32)) { +    if (supports_aliasing && True(types & IR::Type::F32)) {          load_const_func_f32 = make_accessor(F32[1], &UniformDefinitions::F32);      } -    if (True(types & IR::Type::U32)) { +    if (supports_aliasing && True(types & IR::Type::U32)) {          load_const_func_u32 = make_accessor(U32[1], &UniformDefinitions::U32);      } -    if (True(types & IR::Type::U32x2)) { +    if (supports_aliasing && True(types & IR::Type::U32x2)) {          load_const_func_u32x2 = make_accessor(U32[2], &UniformDefinitions::U32x2);      } -    if (True(types & IR::Type::U32x4)) { +    if (!supports_aliasing || True(types & IR::Type::U32x4)) {          load_const_func_u32x4 = make_accessor(U32[4], &UniformDefinitions::U32x4);      }  } diff --git a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp index 0b2c60842..16278faab 100644 --- a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp +++ b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp @@ -32,13 +32,8 @@ void AddConstantBufferDescriptor(Info& info, u32 index, u32 count) {  void AddRegisterIndexedLdc(Info& info) {      info.uses_cbuf_indirect = true; -    // The shader can use any possible constant buffer -    info.constant_buffer_mask = (1 << Info::MAX_CBUFS) - 1; - -    auto& cbufs{info.constant_buffer_descriptors}; -    cbufs.clear(); -    for (u32 i = 0; i < Info::MAX_CBUFS; i++) { -        cbufs.push_back(ConstantBufferDescriptor{.index = i, .count = 1}); +    for (u32 i = 0; i < Info::MAX_INDIRECT_CBUFS; i++) { +        AddConstantBufferDescriptor(info, i, 1);          // The shader can use any possible access size          info.constant_buffer_used_sizes[i] = 0x10'000; diff --git a/src/shader_recompiler/shader_info.h b/src/shader_recompiler/shader_info.h index 9d36bd9eb..a3a09c71c 100644 --- a/src/shader_recompiler/shader_info.h +++ b/src/shader_recompiler/shader_info.h @@ -105,6 +105,7 @@ struct ImageDescriptor {  using ImageDescriptors = boost::container::small_vector<ImageDescriptor, 4>;  struct Info { +    static constexpr size_t MAX_INDIRECT_CBUFS{14};      static constexpr size_t MAX_CBUFS{18};      static constexpr size_t MAX_SSBOS{32}; diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp index ba9ba082f..789af452d 100644 --- a/src/video_core/gpu.cpp +++ b/src/video_core/gpu.cpp @@ -230,7 +230,7 @@ struct GPU::Impl {      void IncrementSyncPoint(u32 syncpoint_id) {          auto& syncpoint = syncpoints.at(syncpoint_id);          syncpoint++; -        std::lock_guard lock{sync_mutex}; +        std::scoped_lock lock{sync_mutex};          sync_cv.notify_all();          auto& interrupt = syncpt_interrupts.at(syncpoint_id);          if (!interrupt.empty()) { @@ -252,7 +252,7 @@ struct GPU::Impl {      }      void RegisterSyncptInterrupt(u32 syncpoint_id, u32 value) { -        std::lock_guard lock{sync_mutex}; +        std::scoped_lock lock{sync_mutex};          auto& interrupt = syncpt_interrupts.at(syncpoint_id);          bool contains = std::any_of(interrupt.begin(), interrupt.end(),                                      [value](u32 in_value) { return in_value == value; }); @@ -263,7 +263,7 @@ struct GPU::Impl {      }      [[nodiscard]] bool CancelSyncptInterrupt(u32 syncpoint_id, u32 value) { -        std::lock_guard lock{sync_mutex}; +        std::scoped_lock lock{sync_mutex};          auto& interrupt = syncpt_interrupts.at(syncpoint_id);          const auto iter =              std::find_if(interrupt.begin(), interrupt.end(), diff --git a/src/video_core/gpu_thread.cpp b/src/video_core/gpu_thread.cpp index 9547f277a..4e8999915 100644 --- a/src/video_core/gpu_thread.cpp +++ b/src/video_core/gpu_thread.cpp @@ -56,7 +56,7 @@ static void RunThread(std::stop_token stop_token, Core::System& system,          if (next.block) {              // We have to lock the write_lock to ensure that the condition_variable wait not get a              // race between the check and the lock itself. -            std::lock_guard lk(state.write_lock); +            std::scoped_lock lk{state.write_lock};              state.cv.notify_all();          }      } diff --git a/src/video_core/host_shaders/CMakeLists.txt b/src/video_core/host_shaders/CMakeLists.txt index af05d47d1..190fc6aea 100644 --- a/src/video_core/host_shaders/CMakeLists.txt +++ b/src/video_core/host_shaders/CMakeLists.txt @@ -18,6 +18,7 @@ set(SHADER_FILES      full_screen_triangle.vert      fxaa.frag      fxaa.vert +    opengl_convert_s8d24.comp      opengl_copy_bc4.comp      opengl_present.frag      opengl_present.vert diff --git a/src/video_core/host_shaders/opengl_convert_s8d24.comp b/src/video_core/host_shaders/opengl_convert_s8d24.comp new file mode 100644 index 000000000..83e1ab176 --- /dev/null +++ b/src/video_core/host_shaders/opengl_convert_s8d24.comp @@ -0,0 +1,18 @@ +// Copyright 2022 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#version 430 core + +layout(local_size_x = 16, local_size_y = 8) in; + +layout(binding = 0, rgba8ui) restrict uniform uimage2D destination; +layout(location = 0) uniform uvec3 size; + +void main() { +    if (any(greaterThanEqual(gl_GlobalInvocationID, size))) { +        return; +    } +    uvec4 components = imageLoad(destination, ivec2(gl_GlobalInvocationID.xy)); +    imageStore(destination, ivec2(gl_GlobalInvocationID.xy), components.wxyz); +} diff --git a/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp b/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp index 9e6732abd..fd40966d5 100644 --- a/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp +++ b/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp @@ -253,7 +253,7 @@ GraphicsPipeline::GraphicsPipeline(              }          }          if (in_parallel) { -            std::lock_guard lock{built_mutex}; +            std::scoped_lock lock{built_mutex};              built_fence.Create();              // Flush this context to ensure compilation commands and fence are in the GPU pipe.              glFlush(); diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index e6f9ece8b..8ef79753f 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -520,6 +520,8 @@ bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& config,      // ASSERT_MSG(image_view->size.width == config.width, "Framebuffer width is different");      // ASSERT_MSG(image_view->size.height == config.height, "Framebuffer height is different"); +    screen_info.texture.width = image_view->size.width; +    screen_info.texture.height = image_view->size.height;      screen_info.display_texture = image_view->Handle(Shader::TextureType::Color2D);      screen_info.display_srgb = VideoCore::Surface::IsPixelFormatSRGB(image_view->format);      return true; @@ -557,12 +559,19 @@ void RasterizerOpenGL::SyncViewport() {      const bool dirty_viewport = flags[Dirty::Viewports] || rescale_viewports;      const bool dirty_clip_control = flags[Dirty::ClipControl]; -    if (dirty_clip_control || flags[Dirty::FrontFace]) { +    if (dirty_viewport || dirty_clip_control || flags[Dirty::FrontFace]) {          flags[Dirty::FrontFace] = false;          GLenum mode = MaxwellToGL::FrontFace(regs.front_face); +        bool flip_faces = false;          if (regs.screen_y_control.triangle_rast_flip != 0 &&              regs.viewport_transform[0].scale_y < 0.0f) { +            flip_faces = !flip_faces; +        } +        if (regs.viewport_transform[0].scale_z < 0.0f) { +            flip_faces = !flip_faces; +        } +        if (flip_faces) {              switch (mode) {              case GL_CW:                  mode = GL_CCW; diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index 6423992c3..05c5e702c 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp @@ -258,7 +258,7 @@ void ShaderCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading,              [this, key, env = std::move(env), &state, &callback](Context* ctx) mutable {                  ctx->pools.ReleaseContents();                  auto pipeline{CreateComputePipeline(ctx->pools, key, env)}; -                std::lock_guard lock{state.mutex}; +                std::scoped_lock lock{state.mutex};                  if (pipeline) {                      compute_cache.emplace(key, std::move(pipeline));                  } @@ -280,7 +280,7 @@ void ShaderCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading,                  }                  ctx->pools.ReleaseContents();                  auto pipeline{CreateGraphicsPipeline(ctx->pools, key, MakeSpan(env_ptrs), false)}; -                std::lock_guard lock{state.mutex}; +                std::scoped_lock lock{state.mutex};                  if (pipeline) {                      graphics_cache.emplace(key, std::move(pipeline));                  } diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp index 8f9a65beb..d12076358 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.cpp +++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp @@ -409,8 +409,8 @@ ImageBufferMap::~ImageBufferMap() {  TextureCacheRuntime::TextureCacheRuntime(const Device& device_, ProgramManager& program_manager,                                           StateTracker& state_tracker_) -    : device{device_}, state_tracker{state_tracker_}, -      util_shaders(program_manager), resolution{Settings::values.resolution_info} { +    : device{device_}, state_tracker{state_tracker_}, util_shaders(program_manager), +      format_conversion_pass{util_shaders}, resolution{Settings::values.resolution_info} {      static constexpr std::array TARGETS{GL_TEXTURE_1D_ARRAY, GL_TEXTURE_2D_ARRAY, GL_TEXTURE_3D};      for (size_t i = 0; i < TARGETS.size(); ++i) {          const GLenum target = TARGETS[i]; @@ -1325,6 +1325,9 @@ Framebuffer::Framebuffer(TextureCacheRuntime& runtime, std::span<ImageView*, NUM  Framebuffer::~Framebuffer() = default; +FormatConversionPass::FormatConversionPass(UtilShaders& util_shaders_) +    : util_shaders{util_shaders_} {} +  void FormatConversionPass::ConvertImage(Image& dst_image, Image& src_image,                                          std::span<const VideoCommon::ImageCopy> copies) {      const GLenum dst_target = ImageTarget(dst_image.info); @@ -1357,6 +1360,12 @@ void FormatConversionPass::ConvertImage(Image& dst_image, Image& src_image,                              dst_origin.z, region.width, region.height, region.depth,                              dst_image.GlFormat(), dst_image.GlType(), nullptr);      } + +    // Swap component order of S8D24 to ABGR8 reinterprets +    if (src_image.info.format == PixelFormat::D24_UNORM_S8_UINT && +        dst_image.info.format == PixelFormat::A8B8G8R8_UNORM) { +        util_shaders.ConvertS8D24(dst_image, copies); +    }  }  } // namespace OpenGL diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h index 53088b66e..672fa8dde 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.h +++ b/src/video_core/renderer_opengl/gl_texture_cache.h @@ -55,13 +55,14 @@ struct FormatProperties {  class FormatConversionPass {  public: -    FormatConversionPass() = default; +    explicit FormatConversionPass(UtilShaders& util_shaders);      ~FormatConversionPass() = default;      void ConvertImage(Image& dst_image, Image& src_image,                        std::span<const VideoCommon::ImageCopy> copies);  private: +    UtilShaders& util_shaders;      OGLBuffer intermediate_pbo;      size_t pbo_size{};  }; diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index f8f29013a..3a3c213bb 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -208,6 +208,8 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf      // Framebuffer orientation handling      framebuffer_transform_flags = framebuffer.transform_flags;      framebuffer_crop_rect = framebuffer.crop_rect; +    framebuffer_width = framebuffer.width; +    framebuffer_height = framebuffer.height;      const VAddr framebuffer_addr{framebuffer.address + framebuffer.offset};      screen_info.was_accelerated = @@ -480,9 +482,12 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) {      ASSERT_MSG(framebuffer_crop_rect.top == 0, "Unimplemented");      ASSERT_MSG(framebuffer_crop_rect.left == 0, "Unimplemented"); +    f32 scale_u = static_cast<f32>(framebuffer_width) / static_cast<f32>(screen_info.texture.width); +    f32 scale_v = +        static_cast<f32>(framebuffer_height) / static_cast<f32>(screen_info.texture.height); +      // Scale the output by the crop width/height. This is commonly used with 1280x720 rendering      // (e.g. handheld mode) on a 1920x1080 framebuffer. -    f32 scale_u = 1.f, scale_v = 1.f;      if (framebuffer_crop_rect.GetWidth() > 0) {          scale_u = static_cast<f32>(framebuffer_crop_rect.GetWidth()) /                    static_cast<f32>(screen_info.texture.width); diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h index aa206878b..ae9558a33 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.h +++ b/src/video_core/renderer_opengl/renderer_opengl.h @@ -137,6 +137,8 @@ private:      /// Used for transforming the framebuffer orientation      Service::android::BufferTransformFlags framebuffer_transform_flags{};      Common::Rectangle<int> framebuffer_crop_rect; +    u32 framebuffer_width; +    u32 framebuffer_height;  };  } // namespace OpenGL diff --git a/src/video_core/renderer_opengl/util_shaders.cpp b/src/video_core/renderer_opengl/util_shaders.cpp index 897c380b3..04c482a09 100644 --- a/src/video_core/renderer_opengl/util_shaders.cpp +++ b/src/video_core/renderer_opengl/util_shaders.cpp @@ -13,6 +13,7 @@  #include "video_core/host_shaders/astc_decoder_comp.h"  #include "video_core/host_shaders/block_linear_unswizzle_2d_comp.h"  #include "video_core/host_shaders/block_linear_unswizzle_3d_comp.h" +#include "video_core/host_shaders/opengl_convert_s8d24_comp.h"  #include "video_core/host_shaders/opengl_copy_bc4_comp.h"  #include "video_core/host_shaders/pitch_unswizzle_comp.h"  #include "video_core/renderer_opengl/gl_shader_manager.h" @@ -50,7 +51,8 @@ UtilShaders::UtilShaders(ProgramManager& program_manager_)        block_linear_unswizzle_2d_program(MakeProgram(BLOCK_LINEAR_UNSWIZZLE_2D_COMP)),        block_linear_unswizzle_3d_program(MakeProgram(BLOCK_LINEAR_UNSWIZZLE_3D_COMP)),        pitch_unswizzle_program(MakeProgram(PITCH_UNSWIZZLE_COMP)), -      copy_bc4_program(MakeProgram(OPENGL_COPY_BC4_COMP)) { +      copy_bc4_program(MakeProgram(OPENGL_COPY_BC4_COMP)), +      convert_s8d24_program(MakeProgram(OPENGL_CONVERT_S8D24_COMP)) {      const auto swizzle_table = Tegra::Texture::MakeSwizzleTable();      swizzle_table_buffer.Create();      glNamedBufferStorage(swizzle_table_buffer.handle, sizeof(swizzle_table), &swizzle_table, 0); @@ -248,6 +250,26 @@ void UtilShaders::CopyBC4(Image& dst_image, Image& src_image, std::span<const Im      program_manager.RestoreGuestCompute();  } +void UtilShaders::ConvertS8D24(Image& dst_image, std::span<const ImageCopy> copies) { +    static constexpr GLuint BINDING_DESTINATION = 0; +    static constexpr GLuint LOC_SIZE = 0; + +    program_manager.BindComputeProgram(convert_s8d24_program.handle); +    for (const ImageCopy& copy : copies) { +        ASSERT(copy.src_subresource.base_layer == 0); +        ASSERT(copy.src_subresource.num_layers == 1); +        ASSERT(copy.dst_subresource.base_layer == 0); +        ASSERT(copy.dst_subresource.num_layers == 1); + +        glUniform3ui(LOC_SIZE, copy.extent.width, copy.extent.height, copy.extent.depth); +        glBindImageTexture(BINDING_DESTINATION, dst_image.StorageHandle(), +                           copy.dst_subresource.base_level, GL_TRUE, 0, GL_READ_WRITE, GL_RGBA8UI); +        glDispatchCompute(Common::DivCeil(copy.extent.width, 16u), +                          Common::DivCeil(copy.extent.height, 8u), copy.extent.depth); +    } +    program_manager.RestoreGuestCompute(); +} +  GLenum StoreFormat(u32 bytes_per_block) {      switch (bytes_per_block) {      case 1: diff --git a/src/video_core/renderer_opengl/util_shaders.h b/src/video_core/renderer_opengl/util_shaders.h index 5de95ea7a..5c132e67f 100644 --- a/src/video_core/renderer_opengl/util_shaders.h +++ b/src/video_core/renderer_opengl/util_shaders.h @@ -39,6 +39,8 @@ public:      void CopyBC4(Image& dst_image, Image& src_image,                   std::span<const VideoCommon::ImageCopy> copies); +    void ConvertS8D24(Image& dst_image, std::span<const VideoCommon::ImageCopy> copies); +  private:      ProgramManager& program_manager; @@ -49,6 +51,7 @@ private:      OGLProgram block_linear_unswizzle_3d_program;      OGLProgram pitch_unswizzle_program;      OGLProgram copy_bc4_program; +    OGLProgram convert_s8d24_program;  };  GLenum StoreFormat(u32 bytes_per_block); diff --git a/src/video_core/renderer_vulkan/pipeline_statistics.cpp b/src/video_core/renderer_vulkan/pipeline_statistics.cpp index bfec931a6..7ccadf084 100644 --- a/src/video_core/renderer_vulkan/pipeline_statistics.cpp +++ b/src/video_core/renderer_vulkan/pipeline_statistics.cpp @@ -57,7 +57,7 @@ void PipelineStatistics::Collect(VkPipeline pipeline) {                  stage_stats.basic_block_count = GetUint64(statistic);              }          } -        std::lock_guard lock{mutex}; +        std::scoped_lock lock{mutex};          collected_stats.push_back(stage_stats);      }  } @@ -66,7 +66,7 @@ void PipelineStatistics::Report() const {      double num{};      Stats total;      { -        std::lock_guard lock{mutex}; +        std::scoped_lock lock{mutex};          for (const Stats& stats : collected_stats) {              total.code_size += stats.code_size;              total.register_count += stats.register_count; diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp index d893c1952..b866e9103 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp +++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp @@ -1406,8 +1406,9 @@ void VKBlitScreen::SetVertexData(BufferData& data, const Tegra::FramebufferConfi      UNIMPLEMENTED_IF(framebuffer_crop_rect.top != 0);      UNIMPLEMENTED_IF(framebuffer_crop_rect.left != 0); -    f32 scale_u = 1.0f; -    f32 scale_v = 1.0f; +    f32 scale_u = static_cast<f32>(framebuffer.width) / static_cast<f32>(screen_info.width); +    f32 scale_v = static_cast<f32>(framebuffer.height) / static_cast<f32>(screen_info.height); +      // Scale the output by the crop width/height. This is commonly used with 1280x720 rendering      // (e.g. handheld mode) on a 1920x1080 framebuffer.      if (!fsr) { diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp index de36bcdb7..97b3594c2 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp @@ -77,7 +77,7 @@ ComputePipeline::ComputePipeline(const Device& device_, DescriptorPool& descript          if (pipeline_statistics) {              pipeline_statistics->Collect(*pipeline);          } -        std::lock_guard lock{build_mutex}; +        std::scoped_lock lock{build_mutex};          is_built = true;          build_condvar.notify_one();          if (shader_notify) { diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index d514b71d0..8959d6059 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -258,7 +258,7 @@ GraphicsPipeline::GraphicsPipeline(              pipeline_statistics->Collect(*pipeline);          } -        std::lock_guard lock{build_mutex}; +        std::scoped_lock lock{build_mutex};          is_built = true;          build_condvar.notify_one();          if (shader_notify) { diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 27e59df73..336d1e9dc 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -404,7 +404,7 @@ void PipelineCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading          workers.QueueWork([this, key, env = std::move(env), &state, &callback]() mutable {              ShaderPools pools;              auto pipeline{CreateComputePipeline(pools, key, env, state.statistics.get(), false)}; -            std::lock_guard lock{state.mutex}; +            std::scoped_lock lock{state.mutex};              if (pipeline) {                  compute_cache.emplace(key, std::move(pipeline));              } @@ -434,7 +434,7 @@ void PipelineCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading              auto pipeline{CreateGraphicsPipeline(pools, key, MakeSpan(env_ptrs),                                                   state.statistics.get(), false)}; -            std::lock_guard lock{state.mutex}; +            std::scoped_lock lock{state.mutex};              graphics_cache.emplace(key, std::move(pipeline));              ++state.built;              if (state.has_loaded) { diff --git a/src/video_core/renderer_vulkan/vk_render_pass_cache.cpp b/src/video_core/renderer_vulkan/vk_render_pass_cache.cpp index 451ffe019..d22bb6694 100644 --- a/src/video_core/renderer_vulkan/vk_render_pass_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_render_pass_cache.cpp @@ -36,7 +36,7 @@ VkAttachmentDescription AttachmentDescription(const Device& device, PixelFormat  RenderPassCache::RenderPassCache(const Device& device_) : device{&device_} {}  VkRenderPass RenderPassCache::Get(const RenderPassKey& key) { -    std::lock_guard lock{mutex}; +    std::scoped_lock lock{mutex};      const auto [pair, is_new] = cache.try_emplace(key);      if (!is_new) {          return *pair->second; diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp index ad320991b..6a9416457 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.cpp +++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp @@ -73,7 +73,7 @@ void VKScheduler::DispatchWork() {          return;      }      { -        std::lock_guard lock{work_mutex}; +        std::scoped_lock lock{work_mutex};          work_queue.push(std::move(chunk));      }      work_cv.notify_one(); @@ -157,7 +157,7 @@ void VKScheduler::WorkerThread(std::stop_token stop_token) {          if (has_submit) {              AllocateWorkerCommandBuffer();          } -        std::lock_guard reserve_lock{reserve_mutex}; +        std::scoped_lock reserve_lock{reserve_mutex};          chunk_reserve.push_back(std::move(work));      } while (!stop_token.stop_requested());  } @@ -282,7 +282,7 @@ void VKScheduler::EndRenderPass() {  }  void VKScheduler::AcquireNewChunk() { -    std::lock_guard lock{reserve_mutex}; +    std::scoped_lock lock{reserve_mutex};      if (chunk_reserve.empty()) {          chunk = std::make_unique<CommandChunk>();          return; diff --git a/src/video_core/shader_cache.cpp b/src/video_core/shader_cache.cpp index 87636857d..75031767a 100644 --- a/src/video_core/shader_cache.cpp +++ b/src/video_core/shader_cache.cpp @@ -25,7 +25,7 @@ void ShaderCache::InvalidateRegion(VAddr addr, size_t size) {  }  void ShaderCache::OnCPUWrite(VAddr addr, size_t size) { -    std::lock_guard lock{invalidation_mutex}; +    std::scoped_lock lock{invalidation_mutex};      InvalidatePagesInRegion(addr, size);  } diff --git a/src/web_service/web_backend.cpp b/src/web_service/web_backend.cpp index 4208bd044..58b0c2f10 100644 --- a/src/web_service/web_backend.cpp +++ b/src/web_service/web_backend.cpp @@ -32,7 +32,7 @@ constexpr std::size_t TIMEOUT_SECONDS = 30;  struct Client::Impl {      Impl(std::string host, std::string username, std::string token)          : host{std::move(host)}, username{std::move(username)}, token{std::move(token)} { -        std::lock_guard lock{jwt_cache.mutex}; +        std::scoped_lock lock{jwt_cache.mutex};          if (this->username == jwt_cache.username && this->token == jwt_cache.token) {              jwt = jwt_cache.jwt;          } @@ -147,7 +147,7 @@ struct Client::Impl {          if (result.result_code != WebResult::Code::Success) {              LOG_ERROR(WebService, "UpdateJWT failed");          } else { -            std::lock_guard lock{jwt_cache.mutex}; +            std::scoped_lock lock{jwt_cache.mutex};              jwt_cache.username = username;              jwt_cache.token = token;              jwt_cache.jwt = jwt = result.returned_data; diff --git a/src/yuzu/util/controller_navigation.cpp b/src/yuzu/util/controller_navigation.cpp index c2b13123d..9a1868cae 100644 --- a/src/yuzu/util/controller_navigation.cpp +++ b/src/yuzu/util/controller_navigation.cpp @@ -39,7 +39,7 @@ void ControllerNavigation::TriggerButton(Settings::NativeButton::Values native_b  }  void ControllerNavigation::ControllerUpdateEvent(Core::HID::ControllerTriggerType type) { -    std::lock_guard lock{mutex}; +    std::scoped_lock lock{mutex};      if (!Settings::values.controller_navigation) {          return;      }  | 
