diff options
32 files changed, 213 insertions, 116 deletions
diff --git a/.ci/scripts/windows/docker.sh b/.ci/scripts/windows/docker.sh index d670fe47d..5bd5f0b6b 100755 --- a/.ci/scripts/windows/docker.sh +++ b/.ci/scripts/windows/docker.sh @@ -65,7 +65,7 @@ python3 .ci/scripts/windows/scan_dll.py package/*.exe package/imageformats/*.dll # copy FFmpeg libraries EXTERNALS_PATH="$(pwd)/build/externals" FFMPEG_DLL_PATH="$(find "${EXTERNALS_PATH}" -maxdepth 1 -type d | grep 'ffmpeg-')/bin" -find ${FFMPEG_DLL_PATH} -type f -regex ".*\.dll" -exec cp -v {} package/ ';' +find ${FFMPEG_DLL_PATH} -type f -regex ".*\.dll" -exec cp -nv {} package/ ';' # copy libraries from yuzu.exe path find "$(pwd)/build/bin/" -type f -regex ".*\.dll" -exec cp -v {} package/ ';' diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d3400670a..8ec7e3c69 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,7 +13,7 @@ jobs: container: yuzuemu/build-environments:linux-transifex if: ${{ github.repository == 'yuzu-emu/yuzu' && !github.head_ref }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: submodules: recursive fetch-depth: 0 diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index 7e39ef847..c1886b9f3 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -12,7 +12,7 @@ jobs: image: yuzuemu/build-environments:linux-clang-format options: -u 1001 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: submodules: false - name: 'Verify Formatting' @@ -35,12 +35,12 @@ jobs: image: yuzuemu/build-environments:${{ matrix.image }} options: -u 1001 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: submodules: recursive fetch-depth: 0 - name: Set up cache - uses: actions/cache@v2 + uses: actions/cache@v3 id: ccache-restore with: path: ~/.ccache @@ -69,7 +69,7 @@ jobs: runs-on: windows-2019 steps: - name: Set up cache - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ~/.buildcache key: ${{ runner.os }}-msvc-${{ github.sha }} @@ -89,7 +89,7 @@ jobs: echo %PATH% >> %GITHUB_PATH% - name: Set up MSVC uses: ilammy/msvc-dev-cmd@v1 - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: submodules: recursive fetch-depth: 0 diff --git a/externals/dynarmic b/externals/dynarmic -Subproject 7f84870712ac2fe06aa62dc2bebbe46b51a2cc2 +Subproject 9ebf6a8384836322ce58beb7ca10f5d4c66e921 diff --git a/src/audio_core/audio_renderer.cpp b/src/audio_core/audio_renderer.cpp index 2ee0a96ed..9191ca093 100644 --- a/src/audio_core/audio_renderer.cpp +++ b/src/audio_core/audio_renderer.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include <limits> +#include <optional> #include <vector> #include "audio_core/audio_out.h" @@ -88,9 +89,12 @@ AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing_, Core::Memor stream = audio_out->OpenStream( core_timing, params.sample_rate, AudioCommon::STREAM_NUM_CHANNELS, fmt::format("AudioRenderer-Instance{}", instance_number), std::move(release_callback)); - process_event = Core::Timing::CreateEvent( - fmt::format("AudioRenderer-Instance{}-Process", instance_number), - [this](std::uintptr_t, std::chrono::nanoseconds) { ReleaseAndQueueBuffers(); }); + process_event = + Core::Timing::CreateEvent(fmt::format("AudioRenderer-Instance{}-Process", instance_number), + [this](std::uintptr_t, s64, std::chrono::nanoseconds) { + ReleaseAndQueueBuffers(); + return std::nullopt; + }); for (s32 i = 0; i < NUM_BUFFERS; ++i) { QueueMixedBuffer(i); } diff --git a/src/audio_core/stream.cpp b/src/audio_core/stream.cpp index f8034b04b..cf3d94c53 100644 --- a/src/audio_core/stream.cpp +++ b/src/audio_core/stream.cpp @@ -34,9 +34,10 @@ Stream::Stream(Core::Timing::CoreTiming& core_timing_, u32 sample_rate_, Format ReleaseCallback&& release_callback_, SinkStream& sink_stream_, std::string&& name_) : sample_rate{sample_rate_}, format{format_}, release_callback{std::move(release_callback_)}, sink_stream{sink_stream_}, core_timing{core_timing_}, name{std::move(name_)} { - release_event = - Core::Timing::CreateEvent(name, [this](std::uintptr_t, std::chrono::nanoseconds ns_late) { + release_event = Core::Timing::CreateEvent( + name, [this](std::uintptr_t, s64 time, std::chrono::nanoseconds ns_late) { ReleaseActiveBuffer(ns_late); + return std::nullopt; }); } diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h index adc31c758..e1e2a90fc 100644 --- a/src/common/common_funcs.h +++ b/src/common/common_funcs.h @@ -18,14 +18,16 @@ /// Helper macros to insert unused bytes or words to properly align structs. These values will be /// zero-initialized. #define INSERT_PADDING_BYTES(num_bytes) \ - std::array<u8, num_bytes> CONCAT2(pad, __LINE__) {} + [[maybe_unused]] std::array<u8, num_bytes> CONCAT2(pad, __LINE__) {} #define INSERT_PADDING_WORDS(num_words) \ - std::array<u32, num_words> CONCAT2(pad, __LINE__) {} + [[maybe_unused]] std::array<u32, num_words> CONCAT2(pad, __LINE__) {} /// These are similar to the INSERT_PADDING_* macros but do not zero-initialize the contents. /// This keeps the structure trivial to construct. -#define INSERT_PADDING_BYTES_NOINIT(num_bytes) std::array<u8, num_bytes> CONCAT2(pad, __LINE__) -#define INSERT_PADDING_WORDS_NOINIT(num_words) std::array<u32, num_words> CONCAT2(pad, __LINE__) +#define INSERT_PADDING_BYTES_NOINIT(num_bytes) \ + [[maybe_unused]] std::array<u8, num_bytes> CONCAT2(pad, __LINE__) +#define INSERT_PADDING_WORDS_NOINIT(num_words) \ + [[maybe_unused]] std::array<u32, num_words> CONCAT2(pad, __LINE__) #ifndef _MSC_VER diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp index 140578069..5425637f5 100644 --- a/src/core/core_timing.cpp +++ b/src/core/core_timing.cpp @@ -22,10 +22,11 @@ std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callbac } struct CoreTiming::Event { - u64 time; + s64 time; u64 fifo_order; std::uintptr_t user_data; std::weak_ptr<EventType> type; + s64 reschedule_time; // Sort by time, unless the times are the same, in which case sort by // the order added to the queue @@ -58,15 +59,11 @@ void CoreTiming::Initialize(std::function<void()>&& on_thread_init_) { event_fifo_id = 0; shutting_down = false; ticks = 0; - const auto empty_timed_callback = [](std::uintptr_t, std::chrono::nanoseconds) {}; + const auto empty_timed_callback = [](std::uintptr_t, u64, std::chrono::nanoseconds) + -> std::optional<std::chrono::nanoseconds> { return std::nullopt; }; ev_lost = CreateEvent("_lost_event", empty_timed_callback); if (is_multicore) { - const auto hardware_concurrency = std::thread::hardware_concurrency(); - size_t id = 0; - worker_threads.emplace_back(ThreadEntry, std::ref(*this), id++); - if (hardware_concurrency > 8) { - worker_threads.emplace_back(ThreadEntry, std::ref(*this), id++); - } + worker_threads.emplace_back(ThreadEntry, std::ref(*this), 0); } } @@ -81,6 +78,7 @@ void CoreTiming::Shutdown() { thread.join(); } worker_threads.clear(); + pause_callbacks.clear(); ClearPendingEvents(); has_started = false; } @@ -98,6 +96,14 @@ void CoreTiming::Pause(bool is_paused_) { } } paused_state.store(is_paused_, std::memory_order_relaxed); + + if (!is_paused_) { + pause_end_time = GetGlobalTimeNs().count(); + } + + for (auto& cb : pause_callbacks) { + cb(is_paused_); + } } void CoreTiming::SyncPause(bool is_paused_) { @@ -121,6 +127,14 @@ void CoreTiming::SyncPause(bool is_paused_) { wait_signal_cv.wait(main_lock, [this] { return pause_count == 0; }); } } + + if (!is_paused_) { + pause_end_time = GetGlobalTimeNs().count(); + } + + for (auto& cb : pause_callbacks) { + cb(is_paused_); + } } bool CoreTiming::IsRunning() const { @@ -134,12 +148,30 @@ bool CoreTiming::HasPendingEvents() const { void CoreTiming::ScheduleEvent(std::chrono::nanoseconds ns_into_future, const std::shared_ptr<EventType>& event_type, - std::uintptr_t user_data) { + std::uintptr_t user_data, bool absolute_time) { std::unique_lock main_lock(event_mutex); - const u64 timeout = static_cast<u64>((GetGlobalTimeNs() + ns_into_future).count()); + const auto next_time{absolute_time ? ns_into_future : GetGlobalTimeNs() + ns_into_future}; - event_queue.emplace_back(Event{timeout, event_fifo_id++, user_data, event_type}); + event_queue.emplace_back(Event{next_time.count(), event_fifo_id++, user_data, event_type, 0}); + pending_events.fetch_add(1, std::memory_order_relaxed); + + std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>()); + + if (is_multicore) { + event_cv.notify_one(); + } +} + +void CoreTiming::ScheduleLoopingEvent(std::chrono::nanoseconds start_time, + std::chrono::nanoseconds resched_time, + const std::shared_ptr<EventType>& event_type, + std::uintptr_t user_data, bool absolute_time) { + std::unique_lock main_lock(event_mutex); + const auto next_time{absolute_time ? start_time : GetGlobalTimeNs() + start_time}; + + event_queue.emplace_back( + Event{next_time.count(), event_fifo_id++, user_data, event_type, resched_time.count()}); pending_events.fetch_add(1, std::memory_order_relaxed); std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>()); @@ -218,6 +250,11 @@ void CoreTiming::RemoveEvent(const std::shared_ptr<EventType>& event_type) { } } +void CoreTiming::RegisterPauseCallback(PauseCallback&& callback) { + std::unique_lock main_lock(event_mutex); + pause_callbacks.emplace_back(std::move(callback)); +} + std::optional<s64> CoreTiming::Advance() { global_timer = GetGlobalTimeNs().count(); @@ -228,17 +265,31 @@ std::optional<s64> CoreTiming::Advance() { event_queue.pop_back(); if (const auto event_type{evt.type.lock()}) { - sequence_mutex.lock(); event_mutex.unlock(); - event_type->guard.lock(); - sequence_mutex.unlock(); - const s64 delay = static_cast<s64>(GetGlobalTimeNs().count() - evt.time); - event_type->callback(evt.user_data, std::chrono::nanoseconds{delay}); - event_type->guard.unlock(); + const auto new_schedule_time{event_type->callback( + evt.user_data, evt.time, + std::chrono::nanoseconds{GetGlobalTimeNs().count() - evt.time})}; event_mutex.lock(); pending_events.fetch_sub(1, std::memory_order_relaxed); + + if (evt.reschedule_time != 0) { + // If this event was scheduled into a pause, its time now is going to be way behind. + // Re-set this event to continue from the end of the pause. + auto next_time{evt.time + evt.reschedule_time}; + if (evt.time < pause_end_time) { + next_time = pause_end_time + evt.reschedule_time; + } + + const auto next_schedule_time{new_schedule_time.has_value() + ? new_schedule_time.value().count() + : evt.reschedule_time}; + event_queue.emplace_back( + Event{next_time, event_fifo_id++, evt.user_data, evt.type, next_schedule_time}); + pending_events.fetch_add(1, std::memory_order_relaxed); + std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>()); + } } global_timer = GetGlobalTimeNs().count(); diff --git a/src/core/core_timing.h b/src/core/core_timing.h index a86553e08..09b6ed81a 100644 --- a/src/core/core_timing.h +++ b/src/core/core_timing.h @@ -20,8 +20,9 @@ namespace Core::Timing { /// A callback that may be scheduled for a particular core timing event. -using TimedCallback = - std::function<void(std::uintptr_t user_data, std::chrono::nanoseconds ns_late)>; +using TimedCallback = std::function<std::optional<std::chrono::nanoseconds>( + std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late)>; +using PauseCallback = std::function<void(bool paused)>; /// Contains the characteristics of a particular event. struct EventType { @@ -32,7 +33,6 @@ struct EventType { TimedCallback callback; /// A pointer to the name of the event. const std::string name; - mutable std::mutex guard; }; /** @@ -94,7 +94,15 @@ public: /// Schedules an event in core timing void ScheduleEvent(std::chrono::nanoseconds ns_into_future, - const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data = 0); + const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data = 0, + bool absolute_time = false); + + /// Schedules an event which will automatically re-schedule itself with the given time, until + /// unscheduled + void ScheduleLoopingEvent(std::chrono::nanoseconds start_time, + std::chrono::nanoseconds resched_time, + const std::shared_ptr<EventType>& event_type, + std::uintptr_t user_data = 0, bool absolute_time = false); void UnscheduleEvent(const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data); @@ -126,6 +134,9 @@ public: /// Checks for events manually and returns time in nanoseconds for next event, threadsafe. std::optional<s64> Advance(); + /// Register a callback function to be called when coretiming pauses. + void RegisterPauseCallback(PauseCallback&& callback); + private: struct Event; @@ -137,7 +148,7 @@ private: std::unique_ptr<Common::WallClock> clock; - u64 global_timer = 0; + s64 global_timer = 0; // The queue is a min-heap using std::make_heap/push_heap/pop_heap. // We don't use std::priority_queue because we need to be able to serialize, unserialize and @@ -157,17 +168,19 @@ private: std::condition_variable wait_pause_cv; std::condition_variable wait_signal_cv; mutable std::mutex event_mutex; - mutable std::mutex sequence_mutex; std::atomic<bool> paused_state{}; bool is_paused{}; bool shutting_down{}; bool is_multicore{}; size_t pause_count{}; + s64 pause_end_time{}; /// Cycle timing u64 ticks{}; s64 downcount{}; + + std::vector<PauseCallback> pause_callbacks{}; }; /// Creates a core timing event with the given name and callback. diff --git a/src/core/hardware_interrupt_manager.cpp b/src/core/hardware_interrupt_manager.cpp index d2d968a76..d08cc3315 100644 --- a/src/core/hardware_interrupt_manager.cpp +++ b/src/core/hardware_interrupt_manager.cpp @@ -11,11 +11,14 @@ namespace Core::Hardware { InterruptManager::InterruptManager(Core::System& system_in) : system(system_in) { gpu_interrupt_event = Core::Timing::CreateEvent( - "GPUInterrupt", [this](std::uintptr_t message, std::chrono::nanoseconds) { + "GPUInterrupt", + [this](std::uintptr_t message, u64 time, + std::chrono::nanoseconds) -> std::optional<std::chrono::nanoseconds> { auto nvdrv = system.ServiceManager().GetService<Service::Nvidia::NVDRV>("nvdrv"); const u32 syncpt = static_cast<u32>(message >> 32); const u32 value = static_cast<u32>(message); nvdrv->SignalGPUInterruptSyncpt(syncpt, value); + return std::nullopt; }); } diff --git a/src/core/hle/kernel/k_code_memory.h b/src/core/hle/kernel/k_code_memory.h index 2410f74a3..2e7e1436a 100644 --- a/src/core/hle/kernel/k_code_memory.h +++ b/src/core/hle/kernel/k_code_memory.h @@ -30,19 +30,19 @@ public: explicit KCodeMemory(KernelCore& kernel_); Result Initialize(Core::DeviceMemory& device_memory, VAddr address, size_t size); - void Finalize(); + void Finalize() override; Result Map(VAddr address, size_t size); Result Unmap(VAddr address, size_t size); Result MapToOwner(VAddr address, size_t size, Svc::MemoryPermission perm); Result UnmapFromOwner(VAddr address, size_t size); - bool IsInitialized() const { + bool IsInitialized() const override { return m_is_initialized; } static void PostDestroy([[maybe_unused]] uintptr_t arg) {} - KProcess* GetOwner() const { + KProcess* GetOwner() const override { return m_owner; } VAddr GetSourceAddress() const { diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index 50cb5fc90..90de86770 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp @@ -308,14 +308,20 @@ void KThread::Finalize() { auto it = waiter_list.begin(); while (it != waiter_list.end()) { - // Clear the lock owner - it->SetLockOwner(nullptr); + // Get the thread. + KThread* const waiter = std::addressof(*it); + + // The thread shouldn't be a kernel waiter. + ASSERT(!IsKernelAddressKey(waiter->GetAddressKey())); + + // Clear the lock owner. + waiter->SetLockOwner(nullptr); // Erase the waiter from our list. it = waiter_list.erase(it); // Cancel the thread's wait. - it->CancelWait(ResultInvalidState, true); + waiter->CancelWait(ResultInvalidState, true); } } diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 0009193be..7307cf262 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -234,17 +234,18 @@ struct KernelCore::Impl { void InitializePreemption(KernelCore& kernel) { preemption_event = Core::Timing::CreateEvent( - "PreemptionCallback", [this, &kernel](std::uintptr_t, std::chrono::nanoseconds) { + "PreemptionCallback", + [this, &kernel](std::uintptr_t, s64 time, + std::chrono::nanoseconds) -> std::optional<std::chrono::nanoseconds> { { KScopedSchedulerLock lock(kernel); global_scheduler_context->PreemptThreads(); } - const auto time_interval = std::chrono::nanoseconds{std::chrono::milliseconds(10)}; - system.CoreTiming().ScheduleEvent(time_interval, preemption_event); + return std::nullopt; }); const auto time_interval = std::chrono::nanoseconds{std::chrono::milliseconds(10)}; - system.CoreTiming().ScheduleEvent(time_interval, preemption_event); + system.CoreTiming().ScheduleLoopingEvent(time_interval, time_interval, preemption_event); } void InitializeShutdownThreads() { diff --git a/src/core/hle/kernel/time_manager.cpp b/src/core/hle/kernel/time_manager.cpp index 2724c3782..5ee72c432 100644 --- a/src/core/hle/kernel/time_manager.cpp +++ b/src/core/hle/kernel/time_manager.cpp @@ -11,15 +11,17 @@ namespace Kernel { TimeManager::TimeManager(Core::System& system_) : system{system_} { - time_manager_event_type = - Core::Timing::CreateEvent("Kernel::TimeManagerCallback", - [this](std::uintptr_t thread_handle, std::chrono::nanoseconds) { - KThread* thread = reinterpret_cast<KThread*>(thread_handle); - { - KScopedSchedulerLock sl(system.Kernel()); - thread->OnTimer(); - } - }); + time_manager_event_type = Core::Timing::CreateEvent( + "Kernel::TimeManagerCallback", + [this](std::uintptr_t thread_handle, s64 time, + std::chrono::nanoseconds) -> std::optional<std::chrono::nanoseconds> { + KThread* thread = reinterpret_cast<KThread*>(thread_handle); + { + KScopedSchedulerLock sl(system.Kernel()); + thread->OnTimer(); + } + return std::nullopt; + }); } void TimeManager::ScheduleTimeEvent(KThread* thread, s64 nanoseconds) { diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index aa7189bda..3c28dee76 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -838,11 +838,11 @@ bool Controller_NPad::VibrateControllerAtIndex(Core::HID::NpadIdType npad_id, const auto now = steady_clock::now(); - // Filter out non-zero vibrations that are within 10ms of each other. + // Filter out non-zero vibrations that are within 15ms of each other. if ((vibration_value.low_amplitude != 0.0f || vibration_value.high_amplitude != 0.0f) && duration_cast<milliseconds>( now - controller.vibration[device_index].last_vibration_timepoint) < - milliseconds(10)) { + milliseconds(15)) { return false; } diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 78efffc50..89bb12442 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -74,26 +74,34 @@ IAppletResource::IAppletResource(Core::System& system_, // Register update callbacks pad_update_event = Core::Timing::CreateEvent( "HID::UpdatePadCallback", - [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { + [this](std::uintptr_t user_data, s64 time, + std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { const auto guard = LockService(); UpdateControllers(user_data, ns_late); + return std::nullopt; }); mouse_keyboard_update_event = Core::Timing::CreateEvent( "HID::UpdateMouseKeyboardCallback", - [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { + [this](std::uintptr_t user_data, s64 time, + std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { const auto guard = LockService(); UpdateMouseKeyboard(user_data, ns_late); + return std::nullopt; }); motion_update_event = Core::Timing::CreateEvent( "HID::UpdateMotionCallback", - [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { + [this](std::uintptr_t user_data, s64 time, + std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { const auto guard = LockService(); UpdateMotion(user_data, ns_late); + return std::nullopt; }); - system.CoreTiming().ScheduleEvent(pad_update_ns, pad_update_event); - system.CoreTiming().ScheduleEvent(mouse_keyboard_update_ns, mouse_keyboard_update_event); - system.CoreTiming().ScheduleEvent(motion_update_ns, motion_update_event); + system.CoreTiming().ScheduleLoopingEvent(pad_update_ns, pad_update_ns, pad_update_event); + system.CoreTiming().ScheduleLoopingEvent(mouse_keyboard_update_ns, mouse_keyboard_update_ns, + mouse_keyboard_update_event); + system.CoreTiming().ScheduleLoopingEvent(motion_update_ns, motion_update_ns, + motion_update_event); system.HIDCore().ReloadInputDevices(); } @@ -135,13 +143,6 @@ void IAppletResource::UpdateControllers(std::uintptr_t user_data, } controller->OnUpdate(core_timing); } - - // If ns_late is higher than the update rate ignore the delay - if (ns_late > pad_update_ns) { - ns_late = {}; - } - - core_timing.ScheduleEvent(pad_update_ns - ns_late, pad_update_event); } void IAppletResource::UpdateMouseKeyboard(std::uintptr_t user_data, @@ -150,26 +151,12 @@ void IAppletResource::UpdateMouseKeyboard(std::uintptr_t user_data, controllers[static_cast<size_t>(HidController::Mouse)]->OnUpdate(core_timing); controllers[static_cast<size_t>(HidController::Keyboard)]->OnUpdate(core_timing); - - // If ns_late is higher than the update rate ignore the delay - if (ns_late > mouse_keyboard_update_ns) { - ns_late = {}; - } - - core_timing.ScheduleEvent(mouse_keyboard_update_ns - ns_late, mouse_keyboard_update_event); } void IAppletResource::UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { auto& core_timing = system.CoreTiming(); controllers[static_cast<size_t>(HidController::NPad)]->OnMotionUpdate(core_timing); - - // If ns_late is higher than the update rate ignore the delay - if (ns_late > motion_update_ns) { - ns_late = {}; - } - - core_timing.ScheduleEvent(motion_update_ns - ns_late, motion_update_event); } class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> { diff --git a/src/core/hle/service/hid/hidbus.cpp b/src/core/hle/service/hid/hidbus.cpp index fa6153b4c..e5e50845f 100644 --- a/src/core/hle/service/hid/hidbus.cpp +++ b/src/core/hle/service/hid/hidbus.cpp @@ -50,12 +50,15 @@ HidBus::HidBus(Core::System& system_) // Register update callbacks hidbus_update_event = Core::Timing::CreateEvent( "Hidbus::UpdateCallback", - [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { + [this](std::uintptr_t user_data, s64 time, + std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { const auto guard = LockService(); UpdateHidbus(user_data, ns_late); + return std::nullopt; }); - system_.CoreTiming().ScheduleEvent(hidbus_update_ns, hidbus_update_event); + system_.CoreTiming().ScheduleLoopingEvent(hidbus_update_ns, hidbus_update_ns, + hidbus_update_event); } HidBus::~HidBus() { @@ -63,8 +66,6 @@ HidBus::~HidBus() { } void HidBus::UpdateHidbus(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { - auto& core_timing = system.CoreTiming(); - if (is_hidbus_enabled) { for (std::size_t i = 0; i < devices.size(); ++i) { if (!devices[i].is_device_initializated) { @@ -82,13 +83,6 @@ void HidBus::UpdateHidbus(std::uintptr_t user_data, std::chrono::nanoseconds ns_ sizeof(HidbusStatusManagerEntry)); } } - - // If ns_late is higher than the update rate ignore the delay - if (ns_late > hidbus_update_ns) { - ns_late = {}; - } - - core_timing.ScheduleEvent(hidbus_update_ns - ns_late, hidbus_update_event); } std::optional<std::size_t> HidBus::GetDeviceIndexFromHandle(BusHandle handle) const { diff --git a/src/core/hle/service/nvflinger/binder.h b/src/core/hle/service/nvflinger/binder.h index 21aaa40cd..157333ff8 100644 --- a/src/core/hle/service/nvflinger/binder.h +++ b/src/core/hle/service/nvflinger/binder.h @@ -34,6 +34,7 @@ enum class TransactionId { class IBinder { public: + virtual ~IBinder() = default; virtual void Transact(Kernel::HLERequestContext& ctx, android::TransactionId code, u32 flags) = 0; virtual Kernel::KReadableEvent& GetNativeHandle() = 0; diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index 2b2985a2d..5f69c8c2c 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp @@ -67,21 +67,20 @@ NVFlinger::NVFlinger(Core::System& system_, HosBinderDriverServer& hos_binder_dr // Schedule the screen composition events composition_event = Core::Timing::CreateEvent( - "ScreenComposition", [this](std::uintptr_t, std::chrono::nanoseconds ns_late) { + "ScreenComposition", + [this](std::uintptr_t, s64 time, + std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { const auto lock_guard = Lock(); Compose(); - const auto ticks = std::chrono::nanoseconds{GetNextTicks()}; - const auto ticks_delta = ticks - ns_late; - const auto future_ns = std::max(std::chrono::nanoseconds::zero(), ticks_delta); - - this->system.CoreTiming().ScheduleEvent(future_ns, composition_event); + return std::max(std::chrono::nanoseconds::zero(), + std::chrono::nanoseconds(GetNextTicks()) - ns_late); }); if (system.IsMulticore()) { vsync_thread = std::jthread([this](std::stop_token token) { SplitVSync(token); }); } else { - system.CoreTiming().ScheduleEvent(frame_ns, composition_event); + system.CoreTiming().ScheduleLoopingEvent(frame_ns, frame_ns, composition_event); } } diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp index 5f71f0ff5..ffdbacc18 100644 --- a/src/core/memory/cheat_engine.cpp +++ b/src/core/memory/cheat_engine.cpp @@ -184,10 +184,12 @@ CheatEngine::~CheatEngine() { void CheatEngine::Initialize() { event = Core::Timing::CreateEvent( "CheatEngine::FrameCallback::" + Common::HexToString(metadata.main_nso_build_id), - [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { + [this](std::uintptr_t user_data, s64 time, + std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { FrameCallback(user_data, ns_late); + return std::nullopt; }); - core_timing.ScheduleEvent(CHEAT_ENGINE_NS, event); + core_timing.ScheduleLoopingEvent(CHEAT_ENGINE_NS, CHEAT_ENGINE_NS, event); metadata.process_id = system.CurrentProcess()->GetProcessID(); metadata.title_id = system.GetCurrentProcessProgramID(); @@ -237,8 +239,6 @@ void CheatEngine::FrameCallback(std::uintptr_t, std::chrono::nanoseconds ns_late MICROPROFILE_SCOPE(Cheat_Engine); vm.Execute(metadata); - - core_timing.ScheduleEvent(CHEAT_ENGINE_NS - ns_late, event); } } // namespace Core::Memory diff --git a/src/core/tools/freezer.cpp b/src/core/tools/freezer.cpp index 5cc99fbe4..98ebbbf32 100644 --- a/src/core/tools/freezer.cpp +++ b/src/core/tools/freezer.cpp @@ -53,8 +53,10 @@ Freezer::Freezer(Core::Timing::CoreTiming& core_timing_, Core::Memory::Memory& m : core_timing{core_timing_}, memory{memory_} { event = Core::Timing::CreateEvent( "MemoryFreezer::FrameCallback", - [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { + [this](std::uintptr_t user_data, s64 time, + std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { FrameCallback(user_data, ns_late); + return std::nullopt; }); core_timing.ScheduleEvent(memory_freezer_ns, event); } diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp index 446c027d3..00474ac77 100644 --- a/src/input_common/drivers/sdl_driver.cpp +++ b/src/input_common/drivers/sdl_driver.cpp @@ -438,10 +438,17 @@ SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_en using namespace std::chrono_literals; while (initialized) { SDL_PumpEvents(); - SendVibrations(); std::this_thread::sleep_for(1ms); } }); + vibration_thread = std::thread([this] { + Common::SetCurrentThreadName("yuzu:input:SDL_Vibration"); + using namespace std::chrono_literals; + while (initialized) { + SendVibrations(); + std::this_thread::sleep_for(10ms); + } + }); } // Because the events for joystick connection happens before we have our event watcher added, we // can just open all the joysticks right here @@ -457,6 +464,7 @@ SDLDriver::~SDLDriver() { initialized = false; if (start_thread) { poll_thread.join(); + vibration_thread.join(); SDL_QuitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER); } } diff --git a/src/input_common/drivers/sdl_driver.h b/src/input_common/drivers/sdl_driver.h index 0846fbb50..7dc7a93c7 100644 --- a/src/input_common/drivers/sdl_driver.h +++ b/src/input_common/drivers/sdl_driver.h @@ -128,5 +128,6 @@ private: std::atomic<bool> initialized = false; std::thread poll_thread; + std::thread vibration_thread; }; } // namespace InputCommon diff --git a/src/tests/core/core_timing.cpp b/src/tests/core/core_timing.cpp index e687416a8..894975e6f 100644 --- a/src/tests/core/core_timing.cpp +++ b/src/tests/core/core_timing.cpp @@ -9,6 +9,7 @@ #include <cstdlib> #include <memory> #include <mutex> +#include <optional> #include <string> #include "core/core.h" @@ -25,13 +26,15 @@ u64 expected_callback = 0; std::mutex control_mutex; template <unsigned int IDX> -void HostCallbackTemplate(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { +std::optional<std::chrono::nanoseconds> HostCallbackTemplate(std::uintptr_t user_data, s64 time, + std::chrono::nanoseconds ns_late) { std::unique_lock<std::mutex> lk(control_mutex); static_assert(IDX < CB_IDS.size(), "IDX out of range"); callbacks_ran_flags.set(IDX); REQUIRE(CB_IDS[IDX] == user_data); delays[IDX] = ns_late.count(); ++expected_callback; + return std::nullopt; } struct ScopeInit final { diff --git a/src/video_core/compatible_formats.cpp b/src/video_core/compatible_formats.cpp index 014d880e2..4e75f33ca 100644 --- a/src/video_core/compatible_formats.cpp +++ b/src/video_core/compatible_formats.cpp @@ -131,9 +131,12 @@ constexpr std::array VIEW_CLASS_ASTC_8x8_RGBA{ // PixelFormat::ASTC_2D_10X5_SRGB // Missing formats: -// PixelFormat::ASTC_2D_10X6_UNORM // PixelFormat::ASTC_2D_10X6_SRGB +constexpr std::array VIEW_CLASS_ASTC_10x6_RGBA{ + PixelFormat::ASTC_2D_10X6_UNORM, +}; + constexpr std::array VIEW_CLASS_ASTC_10x8_RGBA{ PixelFormat::ASTC_2D_10X8_UNORM, PixelFormat::ASTC_2D_10X8_SRGB, @@ -226,6 +229,7 @@ constexpr Table MakeViewTable() { EnableRange(view, VIEW_CLASS_ASTC_6x6_RGBA); EnableRange(view, VIEW_CLASS_ASTC_8x5_RGBA); EnableRange(view, VIEW_CLASS_ASTC_8x8_RGBA); + EnableRange(view, VIEW_CLASS_ASTC_10x6_RGBA); EnableRange(view, VIEW_CLASS_ASTC_10x8_RGBA); EnableRange(view, VIEW_CLASS_ASTC_10x10_RGBA); EnableRange(view, VIEW_CLASS_ASTC_12x12_RGBA); diff --git a/src/video_core/renderer_opengl/maxwell_to_gl.h b/src/video_core/renderer_opengl/maxwell_to_gl.h index 644b60d73..9a72d0d6d 100644 --- a/src/video_core/renderer_opengl/maxwell_to_gl.h +++ b/src/video_core/renderer_opengl/maxwell_to_gl.h @@ -98,6 +98,7 @@ constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> FORMAT_TAB {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR}, // ASTC_2D_10X8_SRGB {GL_COMPRESSED_RGBA_ASTC_6x6_KHR}, // ASTC_2D_6X6_UNORM {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR}, // ASTC_2D_6X6_SRGB + {GL_COMPRESSED_RGBA_ASTC_10x6_KHR}, // ASTC_2D_10X6_UNORM {GL_COMPRESSED_RGBA_ASTC_10x10_KHR}, // ASTC_2D_10X10_UNORM {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR}, // ASTC_2D_10X10_SRGB {GL_COMPRESSED_RGBA_ASTC_12x12_KHR}, // ASTC_2D_12X12_UNORM diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp index 193cbe15e..689164a6a 100644 --- a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp +++ b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp @@ -195,6 +195,7 @@ struct FormatTuple { {VK_FORMAT_ASTC_10x8_SRGB_BLOCK}, // ASTC_2D_10X8_SRGB {VK_FORMAT_ASTC_6x6_UNORM_BLOCK}, // ASTC_2D_6X6_UNORM {VK_FORMAT_ASTC_6x6_SRGB_BLOCK}, // ASTC_2D_6X6_SRGB + {VK_FORMAT_ASTC_10x6_UNORM_BLOCK}, // ASTC_2D_10X6_UNORM {VK_FORMAT_ASTC_10x10_UNORM_BLOCK}, // ASTC_2D_10X10_UNORM {VK_FORMAT_ASTC_10x10_SRGB_BLOCK}, // ASTC_2D_10X10_SRGB {VK_FORMAT_ASTC_12x12_UNORM_BLOCK}, // ASTC_2D_12X12_UNORM diff --git a/src/video_core/surface.cpp b/src/video_core/surface.cpp index 69c1b1e6d..eecd0deff 100644 --- a/src/video_core/surface.cpp +++ b/src/video_core/surface.cpp @@ -247,6 +247,7 @@ bool IsPixelFormatASTC(PixelFormat format) { case PixelFormat::ASTC_2D_10X8_SRGB: case PixelFormat::ASTC_2D_6X6_UNORM: case PixelFormat::ASTC_2D_6X6_SRGB: + case PixelFormat::ASTC_2D_10X6_UNORM: case PixelFormat::ASTC_2D_10X10_UNORM: case PixelFormat::ASTC_2D_10X10_SRGB: case PixelFormat::ASTC_2D_12X12_UNORM: diff --git a/src/video_core/surface.h b/src/video_core/surface.h index 75e055592..0175432ff 100644 --- a/src/video_core/surface.h +++ b/src/video_core/surface.h @@ -94,6 +94,7 @@ enum class PixelFormat { ASTC_2D_10X8_SRGB, ASTC_2D_6X6_UNORM, ASTC_2D_6X6_SRGB, + ASTC_2D_10X6_UNORM, ASTC_2D_10X10_UNORM, ASTC_2D_10X10_SRGB, ASTC_2D_12X12_UNORM, @@ -227,6 +228,7 @@ constexpr std::array<u8, MaxPixelFormat> BLOCK_WIDTH_TABLE = {{ 10, // ASTC_2D_10X8_SRGB 6, // ASTC_2D_6X6_UNORM 6, // ASTC_2D_6X6_SRGB + 10, // ASTC_2D_10X6_UNORM 10, // ASTC_2D_10X10_UNORM 10, // ASTC_2D_10X10_SRGB 12, // ASTC_2D_12X12_UNORM @@ -329,6 +331,7 @@ constexpr std::array<u8, MaxPixelFormat> BLOCK_HEIGHT_TABLE = {{ 8, // ASTC_2D_10X8_SRGB 6, // ASTC_2D_6X6_UNORM 6, // ASTC_2D_6X6_SRGB + 6, // ASTC_2D_10X6_UNORM 10, // ASTC_2D_10X10_UNORM 10, // ASTC_2D_10X10_SRGB 12, // ASTC_2D_12X12_UNORM @@ -431,6 +434,7 @@ constexpr std::array<u8, MaxPixelFormat> BITS_PER_BLOCK_TABLE = {{ 128, // ASTC_2D_10X8_SRGB 128, // ASTC_2D_6X6_UNORM 128, // ASTC_2D_6X6_SRGB + 128, // ASTC_2D_10X6_UNORM 128, // ASTC_2D_10X10_UNORM 128, // ASTC_2D_10X10_SRGB 128, // ASTC_2D_12X12_UNORM diff --git a/src/video_core/texture_cache/format_lookup_table.cpp b/src/video_core/texture_cache/format_lookup_table.cpp index 0937768d6..1412aa076 100644 --- a/src/video_core/texture_cache/format_lookup_table.cpp +++ b/src/video_core/texture_cache/format_lookup_table.cpp @@ -206,6 +206,8 @@ PixelFormat PixelFormatFromTextureInfo(TextureFormat format, ComponentType red, return PixelFormat::ASTC_2D_6X6_UNORM; case Hash(TextureFormat::ASTC_2D_6X6, UNORM, SRGB): return PixelFormat::ASTC_2D_6X6_SRGB; + case Hash(TextureFormat::ASTC_2D_10X6, UNORM, LINEAR): + return PixelFormat::ASTC_2D_10X6_UNORM; case Hash(TextureFormat::ASTC_2D_10X10, UNORM, LINEAR): return PixelFormat::ASTC_2D_10X10_UNORM; case Hash(TextureFormat::ASTC_2D_10X10, UNORM, SRGB): diff --git a/src/video_core/texture_cache/formatter.h b/src/video_core/texture_cache/formatter.h index 1b78ed445..95a572604 100644 --- a/src/video_core/texture_cache/formatter.h +++ b/src/video_core/texture_cache/formatter.h @@ -175,6 +175,8 @@ struct fmt::formatter<VideoCore::Surface::PixelFormat> : fmt::formatter<fmt::str return "ASTC_2D_6X6_UNORM"; case PixelFormat::ASTC_2D_6X6_SRGB: return "ASTC_2D_6X6_SRGB"; + case PixelFormat::ASTC_2D_10X6_UNORM: + return "ASTC_2D_10X6_UNORM"; case PixelFormat::ASTC_2D_10X10_UNORM: return "ASTC_2D_10X10_UNORM"; case PixelFormat::ASTC_2D_10X10_SRGB: diff --git a/src/yuzu/applets/qt_web_browser.cpp b/src/yuzu/applets/qt_web_browser.cpp index 790edbb2a..89bd482e0 100644 --- a/src/yuzu/applets/qt_web_browser.cpp +++ b/src/yuzu/applets/qt_web_browser.cpp @@ -2,6 +2,8 @@ // SPDX-License-Identifier: GPL-2.0-or-later #ifdef YUZU_USE_QT_WEB_ENGINE +#include <bit> + #include <QApplication> #include <QKeyEvent> @@ -211,8 +213,10 @@ template <Core::HID::NpadButton... T> void QtNXWebEngineView::HandleWindowFooterButtonPressedOnce() { const auto f = [this](Core::HID::NpadButton button) { if (input_interpreter->IsButtonPressedOnce(button)) { + const auto button_index = std::countr_zero(static_cast<u64>(button)); + page()->runJavaScript( - QStringLiteral("yuzu_key_callbacks[%1] == null;").arg(static_cast<u8>(button)), + QStringLiteral("yuzu_key_callbacks[%1] == null;").arg(button_index), [this, button](const QVariant& variant) { if (variant.toBool()) { switch (button) { @@ -236,7 +240,7 @@ void QtNXWebEngineView::HandleWindowFooterButtonPressedOnce() { page()->runJavaScript( QStringLiteral("if (yuzu_key_callbacks[%1] != null) { yuzu_key_callbacks[%1](); }") - .arg(static_cast<u8>(button))); + .arg(button_index)); } }; |