From c2e79038252dbf7bbbfbf5aaa09bb5450691186f Mon Sep 17 00:00:00 2001 From: James Rowe Date: Mon, 16 Sep 2019 20:36:16 -0600 Subject: [PATCH] Split graphics out of EmuWindow in preparation of shared contexts --- src/core/frontend/emu_window.cpp | 2 + src/core/frontend/emu_window.h | 72 ++++++++++++++++++++++++++++---- 2 files changed, 65 insertions(+), 9 deletions(-) diff --git a/src/core/frontend/emu_window.cpp b/src/core/frontend/emu_window.cpp index 4fc285fee7..f393e4c764 100644 --- a/src/core/frontend/emu_window.cpp +++ b/src/core/frontend/emu_window.cpp @@ -10,6 +10,8 @@ namespace Frontend { +GraphicsContext::~GraphicsContext() = default; + class EmuWindow::TouchState : public Input::Factory, public std::enable_shared_from_this { public: diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h index f2878b202a..be868f5064 100644 --- a/src/core/frontend/emu_window.h +++ b/src/core/frontend/emu_window.h @@ -12,6 +12,54 @@ namespace Frontend { +struct Frame; +/** + * For smooth Vsync rendering, we want to always present the latest frame that the core generates, + * but also make sure that rendering happens at the pace that the frontend dictates. This is a + * helper class that the renderer can define to sync frames between the render thread and the + * presentation thread + */ +class TextureMailbox { +public: + virtual ~TextureMailbox() = default; + + /** + * Retrieve a frame that is ready to be rendered into + */ + virtual Frame& GetRenderFrame() = 0; + + /** + * Mark this frame as ready to present + */ + virtual void RenderComplete() = 0; + + /** + * Retrieve the latest frame to present in the frontend + */ + virtual Frame& GetPresentationFrame() = 0; + + /** + * Mark the presentation frame as complete and set it for reuse + */ + virtual void PresentationComplete() = 0; +}; + +/** + * Represents a graphics context that can be used for background computation or drawing. If the + * graphics backend doesn't require the context, then the implementation of these methods can be + * stubs + */ +class GraphicsContext { +public: + virtual ~GraphicsContext(); + + /// Makes the graphics context current for the caller thread + virtual void MakeCurrent() = 0; + + /// Releases (dunno if this is the "right" word) the context from the caller thread + virtual void DoneCurrent() = 0; +}; + /** * Abstraction class used to provide an interface between emulation code and the frontend * (e.g. SDL, QGLWidget, GLFW, etc...). @@ -30,7 +78,7 @@ namespace Frontend { * - DO NOT TREAT THIS CLASS AS A GUI TOOLKIT ABSTRACTION LAYER. That's not what it is. Please * re-read the upper points again and think about it if you don't see this. */ -class EmuWindow { +class EmuWindow : public GraphicsContext { public: /// Data structure to store emuwindow configuration struct WindowConfig { @@ -40,17 +88,21 @@ public: std::pair min_client_area_size; }; - /// Swap buffers to display the next frame - virtual void SwapBuffers() = 0; - /// Polls window events virtual void PollEvents() = 0; - /// Makes the graphics context current for the caller thread - virtual void MakeCurrent() = 0; - - /// Releases (dunno if this is the "right" word) the GLFW context from the caller thread - virtual void DoneCurrent() = 0; + /** + * Returns a GraphicsContext that the frontend provides that is shared with the emu window. This + * context can be used from other threads for background graphics computation. If the frontend + * is using a graphics backend that doesn't need anything specific to run on a different thread, + * then it can use a stubbed implemenation for GraphicsContext. + * + * If the return value is null, then the core should assume that the frontend cannot provide a + * Shared Context + */ + virtual std::unique_ptr CreateSharedContext() const { + return nullptr; + } /** * Signal that a touch pressed event has occurred (e.g. mouse click pressed) @@ -102,6 +154,8 @@ public: */ void UpdateCurrentFramebufferLayout(unsigned width, unsigned height); + std::unique_ptr mailbox = nullptr; + protected: EmuWindow(); virtual ~EmuWindow();