From 4f14b42f7dc289cd73a5e7aa934d6052c708bac3 Mon Sep 17 00:00:00 2001 From: Milian Wolff Date: Mon, 14 Jan 2013 16:26:03 +0100 Subject: [PATCH] Add support for forced VSYNC using the EGLFS platform plugin. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before a buffer swap the new QEglFSHooks::waitForVSync method is called which looks at QT_QPA_EGLFS_FORCEVSYNC and - if that is set and non-null - calls ioctl with the FBIO_WAITFORVSYNC request on the framebuffer device. This is required on some embedded platforms where the driver does not support VSYNC yet the Kernel provides a generic implementation. I tested this using QML_RENDER_TIMING=1 which proofs that the frame rate for an example of mine drops from >125fps to a straight ~60fps with a few frames that take ~33ms (i.e. 30fps) as expected for VSYNC. To prevent excessive open/close calls on the frame buffer device per frame, the file descriptor is now cached. To keep the QEglFSHooks interface as clean as possible this is done via a global static in qeglfshooks_stub.cpp and initialized and freed in platformInit and platformDestroy. Change-Id: I4d31b227c65ff22aa089db0fbc62c89a59cbb6c7 Reviewed-by: Sean Harmer Reviewed-by: Samuel Rødal --- src/plugins/platforms/eglfs/qeglfscontext.cpp | 1 + src/plugins/platforms/eglfs/qeglfshooks.h | 1 + .../platforms/eglfs/qeglfshooks_stub.cpp | 50 +++++++++++-------- 3 files changed, 30 insertions(+), 22 deletions(-) diff --git a/src/plugins/platforms/eglfs/qeglfscontext.cpp b/src/plugins/platforms/eglfs/qeglfscontext.cpp index 06db4e02db..44bc9b2344 100644 --- a/src/plugins/platforms/eglfs/qeglfscontext.cpp +++ b/src/plugins/platforms/eglfs/qeglfscontext.cpp @@ -79,6 +79,7 @@ void QEglFSContext::swapBuffers(QPlatformSurface *surface) cursor->paintOnScreen(); } + hooks->waitForVSync(); QEGLPlatformContext::swapBuffers(surface); } diff --git a/src/plugins/platforms/eglfs/qeglfshooks.h b/src/plugins/platforms/eglfs/qeglfshooks.h index f3b6a28e70..fc1ee16073 100644 --- a/src/plugins/platforms/eglfs/qeglfshooks.h +++ b/src/plugins/platforms/eglfs/qeglfshooks.h @@ -69,6 +69,7 @@ public: virtual bool hasCapability(QPlatformIntegration::Capability cap) const; virtual QEglFSCursor *createCursor(QEglFSScreen *screen) const; virtual bool filterConfig(EGLDisplay display, EGLConfig config) const; + virtual void waitForVSync() const; virtual const char *fbDeviceName() const; }; diff --git a/src/plugins/platforms/eglfs/qeglfshooks_stub.cpp b/src/plugins/platforms/eglfs/qeglfshooks_stub.cpp index a8fa81a6ec..6c036cd680 100644 --- a/src/plugins/platforms/eglfs/qeglfshooks_stub.cpp +++ b/src/plugins/platforms/eglfs/qeglfshooks_stub.cpp @@ -47,9 +47,14 @@ #include #include +#include QT_BEGIN_NAMESPACE +// file descriptor for the frame buffer +// this is a global static to keep the QEglFSHooks interface as clean as possible +static int framebuffer = -1; + const char *QEglFSHooks::fbDeviceName() const { return "/dev/fb0"; @@ -58,10 +63,17 @@ const char *QEglFSHooks::fbDeviceName() const void QEglFSHooks::platformInit() { Q_UNUSED(hooks); + + framebuffer = qt_safe_open(fbDeviceName(), O_RDONLY); + + if (framebuffer == -1) + qWarning("EGLFS: Failed to open %s", fbDeviceName()); } void QEglFSHooks::platformDestroy() { + if (framebuffer != -1) + close(framebuffer); } EGLNativeDisplayType QEglFSHooks::platformDisplay() const @@ -86,22 +98,16 @@ QSizeF QEglFSHooks::physicalScreenSize() const } struct fb_var_screeninfo vinfo; - int fd = open(fbDeviceName(), O_RDONLY); - int w = -1; int h = -1; - if (fd != -1) { - if (ioctl(fd, FBIOGET_VSCREENINFO, &vinfo) == -1) { + if (framebuffer != -1) { + if (ioctl(framebuffer, FBIOGET_VSCREENINFO, &vinfo) == -1) { qWarning("EGLFS: Could not query variable screen info."); } else { w = vinfo.width; h = vinfo.height; } - - close(fd); - } else { - qWarning("EGLFS: Failed to open %s to detect physical screen size.", fbDeviceName()); } const int defaultPhysicalDpi = 100; @@ -140,22 +146,17 @@ QSize QEglFSHooks::screenSize() const } struct fb_var_screeninfo vinfo; - int fd = open(fbDeviceName(), O_RDONLY); int xres = -1; int yres = -1; - if (fd != -1) { - if (ioctl(fd, FBIOGET_VSCREENINFO, &vinfo) == -1) { + if (framebuffer != -1) { + if (ioctl(framebuffer, FBIOGET_VSCREENINFO, &vinfo) == -1) { qWarning("EGLFS: Could not query variable screen info."); } else { xres = vinfo.xres; yres = vinfo.yres; } - - close(fd); - } else { - qWarning("EGLFS: Failed to open %s to detect screen resolution.", fbDeviceName()); } const int defaultWidth = 800; @@ -185,17 +186,12 @@ int QEglFSHooks::screenDepth() const if (depth == 0) { struct fb_var_screeninfo vinfo; - int fd = open(fbDeviceName(), O_RDONLY); - if (fd != -1) { - if (ioctl(fd, FBIOGET_VSCREENINFO, &vinfo) == -1) + if (framebuffer != -1) { + if (ioctl(framebuffer, FBIOGET_VSCREENINFO, &vinfo) == -1) qWarning("EGLFS: Could not query variable screen info."); else depth = vinfo.bits_per_pixel; - - close(fd); - } else { - qWarning("EGLFS: Failed to open %s to detect screen depth.", fbDeviceName()); } const int defaultDepth = 32; @@ -250,6 +246,16 @@ QEglFSCursor *QEglFSHooks::createCursor(QEglFSScreen *screen) const return 0; } +void QEglFSHooks::waitForVSync() const +{ + static const bool forceSync = qgetenv("QT_QPA_EGLFS_FORCEVSYNC").toInt(); + if (forceSync && framebuffer != -1) { + int arg = 0; + if (ioctl(framebuffer, FBIO_WAITFORVSYNC, &arg) == -1) + qWarning("Could not wait for vsync."); + } +} + #ifndef EGLFS_PLATFORM_HOOKS QEglFSHooks stubHooks; #endif