From 22f5665de79513c41fbef8f1b918f44d184daf1f Mon Sep 17 00:00:00 2001 From: Jeffy Chen Date: Tue, 16 Apr 2019 18:46:49 +0800 Subject: [PATCH 17/31] linuxfb: Use triple buffer by default Signed-off-by: Jeffy Chen --- .../platforms/linuxfb/qlinuxfbdrmscreen.cpp | 56 +++++++++++++++---- 1 file changed, 44 insertions(+), 12 deletions(-) diff --git a/src/plugins/platforms/linuxfb/qlinuxfbdrmscreen.cpp b/src/plugins/platforms/linuxfb/qlinuxfbdrmscreen.cpp index dcc1ef27..29d146f4 100644 --- a/src/plugins/platforms/linuxfb/qlinuxfbdrmscreen.cpp +++ b/src/plugins/platforms/linuxfb/qlinuxfbdrmscreen.cpp @@ -59,7 +59,13 @@ QT_BEGIN_NAMESPACE Q_LOGGING_CATEGORY(qLcFbDrm, "qt.qpa.fb") +#define TRIPLE_BUFFER + +#ifdef TRIPLE_BUFFER +static const int BUFFER_COUNT = 3; +#else static const int BUFFER_COUNT = 2; +#endif class QLinuxFbDevice : public QKmsDevice { @@ -75,12 +81,12 @@ public: }; struct Output { - Output() : backFb(0), flipped(false) { } + Output() : backFb(0), flipPending(false) { } QKmsOutput kmsOutput; Framebuffer fb[BUFFER_COUNT]; QRegion dirty[BUFFER_COUNT]; int backFb; - bool flipped; + bool flipPending; QSize currentRes() const { const drmModeModeInfo &modeInfo(kmsOutput.modes[kmsOutput.mode]); return QSize(modeInfo.hdisplay, modeInfo.vdisplay); @@ -97,6 +103,7 @@ public: void setMode(); void swapBuffers(Output *output); + void waitForFlip(Output *output); int outputCount() const { return m_outputs.count(); } Output *output(int idx) { return &m_outputs[idx]; } @@ -301,7 +308,7 @@ void QLinuxFbDevice::createFramebuffers() return; } output.backFb = 0; - output.flipped = false; + output.flipPending = false; } } @@ -355,19 +362,18 @@ void QLinuxFbDevice::pageFlipHandler(int fd, unsigned int sequence, Q_UNUSED(tv_usec); Output *output = static_cast(user_data); + +#ifndef TRIPLE_BUFFER + // The next buffer would be available after flipped output->backFb = (output->backFb + 1) % BUFFER_COUNT; +#endif + + output->flipPending = false; } -void QLinuxFbDevice::swapBuffers(Output *output) +void QLinuxFbDevice::waitForFlip(Output *output) { - Framebuffer &fb(output->fb[output->backFb]); - if (drmModePageFlip(fd(), output->kmsOutput.crtc_id, fb.fb, DRM_MODE_PAGE_FLIP_EVENT, output) == -1) { - qErrnoWarning(errno, "Page flip failed"); - return; - } - - const int fbIdx = output->backFb; - while (output->backFb == fbIdx) { + while (output->flipPending) { drmEventContext drmEvent; memset(&drmEvent, 0, sizeof(drmEvent)); drmEvent.version = 2; @@ -379,6 +385,27 @@ void QLinuxFbDevice::swapBuffers(Output *output) } } +void QLinuxFbDevice::swapBuffers(Output *output) +{ +#ifdef TRIPLE_BUFFER + // Wait flip to make sure last buffer displayed + waitForFlip(output); +#endif + + Framebuffer &fb(output->fb[output->backFb]); + if (drmModePageFlip(fd(), output->kmsOutput.crtc_id, fb.fb, DRM_MODE_PAGE_FLIP_EVENT, output) == -1) { + qErrnoWarning(errno, "Page flip failed"); + return; + } + + output->flipPending = true; + +#ifdef TRIPLE_BUFFER + // The next buffer should always available in triple buffer case. + output->backFb = (output->backFb + 1) % BUFFER_COUNT; +#endif +} + QLinuxFbDrmScreen::QLinuxFbDrmScreen(const QStringList &args) : m_screenConfig(nullptr), m_device(nullptr) @@ -436,6 +463,11 @@ QRegion QLinuxFbDrmScreen::doRedraw() for (int i = 0; i < BUFFER_COUNT; ++i) output->dirty[i] += dirty; +#ifndef TRIPLE_BUFFER + // Wait flip before accessing new buffer + m_device->waitForFlip(output); +#endif + if (output->fb[output->backFb].wrapper.isNull()) return dirty; -- 2.20.1