Qt5.5 支持eglfs旋转(Support rotation for raster content in eglfs)

好久没有上技术累人贴了,今日奉上一贴。
相信很多人已经说过一个问题,就是QT5在嵌入式设备上不能旋转的问题。即使可以旋转你也不一定正好使用的是QML,即使你正好使用的是QML你也不一定有这个魄力铺天盖地的添加transform,正如“史蒂夫嘰嘰叫” 在 QT5 EGLFS rotate screen 说的一样,很遗憾这个blog在长城里面是不能访问的,不过文章的大意就是修改EGLFS去使得屏幕旋转90度。好吧,QTBUG-39959 这篇文章或许可以在长城里面访问到。

但是,很遗憾,这个是Qt5.3左右的代码,那个时候还有qeglcompositor.cpp,在Qt5.5已经没有这只文件了,而且qeglfshooks_stub.cpp 这只文件也遗憾的没有了,肿么办?肿么办?

木有关系,只要看懂了“史蒂夫嘰嘰叫”的文章,其实还是比较容易改的。但是总有读者看不懂!也没有关系,看懂这篇文章也可以。实话实说,开始了:

qeglcompositor.cpp 在QT 5.5里面变成了QOpenGLCompositor在文件
qtbase/src/platformsupport/platformcompositor/qopenglcompositor.cpp 中实现。请找到void QOpenGLCompositor::render函数,在blit之前做一次旋转变换就好了,代码如下:

    for (int i = 0; i < textures->count(); ++i) {
        uint textureId = textures->textureId(i);
        const float opacity = window->sourceWindow()->opacity();
        if (opacity != currentOpacity) {
            currentOpacity = opacity;
            m_blitter.setOpacity(currentOpacity);
        }

        if (textures->count() > 1 && i == textures->count() - 1) {
            // Backingstore for a widget with QOpenGLWidget subwidgets
            blend.set(true);
            const QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(textures->geometry(i), targetWindowRect);
            m_blitter.blit(textureId, target, QOpenGLTextureBlitter::OriginTopLeft);
        } else if (textures->count() == 1) {
            // A regular QWidget window
#if 0
            // normal
            const bool translucent = window->sourceWindow()->requestedFormat().alphaBufferSize() > 0;
            blend.set(translucent);
            const QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(textures->geometry(i), targetWindowRect);
            m_blitter.blit(textureId, target, QOpenGLTextureBlitter::OriginTopLeft);
#else
            // rotate 90
            const bool translucent = window->sourceWindow()->requestedFormat().alphaBufferSize() > 0;
            blend.set(translucent);
            QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(textures->geometry(i), targetWindowRect);
            target.rotate(90,0,0,1);
            m_blitter.blit(textureId, target, QOpenGLTextureBlitter::OriginTopLeft);
#endif      
        } else if (!textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) {
            // Texture from an FBO belonging to a QOpenGLWidget
            blend.set(false);
            clippedBlit(textures, i, targetWindowRect, &m_blitter);
        }
    }

编译以后你会发现,画面被拉长了一样,肿么办?找到void QOpenGLCompositor::renderAll函数,把viewport修改一下,如果是旋转180度之类的,这一步是不需要的。代码修改如下:

    if (fbo)
        fbo->bind();

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

    const QRect targetWindowRect(QPoint(0, 0), m_targetWindow->geometry().size());

#if 0
    // normal
    glViewport(0, 0, targetWindowRect.width(), targetWindowRect.height());
#else
    // rotate 90
    glViewport(0, 0, targetWindowRect.height(), targetWindowRect.width()); //swap width / height
#endif

    if (!m_blitter.isCreated())
        m_blitter.create();

    m_blitter.bind();

是不是一切就要变的很美好了?编译运行一看,还是一片狼藉。好了,旋转是一方面,我们还要告(qi)诉(pian)系统显示的分辨率变了。这个时候需要找到 qtbase/src/plugins/platforms/eglfs/deviceintegration/qeglfsvivintegration.cpp

我突然想到,当然这里要排除一种情况,那就是各位的显示屏是方的,正方形的方,如果是方的显示屏这些问题都没有,愉快啊。

上代码:

    int width, height;

    bool multiBufferNotEnabledYet = qEnvironmentVariableIsEmpty("FB_MULTI_BUFFER");
    bool multiBuffer = qEnvironmentVariableIsEmpty("QT_EGLFS_IMX6_NO_FB_MULTI_BUFFER");
    if (multiBufferNotEnabledYet && multiBuffer) {
        qWarning() << "QEglFSVivIntegration will set environment variable FB_MULTI_BUFFER=2 to enable double buffering and vsync.\n"
                   << "If this is not desired, you can override this via: export QT_EGLFS_IMX6_NO_FB_MULTI_BUFFER=1";
        qputenv("FB_MULTI_BUFFER", "2");
    }

    mNativeDisplay = fbGetDisplayByIndex(framebufferIndex());
    fbGetDisplayGeometry(mNativeDisplay, &width, &height);
#if 0
    // normal
    mScreenSize.setHeight(height);
    mScreenSize.setWidth(width);
#else
    // rotate 90
    mScreenSize.setHeight(width);
    mScreenSize.setWidth(height);
#endif

运行的结果让人欢喜让人愁,不对,只显示了一部分,虽然画面没有被拉伸或者扭曲。思考,思考,科学不是撞大运,认真冷静的分析一下。
原始画面是1024x768,旋转以后变为768x1024,在768x1024的画面中,我们只能看到上半部分,且显示的原点这些都对,很奇怪,这样说明我们的旋转其实是没有任何错误的,真相只有一个,窗口在渲染的时候只渲染了一部分!是时候改变了

EGLNativeWindowType QEglFSVivIntegration::createNativeWindow(QPlatformWindow *window, const QSize &size, const QSurfaceFormat &format)
{
    Q_UNUSED(window)
    Q_UNUSED(format)
#if 0
    // normal
    EGLNativeWindowType eglWindow = fbCreateWindow(mNativeDisplay, 0, 0, size.width(), size.height());
#else
    // rotate 90
    EGLNativeWindowType eglWindow = fbCreateWindow(mNativeDisplay, 0, 0, size.height(), size.width());
#endif
    return eglWindow;
}

运行程序大功告成。
我用的是freescale/imx6平台!欢迎赐教!

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值