Qt: Improve GL sync (really)
Vicki Pfau vi@endrift.com
Mon, 16 Sep 2019 19:14:52 -0700
2 files changed,
31 insertions(+),
54 deletions(-)
M
src/platform/qt/DisplayGL.cpp
→
src/platform/qt/DisplayGL.cpp
@@ -12,7 +12,9 @@
#include <QApplication> #include <QOpenGLContext> #include <QOpenGLPaintDevice> +#include <QMutexLocker> #include <QResizeEvent> +#include <QScreen> #include <QTimer> #include <QWindow>@@ -278,9 +280,14 @@ }
#endif m_backend->swap = [](VideoBackend* v) { PainterGL* painter = static_cast<PainterGL*>(v->user); - if (!painter->m_swapTimer.isActive()) { - QMetaObject::invokeMethod(&painter->m_swapTimer, "start"); + if (!painter->m_gl->isValid()) { + return; } + painter->m_gl->swapBuffers(painter->m_surface); + painter->m_gl->makeCurrent(painter->m_surface); +#if defined(_WIN32) && defined(USE_EPOXY) + epoxy_handle_external_wglMakeCurrent(); +#endif }; m_backend->init(m_backend, 0);@@ -289,6 +296,7 @@ if (m_supportsShaders) {
m_shader.preprocessShader = static_cast<void*>(&reinterpret_cast<mGLES2Context*>(m_backend)->initialShader); } #endif + m_gl->doneCurrent(); m_backend->user = this; m_backend->filter = false;@@ -298,10 +306,6 @@
for (int i = 0; i < 2; ++i) { m_free.append(new uint32_t[1024 * 2048]); } - - m_swapTimer.setInterval(16); - m_swapTimer.setSingleShot(true); - connect(&m_swapTimer, &QTimer::timeout, this, &PainterGL::swap); } PainterGL::~PainterGL() {@@ -390,32 +394,35 @@ m_started = true;
} void PainterGL::draw() { - if (m_queue.isEmpty()) { + if (!m_active || m_queue.isEmpty()) { return; } - - if (m_needsUnlock) { - QTimer::singleShot(0, this, &PainterGL::draw); - return; + mCoreSync* sync = &m_context->thread()->impl->sync; + mCoreSyncWaitFrameStart(sync); + dequeue(); + if (!m_delayTimer.isValid()) { + m_delayTimer.start(); + } else if (sync->audioWait || sync->videoFrameWait) { + while (m_delayTimer.nsecsElapsed() + 2000000 < 1000000000 / sync->fpsTarget) { + QThread::usleep(500); + } + m_delayTimer.restart(); } + mCoreSyncWaitFrameEnd(sync); - if (mCoreSyncWaitFrameStart(&m_context->thread()->impl->sync) || !m_queue.isEmpty()) { - dequeue(); - forceDraw(); - if (m_context->thread()->impl->sync.videoFrameWait) { - m_needsUnlock = true; - } else { - mCoreSyncWaitFrameEnd(&m_context->thread()->impl->sync); - } - } else { - mCoreSyncWaitFrameEnd(&m_context->thread()->impl->sync); - } + forceDraw(); } void PainterGL::forceDraw() { m_painter.begin(m_window); performDraw(); m_painter.end(); + if (!m_context->thread()->impl->sync.audioWait && !m_context->thread()->impl->sync.videoFrameWait) { + if (m_delayTimer.elapsed() < 1000 / m_surface->screen()->refreshRate()) { + return; + } + m_delayTimer.restart(); + } m_backend->swap(m_backend); }@@ -425,10 +432,6 @@ m_started = false;
dequeueAll(); m_backend->clear(m_backend); m_backend->swap(m_backend); - if (m_swapTimer.isActive()) { - swap(); - m_swapTimer.stop(); - } if (m_videoProxy) { m_videoProxy->reset(); }@@ -457,28 +460,6 @@ m_backend->drawFrame(m_backend);
m_painter.endNativePainting(); if (m_messagePainter) { m_messagePainter->paint(&m_painter); - } - m_frameReady = true; -} - -void PainterGL::swap() { - if (!m_gl->isValid()) { - return; - } - if (m_frameReady) { - m_gl->swapBuffers(m_surface); - m_gl->makeCurrent(m_surface); -#if defined(_WIN32) && defined(USE_EPOXY) - epoxy_handle_external_wglMakeCurrent(); -#endif - m_frameReady = false; - } - if (m_needsUnlock) { - mCoreSyncWaitFrameEnd(&m_context->thread()->impl->sync); - m_needsUnlock = false; - } - if (!m_queue.isEmpty()) { - QMetaObject::invokeMethod(this, "draw", Qt::QueuedConnection); } }
M
src/platform/qt/DisplayGL.h
→
src/platform/qt/DisplayGL.h
@@ -16,6 +16,7 @@ #define GLdouble GLdouble
#endif #endif +#include <QElapsedTimer> #include <QOpenGLContext> #include <QList> #include <QMouseEvent>@@ -108,9 +109,6 @@ VideoShader* shaders();
int glTex(); -private slots: - void swap(); - private: void performDraw(); void dequeue();@@ -131,9 +129,7 @@ VideoShader m_shader{};
VideoBackend* m_backend = nullptr; QSize m_size; MessagePainter* m_messagePainter = nullptr; - QTimer m_swapTimer{this}; - bool m_needsUnlock = false; - bool m_frameReady = false; + QElapsedTimer m_delayTimer; std::shared_ptr<VideoProxy> m_videoProxy; };