Qt: Improve frame pacing, maybe

This commit is contained in:
Vicki Pfau 2022-07-03 05:27:15 -07:00
parent 9bcfd248e9
commit 76d6055bb0
3 changed files with 37 additions and 19 deletions

View File

@ -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;
}
}

View File

@ -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() {

View File

@ -176,8 +176,9 @@ private:
void performDraw();
void dequeue();
void dequeueAll(bool keep = false);
void resetTiming();
std::array<std::array<uint32_t, 0x100000>, 3> m_buffers;
std::array<std::array<uint32_t, 0x100000>, 8> m_buffers;
QList<uint32_t*> m_free;
QQueue<uint32_t*> 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<CoreController> m_context;
CoreController::Interrupter m_interrupter;
bool m_supportsShaders;