aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTakoroka <137927095+Takoroka@users.noreply.github.com>2026-10-29 15:55:00 -0400
committerTakoroka <137927095+Takoroka@users.noreply.github.com>2026-10-29 20:49:48 -0400
commit158e3733f25d61cfaeebbf312cafb389fb8e84f3 (patch)
treee4c8f9b7e8914af06b883cfc482ef990b9346e39 /src
parent0a43245033fc9407f30a239c856bcbf0d2dd619d (diff)
nx2: syncpt cancel always signals; a new slot request starts unsignalled
nn::syncpt::sdk's CancelSyncPointEvent sends 202 and then always waits on the slot's event, so 202 now signals it also when no request was pending. Title 1's movie player cancels each output-buffer slot before its first request and hung there forever (the cup-opening screen stayed black and the decoder was never started). Slots are reused by different client objects: the movie player got slot 0 after NVN's fence waits had left its event signalled, read that as a decoded frame, found none and aborted with 2111-3604. 201 now clears the slot's event before registering the new request.
Diffstat (limited to 'src')
-rw-r--r--src/core/hle/service/nx2_gsv.h25
1 files changed, 17 insertions, 8 deletions
diff --git a/src/core/hle/service/nx2_gsv.h b/src/core/hle/service/nx2_gsv.h
index e4c4939bce..9a90a27f79 100644
--- a/src/core/hle/service/nx2_gsv.h
+++ b/src/core/hle/service/nx2_gsv.h
@@ -213,6 +213,10 @@ private:
}
auto& request = m_requests[slot];
Cancel(request);
+ // A new request starts unsignalled. Slots are reused by different client objects: title 1's
+ // movie player got slot 0 after NVN's fence waits had left it signalled, took that as a
+ // decoded frame and aborted when the decoder had none.
+ event->Clear(system.Kernel());
request.syncpoint = syncpoint;
request.pending = true;
auto& manager = system.Host1x().GetSyncpointManager();
@@ -234,15 +238,20 @@ private:
void CancelSlotEvent(HLERequestContext& ctx) {
const u32 slot = ctx.CommandBuffer()[2];
LOG_INFO(Service, "nx2:syncpt TIPC 202 slot={:#x}", slot);
- if (auto it = m_requests.find(slot); it != m_requests.end() && Cancel(it->second)) {
- // The client waits on the slot's event after a cancel (NvOsEventPool, after its
- // ~100 ms wait times out), so a cancel must signal it like a completion; it rechecks
- // the counter (TIPC 103) itself. Title 1 hung forever there when the GPU thread ran
- // a frame behind (EDEN_NX2_FRAMES_AHEAD) and a mid-frame wait outlasted 100 ms.
- if (const auto event = m_events.find(slot); event != m_events.end()) {
- event->second->Signal(system.Kernel());
- }
+ if (auto it = m_requests.find(slot); it != m_requests.end()) {
+ Cancel(it->second);
+ }
+ // nn::syncpt::sdk's cancel always waits on the slot's event after this reply, so a cancel
+ // signals it like a completion, also when nothing was pending; the client rechecks the
+ // counter (TIPC 103) itself. Title 1 hung forever there when the GPU thread ran a frame
+ // behind (EDEN_NX2_FRAMES_AHEAD) and a mid-frame wait outlasted NvOsEventPool's 100 ms,
+ // and its movie player cancels each slot before its first request: signalled only for
+ // pending requests, the player never got to start a movie.
+ auto*& event = m_events[slot];
+ if (event == nullptr) {
+ event = m_context.CreateEvent(fmt::format("nx2:syncpt:Slot{:x}", slot));
}
+ event->Signal(system.Kernel());
TipcReplyWords(ctx, {});
}