presenting if need

This commit is contained in:
weihuoya 2020-06-03 10:20:56 +08:00 committed by xperia64
parent c946a05ca0
commit a1a446d720
5 changed files with 31 additions and 71 deletions

View File

@ -48,7 +48,7 @@ public:
* frame available after timeout, returns the previous frame. If there is no previous frame it * frame available after timeout, returns the previous frame. If there is no previous frame it
* returns nullptr * returns nullptr
*/ */
virtual Frontend::Frame* TryGetPresentFrame(int timeout_ms) = 0; virtual Frontend::Frame* TryGetPresentFrame() = 0;
}; };
/** /**

View File

@ -31,7 +31,7 @@ public:
/// Draws the latest frame to the window waiting timeout_ms for a frame to arrive (Renderer /// Draws the latest frame to the window waiting timeout_ms for a frame to arrive (Renderer
/// specific implementation) /// specific implementation)
virtual void TryPresent(int timeout_ms) = 0; virtual bool TryPresent() = 0;
/// Prepares for video dumping (e.g. create necessary buffers, etc) /// Prepares for video dumping (e.g. create necessary buffers, etc)
virtual void PrepareVideoDumping() = 0; virtual void PrepareVideoDumping() = 0;

View File

@ -44,7 +44,7 @@ void FrameDumperOpenGL::PresentLoop() {
const auto& layout = GetLayout(); const auto& layout = GetLayout();
while (!stop_requested.exchange(false)) { while (!stop_requested.exchange(false)) {
auto frame = mailbox->TryGetPresentFrame(200); auto frame = mailbox->TryGetPresentFrame();
if (!frame) { if (!frame) {
continue; continue;
} }

View File

@ -55,11 +55,11 @@ class OGLTextureMailbox : public Frontend::TextureMailbox {
public: public:
std::mutex swap_chain_lock; std::mutex swap_chain_lock;
std::condition_variable free_cv; std::condition_variable free_cv;
std::condition_variable present_cv;
std::array<Frontend::Frame, SWAP_CHAIN_SIZE> swap_chain{}; std::array<Frontend::Frame, SWAP_CHAIN_SIZE> swap_chain{};
std::queue<Frontend::Frame*> free_queue{}; std::queue<Frontend::Frame*> free_queue{};
std::deque<Frontend::Frame*> present_queue{}; std::deque<Frontend::Frame*> present_queue{};
Frontend::Frame* previous_frame = nullptr; Frontend::Frame* previous_frame = nullptr;
const std::chrono::milliseconds elapsed{100};
OGLTextureMailbox() { OGLTextureMailbox() {
for (auto& frame : swap_chain) { for (auto& frame : swap_chain) {
@ -73,7 +73,6 @@ public:
std::scoped_lock lock(swap_chain_lock); std::scoped_lock lock(swap_chain_lock);
std::queue<Frontend::Frame*>().swap(free_queue); std::queue<Frontend::Frame*>().swap(free_queue);
present_queue.clear(); present_queue.clear();
present_cv.notify_all();
free_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 theres no free frames, we will reuse the oldest render frame
if (free_queue.empty()) { if (free_queue.empty()) {
auto frame = present_queue.back(); // wait for new entries in the present_queue
present_queue.pop_back(); free_cv.wait_for(lock, elapsed, [this] { return !free_queue.empty(); });
return frame; if (free_queue.empty()) {
auto frame = present_queue.back();
present_queue.pop_back();
return frame;
}
} }
Frontend::Frame* frame = free_queue.front(); Frontend::Frame* frame = free_queue.front();
@ -137,41 +140,25 @@ public:
void ReleaseRenderFrame(Frontend::Frame* frame) override { void ReleaseRenderFrame(Frontend::Frame* frame) override {
std::unique_lock<std::mutex> lock(swap_chain_lock); std::unique_lock<std::mutex> lock(swap_chain_lock);
present_queue.push_front(frame); present_queue.push_back(frame);
present_cv.notify_one();
} }
// This is virtual as it is to be overriden in OGLVideoDumpingMailbox below. Frontend::Frame* TryGetPresentFrame() override {
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<std::mutex> 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()) { if (present_queue.empty()) {
// timed out waiting for a frame to draw so return the previous frame return nullptr;
} else {
std::unique_lock<std::mutex> 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; return previous_frame;
} }
LoadPresentFrame();
return previous_frame;
} }
}; };
@ -200,35 +187,6 @@ public:
free_queue.pop(); free_queue.pop();
return frame; 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<std::mutex> 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"( 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(); const auto& layout = render_window.GetFramebufferLayout();
auto frame = render_window.mailbox->TryGetPresentFrame(timeout_ms); auto frame = render_window.mailbox->TryGetPresentFrame();
if (!frame) { if (!frame) {
LOG_DEBUG(Render_OpenGL, "TryGetPresentFrame returned no frame to present"); 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 // 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(); glFlush();
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
return true;
} }
/// Updates the framerate /// Updates the framerate

View File

@ -73,7 +73,7 @@ public:
/// Draws the latest frame from texture mailbox to the currently bound draw framebuffer in this /// Draws the latest frame from texture mailbox to the currently bound draw framebuffer in this
/// context /// context
void TryPresent(int timeout_ms) override; bool TryPresent() override;
/// Prepares for video dumping (e.g. create necessary buffers, etc) /// Prepares for video dumping (e.g. create necessary buffers, etc)
void PrepareVideoDumping() override; void PrepareVideoDumping() override;