好久没有上技术累人贴了,今日奉上一贴。
相信很多人已经说过一个问题,就是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平台!欢迎赐教!