diff options
| author | 2020-03-24 20:58:49 -0600 | |
|---|---|---|
| committer | 2020-03-24 21:03:42 -0600 | |
| commit | 282adfc70b5d7d958d564bfda0227bb3fbd8d110 (patch) | |
| tree | 2a98e3bedec2e7fdb33478814a73be664661aecc /src/video_core | |
| parent | Use the correct directory for Qt Plugins (diff) | |
| download | yuzu-282adfc70b5d7d958d564bfda0227bb3fbd8d110.tar.gz yuzu-282adfc70b5d7d958d564bfda0227bb3fbd8d110.tar.xz yuzu-282adfc70b5d7d958d564bfda0227bb3fbd8d110.zip | |
Frontend/GPU: Refactor context management
Changes the GraphicsContext to be managed by the GPU core. This
eliminates the need for the frontends to fool around with tricky
MakeCurrent/DoneCurrent calls that are dependent on the settings (such
as async gpu option).
This also refactors out the need to use QWidget::fromWindowContainer as
that caused issues with focus and input handling. Now we use a regular
QWidget and just access the native windowHandle() directly.
Another change is removing the debug tool setting in FrameMailbox.
Instead of trying to block the frontend until a new frame is ready, the
core will now take over presentation and draw directly to the window if
the renderer detects that its hooked by NSight or RenderDoc
Lastly, since it was in the way, I removed ScopeAcquireWindowContext and
replaced it with a simple subclass in GraphicsContext that achieves the
same result
Diffstat (limited to 'src/video_core')
| -rw-r--r-- | src/video_core/gpu.cpp | 10 | ||||
| -rw-r--r-- | src/video_core/gpu.h | 18 | ||||
| -rw-r--r-- | src/video_core/gpu_asynch.cpp | 9 | ||||
| -rw-r--r-- | src/video_core/gpu_asynch.h | 9 | ||||
| -rw-r--r-- | src/video_core/gpu_synch.cpp | 17 | ||||
| -rw-r--r-- | src/video_core/gpu_synch.h | 10 | ||||
| -rw-r--r-- | src/video_core/gpu_thread.cpp | 15 | ||||
| -rw-r--r-- | src/video_core/gpu_thread.h | 7 | ||||
| -rw-r--r-- | src/video_core/renderer_base.h | 3 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_cache.cpp | 5 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/renderer_opengl.cpp | 69 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/renderer_opengl.h | 10 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/renderer_vulkan.cpp | 3 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/renderer_vulkan.h | 2 | ||||
| -rw-r--r-- | src/video_core/video_core.cpp | 28 | ||||
| -rw-r--r-- | src/video_core/video_core.h | 11 |
16 files changed, 129 insertions, 97 deletions
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp index e8f763ce9..8acf2eda2 100644 --- a/src/video_core/gpu.cpp +++ b/src/video_core/gpu.cpp | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | #include "core/core.h" | 7 | #include "core/core.h" |
| 8 | #include "core/core_timing.h" | 8 | #include "core/core_timing.h" |
| 9 | #include "core/core_timing_util.h" | 9 | #include "core/core_timing_util.h" |
| 10 | #include "core/frontend/emu_window.h" | ||
| 10 | #include "core/memory.h" | 11 | #include "core/memory.h" |
| 11 | #include "video_core/engines/fermi_2d.h" | 12 | #include "video_core/engines/fermi_2d.h" |
| 12 | #include "video_core/engines/kepler_compute.h" | 13 | #include "video_core/engines/kepler_compute.h" |
| @@ -16,14 +17,15 @@ | |||
| 16 | #include "video_core/gpu.h" | 17 | #include "video_core/gpu.h" |
| 17 | #include "video_core/memory_manager.h" | 18 | #include "video_core/memory_manager.h" |
| 18 | #include "video_core/renderer_base.h" | 19 | #include "video_core/renderer_base.h" |
| 20 | #include "video_core/video_core.h" | ||
| 19 | 21 | ||
| 20 | namespace Tegra { | 22 | namespace Tegra { |
| 21 | 23 | ||
| 22 | MICROPROFILE_DEFINE(GPU_wait, "GPU", "Wait for the GPU", MP_RGB(128, 128, 192)); | 24 | MICROPROFILE_DEFINE(GPU_wait, "GPU", "Wait for the GPU", MP_RGB(128, 128, 192)); |
| 23 | 25 | ||
| 24 | GPU::GPU(Core::System& system, VideoCore::RendererBase& renderer, bool is_async) | 26 | GPU::GPU(Core::System& system, std::unique_ptr<VideoCore::RendererBase>&& renderer_, bool is_async) |
| 25 | : system{system}, renderer{renderer}, is_async{is_async} { | 27 | : system{system}, renderer{std::move(renderer_)}, is_async{is_async} { |
| 26 | auto& rasterizer{renderer.Rasterizer()}; | 28 | auto& rasterizer{renderer->Rasterizer()}; |
| 27 | memory_manager = std::make_unique<Tegra::MemoryManager>(system, rasterizer); | 29 | memory_manager = std::make_unique<Tegra::MemoryManager>(system, rasterizer); |
| 28 | dma_pusher = std::make_unique<Tegra::DmaPusher>(*this); | 30 | dma_pusher = std::make_unique<Tegra::DmaPusher>(*this); |
| 29 | maxwell_3d = std::make_unique<Engines::Maxwell3D>(system, rasterizer, *memory_manager); | 31 | maxwell_3d = std::make_unique<Engines::Maxwell3D>(system, rasterizer, *memory_manager); |
| @@ -137,7 +139,7 @@ u64 GPU::GetTicks() const { | |||
| 137 | } | 139 | } |
| 138 | 140 | ||
| 139 | void GPU::FlushCommands() { | 141 | void GPU::FlushCommands() { |
| 140 | renderer.Rasterizer().FlushCommands(); | 142 | renderer->Rasterizer().FlushCommands(); |
| 141 | } | 143 | } |
| 142 | 144 | ||
| 143 | // Note that, traditionally, methods are treated as 4-byte addressable locations, and hence | 145 | // Note that, traditionally, methods are treated as 4-byte addressable locations, and hence |
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h index 64acb17df..ced9d7e28 100644 --- a/src/video_core/gpu.h +++ b/src/video_core/gpu.h | |||
| @@ -25,8 +25,11 @@ inline u8* FromCacheAddr(CacheAddr cache_addr) { | |||
| 25 | } | 25 | } |
| 26 | 26 | ||
| 27 | namespace Core { | 27 | namespace Core { |
| 28 | class System; | 28 | namespace Frontend { |
| 29 | class EmuWindow; | ||
| 29 | } | 30 | } |
| 31 | class System; | ||
| 32 | } // namespace Core | ||
| 30 | 33 | ||
| 31 | namespace VideoCore { | 34 | namespace VideoCore { |
| 32 | class RendererBase; | 35 | class RendererBase; |
| @@ -129,7 +132,8 @@ class MemoryManager; | |||
| 129 | 132 | ||
| 130 | class GPU { | 133 | class GPU { |
| 131 | public: | 134 | public: |
| 132 | explicit GPU(Core::System& system, VideoCore::RendererBase& renderer, bool is_async); | 135 | explicit GPU(Core::System& system, std::unique_ptr<VideoCore::RendererBase>&& renderer, |
| 136 | bool is_async); | ||
| 133 | 137 | ||
| 134 | virtual ~GPU(); | 138 | virtual ~GPU(); |
| 135 | 139 | ||
| @@ -174,6 +178,14 @@ public: | |||
| 174 | /// Returns a reference to the GPU DMA pusher. | 178 | /// Returns a reference to the GPU DMA pusher. |
| 175 | Tegra::DmaPusher& DmaPusher(); | 179 | Tegra::DmaPusher& DmaPusher(); |
| 176 | 180 | ||
| 181 | VideoCore::RendererBase& Renderer() { | ||
| 182 | return *renderer; | ||
| 183 | } | ||
| 184 | |||
| 185 | const VideoCore::RendererBase& Renderer() const { | ||
| 186 | return *renderer; | ||
| 187 | } | ||
| 188 | |||
| 177 | // Waits for the GPU to finish working | 189 | // Waits for the GPU to finish working |
| 178 | virtual void WaitIdle() const = 0; | 190 | virtual void WaitIdle() const = 0; |
| 179 | 191 | ||
| @@ -287,7 +299,7 @@ private: | |||
| 287 | protected: | 299 | protected: |
| 288 | std::unique_ptr<Tegra::DmaPusher> dma_pusher; | 300 | std::unique_ptr<Tegra::DmaPusher> dma_pusher; |
| 289 | Core::System& system; | 301 | Core::System& system; |
| 290 | VideoCore::RendererBase& renderer; | 302 | std::unique_ptr<VideoCore::RendererBase> renderer; |
| 291 | 303 | ||
| 292 | private: | 304 | private: |
| 293 | std::unique_ptr<Tegra::MemoryManager> memory_manager; | 305 | std::unique_ptr<Tegra::MemoryManager> memory_manager; |
diff --git a/src/video_core/gpu_asynch.cpp b/src/video_core/gpu_asynch.cpp index 04222d060..925be8d7b 100644 --- a/src/video_core/gpu_asynch.cpp +++ b/src/video_core/gpu_asynch.cpp | |||
| @@ -10,13 +10,16 @@ | |||
| 10 | 10 | ||
| 11 | namespace VideoCommon { | 11 | namespace VideoCommon { |
| 12 | 12 | ||
| 13 | GPUAsynch::GPUAsynch(Core::System& system, VideoCore::RendererBase& renderer) | 13 | GPUAsynch::GPUAsynch(Core::System& system, std::unique_ptr<VideoCore::RendererBase>&& renderer_, |
| 14 | : GPU(system, renderer, true), gpu_thread{system} {} | 14 | std::unique_ptr<Core::Frontend::GraphicsContext>&& context) |
| 15 | : GPU(system, std::move(renderer_), true), gpu_thread{system}, gpu_context(std::move(context)), | ||
| 16 | cpu_context(renderer->GetRenderWindow().CreateSharedContext()) {} | ||
| 15 | 17 | ||
| 16 | GPUAsynch::~GPUAsynch() = default; | 18 | GPUAsynch::~GPUAsynch() = default; |
| 17 | 19 | ||
| 18 | void GPUAsynch::Start() { | 20 | void GPUAsynch::Start() { |
| 19 | gpu_thread.StartThread(renderer, *dma_pusher); | 21 | cpu_context->MakeCurrent(); |
| 22 | gpu_thread.StartThread(*renderer, *gpu_context, *dma_pusher); | ||
| 20 | } | 23 | } |
| 21 | 24 | ||
| 22 | void GPUAsynch::PushGPUEntries(Tegra::CommandList&& entries) { | 25 | void GPUAsynch::PushGPUEntries(Tegra::CommandList&& entries) { |
diff --git a/src/video_core/gpu_asynch.h b/src/video_core/gpu_asynch.h index 1241ade1d..265c62758 100644 --- a/src/video_core/gpu_asynch.h +++ b/src/video_core/gpu_asynch.h | |||
| @@ -7,6 +7,10 @@ | |||
| 7 | #include "video_core/gpu.h" | 7 | #include "video_core/gpu.h" |
| 8 | #include "video_core/gpu_thread.h" | 8 | #include "video_core/gpu_thread.h" |
| 9 | 9 | ||
| 10 | namespace Core::Frontend { | ||
| 11 | class GraphicsContext; | ||
| 12 | } | ||
| 13 | |||
| 10 | namespace VideoCore { | 14 | namespace VideoCore { |
| 11 | class RendererBase; | 15 | class RendererBase; |
| 12 | } // namespace VideoCore | 16 | } // namespace VideoCore |
| @@ -16,7 +20,8 @@ namespace VideoCommon { | |||
| 16 | /// Implementation of GPU interface that runs the GPU asynchronously | 20 | /// Implementation of GPU interface that runs the GPU asynchronously |
| 17 | class GPUAsynch final : public Tegra::GPU { | 21 | class GPUAsynch final : public Tegra::GPU { |
| 18 | public: | 22 | public: |
| 19 | explicit GPUAsynch(Core::System& system, VideoCore::RendererBase& renderer); | 23 | explicit GPUAsynch(Core::System& system, std::unique_ptr<VideoCore::RendererBase>&& renderer, |
| 24 | std::unique_ptr<Core::Frontend::GraphicsContext>&& context); | ||
| 20 | ~GPUAsynch() override; | 25 | ~GPUAsynch() override; |
| 21 | 26 | ||
| 22 | void Start() override; | 27 | void Start() override; |
| @@ -32,6 +37,8 @@ protected: | |||
| 32 | 37 | ||
| 33 | private: | 38 | private: |
| 34 | GPUThread::ThreadManager gpu_thread; | 39 | GPUThread::ThreadManager gpu_thread; |
| 40 | std::unique_ptr<Core::Frontend::GraphicsContext> cpu_context; | ||
| 41 | std::unique_ptr<Core::Frontend::GraphicsContext> gpu_context; | ||
| 35 | }; | 42 | }; |
| 36 | 43 | ||
| 37 | } // namespace VideoCommon | 44 | } // namespace VideoCommon |
diff --git a/src/video_core/gpu_synch.cpp b/src/video_core/gpu_synch.cpp index d48221077..bd5278a5c 100644 --- a/src/video_core/gpu_synch.cpp +++ b/src/video_core/gpu_synch.cpp | |||
| @@ -7,12 +7,15 @@ | |||
| 7 | 7 | ||
| 8 | namespace VideoCommon { | 8 | namespace VideoCommon { |
| 9 | 9 | ||
| 10 | GPUSynch::GPUSynch(Core::System& system, VideoCore::RendererBase& renderer) | 10 | GPUSynch::GPUSynch(Core::System& system, std::unique_ptr<VideoCore::RendererBase>&& renderer, |
| 11 | : GPU(system, renderer, false) {} | 11 | std::unique_ptr<Core::Frontend::GraphicsContext>&& context) |
| 12 | : GPU(system, std::move(renderer), false), context{std::move(context)} {} | ||
| 12 | 13 | ||
| 13 | GPUSynch::~GPUSynch() = default; | 14 | GPUSynch::~GPUSynch() = default; |
| 14 | 15 | ||
| 15 | void GPUSynch::Start() {} | 16 | void GPUSynch::Start() { |
| 17 | context->MakeCurrent(); | ||
| 18 | } | ||
| 16 | 19 | ||
| 17 | void GPUSynch::PushGPUEntries(Tegra::CommandList&& entries) { | 20 | void GPUSynch::PushGPUEntries(Tegra::CommandList&& entries) { |
| 18 | dma_pusher->Push(std::move(entries)); | 21 | dma_pusher->Push(std::move(entries)); |
| @@ -20,19 +23,19 @@ void GPUSynch::PushGPUEntries(Tegra::CommandList&& entries) { | |||
| 20 | } | 23 | } |
| 21 | 24 | ||
| 22 | void GPUSynch::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { | 25 | void GPUSynch::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { |
| 23 | renderer.SwapBuffers(framebuffer); | 26 | renderer->SwapBuffers(framebuffer); |
| 24 | } | 27 | } |
| 25 | 28 | ||
| 26 | void GPUSynch::FlushRegion(CacheAddr addr, u64 size) { | 29 | void GPUSynch::FlushRegion(CacheAddr addr, u64 size) { |
| 27 | renderer.Rasterizer().FlushRegion(addr, size); | 30 | renderer->Rasterizer().FlushRegion(addr, size); |
| 28 | } | 31 | } |
| 29 | 32 | ||
| 30 | void GPUSynch::InvalidateRegion(CacheAddr addr, u64 size) { | 33 | void GPUSynch::InvalidateRegion(CacheAddr addr, u64 size) { |
| 31 | renderer.Rasterizer().InvalidateRegion(addr, size); | 34 | renderer->Rasterizer().InvalidateRegion(addr, size); |
| 32 | } | 35 | } |
| 33 | 36 | ||
| 34 | void GPUSynch::FlushAndInvalidateRegion(CacheAddr addr, u64 size) { | 37 | void GPUSynch::FlushAndInvalidateRegion(CacheAddr addr, u64 size) { |
| 35 | renderer.Rasterizer().FlushAndInvalidateRegion(addr, size); | 38 | renderer->Rasterizer().FlushAndInvalidateRegion(addr, size); |
| 36 | } | 39 | } |
| 37 | 40 | ||
| 38 | } // namespace VideoCommon | 41 | } // namespace VideoCommon |
diff --git a/src/video_core/gpu_synch.h b/src/video_core/gpu_synch.h index c71baee89..866a94c8c 100644 --- a/src/video_core/gpu_synch.h +++ b/src/video_core/gpu_synch.h | |||
| @@ -6,6 +6,10 @@ | |||
| 6 | 6 | ||
| 7 | #include "video_core/gpu.h" | 7 | #include "video_core/gpu.h" |
| 8 | 8 | ||
| 9 | namespace Core::Frontend { | ||
| 10 | class GraphicsContext; | ||
| 11 | } | ||
| 12 | |||
| 9 | namespace VideoCore { | 13 | namespace VideoCore { |
| 10 | class RendererBase; | 14 | class RendererBase; |
| 11 | } // namespace VideoCore | 15 | } // namespace VideoCore |
| @@ -15,7 +19,8 @@ namespace VideoCommon { | |||
| 15 | /// Implementation of GPU interface that runs the GPU synchronously | 19 | /// Implementation of GPU interface that runs the GPU synchronously |
| 16 | class GPUSynch final : public Tegra::GPU { | 20 | class GPUSynch final : public Tegra::GPU { |
| 17 | public: | 21 | public: |
| 18 | explicit GPUSynch(Core::System& system, VideoCore::RendererBase& renderer); | 22 | explicit GPUSynch(Core::System& system, std::unique_ptr<VideoCore::RendererBase>&& renderer, |
| 23 | std::unique_ptr<Core::Frontend::GraphicsContext>&& context); | ||
| 19 | ~GPUSynch() override; | 24 | ~GPUSynch() override; |
| 20 | 25 | ||
| 21 | void Start() override; | 26 | void Start() override; |
| @@ -29,6 +34,9 @@ public: | |||
| 29 | protected: | 34 | protected: |
| 30 | void TriggerCpuInterrupt([[maybe_unused]] u32 syncpoint_id, | 35 | void TriggerCpuInterrupt([[maybe_unused]] u32 syncpoint_id, |
| 31 | [[maybe_unused]] u32 value) const override {} | 36 | [[maybe_unused]] u32 value) const override {} |
| 37 | |||
| 38 | private: | ||
| 39 | std::unique_ptr<Core::Frontend::GraphicsContext> context; | ||
| 32 | }; | 40 | }; |
| 33 | 41 | ||
| 34 | } // namespace VideoCommon | 42 | } // namespace VideoCommon |
diff --git a/src/video_core/gpu_thread.cpp b/src/video_core/gpu_thread.cpp index b1088af3d..270c7ae0d 100644 --- a/src/video_core/gpu_thread.cpp +++ b/src/video_core/gpu_thread.cpp | |||
| @@ -5,7 +5,7 @@ | |||
| 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/frontend/scope_acquire_context.h" | 8 | #include "core/frontend/emu_window.h" |
| 9 | #include "video_core/dma_pusher.h" | 9 | #include "video_core/dma_pusher.h" |
| 10 | #include "video_core/gpu.h" | 10 | #include "video_core/gpu.h" |
| 11 | #include "video_core/gpu_thread.h" | 11 | #include "video_core/gpu_thread.h" |
| @@ -14,8 +14,8 @@ | |||
| 14 | namespace VideoCommon::GPUThread { | 14 | namespace VideoCommon::GPUThread { |
| 15 | 15 | ||
| 16 | /// Runs the GPU thread | 16 | /// Runs the GPU thread |
| 17 | static void RunThread(VideoCore::RendererBase& renderer, Tegra::DmaPusher& dma_pusher, | 17 | static void RunThread(VideoCore::RendererBase& renderer, Core::Frontend::GraphicsContext& context, |
| 18 | SynchState& state) { | 18 | Tegra::DmaPusher& dma_pusher, SynchState& state) { |
| 19 | MicroProfileOnThreadCreate("GpuThread"); | 19 | MicroProfileOnThreadCreate("GpuThread"); |
| 20 | 20 | ||
| 21 | // Wait for first GPU command before acquiring the window context | 21 | // Wait for first GPU command before acquiring the window context |
| @@ -27,7 +27,7 @@ static void RunThread(VideoCore::RendererBase& renderer, Tegra::DmaPusher& dma_p | |||
| 27 | return; | 27 | return; |
| 28 | } | 28 | } |
| 29 | 29 | ||
| 30 | Core::Frontend::ScopeAcquireContext acquire_context{renderer.GetRenderWindow()}; | 30 | auto current_context = context.Acquire(); |
| 31 | 31 | ||
| 32 | CommandDataContainer next; | 32 | CommandDataContainer next; |
| 33 | while (state.is_running) { | 33 | while (state.is_running) { |
| @@ -62,8 +62,11 @@ ThreadManager::~ThreadManager() { | |||
| 62 | thread.join(); | 62 | thread.join(); |
| 63 | } | 63 | } |
| 64 | 64 | ||
| 65 | void ThreadManager::StartThread(VideoCore::RendererBase& renderer, Tegra::DmaPusher& dma_pusher) { | 65 | void ThreadManager::StartThread(VideoCore::RendererBase& renderer, |
| 66 | thread = std::thread{RunThread, std::ref(renderer), std::ref(dma_pusher), std::ref(state)}; | 66 | Core::Frontend::GraphicsContext& context, |
| 67 | Tegra::DmaPusher& dma_pusher) { | ||
| 68 | thread = std::thread{RunThread, std::ref(renderer), std::ref(context), std::ref(dma_pusher), | ||
| 69 | std::ref(state)}; | ||
| 67 | } | 70 | } |
| 68 | 71 | ||
| 69 | void ThreadManager::SubmitList(Tegra::CommandList&& entries) { | 72 | void ThreadManager::SubmitList(Tegra::CommandList&& entries) { |
diff --git a/src/video_core/gpu_thread.h b/src/video_core/gpu_thread.h index 882e2d9c7..be36c580e 100644 --- a/src/video_core/gpu_thread.h +++ b/src/video_core/gpu_thread.h | |||
| @@ -10,7 +10,6 @@ | |||
| 10 | #include <optional> | 10 | #include <optional> |
| 11 | #include <thread> | 11 | #include <thread> |
| 12 | #include <variant> | 12 | #include <variant> |
| 13 | |||
| 14 | #include "common/threadsafe_queue.h" | 13 | #include "common/threadsafe_queue.h" |
| 15 | #include "video_core/gpu.h" | 14 | #include "video_core/gpu.h" |
| 16 | 15 | ||
| @@ -20,6 +19,9 @@ class DmaPusher; | |||
| 20 | } // namespace Tegra | 19 | } // namespace Tegra |
| 21 | 20 | ||
| 22 | namespace Core { | 21 | namespace Core { |
| 22 | namespace Frontend { | ||
| 23 | class GraphicsContext; | ||
| 24 | } | ||
| 23 | class System; | 25 | class System; |
| 24 | } // namespace Core | 26 | } // namespace Core |
| 25 | 27 | ||
| @@ -99,7 +101,8 @@ public: | |||
| 99 | ~ThreadManager(); | 101 | ~ThreadManager(); |
| 100 | 102 | ||
| 101 | /// Creates and starts the GPU thread. | 103 | /// Creates and starts the GPU thread. |
| 102 | void StartThread(VideoCore::RendererBase& renderer, Tegra::DmaPusher& dma_pusher); | 104 | void StartThread(VideoCore::RendererBase& renderer, Core::Frontend::GraphicsContext& context, |
| 105 | Tegra::DmaPusher& dma_pusher); | ||
| 103 | 106 | ||
| 104 | /// Push GPU command entries to be processed | 107 | /// Push GPU command entries to be processed |
| 105 | void SubmitList(Tegra::CommandList&& entries); | 108 | void SubmitList(Tegra::CommandList&& entries); |
diff --git a/src/video_core/renderer_base.h b/src/video_core/renderer_base.h index 5ec99a126..1d85219b6 100644 --- a/src/video_core/renderer_base.h +++ b/src/video_core/renderer_base.h | |||
| @@ -46,7 +46,8 @@ public: | |||
| 46 | 46 | ||
| 47 | /// Draws the latest frame to the window waiting timeout_ms for a frame to arrive (Renderer | 47 | /// Draws the latest frame to the window waiting timeout_ms for a frame to arrive (Renderer |
| 48 | /// specific implementation) | 48 | /// specific implementation) |
| 49 | virtual void TryPresent(int timeout_ms) = 0; | 49 | /// Returns true if a frame was drawn |
| 50 | virtual bool TryPresent(int timeout_ms) = 0; | ||
| 50 | 51 | ||
| 51 | // Getter/setter functions: | 52 | // Getter/setter functions: |
| 52 | // ------------------------ | 53 | // ------------------------ |
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index e3d31c3eb..8f59e0442 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp | |||
| @@ -305,7 +305,6 @@ void ShaderCacheOpenGL::LoadDiskCache(const std::atomic_bool& stop_loading, | |||
| 305 | } | 305 | } |
| 306 | 306 | ||
| 307 | const std::vector gl_cache = disk_cache.LoadPrecompiled(); | 307 | const std::vector gl_cache = disk_cache.LoadPrecompiled(); |
| 308 | const auto supported_formats = GetSupportedFormats(); | ||
| 309 | 308 | ||
| 310 | // Track if precompiled cache was altered during loading to know if we have to | 309 | // Track if precompiled cache was altered during loading to know if we have to |
| 311 | // serialize the virtual precompiled cache file back to the hard drive | 310 | // serialize the virtual precompiled cache file back to the hard drive |
| @@ -327,8 +326,8 @@ void ShaderCacheOpenGL::LoadDiskCache(const std::atomic_bool& stop_loading, | |||
| 327 | 326 | ||
| 328 | const auto worker = [&](Core::Frontend::GraphicsContext* context, std::size_t begin, | 327 | const auto worker = [&](Core::Frontend::GraphicsContext* context, std::size_t begin, |
| 329 | std::size_t end) { | 328 | std::size_t end) { |
| 330 | context->MakeCurrent(); | 329 | const auto scope = context->Acquire(); |
| 331 | SCOPE_EXIT({ return context->DoneCurrent(); }); | 330 | const auto supported_formats = GetSupportedFormats(); |
| 332 | 331 | ||
| 333 | for (std::size_t i = begin; i < end; ++i) { | 332 | for (std::size_t i = begin; i < end; ++i) { |
| 334 | if (stop_loading) { | 333 | if (stop_loading) { |
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index fca5e3ec0..6f08803c1 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp | |||
| @@ -7,9 +7,7 @@ | |||
| 7 | #include <cstdlib> | 7 | #include <cstdlib> |
| 8 | #include <cstring> | 8 | #include <cstring> |
| 9 | #include <memory> | 9 | #include <memory> |
| 10 | |||
| 11 | #include <glad/glad.h> | 10 | #include <glad/glad.h> |
| 12 | |||
| 13 | #include "common/assert.h" | 11 | #include "common/assert.h" |
| 14 | #include "common/logging/log.h" | 12 | #include "common/logging/log.h" |
| 15 | #include "common/microprofile.h" | 13 | #include "common/microprofile.h" |
| @@ -30,8 +28,6 @@ namespace OpenGL { | |||
| 30 | 28 | ||
| 31 | namespace { | 29 | namespace { |
| 32 | 30 | ||
| 33 | // If the size of this is too small, it ends up creating a soft cap on FPS as the renderer will have | ||
| 34 | // to wait on available presentation frames. | ||
| 35 | constexpr std::size_t SWAP_CHAIN_SIZE = 3; | 31 | constexpr std::size_t SWAP_CHAIN_SIZE = 3; |
| 36 | 32 | ||
| 37 | struct Frame { | 33 | struct Frame { |
| @@ -214,7 +210,7 @@ public: | |||
| 214 | std::deque<Frame*> present_queue; | 210 | std::deque<Frame*> present_queue; |
| 215 | Frame* previous_frame{}; | 211 | Frame* previous_frame{}; |
| 216 | 212 | ||
| 217 | FrameMailbox() : has_debug_tool{HasDebugTool()} { | 213 | FrameMailbox() { |
| 218 | for (auto& frame : swap_chain) { | 214 | for (auto& frame : swap_chain) { |
| 219 | free_queue.push(&frame); | 215 | free_queue.push(&frame); |
| 220 | } | 216 | } |
| @@ -285,13 +281,9 @@ public: | |||
| 285 | std::unique_lock lock{swap_chain_lock}; | 281 | std::unique_lock lock{swap_chain_lock}; |
| 286 | present_queue.push_front(frame); | 282 | present_queue.push_front(frame); |
| 287 | present_cv.notify_one(); | 283 | present_cv.notify_one(); |
| 288 | |||
| 289 | DebugNotifyNextFrame(); | ||
| 290 | } | 284 | } |
| 291 | 285 | ||
| 292 | Frame* TryGetPresentFrame(int timeout_ms) { | 286 | Frame* TryGetPresentFrame(int timeout_ms) { |
| 293 | DebugWaitForNextFrame(); | ||
| 294 | |||
| 295 | std::unique_lock lock{swap_chain_lock}; | 287 | std::unique_lock lock{swap_chain_lock}; |
| 296 | // wait for new entries in the present_queue | 288 | // wait for new entries in the present_queue |
| 297 | present_cv.wait_for(lock, std::chrono::milliseconds(timeout_ms), | 289 | present_cv.wait_for(lock, std::chrono::milliseconds(timeout_ms), |
| @@ -317,38 +309,12 @@ public: | |||
| 317 | previous_frame = frame; | 309 | previous_frame = frame; |
| 318 | return frame; | 310 | return frame; |
| 319 | } | 311 | } |
| 320 | |||
| 321 | private: | ||
| 322 | std::mutex debug_synch_mutex; | ||
| 323 | std::condition_variable debug_synch_condition; | ||
| 324 | std::atomic_int frame_for_debug{}; | ||
| 325 | const bool has_debug_tool; // When true, using a GPU debugger, so keep frames in lock-step | ||
| 326 | |||
| 327 | /// Signal that a new frame is available (called from GPU thread) | ||
| 328 | void DebugNotifyNextFrame() { | ||
| 329 | if (!has_debug_tool) { | ||
| 330 | return; | ||
| 331 | } | ||
| 332 | frame_for_debug++; | ||
| 333 | std::lock_guard lock{debug_synch_mutex}; | ||
| 334 | debug_synch_condition.notify_one(); | ||
| 335 | } | ||
| 336 | |||
| 337 | /// Wait for a new frame to be available (called from presentation thread) | ||
| 338 | void DebugWaitForNextFrame() { | ||
| 339 | if (!has_debug_tool) { | ||
| 340 | return; | ||
| 341 | } | ||
| 342 | const int last_frame = frame_for_debug; | ||
| 343 | std::unique_lock lock{debug_synch_mutex}; | ||
| 344 | debug_synch_condition.wait(lock, | ||
| 345 | [this, last_frame] { return frame_for_debug > last_frame; }); | ||
| 346 | } | ||
| 347 | }; | 312 | }; |
| 348 | 313 | ||
| 349 | RendererOpenGL::RendererOpenGL(Core::Frontend::EmuWindow& emu_window, Core::System& system) | 314 | RendererOpenGL::RendererOpenGL(Core::Frontend::EmuWindow& emu_window, Core::System& system, |
| 350 | : VideoCore::RendererBase{emu_window}, emu_window{emu_window}, system{system}, | 315 | Core::Frontend::GraphicsContext& context) |
| 351 | frame_mailbox{std::make_unique<FrameMailbox>()} {} | 316 | : VideoCore::RendererBase{emu_window}, emu_window{emu_window}, system{system}, frame_mailbox{}, |
| 317 | has_debug_tool{HasDebugTool()}, context{context} {} | ||
| 352 | 318 | ||
| 353 | RendererOpenGL::~RendererOpenGL() = default; | 319 | RendererOpenGL::~RendererOpenGL() = default; |
| 354 | 320 | ||
| @@ -356,8 +322,6 @@ MICROPROFILE_DEFINE(OpenGL_RenderFrame, "OpenGL", "Render Frame", MP_RGB(128, 12 | |||
| 356 | MICROPROFILE_DEFINE(OpenGL_WaitPresent, "OpenGL", "Wait For Present", MP_RGB(128, 128, 128)); | 322 | MICROPROFILE_DEFINE(OpenGL_WaitPresent, "OpenGL", "Wait For Present", MP_RGB(128, 128, 128)); |
| 357 | 323 | ||
| 358 | void RendererOpenGL::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { | 324 | void RendererOpenGL::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { |
| 359 | render_window.PollEvents(); | ||
| 360 | |||
| 361 | if (!framebuffer) { | 325 | if (!framebuffer) { |
| 362 | return; | 326 | return; |
| 363 | } | 327 | } |
| @@ -413,6 +377,13 @@ void RendererOpenGL::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { | |||
| 413 | m_current_frame++; | 377 | m_current_frame++; |
| 414 | rasterizer->TickFrame(); | 378 | rasterizer->TickFrame(); |
| 415 | } | 379 | } |
| 380 | |||
| 381 | render_window.PollEvents(); | ||
| 382 | if (has_debug_tool) { | ||
| 383 | glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); | ||
| 384 | Present(0); | ||
| 385 | context.SwapBuffers(); | ||
| 386 | } | ||
| 416 | } | 387 | } |
| 417 | 388 | ||
| 418 | void RendererOpenGL::PrepareRendertarget(const Tegra::FramebufferConfig* framebuffer) { | 389 | void RendererOpenGL::PrepareRendertarget(const Tegra::FramebufferConfig* framebuffer) { |
| @@ -480,6 +451,8 @@ void RendererOpenGL::LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color | |||
| 480 | } | 451 | } |
| 481 | 452 | ||
| 482 | void RendererOpenGL::InitOpenGLObjects() { | 453 | void RendererOpenGL::InitOpenGLObjects() { |
| 454 | frame_mailbox = std::make_unique<FrameMailbox>(); | ||
| 455 | |||
| 483 | glClearColor(Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue, | 456 | glClearColor(Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue, |
| 484 | 0.0f); | 457 | 0.0f); |
| 485 | 458 | ||
| @@ -692,12 +665,21 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) { | |||
| 692 | glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); | 665 | glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); |
| 693 | } | 666 | } |
| 694 | 667 | ||
| 695 | void RendererOpenGL::TryPresent(int timeout_ms) { | 668 | bool RendererOpenGL::TryPresent(int timeout_ms) { |
| 669 | if (has_debug_tool) { | ||
| 670 | LOG_DEBUG(Render_OpenGL, | ||
| 671 | "Skipping presentation because we are presenting on the main context"); | ||
| 672 | return false; | ||
| 673 | } | ||
| 674 | return Present(timeout_ms); | ||
| 675 | } | ||
| 676 | |||
| 677 | bool RendererOpenGL::Present(int timeout_ms) { | ||
| 696 | const auto& layout = render_window.GetFramebufferLayout(); | 678 | const auto& layout = render_window.GetFramebufferLayout(); |
| 697 | auto frame = frame_mailbox->TryGetPresentFrame(timeout_ms); | 679 | auto frame = frame_mailbox->TryGetPresentFrame(timeout_ms); |
| 698 | if (!frame) { | 680 | if (!frame) { |
| 699 | LOG_DEBUG(Render_OpenGL, "TryGetPresentFrame returned no frame to present"); | 681 | LOG_DEBUG(Render_OpenGL, "TryGetPresentFrame returned no frame to present"); |
| 700 | return; | 682 | return false; |
| 701 | } | 683 | } |
| 702 | 684 | ||
| 703 | // Clearing before a full overwrite of a fbo can signal to drivers that they can avoid a | 685 | // Clearing before a full overwrite of a fbo can signal to drivers that they can avoid a |
| @@ -725,6 +707,7 @@ void RendererOpenGL::TryPresent(int timeout_ms) { | |||
| 725 | glFlush(); | 707 | glFlush(); |
| 726 | 708 | ||
| 727 | glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); | 709 | glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); |
| 710 | return true; | ||
| 728 | } | 711 | } |
| 729 | 712 | ||
| 730 | void RendererOpenGL::RenderScreenshot() { | 713 | void RendererOpenGL::RenderScreenshot() { |
diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h index 33073ce5b..50b647661 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.h +++ b/src/video_core/renderer_opengl/renderer_opengl.h | |||
| @@ -55,13 +55,14 @@ class FrameMailbox; | |||
| 55 | 55 | ||
| 56 | class RendererOpenGL final : public VideoCore::RendererBase { | 56 | class RendererOpenGL final : public VideoCore::RendererBase { |
| 57 | public: | 57 | public: |
| 58 | explicit RendererOpenGL(Core::Frontend::EmuWindow& emu_window, Core::System& system); | 58 | explicit RendererOpenGL(Core::Frontend::EmuWindow& emu_window, Core::System& system, |
| 59 | Core::Frontend::GraphicsContext& context); | ||
| 59 | ~RendererOpenGL() override; | 60 | ~RendererOpenGL() override; |
| 60 | 61 | ||
| 61 | bool Init() override; | 62 | bool Init() override; |
| 62 | void ShutDown() override; | 63 | void ShutDown() override; |
| 63 | void SwapBuffers(const Tegra::FramebufferConfig* framebuffer) override; | 64 | void SwapBuffers(const Tegra::FramebufferConfig* framebuffer) override; |
| 64 | void TryPresent(int timeout_ms) override; | 65 | bool TryPresent(int timeout_ms) override; |
| 65 | 66 | ||
| 66 | private: | 67 | private: |
| 67 | /// Initializes the OpenGL state and creates persistent objects. | 68 | /// Initializes the OpenGL state and creates persistent objects. |
| @@ -89,8 +90,11 @@ private: | |||
| 89 | 90 | ||
| 90 | void PrepareRendertarget(const Tegra::FramebufferConfig* framebuffer); | 91 | void PrepareRendertarget(const Tegra::FramebufferConfig* framebuffer); |
| 91 | 92 | ||
| 93 | bool Present(int timeout_ms); | ||
| 94 | |||
| 92 | Core::Frontend::EmuWindow& emu_window; | 95 | Core::Frontend::EmuWindow& emu_window; |
| 93 | Core::System& system; | 96 | Core::System& system; |
| 97 | Core::Frontend::GraphicsContext& context; | ||
| 94 | 98 | ||
| 95 | StateTracker state_tracker{system}; | 99 | StateTracker state_tracker{system}; |
| 96 | 100 | ||
| @@ -115,6 +119,8 @@ private: | |||
| 115 | 119 | ||
| 116 | /// Frame presentation mailbox | 120 | /// Frame presentation mailbox |
| 117 | std::unique_ptr<FrameMailbox> frame_mailbox; | 121 | std::unique_ptr<FrameMailbox> frame_mailbox; |
| 122 | |||
| 123 | bool has_debug_tool = false; | ||
| 118 | }; | 124 | }; |
| 119 | 125 | ||
| 120 | } // namespace OpenGL | 126 | } // namespace OpenGL |
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index 42bb01418..6953aaafe 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp | |||
| @@ -141,8 +141,9 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { | |||
| 141 | render_window.PollEvents(); | 141 | render_window.PollEvents(); |
| 142 | } | 142 | } |
| 143 | 143 | ||
| 144 | void RendererVulkan::TryPresent(int /*timeout_ms*/) { | 144 | bool RendererVulkan::TryPresent(int /*timeout_ms*/) { |
| 145 | // TODO (bunnei): ImplementMe | 145 | // TODO (bunnei): ImplementMe |
| 146 | return true; | ||
| 146 | } | 147 | } |
| 147 | 148 | ||
| 148 | bool RendererVulkan::Init() { | 149 | bool RendererVulkan::Init() { |
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h index 3da08d2e4..d14384e79 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.h +++ b/src/video_core/renderer_vulkan/renderer_vulkan.h | |||
| @@ -42,7 +42,7 @@ public: | |||
| 42 | bool Init() override; | 42 | bool Init() override; |
| 43 | void ShutDown() override; | 43 | void ShutDown() override; |
| 44 | void SwapBuffers(const Tegra::FramebufferConfig* framebuffer) override; | 44 | void SwapBuffers(const Tegra::FramebufferConfig* framebuffer) override; |
| 45 | void TryPresent(int timeout_ms) override; | 45 | bool TryPresent(int timeout_ms) override; |
| 46 | 46 | ||
| 47 | private: | 47 | private: |
| 48 | std::optional<vk::DebugUtilsMessengerEXT> CreateDebugCallback( | 48 | std::optional<vk::DebugUtilsMessengerEXT> CreateDebugCallback( |
diff --git a/src/video_core/video_core.cpp b/src/video_core/video_core.cpp index a5f81a8a0..fd9fec018 100644 --- a/src/video_core/video_core.cpp +++ b/src/video_core/video_core.cpp | |||
| @@ -15,13 +15,13 @@ | |||
| 15 | #endif | 15 | #endif |
| 16 | #include "video_core/video_core.h" | 16 | #include "video_core/video_core.h" |
| 17 | 17 | ||
| 18 | namespace VideoCore { | 18 | namespace { |
| 19 | 19 | std::unique_ptr<VideoCore::RendererBase> CreateRenderer(Core::Frontend::EmuWindow& emu_window, | |
| 20 | std::unique_ptr<RendererBase> CreateRenderer(Core::Frontend::EmuWindow& emu_window, | 20 | Core::System& system, |
| 21 | Core::System& system) { | 21 | Core::Frontend::GraphicsContext& context) { |
| 22 | switch (Settings::values.renderer_backend) { | 22 | switch (Settings::values.renderer_backend) { |
| 23 | case Settings::RendererBackend::OpenGL: | 23 | case Settings::RendererBackend::OpenGL: |
| 24 | return std::make_unique<OpenGL::RendererOpenGL>(emu_window, system); | 24 | return std::make_unique<OpenGL::RendererOpenGL>(emu_window, system, context); |
| 25 | #ifdef HAS_VULKAN | 25 | #ifdef HAS_VULKAN |
| 26 | case Settings::RendererBackend::Vulkan: | 26 | case Settings::RendererBackend::Vulkan: |
| 27 | return std::make_unique<Vulkan::RendererVulkan>(emu_window, system); | 27 | return std::make_unique<Vulkan::RendererVulkan>(emu_window, system); |
| @@ -30,13 +30,23 @@ std::unique_ptr<RendererBase> CreateRenderer(Core::Frontend::EmuWindow& emu_wind | |||
| 30 | return nullptr; | 30 | return nullptr; |
| 31 | } | 31 | } |
| 32 | } | 32 | } |
| 33 | } // namespace | ||
| 33 | 34 | ||
| 34 | std::unique_ptr<Tegra::GPU> CreateGPU(Core::System& system) { | 35 | namespace VideoCore { |
| 35 | if (Settings::values.use_asynchronous_gpu_emulation) { | 36 | |
| 36 | return std::make_unique<VideoCommon::GPUAsynch>(system, system.Renderer()); | 37 | std::unique_ptr<Tegra::GPU> CreateGPU(Core::Frontend::EmuWindow& emu_window, Core::System& system) { |
| 38 | auto context = emu_window.CreateSharedContext(); | ||
| 39 | const auto scope = context->Acquire(); | ||
| 40 | auto renderer = CreateRenderer(emu_window, system, *context); | ||
| 41 | if (!renderer->Init()) { | ||
| 42 | return {}; | ||
| 37 | } | 43 | } |
| 38 | 44 | ||
| 39 | return std::make_unique<VideoCommon::GPUSynch>(system, system.Renderer()); | 45 | if (Settings::values.use_asynchronous_gpu_emulation) { |
| 46 | return std::make_unique<VideoCommon::GPUAsynch>(system, std::move(renderer), | ||
| 47 | std::move(context)); | ||
| 48 | } | ||
| 49 | return std::make_unique<VideoCommon::GPUSynch>(system, std::move(renderer), std::move(context)); | ||
| 40 | } | 50 | } |
| 41 | 51 | ||
| 42 | u16 GetResolutionScaleFactor(const RendererBase& renderer) { | 52 | u16 GetResolutionScaleFactor(const RendererBase& renderer) { |
diff --git a/src/video_core/video_core.h b/src/video_core/video_core.h index b8e0ac372..f5c27125d 100644 --- a/src/video_core/video_core.h +++ b/src/video_core/video_core.h | |||
| @@ -22,17 +22,8 @@ namespace VideoCore { | |||
| 22 | 22 | ||
| 23 | class RendererBase; | 23 | class RendererBase; |
| 24 | 24 | ||
| 25 | /** | ||
| 26 | * Creates a renderer instance. | ||
| 27 | * | ||
| 28 | * @note The returned renderer instance is simply allocated. Its Init() | ||
| 29 | * function still needs to be called to fully complete its setup. | ||
| 30 | */ | ||
| 31 | std::unique_ptr<RendererBase> CreateRenderer(Core::Frontend::EmuWindow& emu_window, | ||
| 32 | Core::System& system); | ||
| 33 | |||
| 34 | /// Creates an emulated GPU instance using the given system context. | 25 | /// Creates an emulated GPU instance using the given system context. |
| 35 | std::unique_ptr<Tegra::GPU> CreateGPU(Core::System& system); | 26 | std::unique_ptr<Tegra::GPU> CreateGPU(Core::Frontend::EmuWindow& emu_window, Core::System& system); |
| 36 | 27 | ||
| 37 | u16 GetResolutionScaleFactor(const RendererBase& renderer); | 28 | u16 GetResolutionScaleFactor(const RendererBase& renderer); |
| 38 | 29 | ||