diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/hle/service/nvflinger/nvflinger.cpp | 21 | ||||
| -rw-r--r-- | src/core/hle/service/nvflinger/nvflinger.h | 2 | ||||
| -rw-r--r-- | src/video_core/gpu.cpp | 13 | ||||
| -rw-r--r-- | src/video_core/gpu.h | 3 | ||||
| -rw-r--r-- | src/video_core/gpu_thread.cpp | 14 | ||||
| -rw-r--r-- | src/video_core/gpu_thread.h | 6 |
6 files changed, 38 insertions, 21 deletions
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index 3b251f8c8..86a90526c 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp | |||
| @@ -36,6 +36,10 @@ NVFlinger::NVFlinger(Core::System& system) : system(system) { | |||
| 36 | displays.emplace_back(3, "Internal", system); | 36 | displays.emplace_back(3, "Internal", system); |
| 37 | displays.emplace_back(4, "Null", system); | 37 | displays.emplace_back(4, "Null", system); |
| 38 | 38 | ||
| 39 | for (auto& display : displays) { | ||
| 40 | display.SignalVSyncEvent(); | ||
| 41 | } | ||
| 42 | |||
| 39 | // Schedule the screen composition events | 43 | // Schedule the screen composition events |
| 40 | composition_event = system.CoreTiming().RegisterEvent( | 44 | composition_event = system.CoreTiming().RegisterEvent( |
| 41 | "ScreenComposition", [this](u64 userdata, s64 cycles_late) { | 45 | "ScreenComposition", [this](u64 userdata, s64 cycles_late) { |
| @@ -173,7 +177,13 @@ void NVFlinger::Compose() { | |||
| 173 | bool trigger_event = false; | 177 | bool trigger_event = false; |
| 174 | // Trigger vsync for this display at the end of drawing | 178 | // Trigger vsync for this display at the end of drawing |
| 175 | SCOPE_EXIT({ | 179 | SCOPE_EXIT({ |
| 176 | if (trigger_event) { | 180 | // TODO(Blinkhawk): Correctly send buffers through nvflinger while |
| 181 | // loading the game thorugh the OS. | ||
| 182 | // During loading, the OS takes care of sending buffers to vsync, | ||
| 183 | // thus it triggers, since this is not properly emulated due to | ||
| 184 | // HLE complications, we allow it to signal until the game enqueues | ||
| 185 | // it's first buffer. | ||
| 186 | if (trigger_event || !first_buffer_enqueued) { | ||
| 177 | display.SignalVSyncEvent(); | 187 | display.SignalVSyncEvent(); |
| 178 | } | 188 | } |
| 179 | }); | 189 | }); |
| @@ -193,13 +203,20 @@ void NVFlinger::Compose() { | |||
| 193 | 203 | ||
| 194 | if (!buffer) { | 204 | if (!buffer) { |
| 195 | // There was no queued buffer to draw, render previous frame | 205 | // There was no queued buffer to draw, render previous frame |
| 196 | system.GetPerfStats().EndGameFrame(); | ||
| 197 | system.GPU().SwapBuffers({}); | 206 | system.GPU().SwapBuffers({}); |
| 198 | continue; | 207 | continue; |
| 199 | } | 208 | } |
| 200 | 209 | ||
| 201 | const auto& igbp_buffer = buffer->get().igbp_buffer; | 210 | const auto& igbp_buffer = buffer->get().igbp_buffer; |
| 202 | trigger_event = true; | 211 | trigger_event = true; |
| 212 | first_buffer_enqueued = true; | ||
| 213 | |||
| 214 | const auto& gpu = system.GPU(); | ||
| 215 | const auto& multi_fence = buffer->get().multi_fence; | ||
| 216 | for (u32 fence_id = 0; fence_id < multi_fence.num_fences; fence_id++) { | ||
| 217 | const auto& fence = multi_fence.fences[fence_id]; | ||
| 218 | gpu.WaitFence(fence.id, fence.value); | ||
| 219 | } | ||
| 203 | 220 | ||
| 204 | // Now send the buffer to the GPU for drawing. | 221 | // Now send the buffer to the GPU for drawing. |
| 205 | // TODO(Subv): Support more than just disp0. The display device selection is probably based | 222 | // TODO(Subv): Support more than just disp0. The display device selection is probably based |
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h index 5d7e3bfb8..95d7278f5 100644 --- a/src/core/hle/service/nvflinger/nvflinger.h +++ b/src/core/hle/service/nvflinger/nvflinger.h | |||
| @@ -102,6 +102,8 @@ private: | |||
| 102 | 102 | ||
| 103 | u32 swap_interval = 1; | 103 | u32 swap_interval = 1; |
| 104 | 104 | ||
| 105 | bool first_buffer_enqueued{}; | ||
| 106 | |||
| 105 | /// Event that handles screen composition. | 107 | /// Event that handles screen composition. |
| 106 | Core::Timing::EventType* composition_event; | 108 | Core::Timing::EventType* composition_event; |
| 107 | 109 | ||
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp index 76cfe8107..d94be9c9d 100644 --- a/src/video_core/gpu.cpp +++ b/src/video_core/gpu.cpp | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include "common/assert.h" | 5 | #include "common/assert.h" |
| 6 | #include "common/microprofile.h" | ||
| 6 | #include "core/core.h" | 7 | #include "core/core.h" |
| 7 | #include "core/core_timing.h" | 8 | #include "core/core_timing.h" |
| 8 | #include "core/memory.h" | 9 | #include "core/memory.h" |
| @@ -17,6 +18,8 @@ | |||
| 17 | 18 | ||
| 18 | namespace Tegra { | 19 | namespace Tegra { |
| 19 | 20 | ||
| 21 | MICROPROFILE_DEFINE(GPU_wait, "GPU", "Wait for the GPU", MP_RGB(128, 128, 192)); | ||
| 22 | |||
| 20 | GPU::GPU(Core::System& system, VideoCore::RendererBase& renderer, bool is_async) | 23 | GPU::GPU(Core::System& system, VideoCore::RendererBase& renderer, bool is_async) |
| 21 | : system{system}, renderer{renderer}, is_async{is_async} { | 24 | : system{system}, renderer{renderer}, is_async{is_async} { |
| 22 | auto& rasterizer{renderer.Rasterizer()}; | 25 | auto& rasterizer{renderer.Rasterizer()}; |
| @@ -63,6 +66,16 @@ const DmaPusher& GPU::DmaPusher() const { | |||
| 63 | return *dma_pusher; | 66 | return *dma_pusher; |
| 64 | } | 67 | } |
| 65 | 68 | ||
| 69 | void GPU::WaitFence(u32 syncpoint_id, u32 value) const { | ||
| 70 | // Synced GPU, is always in sync | ||
| 71 | if (!is_async) { | ||
| 72 | return; | ||
| 73 | } | ||
| 74 | MICROPROFILE_SCOPE(GPU_wait); | ||
| 75 | while (syncpoints[syncpoint_id].load() < value) { | ||
| 76 | } | ||
| 77 | } | ||
| 78 | |||
| 66 | void GPU::IncrementSyncPoint(const u32 syncpoint_id) { | 79 | void GPU::IncrementSyncPoint(const u32 syncpoint_id) { |
| 67 | syncpoints[syncpoint_id]++; | 80 | syncpoints[syncpoint_id]++; |
| 68 | std::lock_guard lock{sync_mutex}; | 81 | std::lock_guard lock{sync_mutex}; |
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h index 29fa8e95b..e20b0687a 100644 --- a/src/video_core/gpu.h +++ b/src/video_core/gpu.h | |||
| @@ -177,6 +177,9 @@ public: | |||
| 177 | /// Returns a reference to the GPU DMA pusher. | 177 | /// Returns a reference to the GPU DMA pusher. |
| 178 | Tegra::DmaPusher& DmaPusher(); | 178 | Tegra::DmaPusher& DmaPusher(); |
| 179 | 179 | ||
| 180 | /// Allows the CPU/NvFlinger to wait on the GPU before presenting a frame. | ||
| 181 | void WaitFence(u32 syncpoint_id, u32 value) const; | ||
| 182 | |||
| 180 | void IncrementSyncPoint(u32 syncpoint_id); | 183 | void IncrementSyncPoint(u32 syncpoint_id); |
| 181 | 184 | ||
| 182 | u32 GetSyncpointValue(u32 syncpoint_id) const; | 185 | u32 GetSyncpointValue(u32 syncpoint_id) const; |
diff --git a/src/video_core/gpu_thread.cpp b/src/video_core/gpu_thread.cpp index 5f039e4fd..d7048b6ae 100644 --- a/src/video_core/gpu_thread.cpp +++ b/src/video_core/gpu_thread.cpp | |||
| @@ -5,8 +5,6 @@ | |||
| 5 | #include "common/assert.h" | 5 | #include "common/assert.h" |
| 6 | #include "common/microprofile.h" | 6 | #include "common/microprofile.h" |
| 7 | #include "core/core.h" | 7 | #include "core/core.h" |
| 8 | #include "core/core_timing.h" | ||
| 9 | #include "core/core_timing_util.h" | ||
| 10 | #include "core/frontend/scope_acquire_window_context.h" | 8 | #include "core/frontend/scope_acquire_window_context.h" |
| 11 | #include "video_core/dma_pusher.h" | 9 | #include "video_core/dma_pusher.h" |
| 12 | #include "video_core/gpu.h" | 10 | #include "video_core/gpu.h" |
| @@ -68,14 +66,10 @@ ThreadManager::~ThreadManager() { | |||
| 68 | 66 | ||
| 69 | void ThreadManager::StartThread(VideoCore::RendererBase& renderer, Tegra::DmaPusher& dma_pusher) { | 67 | void ThreadManager::StartThread(VideoCore::RendererBase& renderer, Tegra::DmaPusher& dma_pusher) { |
| 70 | thread = std::thread{RunThread, std::ref(renderer), std::ref(dma_pusher), std::ref(state)}; | 68 | thread = std::thread{RunThread, std::ref(renderer), std::ref(dma_pusher), std::ref(state)}; |
| 71 | synchronization_event = system.CoreTiming().RegisterEvent( | ||
| 72 | "GPUThreadSynch", [this](u64 fence, s64) { state.WaitForSynchronization(fence); }); | ||
| 73 | } | 69 | } |
| 74 | 70 | ||
| 75 | void ThreadManager::SubmitList(Tegra::CommandList&& entries) { | 71 | void ThreadManager::SubmitList(Tegra::CommandList&& entries) { |
| 76 | const u64 fence{PushCommand(SubmitListCommand(std::move(entries)))}; | 72 | PushCommand(SubmitListCommand(std::move(entries))); |
| 77 | const s64 synchronization_ticks{Core::Timing::usToCycles(std::chrono::microseconds{9000})}; | ||
| 78 | system.CoreTiming().ScheduleEvent(synchronization_ticks, synchronization_event, fence); | ||
| 79 | } | 73 | } |
| 80 | 74 | ||
| 81 | void ThreadManager::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { | 75 | void ThreadManager::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { |
| @@ -102,10 +96,4 @@ u64 ThreadManager::PushCommand(CommandData&& command_data) { | |||
| 102 | return fence; | 96 | return fence; |
| 103 | } | 97 | } |
| 104 | 98 | ||
| 105 | MICROPROFILE_DEFINE(GPU_wait, "GPU", "Wait for the GPU", MP_RGB(128, 128, 192)); | ||
| 106 | void SynchState::WaitForSynchronization(u64 fence) { | ||
| 107 | while (signaled_fence.load() < fence) | ||
| 108 | ; | ||
| 109 | } | ||
| 110 | |||
| 111 | } // namespace VideoCommon::GPUThread | 99 | } // namespace VideoCommon::GPUThread |
diff --git a/src/video_core/gpu_thread.h b/src/video_core/gpu_thread.h index 3ae0ec9f3..108f456bd 100644 --- a/src/video_core/gpu_thread.h +++ b/src/video_core/gpu_thread.h | |||
| @@ -21,9 +21,6 @@ class DmaPusher; | |||
| 21 | 21 | ||
| 22 | namespace Core { | 22 | namespace Core { |
| 23 | class System; | 23 | class System; |
| 24 | namespace Timing { | ||
| 25 | struct EventType; | ||
| 26 | } // namespace Timing | ||
| 27 | } // namespace Core | 24 | } // namespace Core |
| 28 | 25 | ||
| 29 | namespace VideoCommon::GPUThread { | 26 | namespace VideoCommon::GPUThread { |
| @@ -89,8 +86,6 @@ struct CommandDataContainer { | |||
| 89 | struct SynchState final { | 86 | struct SynchState final { |
| 90 | std::atomic_bool is_running{true}; | 87 | std::atomic_bool is_running{true}; |
| 91 | 88 | ||
| 92 | void WaitForSynchronization(u64 fence); | ||
| 93 | |||
| 94 | using CommandQueue = Common::SPSCQueue<CommandDataContainer>; | 89 | using CommandQueue = Common::SPSCQueue<CommandDataContainer>; |
| 95 | CommandQueue queue; | 90 | CommandQueue queue; |
| 96 | u64 last_fence{}; | 91 | u64 last_fence{}; |
| @@ -128,7 +123,6 @@ private: | |||
| 128 | private: | 123 | private: |
| 129 | SynchState state; | 124 | SynchState state; |
| 130 | Core::System& system; | 125 | Core::System& system; |
| 131 | Core::Timing::EventType* synchronization_event{}; | ||
| 132 | std::thread thread; | 126 | std::thread thread; |
| 133 | std::thread::id thread_id; | 127 | std::thread::id thread_id; |
| 134 | }; | 128 | }; |