diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/hle/service/nx2_gsv.h | 27 |
1 files changed, 24 insertions, 3 deletions
diff --git a/src/core/hle/service/nx2_gsv.h b/src/core/hle/service/nx2_gsv.h index 259681a2a2..e488be098c 100644 --- a/src/core/hle/service/nx2_gsv.h +++ b/src/core/hle/service/nx2_gsv.h @@ -2513,7 +2513,19 @@ private: if (release_fence) { m_release_fences[image] = *release_fence; } - value = m_sync_base + ++m_handed; + // After the end of a stream nothing fills an image again, so a release completes at + // once: its fence is the syncpoint's current value. Mario Kart World releases its + // images after a movie ends and waits for the returned fences; a fence for a frame + // that never comes hung the game on a black screen after its title movie. + if (release_fence && m_stream_ended && m_inputs.empty() && m_decoded.empty()) { + const u32 reached = static_cast<u32>( + system.Host1x().GetSyncpointManager().GetGuestSyncpointValue(m_syncpoint)); + m_sync_base = reached; + m_handed = 0; + value = reached; + } else { + value = m_sync_base + ++m_handed; + } } m_cv.notify_one(); return {~m_syncpoint, 0, value, 0}; @@ -2559,7 +2571,8 @@ private: { std::scoped_lock lk{m_mutex}; m_inputs.push_back(std::move(input)); - m_ready->room.store(m_inputs.size() < MaxQueuedInputs, std::memory_order_relaxed); + m_stream_ended = false; + m_ready->room.store(!end && m_inputs.size() < MaxQueuedInputs, std::memory_order_relaxed); } m_cv.notify_one(); const u64 id = ++m_submitted; @@ -2574,6 +2587,7 @@ private: std::scoped_lock lk{m_mutex}; m_inputs.clear(); m_flush = true; + m_stream_ended = false; m_ready->room.store(true, std::memory_order_relaxed); } m_cv.notify_one(); @@ -2647,6 +2661,10 @@ private: lk.lock(); // Even an image written during a flush counts: the client waits for its value. m_outputs.push_back({image, width, height, frame.pts, frame.end}); + if (frame.end) { + m_stream_ended = true; + m_ready->room.store(false, std::memory_order_relaxed); + } system.Host1x().GetSyncpointManager().IncrementGuest(m_syncpoint); ++m_frames_out; if (m_frames_out == 1 || (m_frames_out % 600) == 0 || frame.end) { @@ -2658,7 +2676,9 @@ private: } Input input = std::move(m_inputs.front()); m_inputs.pop_front(); - m_ready->room.store(m_inputs.size() < MaxQueuedInputs, std::memory_order_relaxed); + if (!m_stream_ended) { + m_ready->room.store(m_inputs.size() < MaxQueuedInputs, std::memory_order_relaxed); + } const std::string codec = m_codec; lk.unlock(); if (!decoder || decoder->Name() != codec) { @@ -2809,6 +2829,7 @@ private: std::deque<u32> m_free; ///< Output images, in the order the client acquires them std::map<u32, Fence> m_release_fences; std::deque<Output> m_outputs; ///< Finished, for 213 + bool m_stream_ended{}; ///< End-of-stream frame handed out, nothing submitted since bool m_flush{}; bool m_quit{}; std::thread m_worker; |
