From a1a446d72032dac0ec2ce46f3da656edddaebf56 Mon Sep 17 00:00:00 2001 From: weihuoya Date: Wed, 3 Jun 2020 10:20:56 +0800 Subject: [PATCH] presenting if need --- src/core/frontend/emu_window.h | 2 +- src/video_core/renderer_base.h | 2 +- .../renderer_opengl/frame_dumper_opengl.cpp | 2 +- .../renderer_opengl/renderer_opengl.cpp | 94 ++++++------------- .../renderer_opengl/renderer_opengl.h | 2 +- 5 files changed, 31 insertions(+), 71 deletions(-) diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h index 326563655..f34097a41 100644 --- a/src/core/frontend/emu_window.h +++ b/src/core/frontend/emu_window.h @@ -48,7 +48,7 @@ public: * frame available after timeout, returns the previous frame. If there is no previous frame it * returns nullptr */ - virtual Frontend::Frame* TryGetPresentFrame(int timeout_ms) = 0; + virtual Frontend::Frame* TryGetPresentFrame() = 0; }; /** diff --git a/src/video_core/renderer_base.h b/src/video_core/renderer_base.h index b1612d82d..f859807a0 100644 --- a/src/video_core/renderer_base.h +++ b/src/video_core/renderer_base.h @@ -31,7 +31,7 @@ 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; + virtual bool TryPresent() = 0; /// Prepares for video dumping (e.g. create necessary buffers, etc) virtual void PrepareVideoDumping() = 0; diff --git a/src/video_core/renderer_opengl/frame_dumper_opengl.cpp b/src/video_core/renderer_opengl/frame_dumper_opengl.cpp index 53985823c..575483989 100644 --- a/src/video_core/renderer_opengl/frame_dumper_opengl.cpp +++ b/src/video_core/renderer_opengl/frame_dumper_opengl.cpp @@ -44,7 +44,7 @@ void FrameDumperOpenGL::PresentLoop() { const auto& layout = GetLayout(); while (!stop_requested.exchange(false)) { - auto frame = mailbox->TryGetPresentFrame(200); + auto frame = mailbox->TryGetPresentFrame(); if (!frame) { continue; } diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index be9525c0c..02effe50b 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -55,11 +55,11 @@ class OGLTextureMailbox : public Frontend::TextureMailbox { public: std::mutex swap_chain_lock; std::condition_variable free_cv; - std::condition_variable present_cv; std::array swap_chain{}; std::queue free_queue{}; std::deque present_queue{}; Frontend::Frame* previous_frame = nullptr; + const std::chrono::milliseconds elapsed{100}; OGLTextureMailbox() { for (auto& frame : swap_chain) { @@ -73,7 +73,6 @@ public: std::scoped_lock lock(swap_chain_lock); std::queue().swap(free_queue); present_queue.clear(); - present_cv.notify_all(); free_cv.notify_all(); } @@ -125,9 +124,13 @@ public: // If theres no free frames, we will reuse the oldest render frame if (free_queue.empty()) { - auto frame = present_queue.back(); - present_queue.pop_back(); - return frame; + // wait for new entries in the present_queue + free_cv.wait_for(lock, elapsed, [this] { return !free_queue.empty(); }); + if (free_queue.empty()) { + auto frame = present_queue.back(); + present_queue.pop_back(); + return frame; + } } Frontend::Frame* frame = free_queue.front(); @@ -137,41 +140,25 @@ public: void ReleaseRenderFrame(Frontend::Frame* frame) override { std::unique_lock lock(swap_chain_lock); - present_queue.push_front(frame); - present_cv.notify_one(); + present_queue.push_back(frame); } - // This is virtual as it is to be overriden in OGLVideoDumpingMailbox below. - virtual void LoadPresentFrame() { - // free the previous frame and add it back to the free queue - if (previous_frame) { - free_queue.push(previous_frame); - free_cv.notify_one(); - } - - // the newest entries are pushed to the front of the queue - Frontend::Frame* frame = present_queue.front(); - present_queue.pop_front(); - // remove all old entries from the present queue and move them back to the free_queue - for (auto f : present_queue) { - free_queue.push(f); - } - present_queue.clear(); - previous_frame = frame; - } - - Frontend::Frame* TryGetPresentFrame(int timeout_ms) override { - 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), - [&] { return !present_queue.empty(); }); + Frontend::Frame* TryGetPresentFrame() override { if (present_queue.empty()) { - // timed out waiting for a frame to draw so return the previous frame + return nullptr; + } else { + std::unique_lock lock(swap_chain_lock); + + // free the previous frame and add it back to the free queue + if (previous_frame) { + free_queue.push(previous_frame); + free_cv.notify_one(); + } + + previous_frame = present_queue.front(); + present_queue.pop_front(); return previous_frame; } - - LoadPresentFrame(); - return previous_frame; } }; @@ -200,35 +187,6 @@ public: free_queue.pop(); return frame; } - - void LoadPresentFrame() override { - // free the previous frame and add it back to the free queue - if (previous_frame) { - free_queue.push(previous_frame); - free_cv.notify_one(); - } - - Frontend::Frame* frame = present_queue.back(); - present_queue.pop_back(); - previous_frame = frame; - - // Do not remove entries from the present_queue, as video dumping would require - // that we preserve all frames - } - - Frontend::Frame* TryGetPresentFrame(int timeout_ms) override { - 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), - [&] { return !present_queue.empty(); }); - if (present_queue.empty()) { - // timed out waiting for a frame - return nullptr; - } - - LoadPresentFrame(); - return previous_frame; - } }; static const char vertex_shader[] = R"( @@ -1084,12 +1042,12 @@ void RendererOpenGL::DrawScreens(const Layout::FramebufferLayout& layout, bool f } } -void RendererOpenGL::TryPresent(int timeout_ms) { +bool RendererOpenGL::TryPresent() { const auto& layout = render_window.GetFramebufferLayout(); - auto frame = render_window.mailbox->TryGetPresentFrame(timeout_ms); + auto frame = render_window.mailbox->TryGetPresentFrame(); 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 @@ -1122,6 +1080,8 @@ void RendererOpenGL::TryPresent(int timeout_ms) { glFlush(); glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + + return true; } /// Updates the framerate diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h index 1633bf8f0..3a15139a2 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.h +++ b/src/video_core/renderer_opengl/renderer_opengl.h @@ -73,7 +73,7 @@ public: /// Draws the latest frame from texture mailbox to the currently bound draw framebuffer in this /// context - void TryPresent(int timeout_ms) override; + bool TryPresent() override; /// Prepares for video dumping (e.g. create necessary buffers, etc) void PrepareVideoDumping() override;