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

4 則留言:

  1. Steve, hello.
    Great thanks for your job.
    I'm porting my app from Qt4.8 to Qt5.4 and your patch was very suitable.
    Graphical view working fine, but I have a great problem with input from touchscreen.
    I tried and evdev, and tslib - no luck.
    I want to ask - your application proccessing input?
    Thanks.

    回覆刪除
    回覆
    1. Make sure the input device node of your touchscreen (For example, /dev/input/event0).
      Then
      $ cat /dev/input/event0

      touch your touchscreen and see if there's any output on you console. If there's no response check your touchscreen driver else check you tslib environment variables

      Good luck

      刪除
  2. Very useful post. This is the easiest way to check what is my screen resolution.
    what is my screen resolution

    回覆刪除