diff options
| author | 2020-02-17 14:31:14 -0500 | |
|---|---|---|
| committer | 2020-02-25 21:22:59 -0500 | |
| commit | dc672ca4b39c1ab9c2ee81257b6fb605a23cbcd8 (patch) | |
| tree | 15415ab06bdba99ca408dad1c526c31313c3e8af /src | |
| parent | renderer_opengl: Add OGLRenderbuffer to resource/state management. (diff) | |
| download | yuzu-dc672ca4b39c1ab9c2ee81257b6fb605a23cbcd8.tar.gz yuzu-dc672ca4b39c1ab9c2ee81257b6fb605a23cbcd8.tar.xz yuzu-dc672ca4b39c1ab9c2ee81257b6fb605a23cbcd8.zip | |
renderer_opengl: Add texture mailbox support for presenter thread.
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/frontend/framebuffer_layout.h | 1 | ||||
| -rw-r--r-- | src/video_core/renderer_base.h | 10 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/renderer_opengl.cpp | 269 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/renderer_opengl.h | 24 |
4 files changed, 269 insertions, 35 deletions
diff --git a/src/core/frontend/framebuffer_layout.h b/src/core/frontend/framebuffer_layout.h index 1d39c1faf..e9d0a40d3 100644 --- a/src/core/frontend/framebuffer_layout.h +++ b/src/core/frontend/framebuffer_layout.h | |||
| @@ -29,6 +29,7 @@ enum class AspectRatio { | |||
| 29 | struct FramebufferLayout { | 29 | struct FramebufferLayout { |
| 30 | u32 width{ScreenUndocked::Width}; | 30 | u32 width{ScreenUndocked::Width}; |
| 31 | u32 height{ScreenUndocked::Height}; | 31 | u32 height{ScreenUndocked::Height}; |
| 32 | bool is_srgb{}; | ||
| 32 | 33 | ||
| 33 | Common::Rectangle<u32> screen; | 34 | Common::Rectangle<u32> screen; |
| 34 | 35 | ||
diff --git a/src/video_core/renderer_base.h b/src/video_core/renderer_base.h index af1bebc4f..5ec99a126 100644 --- a/src/video_core/renderer_base.h +++ b/src/video_core/renderer_base.h | |||
| @@ -35,15 +35,19 @@ public: | |||
| 35 | explicit RendererBase(Core::Frontend::EmuWindow& window); | 35 | explicit RendererBase(Core::Frontend::EmuWindow& window); |
| 36 | virtual ~RendererBase(); | 36 | virtual ~RendererBase(); |
| 37 | 37 | ||
| 38 | /// Swap buffers (render frame) | ||
| 39 | virtual void SwapBuffers(const Tegra::FramebufferConfig* framebuffer) = 0; | ||
| 40 | |||
| 41 | /// Initialize the renderer | 38 | /// Initialize the renderer |
| 42 | virtual bool Init() = 0; | 39 | virtual bool Init() = 0; |
| 43 | 40 | ||
| 44 | /// Shutdown the renderer | 41 | /// Shutdown the renderer |
| 45 | virtual void ShutDown() = 0; | 42 | virtual void ShutDown() = 0; |
| 46 | 43 | ||
| 44 | /// Finalize rendering the guest frame and draw into the presentation texture | ||
| 45 | virtual void SwapBuffers(const Tegra::FramebufferConfig* framebuffer) = 0; | ||
| 46 | |||
| 47 | /// Draws the latest frame to the window waiting timeout_ms for a frame to arrive (Renderer | ||
| 48 | /// specific implementation) | ||
| 49 | virtual void TryPresent(int timeout_ms) = 0; | ||
| 50 | |||
| 47 | // Getter/setter functions: | 51 | // Getter/setter functions: |
| 48 | // ------------------------ | 52 | // ------------------------ |
| 49 | 53 | ||
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index bba16afaf..ee69caa3a 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp | |||
| @@ -9,11 +9,11 @@ | |||
| 9 | #include <glad/glad.h> | 9 | #include <glad/glad.h> |
| 10 | #include "common/assert.h" | 10 | #include "common/assert.h" |
| 11 | #include "common/logging/log.h" | 11 | #include "common/logging/log.h" |
| 12 | #include "common/microprofile.h" | ||
| 12 | #include "common/telemetry.h" | 13 | #include "common/telemetry.h" |
| 13 | #include "core/core.h" | 14 | #include "core/core.h" |
| 14 | #include "core/core_timing.h" | 15 | #include "core/core_timing.h" |
| 15 | #include "core/frontend/emu_window.h" | 16 | #include "core/frontend/emu_window.h" |
| 16 | #include "core/frontend/scope_acquire_window_context.h" | ||
| 17 | #include "core/memory.h" | 17 | #include "core/memory.h" |
| 18 | #include "core/perf_stats.h" | 18 | #include "core/perf_stats.h" |
| 19 | #include "core/settings.h" | 19 | #include "core/settings.h" |
| @@ -22,8 +22,145 @@ | |||
| 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 { | ||
| 26 | |||
| 27 | struct Frame { | ||
| 28 | u32 width{}; /// Width of the frame (to detect resize) | ||
| 29 | u32 height{}; /// Height of the frame | ||
| 30 | bool color_reloaded = false; /// Texture attachment was recreated (ie: resized) | ||
| 31 | OpenGL::OGLRenderbuffer color{}; /// Buffer shared between the render/present FBO | ||
| 32 | OpenGL::OGLFramebuffer render{}; /// FBO created on the render thread | ||
| 33 | OpenGL::OGLFramebuffer present{}; /// FBO created on the present thread | ||
| 34 | GLsync render_fence{}; /// Fence created on the render thread | ||
| 35 | GLsync present_fence{}; /// Fence created on the presentation thread | ||
| 36 | bool is_srgb{}; /// Framebuffer is sRGB or RGB | ||
| 37 | }; | ||
| 38 | |||
| 39 | } // namespace Core::Frontend | ||
| 40 | |||
| 25 | namespace OpenGL { | 41 | namespace OpenGL { |
| 26 | 42 | ||
| 43 | // If the size of this is too small, it ends up creating a soft cap on FPS as the renderer will have | ||
| 44 | // to wait on available presentation frames. There doesn't seem to be much of a downside to a larger | ||
| 45 | // number but 9 swap textures at 60FPS presentation allows for 800% speed so thats probably fine | ||
| 46 | constexpr std::size_t SWAP_CHAIN_SIZE = 9; | ||
| 47 | |||
| 48 | class OGLTextureMailbox : public Core::Frontend::TextureMailbox { | ||
| 49 | public: | ||
| 50 | std::mutex swap_chain_lock; | ||
| 51 | std::condition_variable present_cv; | ||
| 52 | std::array<Core::Frontend::Frame, SWAP_CHAIN_SIZE> swap_chain{}; | ||
| 53 | std::queue<Core::Frontend::Frame*> free_queue; | ||
| 54 | std::deque<Core::Frontend::Frame*> present_queue; | ||
| 55 | Core::Frontend::Frame* previous_frame{}; | ||
| 56 | |||
| 57 | OGLTextureMailbox() { | ||
| 58 | for (auto& frame : swap_chain) { | ||
| 59 | free_queue.push(&frame); | ||
| 60 | } | ||
| 61 | } | ||
| 62 | |||
| 63 | ~OGLTextureMailbox() override { | ||
| 64 | // lock the mutex and clear out the present and free_queues and notify any people who are | ||
| 65 | // blocked to prevent deadlock on shutdown | ||
| 66 | std::scoped_lock lock(swap_chain_lock); | ||
| 67 | std::queue<Core::Frontend::Frame*>().swap(free_queue); | ||
| 68 | present_queue.clear(); | ||
| 69 | present_cv.notify_all(); | ||
| 70 | } | ||
| 71 | |||
| 72 | void ReloadPresentFrame(Core::Frontend::Frame* frame, u32 height, u32 width) override { | ||
| 73 | frame->present.Release(); | ||
| 74 | frame->present.Create(); | ||
| 75 | GLint previous_draw_fbo{}; | ||
| 76 | glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &previous_draw_fbo); | ||
| 77 | glBindFramebuffer(GL_FRAMEBUFFER, frame->present.handle); | ||
| 78 | glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, | ||
| 79 | frame->color.handle); | ||
| 80 | if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { | ||
| 81 | LOG_CRITICAL(Render_OpenGL, "Failed to recreate present FBO!"); | ||
| 82 | } | ||
| 83 | glBindFramebuffer(GL_DRAW_FRAMEBUFFER, previous_draw_fbo); | ||
| 84 | frame->color_reloaded = false; | ||
| 85 | } | ||
| 86 | |||
| 87 | void ReloadRenderFrame(Core::Frontend::Frame* frame, u32 width, u32 height) override { | ||
| 88 | OpenGLState prev_state = OpenGLState::GetCurState(); | ||
| 89 | OpenGLState state = OpenGLState::GetCurState(); | ||
| 90 | |||
| 91 | // Recreate the color texture attachment | ||
| 92 | frame->color.Release(); | ||
| 93 | frame->color.Create(); | ||
| 94 | state.renderbuffer = frame->color.handle; | ||
| 95 | state.Apply(); | ||
| 96 | glRenderbufferStorage(GL_RENDERBUFFER, frame->is_srgb ? GL_SRGB8 : GL_RGB8, width, height); | ||
| 97 | |||
| 98 | // Recreate the FBO for the render target | ||
| 99 | frame->render.Release(); | ||
| 100 | frame->render.Create(); | ||
| 101 | state.draw.read_framebuffer = frame->render.handle; | ||
| 102 | state.draw.draw_framebuffer = frame->render.handle; | ||
| 103 | state.Apply(); | ||
| 104 | glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, | ||
| 105 | frame->color.handle); | ||
| 106 | if (!glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE) { | ||
| 107 | LOG_CRITICAL(Render_OpenGL, "Failed to recreate render FBO!"); | ||
| 108 | } | ||
| 109 | prev_state.Apply(); | ||
| 110 | frame->width = width; | ||
| 111 | frame->height = height; | ||
| 112 | frame->color_reloaded = true; | ||
| 113 | } | ||
| 114 | |||
| 115 | Core::Frontend::Frame* GetRenderFrame() override { | ||
| 116 | std::unique_lock<std::mutex> lock(swap_chain_lock); | ||
| 117 | |||
| 118 | // If theres no free frames, we will reuse the oldest render frame | ||
| 119 | if (free_queue.empty()) { | ||
| 120 | auto frame = present_queue.back(); | ||
| 121 | present_queue.pop_back(); | ||
| 122 | return frame; | ||
| 123 | } | ||
| 124 | |||
| 125 | Core::Frontend::Frame* frame = free_queue.front(); | ||
| 126 | free_queue.pop(); | ||
| 127 | return frame; | ||
| 128 | } | ||
| 129 | |||
| 130 | void ReleaseRenderFrame(Core::Frontend::Frame* frame) override { | ||
| 131 | std::unique_lock<std::mutex> lock(swap_chain_lock); | ||
| 132 | present_queue.push_front(frame); | ||
| 133 | present_cv.notify_one(); | ||
| 134 | } | ||
| 135 | |||
| 136 | Core::Frontend::Frame* TryGetPresentFrame(int timeout_ms) override { | ||
| 137 | std::unique_lock<std::mutex> lock(swap_chain_lock); | ||
| 138 | // wait for new entries in the present_queue | ||
| 139 | present_cv.wait_for(lock, std::chrono::milliseconds(timeout_ms), | ||
| 140 | [&] { return !present_queue.empty(); }); | ||
| 141 | if (present_queue.empty()) { | ||
| 142 | // timed out waiting for a frame to draw so return the previous frame | ||
| 143 | return previous_frame; | ||
| 144 | } | ||
| 145 | |||
| 146 | // free the previous frame and add it back to the free queue | ||
| 147 | if (previous_frame) { | ||
| 148 | free_queue.push(previous_frame); | ||
| 149 | } | ||
| 150 | |||
| 151 | // the newest entries are pushed to the front of the queue | ||
| 152 | Core::Frontend::Frame* frame = present_queue.front(); | ||
| 153 | present_queue.pop_front(); | ||
| 154 | // remove all old entries from the present queue and move them back to the free_queue | ||
| 155 | for (auto f : present_queue) { | ||
| 156 | free_queue.push(f); | ||
| 157 | } | ||
| 158 | present_queue.clear(); | ||
| 159 | previous_frame = frame; | ||
| 160 | return frame; | ||
| 161 | } | ||
| 162 | }; | ||
| 163 | |||
| 27 | namespace { | 164 | namespace { |
| 28 | 165 | ||
| 29 | constexpr char vertex_shader[] = R"( | 166 | constexpr char vertex_shader[] = R"( |
| @@ -158,16 +295,86 @@ void APIENTRY DebugHandler(GLenum source, GLenum type, GLuint id, GLenum severit | |||
| 158 | } // Anonymous namespace | 295 | } // Anonymous namespace |
| 159 | 296 | ||
| 160 | RendererOpenGL::RendererOpenGL(Core::Frontend::EmuWindow& emu_window, Core::System& system) | 297 | RendererOpenGL::RendererOpenGL(Core::Frontend::EmuWindow& emu_window, Core::System& system) |
| 161 | : VideoCore::RendererBase{emu_window}, emu_window{emu_window}, system{system} {} | 298 | : VideoCore::RendererBase{emu_window}, emu_window{emu_window}, system{system} { |
| 299 | emu_window.mailbox = std::make_unique<OGLTextureMailbox>(); | ||
| 300 | } | ||
| 162 | 301 | ||
| 163 | RendererOpenGL::~RendererOpenGL() = default; | 302 | RendererOpenGL::~RendererOpenGL() = default; |
| 164 | 303 | ||
| 304 | MICROPROFILE_DEFINE(OpenGL_RenderFrame, "OpenGL", "Render Frame", MP_RGB(128, 128, 64)); | ||
| 305 | MICROPROFILE_DEFINE(OpenGL_WaitPresent, "OpenGL", "Wait For Present", MP_RGB(128, 128, 128)); | ||
| 306 | |||
| 165 | void RendererOpenGL::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { | 307 | void RendererOpenGL::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { |
| 308 | render_window.PollEvents(); | ||
| 309 | |||
| 310 | if (!framebuffer) { | ||
| 311 | return; | ||
| 312 | } | ||
| 313 | |||
| 166 | // Maintain the rasterizer's state as a priority | 314 | // Maintain the rasterizer's state as a priority |
| 167 | OpenGLState prev_state = OpenGLState::GetCurState(); | 315 | OpenGLState prev_state = OpenGLState::GetCurState(); |
| 168 | state.AllDirty(); | 316 | state.AllDirty(); |
| 169 | state.Apply(); | 317 | state.Apply(); |
| 170 | 318 | ||
| 319 | PrepareRendertarget(framebuffer); | ||
| 320 | RenderScreenshot(); | ||
| 321 | |||
| 322 | Core::Frontend::Frame* frame; | ||
| 323 | { | ||
| 324 | MICROPROFILE_SCOPE(OpenGL_WaitPresent); | ||
| 325 | |||
| 326 | frame = render_window.mailbox->GetRenderFrame(); | ||
| 327 | |||
| 328 | // Clean up sync objects before drawing | ||
| 329 | |||
| 330 | // INTEL driver workaround. We can't delete the previous render sync object until we are | ||
| 331 | // sure that the presentation is done | ||
| 332 | if (frame->present_fence) { | ||
| 333 | glClientWaitSync(frame->present_fence, 0, GL_TIMEOUT_IGNORED); | ||
| 334 | } | ||
| 335 | |||
| 336 | // delete the draw fence if the frame wasn't presented | ||
| 337 | if (frame->render_fence) { | ||
| 338 | glDeleteSync(frame->render_fence); | ||
| 339 | frame->render_fence = 0; | ||
| 340 | } | ||
| 341 | |||
| 342 | // wait for the presentation to be done | ||
| 343 | if (frame->present_fence) { | ||
| 344 | glWaitSync(frame->present_fence, 0, GL_TIMEOUT_IGNORED); | ||
| 345 | glDeleteSync(frame->present_fence); | ||
| 346 | frame->present_fence = 0; | ||
| 347 | } | ||
| 348 | } | ||
| 349 | |||
| 350 | { | ||
| 351 | MICROPROFILE_SCOPE(OpenGL_RenderFrame); | ||
| 352 | const auto& layout = render_window.GetFramebufferLayout(); | ||
| 353 | |||
| 354 | // Recreate the frame if the size of the window has changed | ||
| 355 | if (layout.width != frame->width || layout.height != frame->height || | ||
| 356 | is_srgb != frame->is_srgb) { | ||
| 357 | LOG_DEBUG(Render_OpenGL, "Reloading render frame"); | ||
| 358 | is_srgb = frame->is_srgb = screen_info.display_srgb; | ||
| 359 | render_window.mailbox->ReloadRenderFrame(frame, layout.width, layout.height); | ||
| 360 | } | ||
| 361 | state.draw.draw_framebuffer = frame->render.handle; | ||
| 362 | state.Apply(); | ||
| 363 | DrawScreen(layout); | ||
| 364 | // 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 | glFlush(); | ||
| 367 | render_window.mailbox->ReleaseRenderFrame(frame); | ||
| 368 | m_current_frame++; | ||
| 369 | rasterizer->TickFrame(); | ||
| 370 | } | ||
| 371 | |||
| 372 | // Restore the rasterizer state | ||
| 373 | prev_state.AllDirty(); | ||
| 374 | prev_state.Apply(); | ||
| 375 | } | ||
| 376 | |||
| 377 | void RendererOpenGL::PrepareRendertarget(const Tegra::FramebufferConfig* framebuffer) { | ||
| 171 | if (framebuffer) { | 378 | if (framebuffer) { |
| 172 | // If framebuffer is provided, reload it from memory to a texture | 379 | // If framebuffer is provided, reload it from memory to a texture |
| 173 | if (screen_info.texture.width != static_cast<GLsizei>(framebuffer->width) || | 380 | if (screen_info.texture.width != static_cast<GLsizei>(framebuffer->width) || |
| @@ -181,22 +388,7 @@ void RendererOpenGL::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { | |||
| 181 | 388 | ||
| 182 | // Load the framebuffer from memory, draw it to the screen, and swap buffers | 389 | // Load the framebuffer from memory, draw it to the screen, and swap buffers |
| 183 | LoadFBToScreenInfo(*framebuffer); | 390 | LoadFBToScreenInfo(*framebuffer); |
| 184 | |||
| 185 | if (renderer_settings.screenshot_requested) | ||
| 186 | CaptureScreenshot(); | ||
| 187 | |||
| 188 | DrawScreen(render_window.GetFramebufferLayout()); | ||
| 189 | |||
| 190 | rasterizer->TickFrame(); | ||
| 191 | |||
| 192 | render_window.SwapBuffers(); | ||
| 193 | } | 391 | } |
| 194 | |||
| 195 | render_window.PollEvents(); | ||
| 196 | |||
| 197 | // Restore the rasterizer state | ||
| 198 | prev_state.AllDirty(); | ||
| 199 | prev_state.Apply(); | ||
| 200 | } | 392 | } |
| 201 | 393 | ||
| 202 | void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuffer) { | 394 | void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuffer) { |
| @@ -418,13 +610,48 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) { | |||
| 418 | DrawScreenTriangles(screen_info, static_cast<float>(screen.left), | 610 | DrawScreenTriangles(screen_info, static_cast<float>(screen.left), |
| 419 | static_cast<float>(screen.top), static_cast<float>(screen.GetWidth()), | 611 | static_cast<float>(screen.top), static_cast<float>(screen.GetWidth()), |
| 420 | static_cast<float>(screen.GetHeight())); | 612 | static_cast<float>(screen.GetHeight())); |
| 613 | } | ||
| 421 | 614 | ||
| 422 | m_current_frame++; | 615 | void RendererOpenGL::TryPresent(int timeout_ms) { |
| 616 | const auto& layout = render_window.GetFramebufferLayout(); | ||
| 617 | auto frame = render_window.mailbox->TryGetPresentFrame(timeout_ms); | ||
| 618 | if (!frame) { | ||
| 619 | LOG_DEBUG(Render_OpenGL, "TryGetPresentFrame returned no frame to present"); | ||
| 620 | return; | ||
| 621 | } | ||
| 622 | |||
| 623 | // Clearing before a full overwrite of a fbo can signal to drivers that they can avoid a | ||
| 624 | // readback since we won't be doing any blending | ||
| 625 | glClear(GL_COLOR_BUFFER_BIT); | ||
| 626 | |||
| 627 | // Recreate the presentation FBO if the color attachment was changed | ||
| 628 | if (frame->color_reloaded) { | ||
| 629 | LOG_DEBUG(Render_OpenGL, "Reloading present frame"); | ||
| 630 | render_window.mailbox->ReloadPresentFrame(frame, layout.width, layout.height); | ||
| 631 | } | ||
| 632 | glWaitSync(frame->render_fence, 0, GL_TIMEOUT_IGNORED); | ||
| 633 | // INTEL workaround. | ||
| 634 | // Normally we could just delete the draw fence here, but due to driver bugs, we can just delete | ||
| 635 | // it on the emulation thread without too much penalty | ||
| 636 | // glDeleteSync(frame.render_sync); | ||
| 637 | // frame.render_sync = 0; | ||
| 638 | |||
| 639 | glBindFramebuffer(GL_READ_FRAMEBUFFER, frame->present.handle); | ||
| 640 | glBlitFramebuffer(0, 0, frame->width, frame->height, 0, 0, layout.width, layout.height, | ||
| 641 | GL_COLOR_BUFFER_BIT, GL_LINEAR); | ||
| 642 | |||
| 643 | // Insert fence for the main thread to block on | ||
| 644 | frame->present_fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); | ||
| 645 | glFlush(); | ||
| 646 | |||
| 647 | glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); | ||
| 423 | } | 648 | } |
| 424 | 649 | ||
| 425 | void RendererOpenGL::UpdateFramerate() {} | 650 | void RendererOpenGL::RenderScreenshot() { |
| 651 | if (!renderer_settings.screenshot_requested) { | ||
| 652 | return; | ||
| 653 | } | ||
| 426 | 654 | ||
| 427 | void RendererOpenGL::CaptureScreenshot() { | ||
| 428 | // Draw the current frame to the screenshot framebuffer | 655 | // Draw the current frame to the screenshot framebuffer |
| 429 | screenshot_framebuffer.Create(); | 656 | screenshot_framebuffer.Create(); |
| 430 | GLuint old_read_fb = state.draw.read_framebuffer; | 657 | GLuint old_read_fb = state.draw.read_framebuffer; |
| @@ -459,8 +686,6 @@ void RendererOpenGL::CaptureScreenshot() { | |||
| 459 | } | 686 | } |
| 460 | 687 | ||
| 461 | bool RendererOpenGL::Init() { | 688 | bool RendererOpenGL::Init() { |
| 462 | Core::Frontend::ScopeAcquireWindowContext acquire_context{render_window}; | ||
| 463 | |||
| 464 | if (GLAD_GL_KHR_debug) { | 689 | if (GLAD_GL_KHR_debug) { |
| 465 | glEnable(GL_DEBUG_OUTPUT); | 690 | glEnable(GL_DEBUG_OUTPUT); |
| 466 | glDebugMessageCallback(DebugHandler, nullptr); | 691 | glDebugMessageCallback(DebugHandler, nullptr); |
diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h index b56328a7f..797965925 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.h +++ b/src/video_core/renderer_opengl/renderer_opengl.h | |||
| @@ -44,19 +44,21 @@ struct ScreenInfo { | |||
| 44 | TextureInfo texture; | 44 | TextureInfo texture; |
| 45 | }; | 45 | }; |
| 46 | 46 | ||
| 47 | struct PresentationTexture { | ||
| 48 | u32 width = 0; | ||
| 49 | u32 height = 0; | ||
| 50 | OGLTexture texture; | ||
| 51 | }; | ||
| 52 | |||
| 47 | class RendererOpenGL final : public VideoCore::RendererBase { | 53 | class RendererOpenGL final : public VideoCore::RendererBase { |
| 48 | public: | 54 | public: |
| 49 | explicit RendererOpenGL(Core::Frontend::EmuWindow& emu_window, Core::System& system); | 55 | explicit RendererOpenGL(Core::Frontend::EmuWindow& emu_window, Core::System& system); |
| 50 | ~RendererOpenGL() override; | 56 | ~RendererOpenGL() override; |
| 51 | 57 | ||
| 52 | /// Swap buffers (render frame) | ||
| 53 | void SwapBuffers(const Tegra::FramebufferConfig* framebuffer) override; | ||
| 54 | |||
| 55 | /// Initialize the renderer | ||
| 56 | bool Init() override; | 58 | bool Init() override; |
| 57 | |||
| 58 | /// Shutdown the renderer | ||
| 59 | void ShutDown() override; | 59 | void ShutDown() override; |
| 60 | void SwapBuffers(const Tegra::FramebufferConfig* framebuffer) override; | ||
| 61 | void TryPresent(int timeout_ms) override; | ||
| 60 | 62 | ||
| 61 | private: | 63 | private: |
| 62 | /// Initializes the OpenGL state and creates persistent objects. | 64 | /// Initializes the OpenGL state and creates persistent objects. |
| @@ -74,10 +76,7 @@ private: | |||
| 74 | 76 | ||
| 75 | void DrawScreenTriangles(const ScreenInfo& screen_info, float x, float y, float w, float h); | 77 | void DrawScreenTriangles(const ScreenInfo& screen_info, float x, float y, float w, float h); |
| 76 | 78 | ||
| 77 | /// Updates the framerate. | 79 | void RenderScreenshot(); |
| 78 | void UpdateFramerate(); | ||
| 79 | |||
| 80 | void CaptureScreenshot(); | ||
| 81 | 80 | ||
| 82 | /// Loads framebuffer from emulated memory into the active OpenGL texture. | 81 | /// Loads framebuffer from emulated memory into the active OpenGL texture. |
| 83 | void LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuffer); | 82 | void LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuffer); |
| @@ -87,6 +86,8 @@ private: | |||
| 87 | void LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, u8 color_a, | 86 | void LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, u8 color_a, |
| 88 | const TextureInfo& texture); | 87 | const TextureInfo& texture); |
| 89 | 88 | ||
| 89 | void PrepareRendertarget(const Tegra::FramebufferConfig* framebuffer); | ||
| 90 | |||
| 90 | Core::Frontend::EmuWindow& emu_window; | 91 | Core::Frontend::EmuWindow& emu_window; |
| 91 | Core::System& system; | 92 | Core::System& system; |
| 92 | 93 | ||
| @@ -107,6 +108,9 @@ private: | |||
| 107 | /// Used for transforming the framebuffer orientation | 108 | /// Used for transforming the framebuffer orientation |
| 108 | Tegra::FramebufferConfig::TransformFlags framebuffer_transform_flags; | 109 | Tegra::FramebufferConfig::TransformFlags framebuffer_transform_flags; |
| 109 | Common::Rectangle<int> framebuffer_crop_rect; | 110 | Common::Rectangle<int> framebuffer_crop_rect; |
| 111 | |||
| 112 | /// Represents if the final render frame is sRGB | ||
| 113 | bool is_srgb{}; | ||
| 110 | }; | 114 | }; |
| 111 | 115 | ||
| 112 | } // namespace OpenGL | 116 | } // namespace OpenGL |