2015年3月17日 星期二

QT5 EGLFS rotate screen

I'm working on new project with QT 5.4 and needs to rotate screen 90 degree. After searching on the internet, I found that the only way to do is QML : transform. The dark side of this solution is every widget has to transform, it's such a mass @@.

https://forum.qt.io/topic/22852/qt-5-embedded-screen-rotation

Then I found this and decide to do my 90 degree screen rotation.

https://bugreports.qt.io/browse/QTBUG-39959

I did some modification as follow and it works :)

#
Patch qt5base-5.4.0/src/platformsupport/eglconvenience/qeglcompositor.cpp
#

--- qt5base-5.4.0.original/src/platformsupport/eglconvenience/qeglcompositor.cpp 2014-12-06 00:24:30.000000000 +0800
+++ qt5base-5.4.0/src/platformsupport/eglconvenience/qeglcompositor.cpp 2015-03-17 19:58:59.223562515 +0800
@@ -44,6 +44,7 @@
 QT_BEGIN_NAMESPACE

 static QEGLCompositor *compositor = 0;
+static bool rotate90 = 0;

 QEGLCompositor::QEGLCompositor()
     : m_context(0),
@@ -54,6 +55,8 @@
     m_updateTimer.setSingleShot(true);
     m_updateTimer.setInterval(0);
     connect(&m_updateTimer, SIGNAL(timeout()), SLOT(renderAll()));
+
+    rotate90 = qgetenv("QT_QPA_EGLFS_ROTATE90").toInt();
 }

 QEGLCompositor::~QEGLCompositor()
@@ -127,7 +130,10 @@
         return;

     const QRect targetWindowRect(QPoint(0, 0), window->screen()->geometry().size());
-    glViewport(0, 0, targetWindowRect.width(), targetWindowRect.height());
+    if(rotate90)
+        glViewport(0, 0, targetWindowRect.height(), targetWindowRect.width());
+    else
+        glViewport(0, 0, targetWindowRect.width(), targetWindowRect.height());

     float currentOpacity = 1.0f;
     BlendStateBinder blend;
@@ -136,6 +142,9 @@
         uint textureId = textures->textureId(i);
         QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(textures->geometry(i),
                                                                    targetWindowRect);
+        if(rotate90)
+            target.rotate(90, 0, 0, 1);
+
         const float opacity = window->window()->opacity();
         if (opacity != currentOpacity) {
             currentOpacity = opacity;
@@ -161,6 +170,8 @@
     for (int i = 0; i < textures->count(); ++i) {
         if (textures->stacksOnTop(i)) {
             QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(textures->geometry(i), targetWindowRect);
+            if(rotate90)
+                target.rotate(90, 0, 0, 1);
             blend.set(true);
             m_blitter->blit(textures->textureId(i), target, QOpenGLTextureBlitter::OriginBottomLeft);
         }

#
# Patch qt5base-5.4.0/src/plugins/platforms/eglfs/qeglfshooks_stub.cpp
#

--- qt5base-5.4.0.original/src/plugins/platforms/eglfs/qeglfshooks_stub.cpp 2015-01-27 15:31:55.000000000 +0800
+++ qt5base-5.4.0/src/plugins/platforms/eglfs/qeglfshooks_stub.cpp 2015-03-17 16:58:28.887420851 +0800
@@ -166,6 +166,14 @@
         .width = (short unsigned int)size.width(),
         .height = (short unsigned int)size.height(),
     };
+
+    static const bool rotate90 = qgetenv("QT_QPA_EGLFS_ROTATE90").toInt();
+
+    if(rotate90) {
+        native_window.width = (short unsigned int)size.height();
+        native_window.height = (short unsigned int)size.width();
+    }
+
     return &native_window;
 }

#
#
#

After rebuild qt5base, make sure the following environment variables are correct
For example, my screen resolution is 800x480 with touch.

export QT_QPA_EGLFS_ROTATE90=1

export QT_QPA_EGLFS_PHYSICAL_WIDTH=88
export QT_QPA_EGLFS_PHYSICAL_HEIGHT=156

export QT_QPA_EGLFS_WIDTH=480
export QT_QPA_EGLFS_HEIGHT=800

export QT_QPA_EVDEV_TOUCHSCREEN_PARAMETERS="rotate=180"

Below is example code working with QML

#
# main.cpp
#

#include <QApplication>
#include <QSurfaceFormat>

#include <QtQuickWidgets/QQuickWidget>
#include <QQmlContext>
#include <QQmlProperty>

int main(int argc, char **argv)
{
    QApplication app(argc, argv);

    QSurfaceFormat fmt;
    fmt.setSamples(4);
    QSurfaceFormat::setDefaultFormat(fmt);

    QQuickWidget *w = new QQuickWidget;
    w->setSource(QUrl("./rect.qml"));

    w->show();

    return app.exec();
}

#
# rect.qml
#

import QtQuick 2.1

Rectangle {
    property alias text: textItem.text
    width: 156
    height: 35
    Text {
        width: 150
        height: 20
        text: qsTr("Hello World")
        id: textItem
    }
}