diff options
| author | 2020-02-26 18:28:50 -0500 | |
|---|---|---|
| committer | 2020-02-26 18:28:50 -0500 | |
| commit | aef159354cd6c5cbbf6366bcfd767a9b4e0b7dd9 (patch) | |
| tree | 463fc81637722a45f3cac93bfc183d5024e7212f | |
| parent | renderer_opengl: Create gl_framebuffer_data if empty. (diff) | |
| download | yuzu-aef159354cd6c5cbbf6366bcfd767a9b4e0b7dd9.tar.gz yuzu-aef159354cd6c5cbbf6366bcfd767a9b4e0b7dd9.tar.xz yuzu-aef159354cd6c5cbbf6366bcfd767a9b4e0b7dd9.zip | |
renderer_opengl: Move Frame/FrameMailbox to OpenGL namespace.
| -rw-r--r-- | src/core/frontend/emu_window.h | 41 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/renderer_opengl.cpp | 73 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/renderer_opengl.h | 5 |
3 files changed, 42 insertions, 77 deletions
diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h index 856cb61e9..5eb87fb63 100644 --- a/src/core/frontend/emu_window.h +++ b/src/core/frontend/emu_window.h | |||
| @@ -12,45 +12,6 @@ | |||
| 12 | 12 | ||
| 13 | namespace Core::Frontend { | 13 | namespace Core::Frontend { |
| 14 | 14 | ||
| 15 | struct Frame; | ||
| 16 | /** | ||
| 17 | * For smooth Vsync rendering, we want to always present the latest frame that the core generates, | ||
| 18 | * but also make sure that rendering happens at the pace that the frontend dictates. This is a | ||
| 19 | * helper class that the renderer can define to sync frames between the render thread and the | ||
| 20 | * presentation thread | ||
| 21 | */ | ||
| 22 | class TextureMailbox { | ||
| 23 | public: | ||
| 24 | virtual ~TextureMailbox() = default; | ||
| 25 | |||
| 26 | /** | ||
| 27 | * Recreate the render objects attached to this frame with the new specified width/height | ||
| 28 | */ | ||
| 29 | virtual void ReloadRenderFrame(Frontend::Frame* frame, u32 width, u32 height) = 0; | ||
| 30 | |||
| 31 | /** | ||
| 32 | * Recreate the presentation objects attached to this frame with the new specified width/height | ||
| 33 | */ | ||
| 34 | virtual void ReloadPresentFrame(Frontend::Frame* frame, u32 width, u32 height) = 0; | ||
| 35 | |||
| 36 | /** | ||
| 37 | * Render thread calls this to get an available frame to present | ||
| 38 | */ | ||
| 39 | virtual Frontend::Frame* GetRenderFrame() = 0; | ||
| 40 | |||
| 41 | /** | ||
| 42 | * Render thread calls this after draw commands are done to add to the presentation mailbox | ||
| 43 | */ | ||
| 44 | virtual void ReleaseRenderFrame(Frame* frame) = 0; | ||
| 45 | |||
| 46 | /** | ||
| 47 | * Presentation thread calls this to get the latest frame available to present. If there is no | ||
| 48 | * frame available after timeout, returns the previous frame. If there is no previous frame it | ||
| 49 | * returns nullptr | ||
| 50 | */ | ||
| 51 | virtual Frontend::Frame* TryGetPresentFrame(int timeout_ms) = 0; | ||
| 52 | }; | ||
| 53 | |||
| 54 | /** | 15 | /** |
| 55 | * Represents a graphics context that can be used for background computation or drawing. If the | 16 | * Represents a graphics context that can be used for background computation or drawing. If the |
| 56 | * graphics backend doesn't require the context, then the implementation of these methods can be | 17 | * graphics backend doesn't require the context, then the implementation of these methods can be |
| @@ -168,8 +129,6 @@ public: | |||
| 168 | */ | 129 | */ |
| 169 | void UpdateCurrentFramebufferLayout(unsigned width, unsigned height); | 130 | void UpdateCurrentFramebufferLayout(unsigned width, unsigned height); |
| 170 | 131 | ||
| 171 | std::unique_ptr<TextureMailbox> mailbox; | ||
| 172 | |||
| 173 | protected: | 132 | protected: |
| 174 | EmuWindow(); | 133 | EmuWindow(); |
| 175 | virtual ~EmuWindow(); | 134 | virtual ~EmuWindow(); |
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index fa226c8ca..e516ede9d 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp | |||
| @@ -22,12 +22,17 @@ | |||
| 22 | #include "video_core/renderer_opengl/gl_rasterizer.h" | 22 | #include "video_core/renderer_opengl/gl_rasterizer.h" |
| 23 | #include "video_core/renderer_opengl/renderer_opengl.h" | 23 | #include "video_core/renderer_opengl/renderer_opengl.h" |
| 24 | 24 | ||
| 25 | namespace Core::Frontend { | 25 | namespace OpenGL { |
| 26 | |||
| 27 | // If the size of this is too small, it ends up creating a soft cap on FPS as the renderer will have | ||
| 28 | // to wait on available presentation frames. There doesn't seem to be much of a downside to a larger | ||
| 29 | // number but 9 swap textures at 60FPS presentation allows for 800% speed so thats probably fine | ||
| 30 | constexpr std::size_t SWAP_CHAIN_SIZE = 9; | ||
| 26 | 31 | ||
| 27 | struct Frame { | 32 | struct Frame { |
| 28 | u32 width{}; /// Width of the frame (to detect resize) | 33 | u32 width{}; /// Width of the frame (to detect resize) |
| 29 | u32 height{}; /// Height of the frame | 34 | u32 height{}; /// Height of the frame |
| 30 | bool color_reloaded = false; /// Texture attachment was recreated (ie: resized) | 35 | bool color_reloaded{}; /// Texture attachment was recreated (ie: resized) |
| 31 | OpenGL::OGLRenderbuffer color{}; /// Buffer shared between the render/present FBO | 36 | OpenGL::OGLRenderbuffer color{}; /// Buffer shared between the render/present FBO |
| 32 | OpenGL::OGLFramebuffer render{}; /// FBO created on the render thread | 37 | OpenGL::OGLFramebuffer render{}; /// FBO created on the render thread |
| 33 | OpenGL::OGLFramebuffer present{}; /// FBO created on the present thread | 38 | OpenGL::OGLFramebuffer present{}; /// FBO created on the present thread |
| @@ -36,40 +41,37 @@ struct Frame { | |||
| 36 | bool is_srgb{}; /// Framebuffer is sRGB or RGB | 41 | bool is_srgb{}; /// Framebuffer is sRGB or RGB |
| 37 | }; | 42 | }; |
| 38 | 43 | ||
| 39 | } // namespace Core::Frontend | 44 | /** |
| 40 | 45 | * For smooth Vsync rendering, we want to always present the latest frame that the core generates, | |
| 41 | namespace OpenGL { | 46 | * but also make sure that rendering happens at the pace that the frontend dictates. This is a |
| 42 | 47 | * helper class that the renderer uses to sync frames between the render thread and the presentation | |
| 43 | // If the size of this is too small, it ends up creating a soft cap on FPS as the renderer will have | 48 | * thread |
| 44 | // to wait on available presentation frames. There doesn't seem to be much of a downside to a larger | 49 | */ |
| 45 | // number but 9 swap textures at 60FPS presentation allows for 800% speed so thats probably fine | 50 | class FrameMailbox { |
| 46 | constexpr std::size_t SWAP_CHAIN_SIZE = 9; | ||
| 47 | |||
| 48 | class OGLTextureMailbox : public Core::Frontend::TextureMailbox { | ||
| 49 | public: | 51 | public: |
| 50 | std::mutex swap_chain_lock; | 52 | std::mutex swap_chain_lock; |
| 51 | std::condition_variable present_cv; | 53 | std::condition_variable present_cv; |
| 52 | std::array<Core::Frontend::Frame, SWAP_CHAIN_SIZE> swap_chain{}; | 54 | std::array<Frame, SWAP_CHAIN_SIZE> swap_chain{}; |
| 53 | std::queue<Core::Frontend::Frame*> free_queue; | 55 | std::queue<Frame*> free_queue; |
| 54 | std::deque<Core::Frontend::Frame*> present_queue; | 56 | std::deque<Frame*> present_queue; |
| 55 | Core::Frontend::Frame* previous_frame{}; | 57 | Frame* previous_frame{}; |
| 56 | 58 | ||
| 57 | OGLTextureMailbox() { | 59 | FrameMailbox() { |
| 58 | for (auto& frame : swap_chain) { | 60 | for (auto& frame : swap_chain) { |
| 59 | free_queue.push(&frame); | 61 | free_queue.push(&frame); |
| 60 | } | 62 | } |
| 61 | } | 63 | } |
| 62 | 64 | ||
| 63 | ~OGLTextureMailbox() override { | 65 | ~FrameMailbox() { |
| 64 | // lock the mutex and clear out the present and free_queues and notify any people who are | 66 | // lock the mutex and clear out the present and free_queues and notify any people who are |
| 65 | // blocked to prevent deadlock on shutdown | 67 | // blocked to prevent deadlock on shutdown |
| 66 | std::scoped_lock lock(swap_chain_lock); | 68 | std::scoped_lock lock(swap_chain_lock); |
| 67 | std::queue<Core::Frontend::Frame*>().swap(free_queue); | 69 | std::queue<Frame*>().swap(free_queue); |
| 68 | present_queue.clear(); | 70 | present_queue.clear(); |
| 69 | present_cv.notify_all(); | 71 | present_cv.notify_all(); |
| 70 | } | 72 | } |
| 71 | 73 | ||
| 72 | void ReloadPresentFrame(Core::Frontend::Frame* frame, u32 height, u32 width) override { | 74 | void ReloadPresentFrame(Frame* frame, u32 height, u32 width) { |
| 73 | frame->present.Release(); | 75 | frame->present.Release(); |
| 74 | frame->present.Create(); | 76 | frame->present.Create(); |
| 75 | GLint previous_draw_fbo{}; | 77 | GLint previous_draw_fbo{}; |
| @@ -84,7 +86,7 @@ public: | |||
| 84 | frame->color_reloaded = false; | 86 | frame->color_reloaded = false; |
| 85 | } | 87 | } |
| 86 | 88 | ||
| 87 | void ReloadRenderFrame(Core::Frontend::Frame* frame, u32 width, u32 height) override { | 89 | void ReloadRenderFrame(Frame* frame, u32 width, u32 height) { |
| 88 | OpenGLState prev_state = OpenGLState::GetCurState(); | 90 | OpenGLState prev_state = OpenGLState::GetCurState(); |
| 89 | OpenGLState state = OpenGLState::GetCurState(); | 91 | OpenGLState state = OpenGLState::GetCurState(); |
| 90 | 92 | ||
| @@ -103,7 +105,7 @@ public: | |||
| 103 | state.Apply(); | 105 | state.Apply(); |
| 104 | glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, | 106 | glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, |
| 105 | frame->color.handle); | 107 | frame->color.handle); |
| 106 | if (!glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE) { | 108 | if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { |
| 107 | LOG_CRITICAL(Render_OpenGL, "Failed to recreate render FBO!"); | 109 | LOG_CRITICAL(Render_OpenGL, "Failed to recreate render FBO!"); |
| 108 | } | 110 | } |
| 109 | prev_state.Apply(); | 111 | prev_state.Apply(); |
| @@ -112,7 +114,7 @@ public: | |||
| 112 | frame->color_reloaded = true; | 114 | frame->color_reloaded = true; |
| 113 | } | 115 | } |
| 114 | 116 | ||
| 115 | Core::Frontend::Frame* GetRenderFrame() override { | 117 | Frame* GetRenderFrame() { |
| 116 | std::unique_lock<std::mutex> lock(swap_chain_lock); | 118 | std::unique_lock<std::mutex> lock(swap_chain_lock); |
| 117 | 119 | ||
| 118 | // If theres no free frames, we will reuse the oldest render frame | 120 | // If theres no free frames, we will reuse the oldest render frame |
| @@ -122,18 +124,18 @@ public: | |||
| 122 | return frame; | 124 | return frame; |
| 123 | } | 125 | } |
| 124 | 126 | ||
| 125 | Core::Frontend::Frame* frame = free_queue.front(); | 127 | Frame* frame = free_queue.front(); |
| 126 | free_queue.pop(); | 128 | free_queue.pop(); |
| 127 | return frame; | 129 | return frame; |
| 128 | } | 130 | } |
| 129 | 131 | ||
| 130 | void ReleaseRenderFrame(Core::Frontend::Frame* frame) override { | 132 | void ReleaseRenderFrame(Frame* frame) { |
| 131 | std::unique_lock<std::mutex> lock(swap_chain_lock); | 133 | std::unique_lock<std::mutex> lock(swap_chain_lock); |
| 132 | present_queue.push_front(frame); | 134 | present_queue.push_front(frame); |
| 133 | present_cv.notify_one(); | 135 | present_cv.notify_one(); |
| 134 | } | 136 | } |
| 135 | 137 | ||
| 136 | Core::Frontend::Frame* TryGetPresentFrame(int timeout_ms) override { | 138 | Frame* TryGetPresentFrame(int timeout_ms) { |
| 137 | std::unique_lock<std::mutex> lock(swap_chain_lock); | 139 | std::unique_lock<std::mutex> lock(swap_chain_lock); |
| 138 | // wait for new entries in the present_queue | 140 | // wait for new entries in the present_queue |
| 139 | present_cv.wait_for(lock, std::chrono::milliseconds(timeout_ms), | 141 | present_cv.wait_for(lock, std::chrono::milliseconds(timeout_ms), |
| @@ -149,7 +151,7 @@ public: | |||
| 149 | } | 151 | } |
| 150 | 152 | ||
| 151 | // the newest entries are pushed to the front of the queue | 153 | // the newest entries are pushed to the front of the queue |
| 152 | Core::Frontend::Frame* frame = present_queue.front(); | 154 | Frame* frame = present_queue.front(); |
| 153 | present_queue.pop_front(); | 155 | present_queue.pop_front(); |
| 154 | // remove all old entries from the present queue and move them back to the free_queue | 156 | // remove all old entries from the present queue and move them back to the free_queue |
| 155 | for (auto f : present_queue) { | 157 | for (auto f : present_queue) { |
| @@ -295,9 +297,8 @@ void APIENTRY DebugHandler(GLenum source, GLenum type, GLuint id, GLenum severit | |||
| 295 | } // Anonymous namespace | 297 | } // Anonymous namespace |
| 296 | 298 | ||
| 297 | RendererOpenGL::RendererOpenGL(Core::Frontend::EmuWindow& emu_window, Core::System& system) | 299 | RendererOpenGL::RendererOpenGL(Core::Frontend::EmuWindow& emu_window, Core::System& system) |
| 298 | : VideoCore::RendererBase{emu_window}, emu_window{emu_window}, system{system} { | 300 | : VideoCore::RendererBase{emu_window}, emu_window{emu_window}, system{system}, |
| 299 | emu_window.mailbox = std::make_unique<OGLTextureMailbox>(); | 301 | frame_mailbox{std::make_unique<FrameMailbox>()} {} |
| 300 | } | ||
| 301 | 302 | ||
| 302 | RendererOpenGL::~RendererOpenGL() = default; | 303 | RendererOpenGL::~RendererOpenGL() = default; |
| 303 | 304 | ||
| @@ -319,11 +320,11 @@ void RendererOpenGL::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { | |||
| 319 | PrepareRendertarget(framebuffer); | 320 | PrepareRendertarget(framebuffer); |
| 320 | RenderScreenshot(); | 321 | RenderScreenshot(); |
| 321 | 322 | ||
| 322 | Core::Frontend::Frame* frame; | 323 | Frame* frame; |
| 323 | { | 324 | { |
| 324 | MICROPROFILE_SCOPE(OpenGL_WaitPresent); | 325 | MICROPROFILE_SCOPE(OpenGL_WaitPresent); |
| 325 | 326 | ||
| 326 | frame = render_window.mailbox->GetRenderFrame(); | 327 | frame = frame_mailbox->GetRenderFrame(); |
| 327 | 328 | ||
| 328 | // Clean up sync objects before drawing | 329 | // Clean up sync objects before drawing |
| 329 | 330 | ||
| @@ -356,7 +357,7 @@ void RendererOpenGL::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { | |||
| 356 | is_srgb != frame->is_srgb) { | 357 | is_srgb != frame->is_srgb) { |
| 357 | LOG_DEBUG(Render_OpenGL, "Reloading render frame"); | 358 | LOG_DEBUG(Render_OpenGL, "Reloading render frame"); |
| 358 | is_srgb = frame->is_srgb = screen_info.display_srgb; | 359 | is_srgb = frame->is_srgb = screen_info.display_srgb; |
| 359 | render_window.mailbox->ReloadRenderFrame(frame, layout.width, layout.height); | 360 | frame_mailbox->ReloadRenderFrame(frame, layout.width, layout.height); |
| 360 | } | 361 | } |
| 361 | state.draw.draw_framebuffer = frame->render.handle; | 362 | state.draw.draw_framebuffer = frame->render.handle; |
| 362 | state.Apply(); | 363 | state.Apply(); |
| @@ -364,7 +365,7 @@ void RendererOpenGL::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { | |||
| 364 | // Create a fence for the frontend to wait on and swap this frame to OffTex | 365 | // Create a fence for the frontend to wait on and swap this frame to OffTex |
| 365 | frame->render_fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); | 366 | frame->render_fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); |
| 366 | glFlush(); | 367 | glFlush(); |
| 367 | render_window.mailbox->ReleaseRenderFrame(frame); | 368 | frame_mailbox->ReleaseRenderFrame(frame); |
| 368 | m_current_frame++; | 369 | m_current_frame++; |
| 369 | rasterizer->TickFrame(); | 370 | rasterizer->TickFrame(); |
| 370 | } | 371 | } |
| @@ -615,7 +616,7 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) { | |||
| 615 | 616 | ||
| 616 | void RendererOpenGL::TryPresent(int timeout_ms) { | 617 | void RendererOpenGL::TryPresent(int timeout_ms) { |
| 617 | const auto& layout = render_window.GetFramebufferLayout(); | 618 | const auto& layout = render_window.GetFramebufferLayout(); |
| 618 | auto frame = render_window.mailbox->TryGetPresentFrame(timeout_ms); | 619 | auto frame = frame_mailbox->TryGetPresentFrame(timeout_ms); |
| 619 | if (!frame) { | 620 | if (!frame) { |
| 620 | LOG_DEBUG(Render_OpenGL, "TryGetPresentFrame returned no frame to present"); | 621 | LOG_DEBUG(Render_OpenGL, "TryGetPresentFrame returned no frame to present"); |
| 621 | return; | 622 | return; |
| @@ -628,7 +629,7 @@ void RendererOpenGL::TryPresent(int timeout_ms) { | |||
| 628 | // Recreate the presentation FBO if the color attachment was changed | 629 | // Recreate the presentation FBO if the color attachment was changed |
| 629 | if (frame->color_reloaded) { | 630 | if (frame->color_reloaded) { |
| 630 | LOG_DEBUG(Render_OpenGL, "Reloading present frame"); | 631 | LOG_DEBUG(Render_OpenGL, "Reloading present frame"); |
| 631 | render_window.mailbox->ReloadPresentFrame(frame, layout.width, layout.height); | 632 | frame_mailbox->ReloadPresentFrame(frame, layout.width, layout.height); |
| 632 | } | 633 | } |
| 633 | glWaitSync(frame->render_fence, 0, GL_TIMEOUT_IGNORED); | 634 | glWaitSync(frame->render_fence, 0, GL_TIMEOUT_IGNORED); |
| 634 | // INTEL workaround. | 635 | // INTEL workaround. |
diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h index 797965925..4107e10a9 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.h +++ b/src/video_core/renderer_opengl/renderer_opengl.h | |||
| @@ -50,6 +50,8 @@ struct PresentationTexture { | |||
| 50 | OGLTexture texture; | 50 | OGLTexture texture; |
| 51 | }; | 51 | }; |
| 52 | 52 | ||
| 53 | class FrameMailbox; | ||
| 54 | |||
| 53 | class RendererOpenGL final : public VideoCore::RendererBase { | 55 | class RendererOpenGL final : public VideoCore::RendererBase { |
| 54 | public: | 56 | public: |
| 55 | explicit RendererOpenGL(Core::Frontend::EmuWindow& emu_window, Core::System& system); | 57 | explicit RendererOpenGL(Core::Frontend::EmuWindow& emu_window, Core::System& system); |
| @@ -111,6 +113,9 @@ private: | |||
| 111 | 113 | ||
| 112 | /// Represents if the final render frame is sRGB | 114 | /// Represents if the final render frame is sRGB |
| 113 | bool is_srgb{}; | 115 | bool is_srgb{}; |
| 116 | |||
| 117 | /// Frame presentation mailbox | ||
| 118 | std::unique_ptr<FrameMailbox> frame_mailbox; | ||
| 114 | }; | 119 | }; |
| 115 | 120 | ||
| 116 | } // namespace OpenGL | 121 | } // namespace OpenGL |