aboutsummaryrefslogtreecommitdiff
path: root/src/video_core/gpu_thread.cpp
diff options
context:
space:
mode:
authorTakoroka <137927095+Takoroka@users.noreply.github.com>2026-10-29 03:39:52 -0400
committerTakoroka <137927095+Takoroka@users.noreply.github.com>2026-10-29 03:39:52 -0400
commite17fd9cef116a088f080ca502951e500864a58b6 (patch)
treee7ff65f614622515d6a2e4263521909eea89a5d8 /src/video_core/gpu_thread.cpp
parentea6c1193fbfa95e586bb6d129dc684163a12cb3e (diff)
parent80c79333fe6fd28a31b65b997f1cbf2987711c91 (diff)
Merge Switch 2 work from local Eden (nx2 at b0dd3fe)
Diffstat (limited to 'src/video_core/gpu_thread.cpp')
-rw-r--r--src/video_core/gpu_thread.cpp44
1 files changed, 43 insertions, 1 deletions
diff --git a/src/video_core/gpu_thread.cpp b/src/video_core/gpu_thread.cpp
index a01375e7be..72da1904e1 100644
--- a/src/video_core/gpu_thread.cpp
+++ b/src/video_core/gpu_thread.cpp
@@ -4,6 +4,9 @@
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
+#include <chrono>
+#include <thread>
+
#include "common/assert.h"
#include "common/scope_exit.h"
#include "common/settings.h"
@@ -14,6 +17,7 @@
#include "video_core/dma_pusher.h"
#include "video_core/gpu.h"
#include "video_core/gpu_thread.h"
+#include "video_core/nx2_profile.h"
#include "video_core/host1x/host1x.h"
#include "video_core/renderer_base.h"
@@ -35,18 +39,52 @@ void ThreadManager::StartThread(VideoCore::RendererBase& renderer, Core::Fronten
auto current_context = context.Acquire();
CommandDataContainer next;
+ // When a pending channel last moved or a command arrived (see the polling below).
+ auto last_progress = std::chrono::steady_clock::now();
+ namespace Profile = VideoCommon::Nx2Profile;
while (!stop_token.stop_requested()) {
- state.queue.PopWait(next, stop_token);
+ Profile::Report();
+ if (scheduler.HasPendingChannels()) {
+ // Suspended channels wait on semaphores the CPU releases: poll them meanwhile.
+ {
+ Profile::Scope scope{Profile::Zone::ResumePending};
+ scheduler.ResumePending(system.GPU());
+ }
+ if (!state.queue.TryPop(next)) {
+ // The CPU usually releases the semaphore soon after: poll for half a
+ // millisecond before sleeping, or every wait also waits out a host sleep
+ // (title 1 waits ~25 times a second).
+ Profile::Scope scope{Profile::Zone::PendingSleep};
+ if (std::chrono::steady_clock::now() - last_progress <
+ std::chrono::microseconds{500}) {
+ std::this_thread::yield();
+ } else {
+ std::this_thread::sleep_for(std::chrono::milliseconds{1});
+ }
+ continue;
+ }
+ } else {
+ Profile::Scope scope{Profile::Zone::Idle};
+ state.queue.PopWait(next, stop_token);
+ }
if (stop_token.stop_requested()) {
break;
}
+ last_progress = std::chrono::steady_clock::now();
if (auto* submit_list = std::get_if<SubmitListCommand>(&next.data)) {
+ Profile::Scope scope{Profile::Zone::Push};
scheduler.Push(system.GPU(), submit_list->channel, std::move(submit_list->entries));
} else if (std::holds_alternative<GPUTickCommand>(next.data)) {
+ Profile::Scope scope{Profile::Zone::Tick};
system.GPU().TickWork();
+ } else if (auto* run = std::get_if<RunCommand>(&next.data)) {
+ Profile::Scope scope{Profile::Zone::Run};
+ run->func();
} else if (const auto* flush = std::get_if<FlushRegionCommand>(&next.data)) {
+ Profile::Scope scope{Profile::Zone::FlushInvalidate};
renderer.ReadRasterizer()->FlushRegion(flush->addr, flush->size);
} else if (const auto* invalidate = std::get_if<InvalidateRegionCommand>(&next.data)) {
+ Profile::Scope scope{Profile::Zone::FlushInvalidate};
renderer.ReadRasterizer()->OnCacheInvalidation(invalidate->addr, invalidate->size);
} else {
ASSERT(false);
@@ -77,6 +115,10 @@ void ThreadManager::TickGPU(bool is_async) {
PushCommand(GPUTickCommand(), false, is_async);
}
+void ThreadManager::Run(std::function<void()>&& func, bool is_async) {
+ PushCommand(RunCommand{std::move(func)}, false, is_async);
+}
+
void ThreadManager::InvalidateRegion(DAddr addr, u64 size) {
rasterizer->OnCacheInvalidation(addr, size);
}