summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar bunnei2020-02-26 18:28:50 -0500
committerGravatar bunnei2020-02-26 18:28:50 -0500
commitaef159354cd6c5cbbf6366bcfd767a9b4e0b7dd9 (patch)
tree463fc81637722a45f3cac93bfc183d5024e7212f
parentrenderer_opengl: Create gl_framebuffer_data if empty. (diff)
downloadyuzu-aef159354cd6c5cbbf6366bcfd767a9b4e0b7dd9.tar.gz
yuzu-aef159354cd6c5cbbf6366bcfd767a9b4e0b7dd9.tar.xz
yuzu-aef159354cd6c5cbbf6366bcfd767a9b4e0b7dd9.zip
renderer_opengl: Move Frame/FrameMailbox to OpenGL namespace.
Diffstat (limited to '')
-rw-r--r--src/core/frontend/emu_window.h41
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp73
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.h5
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
13namespace Core::Frontend { 13namespace Core::Frontend {
14 14
15struct 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 */
22class TextureMailbox {
23public:
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
173protected: 132protected:
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
25namespace Core::Frontend { 25namespace 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
30constexpr std::size_t SWAP_CHAIN_SIZE = 9;
26 31
27struct Frame { 32struct 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,
41namespace 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 50class FrameMailbox {
46constexpr std::size_t SWAP_CHAIN_SIZE = 9;
47
48class OGLTextureMailbox : public Core::Frontend::TextureMailbox {
49public: 51public:
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
297RendererOpenGL::RendererOpenGL(Core::Frontend::EmuWindow& emu_window, Core::System& system) 299RendererOpenGL::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
302RendererOpenGL::~RendererOpenGL() = default; 303RendererOpenGL::~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
616void RendererOpenGL::TryPresent(int timeout_ms) { 617void 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
53class FrameMailbox;
54
53class RendererOpenGL final : public VideoCore::RendererBase { 55class RendererOpenGL final : public VideoCore::RendererBase {
54public: 56public:
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