mirror of https://github.com/mgba-emu/mgba.git
Qt: Improve frame pacing, maybe
This commit is contained in:
parent
9bcfd248e9
commit
76d6055bb0
|
@ -25,10 +25,10 @@ void mCoreSyncPostFrame(struct mCoreSync* sync) {
|
||||||
MutexLock(&sync->videoFrameMutex);
|
MutexLock(&sync->videoFrameMutex);
|
||||||
++sync->videoFramePending;
|
++sync->videoFramePending;
|
||||||
do {
|
do {
|
||||||
ConditionWake(&sync->videoFrameAvailableCond);
|
|
||||||
if (sync->videoFrameWait) {
|
if (sync->videoFrameWait) {
|
||||||
ConditionWait(&sync->videoFrameRequiredCond, &sync->videoFrameMutex);
|
ConditionWait(&sync->videoFrameRequiredCond, &sync->videoFrameMutex);
|
||||||
}
|
}
|
||||||
|
ConditionWake(&sync->videoFrameAvailableCond);
|
||||||
} while (sync->videoFrameWait && sync->videoFramePending);
|
} while (sync->videoFrameWait && sync->videoFramePending);
|
||||||
MutexUnlock(&sync->videoFrameMutex);
|
MutexUnlock(&sync->videoFrameMutex);
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ bool mCoreSyncWaitFrameStart(struct mCoreSync* sync) {
|
||||||
}
|
}
|
||||||
if (sync->videoFrameWait) {
|
if (sync->videoFrameWait) {
|
||||||
ConditionWake(&sync->videoFrameRequiredCond);
|
ConditionWake(&sync->videoFrameRequiredCond);
|
||||||
if (ConditionWaitTimed(&sync->videoFrameAvailableCond, &sync->videoFrameMutex, 50)) {
|
if (ConditionWaitTimed(&sync->videoFrameAvailableCond, &sync->videoFrameMutex, 4)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -619,11 +619,12 @@ void PainterGL::start() {
|
||||||
m_buffer = nullptr;
|
m_buffer = nullptr;
|
||||||
m_active = true;
|
m_active = true;
|
||||||
m_started = true;
|
m_started = true;
|
||||||
|
resetTiming();
|
||||||
emit started();
|
emit started();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PainterGL::draw() {
|
void PainterGL::draw() {
|
||||||
if (!m_started || m_queue.isEmpty()) {
|
if (!m_started) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -636,14 +637,16 @@ void PainterGL::draw() {
|
||||||
}
|
}
|
||||||
|
|
||||||
mCoreSync* sync = &m_context->thread()->impl->sync;
|
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)) {
|
if (!mCoreSyncWaitFrameStart(sync)) {
|
||||||
mCoreSyncWaitFrameEnd(sync);
|
mCoreSyncWaitFrameEnd(sync);
|
||||||
if (!sync->audioWait && !sync->videoFrameWait) {
|
if (!sync->audioWait && !sync->videoFrameWait) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (m_delayTimer.elapsed() >= 1000 / m_window->screen()->refreshRate()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!m_drawTimer.isActive()) {
|
if (!m_drawTimer.isActive()) {
|
||||||
m_drawTimer.start(1);
|
m_drawTimer.start(1);
|
||||||
}
|
}
|
||||||
|
@ -651,23 +654,30 @@ void PainterGL::draw() {
|
||||||
}
|
}
|
||||||
dequeue();
|
dequeue();
|
||||||
bool forceRedraw = !m_videoProxy;
|
bool forceRedraw = !m_videoProxy;
|
||||||
if (!m_delayTimer.isValid()) {
|
if (sync->audioWait || sync->videoFrameWait) {
|
||||||
m_delayTimer.start();
|
while (delay + m_delayTimer.nsecsElapsed() + OVERHEAD_NSEC < targetNsec) {
|
||||||
} else {
|
QThread::usleep(200);
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
forceRedraw = sync->videoFrameWait;
|
||||||
|
}
|
||||||
|
if (!forceRedraw) {
|
||||||
|
forceRedraw = delay + m_delayTimer.nsecsElapsed() + OVERHEAD_NSEC >= refreshNsec;
|
||||||
}
|
}
|
||||||
mCoreSyncWaitFrameEnd(sync);
|
mCoreSyncWaitFrameEnd(sync);
|
||||||
|
|
||||||
if (forceRedraw) {
|
if (forceRedraw) {
|
||||||
|
delay += m_delayTimer.nsecsElapsed();
|
||||||
m_delayTimer.restart();
|
m_delayTimer.restart();
|
||||||
|
|
||||||
|
delay -= targetNsec;
|
||||||
|
m_timerResidue = (m_timerResidue + delay) / 2;
|
||||||
|
|
||||||
|
if (m_timerResidue > refreshNsec) {
|
||||||
|
if (!m_drawTimer.isActive()) {
|
||||||
|
m_drawTimer.start(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
performDraw();
|
performDraw();
|
||||||
m_backend->swap(m_backend);
|
m_backend->swap(m_backend);
|
||||||
}
|
}
|
||||||
|
@ -679,11 +689,16 @@ void PainterGL::forceDraw() {
|
||||||
if (m_delayTimer.elapsed() < 1000 / m_window->screen()->refreshRate()) {
|
if (m_delayTimer.elapsed() < 1000 / m_window->screen()->refreshRate()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_delayTimer.restart();
|
resetTiming();
|
||||||
}
|
}
|
||||||
m_backend->swap(m_backend);
|
m_backend->swap(m_backend);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PainterGL::resetTiming() {
|
||||||
|
m_delayTimer.restart();
|
||||||
|
m_timerResidue = 0;
|
||||||
|
}
|
||||||
|
|
||||||
void PainterGL::stop() {
|
void PainterGL::stop() {
|
||||||
m_started = false;
|
m_started = false;
|
||||||
QMetaObject::invokeMethod(this, "doStop", Qt::BlockingQueuedConnection);
|
QMetaObject::invokeMethod(this, "doStop", Qt::BlockingQueuedConnection);
|
||||||
|
@ -721,6 +736,7 @@ void PainterGL::pause() {
|
||||||
|
|
||||||
void PainterGL::unpause() {
|
void PainterGL::unpause() {
|
||||||
m_active = true;
|
m_active = true;
|
||||||
|
resetTiming();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PainterGL::performDraw() {
|
void PainterGL::performDraw() {
|
||||||
|
|
|
@ -176,8 +176,9 @@ private:
|
||||||
void performDraw();
|
void performDraw();
|
||||||
void dequeue();
|
void dequeue();
|
||||||
void dequeueAll(bool keep = false);
|
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;
|
QList<uint32_t*> m_free;
|
||||||
QQueue<uint32_t*> m_queue;
|
QQueue<uint32_t*> m_queue;
|
||||||
uint32_t* m_buffer = nullptr;
|
uint32_t* m_buffer = nullptr;
|
||||||
|
@ -194,6 +195,7 @@ private:
|
||||||
bool m_active = false;
|
bool m_active = false;
|
||||||
bool m_started = false;
|
bool m_started = false;
|
||||||
QTimer m_drawTimer;
|
QTimer m_drawTimer;
|
||||||
|
qint64 m_timerResidue;
|
||||||
std::shared_ptr<CoreController> m_context;
|
std::shared_ptr<CoreController> m_context;
|
||||||
CoreController::Interrupter m_interrupter;
|
CoreController::Interrupter m_interrupter;
|
||||||
bool m_supportsShaders;
|
bool m_supportsShaders;
|
||||||
|
|
Loading…
Reference in New Issue