presenting if need
This commit is contained in:
parent
a2b58a2114
commit
35d79e5df6
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,11 +123,15 @@ public:
|
|||||||
std::unique_lock<std::mutex> lock(swap_chain_lock);
|
std::unique_lock<std::mutex> lock(swap_chain_lock);
|
||||||
|
|
||||||
// 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()) {
|
||||||
|
// wait for new entries in the present_queue
|
||||||
|
free_cv.wait_for(lock, elapsed, [this] { return !free_queue.empty(); });
|
||||||
if (free_queue.empty()) {
|
if (free_queue.empty()) {
|
||||||
auto frame = present_queue.back();
|
auto frame = present_queue.back();
|
||||||
present_queue.pop_back();
|
present_queue.pop_back();
|
||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Frontend::Frame* frame = free_queue.front();
|
Frontend::Frame* frame = free_queue.front();
|
||||||
free_queue.pop();
|
free_queue.pop();
|
||||||
@ -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() {
|
if (present_queue.empty()) {
|
||||||
|
return nullptr;
|
||||||
|
} else {
|
||||||
|
std::unique_lock<std::mutex> lock(swap_chain_lock);
|
||||||
|
|
||||||
// free the previous frame and add it back to the free queue
|
// free the previous frame and add it back to the free queue
|
||||||
if (previous_frame) {
|
if (previous_frame) {
|
||||||
free_queue.push(previous_frame);
|
free_queue.push(previous_frame);
|
||||||
free_cv.notify_one();
|
free_cv.notify_one();
|
||||||
}
|
}
|
||||||
|
|
||||||
// the newest entries are pushed to the front of the queue
|
previous_frame = present_queue.front();
|
||||||
Frontend::Frame* frame = present_queue.front();
|
|
||||||
present_queue.pop_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()) {
|
|
||||||
// timed out waiting for a frame to draw so return the previous frame
|
|
||||||
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"(
|
||||||
@ -1070,12 +1028,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
|
||||||
@ -1103,6 +1061,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
|
||||||
|
@ -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;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user