From 76d6055bb0095caf57431f7250bc0e965aa49e5e Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sun, 3 Jul 2022 05:27:15 -0700 Subject: [PATCH] Qt: Improve frame pacing, maybe --- src/core/sync.c | 4 +-- src/platform/qt/DisplayGL.cpp | 48 +++++++++++++++++++++++------------ src/platform/qt/DisplayGL.h | 4 ++- 3 files changed, 37 insertions(+), 19 deletions(-) diff --git a/src/core/sync.c b/src/core/sync.c index b2a65493b..78b04ea3e 100644 --- a/src/core/sync.c +++ b/src/core/sync.c @@ -25,10 +25,10 @@ void mCoreSyncPostFrame(struct mCoreSync* sync) { MutexLock(&sync->videoFrameMutex); ++sync->videoFramePending; do { - ConditionWake(&sync->videoFrameAvailableCond); if (sync->videoFrameWait) { ConditionWait(&sync->videoFrameRequiredCond, &sync->videoFrameMutex); } + ConditionWake(&sync->videoFrameAvailableCond); } while (sync->videoFrameWait && sync->videoFramePending); MutexUnlock(&sync->videoFrameMutex); } @@ -54,7 +54,7 @@ bool mCoreSyncWaitFrameStart(struct mCoreSync* sync) { } if (sync->videoFrameWait) { ConditionWake(&sync->videoFrameRequiredCond); - if (ConditionWaitTimed(&sync->videoFrameAvailableCond, &sync->videoFrameMutex, 50)) { + if (ConditionWaitTimed(&sync->videoFrameAvailableCond, &sync->videoFrameMutex, 4)) { return false; } } diff --git a/src/platform/qt/DisplayGL.cpp b/src/platform/qt/DisplayGL.cpp index 740604b82..4175505b5 100644 --- a/src/platform/qt/DisplayGL.cpp +++ b/src/platform/qt/DisplayGL.cpp @@ -619,11 +619,12 @@ void PainterGL::start() { m_buffer = nullptr; m_active = true; m_started = true; + resetTiming(); emit started(); } void PainterGL::draw() { - if (!m_started || m_queue.isEmpty()) { + if (!m_started) { return; } @@ -636,14 +637,16 @@ void PainterGL::draw() { } mCoreSync* sync = &m_context->thread()->impl->sync; + + qint64 targetNsec = 1000000000 / sync->fpsTarget; + qint64 refreshNsec = 1000000000 / m_window->screen()->refreshRate(); + qint64 delay = m_timerResidue; + if (!mCoreSyncWaitFrameStart(sync)) { mCoreSyncWaitFrameEnd(sync); if (!sync->audioWait && !sync->videoFrameWait) { return; } - if (m_delayTimer.elapsed() >= 1000 / m_window->screen()->refreshRate()) { - return; - } if (!m_drawTimer.isActive()) { m_drawTimer.start(1); } @@ -651,23 +654,30 @@ void PainterGL::draw() { } dequeue(); bool forceRedraw = !m_videoProxy; - if (!m_delayTimer.isValid()) { - m_delayTimer.start(); - } else { - if (sync->audioWait || sync->videoFrameWait) { - while (m_delayTimer.nsecsElapsed() + OVERHEAD_NSEC < 1000000000 / sync->fpsTarget) { - QThread::usleep(500); - } - forceRedraw = sync->videoFrameWait; - } - if (!forceRedraw) { - forceRedraw = m_delayTimer.nsecsElapsed() + OVERHEAD_NSEC >= 1000000000 / m_window->screen()->refreshRate(); + if (sync->audioWait || sync->videoFrameWait) { + while (delay + m_delayTimer.nsecsElapsed() + OVERHEAD_NSEC < targetNsec) { + QThread::usleep(200); } + forceRedraw = sync->videoFrameWait; + } + if (!forceRedraw) { + forceRedraw = delay + m_delayTimer.nsecsElapsed() + OVERHEAD_NSEC >= refreshNsec; } mCoreSyncWaitFrameEnd(sync); if (forceRedraw) { + delay += m_delayTimer.nsecsElapsed(); m_delayTimer.restart(); + + delay -= targetNsec; + m_timerResidue = (m_timerResidue + delay) / 2; + + if (m_timerResidue > refreshNsec) { + if (!m_drawTimer.isActive()) { + m_drawTimer.start(1); + } + } + performDraw(); m_backend->swap(m_backend); } @@ -679,11 +689,16 @@ void PainterGL::forceDraw() { if (m_delayTimer.elapsed() < 1000 / m_window->screen()->refreshRate()) { return; } - m_delayTimer.restart(); + resetTiming(); } m_backend->swap(m_backend); } +void PainterGL::resetTiming() { + m_delayTimer.restart(); + m_timerResidue = 0; +} + void PainterGL::stop() { m_started = false; QMetaObject::invokeMethod(this, "doStop", Qt::BlockingQueuedConnection); @@ -721,6 +736,7 @@ void PainterGL::pause() { void PainterGL::unpause() { m_active = true; + resetTiming(); } void PainterGL::performDraw() { diff --git a/src/platform/qt/DisplayGL.h b/src/platform/qt/DisplayGL.h index 47f94157d..5b12feae0 100644 --- a/src/platform/qt/DisplayGL.h +++ b/src/platform/qt/DisplayGL.h @@ -176,8 +176,9 @@ private: void performDraw(); void dequeue(); void dequeueAll(bool keep = false); + void resetTiming(); - std::array, 3> m_buffers; + std::array, 8> m_buffers; QList m_free; QQueue m_queue; uint32_t* m_buffer = nullptr; @@ -194,6 +195,7 @@ private: bool m_active = false; bool m_started = false; QTimer m_drawTimer; + qint64 m_timerResidue; std::shared_ptr m_context; CoreController::Interrupter m_interrupter; bool m_supportsShaders;