diff --git a/README.md b/README.md index a530162a2..78217c6e4 100755 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ yuzu emulator early access ============= -This is the source code for early-access 2864. +This is the source code for early-access 2865. ## Legal Notice diff --git a/src/audio_core/renderer/command/command_buffer.cpp b/src/audio_core/renderer/command/command_buffer.cpp index 40074cf14..2ef879ee1 100755 --- a/src/audio_core/renderer/command/command_buffer.cpp +++ b/src/audio_core/renderer/command/command_buffer.cpp @@ -339,7 +339,7 @@ void CommandBuffer::GenerateDepopPrepareCommand(const s32 node_id, const VoiceSt cmd.previous_samples = memory_pool->Translate(CpuAddr(voice_state.previous_samples.data()), MaxMixBuffers * sizeof(s32)); cmd.buffer_count = buffer_count; - cmd.depop_buffer = memory_pool->Translate(CpuAddr(buffer.data()), buffer_count * sizeof(s32)); + cmd.depop_buffer = memory_pool->Translate(CpuAddr(buffer.data()), buffer.size_bytes()); GenerateEnd(cmd); } diff --git a/src/audio_core/renderer/command/mix/depop_prepare.cpp b/src/audio_core/renderer/command/mix/depop_prepare.cpp index 2ee076ef6..69bb78ccc 100755 --- a/src/audio_core/renderer/command/mix/depop_prepare.cpp +++ b/src/audio_core/renderer/command/mix/depop_prepare.cpp @@ -19,7 +19,7 @@ void DepopPrepareCommand::Dump([[maybe_unused]] const ADSP::CommandListProcessor void DepopPrepareCommand::Process(const ADSP::CommandListProcessor& processor) { auto samples{reinterpret_cast(previous_samples)}; - auto buffer{std::span(reinterpret_cast(depop_buffer), buffer_count)}; + auto buffer{reinterpret_cast(depop_buffer)}; for (u32 i = 0; i < buffer_count; i++) { if (samples[i]) { diff --git a/src/common/thread.h b/src/common/thread.h index 1552f58e0..e17a7850f 100755 --- a/src/common/thread.h +++ b/src/common/thread.h @@ -54,6 +54,10 @@ public: is_set = false; } + [[nodiscard]] bool IsSet() { + return is_set; + } + private: std::condition_variable condvar; std::mutex mutex; diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp index 2dbb99c8b..b45c1b918 100755 --- a/src/core/core_timing.cpp +++ b/src/core/core_timing.cpp @@ -243,17 +243,17 @@ std::optional CoreTiming::Advance() { basic_lock.lock(); 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}; + // 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 + next_schedule_time}; + if (evt.time < pause_end_time) { + next_time = pause_end_time + next_schedule_time; + } + event_queue.emplace_back( Event{next_time, event_fifo_id++, evt.user_data, evt.type, next_schedule_time}); std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>()); @@ -264,8 +264,7 @@ std::optional CoreTiming::Advance() { } if (!event_queue.empty()) { - const s64 next_time = event_queue.front().time - global_timer; - return next_time; + return event_queue.front().time; } else { return std::nullopt; } @@ -278,11 +277,28 @@ void CoreTiming::ThreadLoop() { paused_set = false; const auto next_time = Advance(); if (next_time) { - if (*next_time > 0) { - std::chrono::nanoseconds next_time_ns = std::chrono::nanoseconds(*next_time); - event.WaitFor(next_time_ns); + // There are more events left in the queue, sleep until the next event. + const auto diff_ns{*next_time - GetGlobalTimeNs().count()}; + if (diff_ns > 0) { + // Only try to sleep if the remaining time is >= 1ms. Take off 500 microseconds + // from the target time to account for possible over-sleeping, and spin the + // remaining. + const auto sleep_time_ns{diff_ns - 500LL * 1'000LL}; + const auto sleep_time_ms{sleep_time_ns / 1'000'000LL}; + if (sleep_time_ms >= 1) { + event.WaitFor(std::chrono::nanoseconds(sleep_time_ns)); + } + + const auto end_time{std::chrono::nanoseconds(*next_time)}; + while (!paused && !event.IsSet() && GetGlobalTimeNs() < end_time) { + } + + if (event.IsSet()) { + event.Reset(); + } } } else { + // Queue is empty, wait until another event is scheduled and signals us to continue. wait_set = true; event.Wait(); } diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index 883ee0e95..69937e057 100755 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp @@ -40,20 +40,16 @@ void NVFlinger::SplitVSync(std::stop_token stop_token) { Common::SetCurrentThreadName(name.c_str()); Common::SetCurrentThreadPriority(Common::ThreadPriority::High); - s64 delay = 0; + while (!stop_token.stop_requested()) { + vsync_signal.wait(false); + vsync_signal.store(false); + guard->lock(); - const s64 time_start = system.CoreTiming().GetGlobalTimeNs().count(); + Compose(); - const auto ticks = GetNextTicks(); - const s64 time_end = system.CoreTiming().GetGlobalTimeNs().count(); - const s64 time_passed = time_end - time_start; - const s64 next_time = std::max(0, ticks - time_passed - delay); + guard->unlock(); - if (next_time > 0) { - std::this_thread::sleep_for(std::chrono::nanoseconds{next_time}); - } - delay = (system.CoreTiming().GetGlobalTimeNs().count() - time_end) - next_time; } } @@ -68,27 +64,41 @@ NVFlinger::NVFlinger(Core::System& system_, HosBinderDriverServer& hos_binder_dr guard = std::make_shared(); // Schedule the screen composition events - composition_event = Core::Timing::CreateEvent( + multi_composition_event = Core::Timing::CreateEvent( + "ScreenComposition", + [this](std::uintptr_t, s64 time, + std::chrono::nanoseconds ns_late) -> std::optional { + vsync_signal.store(true); + vsync_signal.notify_all(); + return std::chrono::nanoseconds(GetNextTicks()); + }); + + single_composition_event = Core::Timing::CreateEvent( "ScreenComposition", [this](std::uintptr_t, s64 time, std::chrono::nanoseconds ns_late) -> std::optional { const auto lock_guard = Lock(); Compose(); - return std::max(std::chrono::nanoseconds::zero(), - std::chrono::nanoseconds(GetNextTicks()) - ns_late); + return std::chrono::nanoseconds(GetNextTicks()); }); if (system.IsMulticore()) { + system.CoreTiming().ScheduleLoopingEvent(frame_ns, frame_ns, multi_composition_event); vsync_thread = std::jthread([this](std::stop_token token) { SplitVSync(token); }); } else { - system.CoreTiming().ScheduleLoopingEvent(frame_ns, frame_ns, composition_event); + system.CoreTiming().ScheduleLoopingEvent(frame_ns, frame_ns, single_composition_event); } } NVFlinger::~NVFlinger() { - if (!system.IsMulticore()) { - system.CoreTiming().UnscheduleEvent(composition_event, 0); + if (system.IsMulticore()) { + system.CoreTiming().UnscheduleEvent(multi_composition_event, {}); + vsync_thread.request_stop(); + vsync_signal.store(true); + vsync_signal.notify_all(); + } else { + system.CoreTiming().UnscheduleEvent(single_composition_event, {}); } for (auto& display : displays) { diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h index 742b631ec..8b2d31147 100755 --- a/src/core/hle/service/nvflinger/nvflinger.h +++ b/src/core/hle/service/nvflinger/nvflinger.h @@ -127,12 +127,15 @@ private: u32 swap_interval = 1; /// Event that handles screen composition. - std::shared_ptr composition_event; + std::shared_ptr multi_composition_event; + std::shared_ptr single_composition_event; std::shared_ptr guard; Core::System& system; + std::atomic vsync_signal; + std::jthread vsync_thread; KernelHelpers::ServiceContext service_context; diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index d78f312b1..f668d510e 100755 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -1077,12 +1077,26 @@ void GMainWindow::InitializeHotkeys() { [] { Settings::values.audio_muted = !Settings::values.audio_muted; }); connect_shortcut(QStringLiteral("Audio Volume Down"), [] { const auto current_volume = static_cast(Settings::values.volume.GetValue()); - const auto new_volume = std::max(current_volume - 5, 0); + int step = 5; + if (current_volume <= 30) { + step = 2; + } + if (current_volume <= 6) { + step = 1; + } + const auto new_volume = std::max(current_volume - step, 0); Settings::values.volume.SetValue(static_cast(new_volume)); }); connect_shortcut(QStringLiteral("Audio Volume Up"), [] { const auto current_volume = static_cast(Settings::values.volume.GetValue()); - const auto new_volume = std::min(current_volume + 5, 100); + int step = 5; + if (current_volume < 30) { + step = 2; + } + if (current_volume < 6) { + step = 1; + } + const auto new_volume = std::min(current_volume + step, 100); Settings::values.volume.SetValue(static_cast(new_volume)); }); connect_shortcut(QStringLiteral("Toggle Framerate Limit"), [] {