From 282adfc70b5d7d958d564bfda0227bb3fbd8d110 Mon Sep 17 00:00:00 2001 From: James Rowe Date: Tue, 24 Mar 2020 20:58:49 -0600 Subject: 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 --- src/video_core/gpu.cpp | 10 ++-- src/video_core/gpu.h | 18 +++++- src/video_core/gpu_asynch.cpp | 9 ++- src/video_core/gpu_asynch.h | 9 ++- src/video_core/gpu_synch.cpp | 17 +++--- src/video_core/gpu_synch.h | 10 +++- src/video_core/gpu_thread.cpp | 15 +++-- src/video_core/gpu_thread.h | 7 ++- src/video_core/renderer_base.h | 3 +- src/video_core/renderer_opengl/gl_shader_cache.cpp | 5 +- src/video_core/renderer_opengl/renderer_opengl.cpp | 69 ++++++++-------------- src/video_core/renderer_opengl/renderer_opengl.h | 10 +++- src/video_core/renderer_vulkan/renderer_vulkan.cpp | 3 +- src/video_core/renderer_vulkan/renderer_vulkan.h | 2 +- src/video_core/video_core.cpp | 28 ++++++--- src/video_core/video_core.h | 11 +--- 16 files changed, 129 insertions(+), 97 deletions(-) (limited to 'src/video_core') 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 @@ #include "core/core.h" #include "core/core_timing.h" #include "core/core_timing_util.h" +#include "core/frontend/emu_window.h" #include "core/memory.h" #include "video_core/engines/fermi_2d.h" #include "video_core/engines/kepler_compute.h" @@ -16,14 +17,15 @@ #include "video_core/gpu.h" #include "video_core/memory_manager.h" #include "video_core/renderer_base.h" +#include "video_core/video_core.h" namespace Tegra { MICROPROFILE_DEFINE(GPU_wait, "GPU", "Wait for the GPU", MP_RGB(128, 128, 192)); -GPU::GPU(Core::System& system, VideoCore::RendererBase& renderer, bool is_async) - : system{system}, renderer{renderer}, is_async{is_async} { - auto& rasterizer{renderer.Rasterizer()}; +GPU::GPU(Core::System& system, std::unique_ptr&& renderer_, bool is_async) + : system{system}, renderer{std::move(renderer_)}, is_async{is_async} { + auto& rasterizer{renderer->Rasterizer()}; memory_manager = std::make_unique(system, rasterizer); dma_pusher = std::make_unique(*this); maxwell_3d = std::make_unique(system, rasterizer, *memory_manager); @@ -137,7 +139,7 @@ u64 GPU::GetTicks() const { } void GPU::FlushCommands() { - renderer.Rasterizer().FlushCommands(); + renderer->Rasterizer().FlushCommands(); } // 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) { } namespace Core { -class System; +namespace Frontend { +class EmuWindow; } +class System; +} // namespace Core namespace VideoCore { class RendererBase; @@ -129,7 +132,8 @@ class MemoryManager; class GPU { public: - explicit GPU(Core::System& system, VideoCore::RendererBase& renderer, bool is_async); + explicit GPU(Core::System& system, std::unique_ptr&& renderer, + bool is_async); virtual ~GPU(); @@ -174,6 +178,14 @@ public: /// Returns a reference to the GPU DMA pusher. Tegra::DmaPusher& DmaPusher(); + VideoCore::RendererBase& Renderer() { + return *renderer; + } + + const VideoCore::RendererBase& Renderer() const { + return *renderer; + } + // Waits for the GPU to finish working virtual void WaitIdle() const = 0; @@ -287,7 +299,7 @@ private: protected: std::unique_ptr dma_pusher; Core::System& system; - VideoCore::RendererBase& renderer; + std::unique_ptr renderer; private: std::unique_ptr 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 @@ namespace VideoCommon { -GPUAsynch::GPUAsynch(Core::System& system, VideoCore::RendererBase& renderer) - : GPU(system, renderer, true), gpu_thread{system} {} +GPUAsynch::GPUAsynch(Core::System& system, std::unique_ptr&& renderer_, + std::unique_ptr&& context) + : GPU(system, std::move(renderer_), true), gpu_thread{system}, gpu_context(std::move(context)), + cpu_context(renderer->GetRenderWindow().CreateSharedContext()) {} GPUAsynch::~GPUAsynch() = default; void GPUAsynch::Start() { - gpu_thread.StartThread(renderer, *dma_pusher); + cpu_context->MakeCurrent(); + gpu_thread.StartThread(*renderer, *gpu_context, *dma_pusher); } 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 @@ #include "video_core/gpu.h" #include "video_core/gpu_thread.h" +namespace Core::Frontend { +class GraphicsContext; +} + namespace VideoCore { class RendererBase; } // namespace VideoCore @@ -16,7 +20,8 @@ namespace VideoCommon { /// Implementation of GPU interface that runs the GPU asynchronously class GPUAsynch final : public Tegra::GPU { public: - explicit GPUAsynch(Core::System& system, VideoCore::RendererBase& renderer); + explicit GPUAsynch(Core::System& system, std::unique_ptr&& renderer, + std::unique_ptr&& context); ~GPUAsynch() override; void Start() override; @@ -32,6 +37,8 @@ protected: private: GPUThread::ThreadManager gpu_thread; + std::unique_ptr cpu_context; + std::unique_ptr gpu_context; }; } // 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 @@ namespace VideoCommon { -GPUSynch::GPUSynch(Core::System& system, VideoCore::RendererBase& renderer) - : GPU(system, renderer, false) {} +GPUSynch::GPUSynch(Core::System& system, std::unique_ptr&& renderer, + std::unique_ptr&& context) + : GPU(system, std::move(renderer), false), context{std::move(context)} {} GPUSynch::~GPUSynch() = default; -void GPUSynch::Start() {} +void GPUSynch::Start() { + context->MakeCurrent(); +} void GPUSynch::PushGPUEntries(Tegra::CommandList&& entries) { dma_pusher->Push(std::move(entries)); @@ -20,19 +23,19 @@ void GPUSynch::PushGPUEntries(Tegra::CommandList&& entries) { } void GPUSynch::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { - renderer.SwapBuffers(framebuffer); + renderer->SwapBuffers(framebuffer); } void GPUSynch::FlushRegion(CacheAddr addr, u64 size) { - renderer.Rasterizer().FlushRegion(addr, size); + renderer->Rasterizer().FlushRegion(addr, size); } void GPUSynch::InvalidateRegion(CacheAddr addr, u64 size) { - renderer.Rasterizer().InvalidateRegion(addr, size); + renderer->Rasterizer().InvalidateRegion(addr, size); } void GPUSynch::FlushAndInvalidateRegion(CacheAddr addr, u64 size) { - renderer.Rasterizer().FlushAndInvalidateRegion(addr, size); + renderer->Rasterizer().FlushAndInvalidateRegion(addr, size); } } // 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 @@ #include "video_core/gpu.h" +namespace Core::Frontend { +class GraphicsContext; +} + namespace VideoCore { class RendererBase; } // namespace VideoCore @@ -15,7 +19,8 @@ namespace VideoCommon { /// Implementation of GPU interface that runs the GPU synchronously class GPUSynch final : public Tegra::GPU { public: - explicit GPUSynch(Core::System& system, VideoCore::RendererBase& renderer); + explicit GPUSynch(Core::System& system, std::unique_ptr&& renderer, + std::unique_ptr&& context); ~GPUSynch() override; void Start() override; @@ -29,6 +34,9 @@ public: protected: void TriggerCpuInterrupt([[maybe_unused]] u32 syncpoint_id, [[maybe_unused]] u32 value) const override {} + +private: + std::unique_ptr context; }; } // 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 @@ #include "common/assert.h" #include "common/microprofile.h" #include "core/core.h" -#include "core/frontend/scope_acquire_context.h" +#include "core/frontend/emu_window.h" #include "video_core/dma_pusher.h" #include "video_core/gpu.h" #include "video_core/gpu_thread.h" @@ -14,8 +14,8 @@ namespace VideoCommon::GPUThread { /// Runs the GPU thread -static void RunThread(VideoCore::RendererBase& renderer, Tegra::DmaPusher& dma_pusher, - SynchState& state) { +static void RunThread(VideoCore::RendererBase& renderer, Core::Frontend::GraphicsContext& context, + Tegra::DmaPusher& dma_pusher, SynchState& state) { MicroProfileOnThreadCreate("GpuThread"); // Wait for first GPU command before acquiring the window context @@ -27,7 +27,7 @@ static void RunThread(VideoCore::RendererBase& renderer, Tegra::DmaPusher& dma_p return; } - Core::Frontend::ScopeAcquireContext acquire_context{renderer.GetRenderWindow()}; + auto current_context = context.Acquire(); CommandDataContainer next; while (state.is_running) { @@ -62,8 +62,11 @@ ThreadManager::~ThreadManager() { thread.join(); } -void ThreadManager::StartThread(VideoCore::RendererBase& renderer, Tegra::DmaPusher& dma_pusher) { - thread = std::thread{RunThread, std::ref(renderer), std::ref(dma_pusher), std::ref(state)}; +void ThreadManager::StartThread(VideoCore::RendererBase& renderer, + Core::Frontend::GraphicsContext& context, + Tegra::DmaPusher& dma_pusher) { + thread = std::thread{RunThread, std::ref(renderer), std::ref(context), std::ref(dma_pusher), + std::ref(state)}; } 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 @@ #include #include #include - #include "common/threadsafe_queue.h" #include "video_core/gpu.h" @@ -20,6 +19,9 @@ class DmaPusher; } // namespace Tegra namespace Core { +namespace Frontend { +class GraphicsContext; +} class System; } // namespace Core @@ -99,7 +101,8 @@ public: ~ThreadManager(); /// Creates and starts the GPU thread. - void StartThread(VideoCore::RendererBase& renderer, Tegra::DmaPusher& dma_pusher); + void StartThread(VideoCore::RendererBase& renderer, Core::Frontend::GraphicsContext& context, + Tegra::DmaPusher& dma_pusher); /// Push GPU command entries to be processed 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: /// Draws the latest frame to the window waiting timeout_ms for a frame to arrive (Renderer /// specific implementation) - virtual void TryPresent(int timeout_ms) = 0; + /// Returns true if a frame was drawn + virtual bool TryPresent(int timeout_ms) = 0; // Getter/setter functions: // ------------------------ 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, } const std::vector gl_cache = disk_cache.LoadPrecompiled(); - const auto supported_formats = GetSupportedFormats(); // Track if precompiled cache was altered during loading to know if we have to // serialize the virtual precompiled cache file back to the hard drive @@ -327,8 +326,8 @@ void ShaderCacheOpenGL::LoadDiskCache(const std::atomic_bool& stop_loading, const auto worker = [&](Core::Frontend::GraphicsContext* context, std::size_t begin, std::size_t end) { - context->MakeCurrent(); - SCOPE_EXIT({ return context->DoneCurrent(); }); + const auto scope = context->Acquire(); + const auto supported_formats = GetSupportedFormats(); for (std::size_t i = begin; i < end; ++i) { 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 @@ #include #include #include - #include - #include "common/assert.h" #include "common/logging/log.h" #include "common/microprofile.h" @@ -30,8 +28,6 @@ namespace OpenGL { namespace { -// If the size of this is too small, it ends up creating a soft cap on FPS as the renderer will have -// to wait on available presentation frames. constexpr std::size_t SWAP_CHAIN_SIZE = 3; struct Frame { @@ -214,7 +210,7 @@ public: std::deque present_queue; Frame* previous_frame{}; - FrameMailbox() : has_debug_tool{HasDebugTool()} { + FrameMailbox() { for (auto& frame : swap_chain) { free_queue.push(&frame); } @@ -285,13 +281,9 @@ public: std::unique_lock lock{swap_chain_lock}; present_queue.push_front(frame); present_cv.notify_one(); - - DebugNotifyNextFrame(); } Frame* TryGetPresentFrame(int timeout_ms) { - DebugWaitForNextFrame(); - std::unique_lock lock{swap_chain_lock}; // wait for new entries in the present_queue present_cv.wait_for(lock, std::chrono::milliseconds(timeout_ms), @@ -317,38 +309,12 @@ public: previous_frame = frame; return frame; } - -private: - std::mutex debug_synch_mutex; - std::condition_variable debug_synch_condition; - std::atomic_int frame_for_debug{}; - const bool has_debug_tool; // When true, using a GPU debugger, so keep frames in lock-step - - /// Signal that a new frame is available (called from GPU thread) - void DebugNotifyNextFrame() { - if (!has_debug_tool) { - return; - } - frame_for_debug++; - std::lock_guard lock{debug_synch_mutex}; - debug_synch_condition.notify_one(); - } - - /// Wait for a new frame to be available (called from presentation thread) - void DebugWaitForNextFrame() { - if (!has_debug_tool) { - return; - } - const int last_frame = frame_for_debug; - std::unique_lock lock{debug_synch_mutex}; - debug_synch_condition.wait(lock, - [this, last_frame] { return frame_for_debug > last_frame; }); - } }; -RendererOpenGL::RendererOpenGL(Core::Frontend::EmuWindow& emu_window, Core::System& system) - : VideoCore::RendererBase{emu_window}, emu_window{emu_window}, system{system}, - frame_mailbox{std::make_unique()} {} +RendererOpenGL::RendererOpenGL(Core::Frontend::EmuWindow& emu_window, Core::System& system, + Core::Frontend::GraphicsContext& context) + : VideoCore::RendererBase{emu_window}, emu_window{emu_window}, system{system}, frame_mailbox{}, + has_debug_tool{HasDebugTool()}, context{context} {} RendererOpenGL::~RendererOpenGL() = default; @@ -356,8 +322,6 @@ MICROPROFILE_DEFINE(OpenGL_RenderFrame, "OpenGL", "Render Frame", MP_RGB(128, 12 MICROPROFILE_DEFINE(OpenGL_WaitPresent, "OpenGL", "Wait For Present", MP_RGB(128, 128, 128)); void RendererOpenGL::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { - render_window.PollEvents(); - if (!framebuffer) { return; } @@ -413,6 +377,13 @@ void RendererOpenGL::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { m_current_frame++; rasterizer->TickFrame(); } + + render_window.PollEvents(); + if (has_debug_tool) { + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + Present(0); + context.SwapBuffers(); + } } void RendererOpenGL::PrepareRendertarget(const Tegra::FramebufferConfig* framebuffer) { @@ -480,6 +451,8 @@ void RendererOpenGL::LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color } void RendererOpenGL::InitOpenGLObjects() { + frame_mailbox = std::make_unique(); + glClearColor(Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue, 0.0f); @@ -692,12 +665,21 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) { glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } -void RendererOpenGL::TryPresent(int timeout_ms) { +bool RendererOpenGL::TryPresent(int timeout_ms) { + if (has_debug_tool) { + LOG_DEBUG(Render_OpenGL, + "Skipping presentation because we are presenting on the main context"); + return false; + } + return Present(timeout_ms); +} + +bool RendererOpenGL::Present(int timeout_ms) { const auto& layout = render_window.GetFramebufferLayout(); auto frame = frame_mailbox->TryGetPresentFrame(timeout_ms); if (!frame) { LOG_DEBUG(Render_OpenGL, "TryGetPresentFrame returned no frame to present"); - return; + return false; } // 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) { glFlush(); glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + return true; } 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; class RendererOpenGL final : public VideoCore::RendererBase { public: - explicit RendererOpenGL(Core::Frontend::EmuWindow& emu_window, Core::System& system); + explicit RendererOpenGL(Core::Frontend::EmuWindow& emu_window, Core::System& system, + Core::Frontend::GraphicsContext& context); ~RendererOpenGL() override; bool Init() override; void ShutDown() override; void SwapBuffers(const Tegra::FramebufferConfig* framebuffer) override; - void TryPresent(int timeout_ms) override; + bool TryPresent(int timeout_ms) override; private: /// Initializes the OpenGL state and creates persistent objects. @@ -89,8 +90,11 @@ private: void PrepareRendertarget(const Tegra::FramebufferConfig* framebuffer); + bool Present(int timeout_ms); + Core::Frontend::EmuWindow& emu_window; Core::System& system; + Core::Frontend::GraphicsContext& context; StateTracker state_tracker{system}; @@ -115,6 +119,8 @@ private: /// Frame presentation mailbox std::unique_ptr frame_mailbox; + + bool has_debug_tool = false; }; } // 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) { render_window.PollEvents(); } -void RendererVulkan::TryPresent(int /*timeout_ms*/) { +bool RendererVulkan::TryPresent(int /*timeout_ms*/) { // TODO (bunnei): ImplementMe + return true; } 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: bool Init() override; void ShutDown() override; void SwapBuffers(const Tegra::FramebufferConfig* framebuffer) override; - void TryPresent(int timeout_ms) override; + bool TryPresent(int timeout_ms) override; private: std::optional 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 @@ #endif #include "video_core/video_core.h" -namespace VideoCore { - -std::unique_ptr CreateRenderer(Core::Frontend::EmuWindow& emu_window, - Core::System& system) { +namespace { +std::unique_ptr CreateRenderer(Core::Frontend::EmuWindow& emu_window, + Core::System& system, + Core::Frontend::GraphicsContext& context) { switch (Settings::values.renderer_backend) { case Settings::RendererBackend::OpenGL: - return std::make_unique(emu_window, system); + return std::make_unique(emu_window, system, context); #ifdef HAS_VULKAN case Settings::RendererBackend::Vulkan: return std::make_unique(emu_window, system); @@ -30,13 +30,23 @@ std::unique_ptr CreateRenderer(Core::Frontend::EmuWindow& emu_wind return nullptr; } } +} // namespace -std::unique_ptr CreateGPU(Core::System& system) { - if (Settings::values.use_asynchronous_gpu_emulation) { - return std::make_unique(system, system.Renderer()); +namespace VideoCore { + +std::unique_ptr CreateGPU(Core::Frontend::EmuWindow& emu_window, Core::System& system) { + auto context = emu_window.CreateSharedContext(); + const auto scope = context->Acquire(); + auto renderer = CreateRenderer(emu_window, system, *context); + if (!renderer->Init()) { + return {}; } - return std::make_unique(system, system.Renderer()); + if (Settings::values.use_asynchronous_gpu_emulation) { + return std::make_unique(system, std::move(renderer), + std::move(context)); + } + return std::make_unique(system, std::move(renderer), std::move(context)); } 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 { class RendererBase; -/** - * Creates a renderer instance. - * - * @note The returned renderer instance is simply allocated. Its Init() - * function still needs to be called to fully complete its setup. - */ -std::unique_ptr CreateRenderer(Core::Frontend::EmuWindow& emu_window, - Core::System& system); - /// Creates an emulated GPU instance using the given system context. -std::unique_ptr CreateGPU(Core::System& system); +std::unique_ptr CreateGPU(Core::Frontend::EmuWindow& emu_window, Core::System& system); u16 GetResolutionScaleFactor(const RendererBase& renderer); -- cgit v1.2.3 From cf9c94d4017120b618194a720942ef4e5c8289bd Mon Sep 17 00:00:00 2001 From: James Rowe Date: Tue, 24 Mar 2020 22:57:36 -0600 Subject: Address review and fix broken yuzu-tester build --- src/core/core.cpp | 4 +- src/core/frontend/emu_window.h | 2 +- src/video_core/renderer_opengl/gl_shader_cache.cpp | 2 +- src/video_core/renderer_opengl/renderer_opengl.cpp | 6 +- src/video_core/video_core.cpp | 4 +- src/yuzu/bootmanager.cpp | 97 +++++++--------------- src/yuzu/bootmanager.h | 9 +- src/yuzu_cmd/yuzu.cpp | 4 +- .../emu_window/emu_window_sdl2_hide.cpp | 42 +++++++--- src/yuzu_tester/emu_window/emu_window_sdl2_hide.h | 9 +- src/yuzu_tester/yuzu.cpp | 6 +- 11 files changed, 83 insertions(+), 102 deletions(-) (limited to 'src/video_core') diff --git a/src/core/core.cpp b/src/core/core.cpp index 6cc4a0812..26a580cb7 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -169,6 +169,9 @@ struct System::Impl { interrupt_manager = std::make_unique(system); gpu_core = VideoCore::CreateGPU(emu_window, system); + if (!gpu_core) { + return ResultStatus::ErrorVideoCore; + } gpu_core->Renderer().Rasterizer().SetupDirtyFlags(); is_powered_on = true; @@ -181,7 +184,6 @@ struct System::Impl { ResultStatus Load(System& system, Frontend::EmuWindow& emu_window, const std::string& filepath) { - app_loader = Loader::GetLoader(GetGameFileFromPath(virtual_filesystem, filepath)); if (!app_loader) { LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath); diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h index bb283d844..72294d4d8 100644 --- a/src/core/frontend/emu_window.h +++ b/src/core/frontend/emu_window.h @@ -30,7 +30,7 @@ public: class Scoped { public: - Scoped(GraphicsContext& context_) : context(context_) { + explicit Scoped(GraphicsContext& context_) : context(context_) { context.MakeCurrent(); } ~Scoped() { diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index 8f59e0442..046ee55a5 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp @@ -305,6 +305,7 @@ void ShaderCacheOpenGL::LoadDiskCache(const std::atomic_bool& stop_loading, } const std::vector gl_cache = disk_cache.LoadPrecompiled(); + const auto supported_formats = GetSupportedFormats(); // Track if precompiled cache was altered during loading to know if we have to // serialize the virtual precompiled cache file back to the hard drive @@ -327,7 +328,6 @@ void ShaderCacheOpenGL::LoadDiskCache(const std::atomic_bool& stop_loading, const auto worker = [&](Core::Frontend::GraphicsContext* context, std::size_t begin, std::size_t end) { const auto scope = context->Acquire(); - const auto supported_formats = GetSupportedFormats(); for (std::size_t i = begin; i < end; ++i) { if (stop_loading) { diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 6f08803c1..f1a28cc21 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -7,7 +7,9 @@ #include #include #include + #include + #include "common/assert.h" #include "common/logging/log.h" #include "common/microprofile.h" @@ -313,8 +315,8 @@ public: RendererOpenGL::RendererOpenGL(Core::Frontend::EmuWindow& emu_window, Core::System& system, Core::Frontend::GraphicsContext& context) - : VideoCore::RendererBase{emu_window}, emu_window{emu_window}, system{system}, frame_mailbox{}, - has_debug_tool{HasDebugTool()}, context{context} {} + : VideoCore::RendererBase{emu_window}, emu_window{emu_window}, system{system}, + frame_mailbox{}, context{context}, has_debug_tool{HasDebugTool()} {} RendererOpenGL::~RendererOpenGL() = default; diff --git a/src/video_core/video_core.cpp b/src/video_core/video_core.cpp index fd9fec018..f60bdc60a 100644 --- a/src/video_core/video_core.cpp +++ b/src/video_core/video_core.cpp @@ -30,7 +30,7 @@ std::unique_ptr CreateRenderer(Core::Frontend::EmuWindo return nullptr; } } -} // namespace +} // Anonymous namespace namespace VideoCore { @@ -39,7 +39,7 @@ std::unique_ptr CreateGPU(Core::Frontend::EmuWindow& emu_window, Cor const auto scope = context->Acquire(); auto renderer = CreateRenderer(emu_window, system, *context); if (!renderer->Init()) { - return {}; + return nullptr; } if (Settings::values.use_asynchronous_gpu_emulation) { diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index d120ee818..4e9ced8ba 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -42,6 +42,10 @@ EmuThread::~EmuThread() = default; void EmuThread::run() { MicroProfileOnThreadCreate("EmuThread"); + // Main process has been loaded. Make the context current to this thread and begin GPU and CPU + // execution. + Core::System::GetInstance().GPU().Start(); + emit LoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0); Core::System::GetInstance().Renderer().Rasterizer().LoadDiskResources( @@ -51,10 +55,6 @@ void EmuThread::run() { emit LoadProgress(VideoCore::LoadCallbackStage::Complete, 0, 0); - // Main process has been loaded. Make the context current to this thread and begin GPU and CPU - // execution. - Core::System::GetInstance().GPU().Start(); - // Holds whether the cpu was running during the last iteration, // so that the DebugModeLeft signal can be emitted before the // next execution step @@ -152,7 +152,7 @@ public: if (is_current) { return; } - context->makeCurrent(surface); + is_current = context->makeCurrent(surface); } void DoneCurrent() override { @@ -160,7 +160,11 @@ public: is_current = false; } - QOpenGLContext* GetShareContext() const { + QOpenGLContext* GetShareContext() { + return context.get(); + } + + const QOpenGLContext* GetShareContext() const { return context.get(); } @@ -177,13 +181,15 @@ class DummyContext : public Core::Frontend::GraphicsContext {}; class RenderWidget : public QWidget { public: - RenderWidget(GRenderWindow* parent) : QWidget(parent), render_window(parent) { + explicit RenderWidget(GRenderWindow* parent) : QWidget(parent), render_window(parent) { setAttribute(Qt::WA_NativeWindow); setAttribute(Qt::WA_PaintOnScreen); } virtual ~RenderWidget() = default; + /// Called on the UI thread when this Widget is ready to draw + /// Dervied classes can override this to draw the latest frame. virtual void Present() {} void paintEvent(QPaintEvent* event) override { @@ -191,56 +197,6 @@ public: update(); } - void resizeEvent(QResizeEvent* ev) override { - render_window->resize(ev->size()); - render_window->OnFramebufferSizeChanged(); - } - - void keyPressEvent(QKeyEvent* event) override { - InputCommon::GetKeyboard()->PressKey(event->key()); - } - - void keyReleaseEvent(QKeyEvent* event) override { - InputCommon::GetKeyboard()->ReleaseKey(event->key()); - } - - void mousePressEvent(QMouseEvent* event) override { - if (event->source() == Qt::MouseEventSynthesizedBySystem) - return; // touch input is handled in TouchBeginEvent - - const auto pos{event->pos()}; - if (event->button() == Qt::LeftButton) { - const auto [x, y] = render_window->ScaleTouch(pos); - render_window->TouchPressed(x, y); - } else if (event->button() == Qt::RightButton) { - InputCommon::GetMotionEmu()->BeginTilt(pos.x(), pos.y()); - } - } - - void mouseMoveEvent(QMouseEvent* event) override { - if (event->source() == Qt::MouseEventSynthesizedBySystem) - return; // touch input is handled in TouchUpdateEvent - - const auto pos{event->pos()}; - const auto [x, y] = render_window->ScaleTouch(pos); - render_window->TouchMoved(x, y); - InputCommon::GetMotionEmu()->Tilt(pos.x(), pos.y()); - } - - void mouseReleaseEvent(QMouseEvent* event) override { - if (event->source() == Qt::MouseEventSynthesizedBySystem) - return; // touch input is handled in TouchEndEvent - - if (event->button() == Qt::LeftButton) - render_window->TouchReleased(); - else if (event->button() == Qt::RightButton) - InputCommon::GetMotionEmu()->EndTilt(); - } - - std::pair GetSize() const { - return std::make_pair(width(), height()); - } - QPaintEngine* paintEngine() const override { return nullptr; } @@ -276,6 +232,7 @@ private: std::unique_ptr context{}; }; +#ifdef HAS_VULKAN class VulkanRenderWidget : public RenderWidget { public: explicit VulkanRenderWidget(GRenderWindow* parent, QVulkanInstance* instance) @@ -284,6 +241,7 @@ public: windowHandle()->setVulkanInstance(instance); } }; +#endif GRenderWindow::GRenderWindow(GMainWindow* parent_, EmuThread* emu_thread) : QWidget(parent_), emu_thread(emu_thread) { @@ -358,7 +316,7 @@ qreal GRenderWindow::windowPixelRatio() const { return devicePixelRatio(); } -std::pair GRenderWindow::ScaleTouch(const QPointF pos) const { +std::pair GRenderWindow::ScaleTouch(const QPointF& pos) const { const qreal pixel_ratio = windowPixelRatio(); return {static_cast(std::max(std::round(pos.x() * pixel_ratio), qreal{0.0})), static_cast(std::max(std::round(pos.y() * pixel_ratio), qreal{0.0}))}; @@ -378,8 +336,10 @@ void GRenderWindow::keyReleaseEvent(QKeyEvent* event) { } void GRenderWindow::mousePressEvent(QMouseEvent* event) { - if (event->source() == Qt::MouseEventSynthesizedBySystem) - return; // touch input is handled in TouchBeginEvent + // touch input is handled in TouchBeginEvent + if (event->source() == Qt::MouseEventSynthesizedBySystem) { + return; + } auto pos = event->pos(); if (event->button() == Qt::LeftButton) { @@ -391,8 +351,10 @@ void GRenderWindow::mousePressEvent(QMouseEvent* event) { } void GRenderWindow::mouseMoveEvent(QMouseEvent* event) { - if (event->source() == Qt::MouseEventSynthesizedBySystem) - return; // touch input is handled in TouchUpdateEvent + // touch input is handled in TouchUpdateEvent + if (event->source() == Qt::MouseEventSynthesizedBySystem) { + return; + } auto pos = event->pos(); const auto [x, y] = ScaleTouch(pos); @@ -401,13 +363,16 @@ void GRenderWindow::mouseMoveEvent(QMouseEvent* event) { } void GRenderWindow::mouseReleaseEvent(QMouseEvent* event) { - if (event->source() == Qt::MouseEventSynthesizedBySystem) - return; // touch input is handled in TouchEndEvent + // touch input is handled in TouchEndEvent + if (event->source() == Qt::MouseEventSynthesizedBySystem) { + return; + } - if (event->button() == Qt::LeftButton) + if (event->button() == Qt::LeftButton) { this->TouchReleased(); - else if (event->button() == Qt::RightButton) + } else if (event->button() == Qt::RightButton) { InputCommon::GetMotionEmu()->EndTilt(); + } } void GRenderWindow::TouchBeginEvent(const QTouchEvent* event) { diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index 3739ec7ed..d69078df1 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h @@ -7,11 +7,12 @@ #include #include #include -#include + #include #include #include #include + #include "common/thread.h" #include "core/core.h" #include "core/frontend/emu_window.h" @@ -84,8 +85,8 @@ private: bool exec_step = false; bool running = false; std::atomic_bool stop_run{false}; - std::mutex running_mutex = {}; - std::condition_variable running_cv = {}; + std::mutex running_mutex; + std::condition_variable running_cv; signals: /** @@ -154,7 +155,7 @@ public: void CaptureScreenshot(u32 res_scale, const QString& screenshot_path); - std::pair ScaleTouch(const QPointF pos) const; + std::pair ScaleTouch(const QPointF& pos) const; public slots: void OnEmulationStarting(EmuThread* emu_thread); diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index e5db7d819..4d2ea7e9e 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp @@ -230,11 +230,11 @@ int main(int argc, char** argv) { system.TelemetrySession().AddField(Telemetry::FieldType::App, "Frontend", "SDL"); - system.Renderer().Rasterizer().LoadDiskResources(); - // Core is loaded, start the GPU (makes the GPU contexts current to this thread) system.GPU().Start(); + system.Renderer().Rasterizer().LoadDiskResources(); + std::thread render_thread([&emu_window] { emu_window->Present(); }); while (emu_window->IsOpen()) { system.RunLoop(); diff --git a/src/yuzu_tester/emu_window/emu_window_sdl2_hide.cpp b/src/yuzu_tester/emu_window/emu_window_sdl2_hide.cpp index a1bdb1a12..a837430cc 100644 --- a/src/yuzu_tester/emu_window/emu_window_sdl2_hide.cpp +++ b/src/yuzu_tester/emu_window/emu_window_sdl2_hide.cpp @@ -102,8 +102,6 @@ EmuWindow_SDL2_Hide::EmuWindow_SDL2_Hide() { LOG_INFO(Frontend, "yuzu-tester Version: {} | {}-{}", Common::g_build_fullname, Common::g_scm_branch, Common::g_scm_desc); Settings::LogSettings(); - - DoneCurrent(); } EmuWindow_SDL2_Hide::~EmuWindow_SDL2_Hide() { @@ -114,14 +112,6 @@ EmuWindow_SDL2_Hide::~EmuWindow_SDL2_Hide() { void EmuWindow_SDL2_Hide::PollEvents() {} -void EmuWindow_SDL2_Hide::MakeCurrent() { - SDL_GL_MakeCurrent(render_window, gl_context); -} - -void EmuWindow_SDL2_Hide::DoneCurrent() { - SDL_GL_MakeCurrent(render_window, nullptr); -} - bool EmuWindow_SDL2_Hide::IsShown() const { return false; } @@ -129,3 +119,35 @@ bool EmuWindow_SDL2_Hide::IsShown() const { void EmuWindow_SDL2_Hide::RetrieveVulkanHandlers(void*, void*, void*) const { UNREACHABLE(); } + +class SDLGLContext : public Core::Frontend::GraphicsContext { +public: + explicit SDLGLContext() { + // create a hidden window to make the shared context against + window = SDL_CreateWindow(NULL, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 0, 0, + SDL_WINDOW_HIDDEN | SDL_WINDOW_OPENGL); + context = SDL_GL_CreateContext(window); + } + + ~SDLGLContext() { + DoneCurrent(); + SDL_GL_DeleteContext(context); + SDL_DestroyWindow(window); + } + + void MakeCurrent() override { + SDL_GL_MakeCurrent(window, context); + } + + void DoneCurrent() override { + SDL_GL_MakeCurrent(window, nullptr); + } + +private: + SDL_Window* window; + SDL_GLContext context; +}; + +std::unique_ptr EmuWindow_SDL2_Hide::CreateSharedContext() const { + return std::make_unique(); +} diff --git a/src/yuzu_tester/emu_window/emu_window_sdl2_hide.h b/src/yuzu_tester/emu_window/emu_window_sdl2_hide.h index b13e15309..9f5d04fca 100644 --- a/src/yuzu_tester/emu_window/emu_window_sdl2_hide.h +++ b/src/yuzu_tester/emu_window/emu_window_sdl2_hide.h @@ -16,12 +16,6 @@ public: /// Polls window events void PollEvents() override; - /// Makes the graphics context current for the caller thread - void MakeCurrent() override; - - /// Releases the GL context from the caller thread - void DoneCurrent() override; - /// Whether the screen is being shown or not. bool IsShown() const override; @@ -29,8 +23,7 @@ public: void RetrieveVulkanHandlers(void* get_instance_proc_addr, void* instance, void* surface) const override; - /// Whether the window is still open, and a close request hasn't yet been sent - bool IsOpen() const; + std::unique_ptr CreateSharedContext() const override; private: /// Whether the GPU and driver supports the OpenGL extension required diff --git a/src/yuzu_tester/yuzu.cpp b/src/yuzu_tester/yuzu.cpp index 94ad50cb3..676e70ebd 100644 --- a/src/yuzu_tester/yuzu.cpp +++ b/src/yuzu_tester/yuzu.cpp @@ -164,11 +164,6 @@ int main(int argc, char** argv) { std::unique_ptr emu_window{std::make_unique()}; - if (!Settings::values.use_multi_core) { - // Single core mode must acquire OpenGL context for entire emulation session - emu_window->MakeCurrent(); - } - bool finished = false; int return_value = 0; const auto callback = [&finished, @@ -257,6 +252,7 @@ int main(int argc, char** argv) { system.TelemetrySession().AddField(Telemetry::FieldType::App, "Frontend", "SDLHideTester"); + system.GPU().Start(); system.Renderer().Rasterizer().LoadDiskResources(); while (!finished) { -- cgit v1.2.3