Revive eglfs' raster window support

A number of consequences of the new rhi-based backingstore
composition were not handled. Most importantly, the fact
that RasterGLSurface is not a thing anymore in practice
causes challenges because we can no longer decide just
based on the surfaceType what a QWindow with OpenGLSurface
would be. (a plain GL window or a GL window with a backing
store?) Also, the backingstore needs to be able to initialize
its backing QRhi by itself, because with eglfs going through
OpenGL is the only way.

Amends 68a4c5da9a080101cccd8a3b2edb1c908da0ca8e

Fixes: QTBUG-102750
Change-Id: Ia1ca59d01e3012264a76b50e591612fdcc2a0bd6
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Andy Nichols <andy.nichols@qt.io>
This commit is contained in:
Laszlo Agocs 2022-04-26 03:57:12 -07:00
parent 9861fd09cb
commit 8161726619
7 changed files with 61 additions and 48 deletions

View File

@ -94,14 +94,17 @@ QOpenGLCompositor::~QOpenGLCompositor()
compositor = 0; compositor = 0;
} }
void QOpenGLCompositor::setTarget(QOpenGLContext *context, QWindow *targetWindow, void QOpenGLCompositor::setTargetWindow(QWindow *targetWindow, const QRect &nativeTargetGeometry)
const QRect &nativeTargetGeometry)
{ {
m_context = context;
m_targetWindow = targetWindow; m_targetWindow = targetWindow;
m_nativeTargetGeometry = nativeTargetGeometry; m_nativeTargetGeometry = nativeTargetGeometry;
} }
void QOpenGLCompositor::setTargetContext(QOpenGLContext *context)
{
m_context = context;
}
void QOpenGLCompositor::setRotation(int degrees) void QOpenGLCompositor::setRotation(int degrees)
{ {
m_rotation = degrees; m_rotation = degrees;

View File

@ -83,7 +83,8 @@ public:
static QOpenGLCompositor *instance(); static QOpenGLCompositor *instance();
static void destroy(); static void destroy();
void setTarget(QOpenGLContext *context, QWindow *window, const QRect &nativeTargetGeometry); void setTargetWindow(QWindow *window, const QRect &nativeTargetGeometry);
void setTargetContext(QOpenGLContext *context);
void setRotation(int degrees); void setRotation(int degrees);
QOpenGLContext *context() const { return m_context; } QOpenGLContext *context() const { return m_context; }
QWindow *targetWindow() const { return m_targetWindow; } QWindow *targetWindow() const { return m_targetWindow; }

View File

@ -40,7 +40,6 @@
#include <QtGui/QOpenGLContext> #include <QtGui/QOpenGLContext>
#include <QtGui/QWindow> #include <QtGui/QWindow>
#include <QtGui/QPainter> #include <QtGui/QPainter>
#include <QtGui/QOffscreenSurface>
#include <qpa/qplatformbackingstore.h> #include <qpa/qplatformbackingstore.h>
#include <private/qwindow_p.h> #include <private/qwindow_p.h>
#include <private/qrhi_p.h> #include <private/qrhi_p.h>
@ -90,31 +89,12 @@ QOpenGLCompositorBackingStore::QOpenGLCompositorBackingStore(QWindow *window)
QOpenGLCompositorBackingStore::~QOpenGLCompositorBackingStore() QOpenGLCompositorBackingStore::~QOpenGLCompositorBackingStore()
{ {
if (m_bsTexture) { if (m_bsTexture && m_rhi) {
QOpenGLContext *ctx = QOpenGLContext::currentContext(); delete m_bsTextureWrapper;
// With render-to-texture-widgets QWidget makes sure the TLW's shareContext() is // Contexts are sharing resources, won't matter which one is
// made current before destroying backingstores. That is however not the case for // current here, use the rhi's shortcut.
// windows with regular widgets only. m_rhi->makeThreadLocalNativeContextCurrent();
QScopedPointer<QOffscreenSurface> tempSurface; glDeleteTextures(1, &m_bsTexture);
if (!ctx) {
ctx = QOpenGLCompositor::instance()->context();
if (ctx) {
tempSurface.reset(new QOffscreenSurface);
tempSurface->setFormat(ctx->format());
tempSurface->create();
ctx->makeCurrent(tempSurface.data());
}
}
if (m_bsTextureContext && ctx && ctx->shareGroup() == m_bsTextureContext->shareGroup()) {
delete m_bsTextureWrapper;
glDeleteTextures(1, &m_bsTexture);
} else {
qWarning("QOpenGLCompositorBackingStore: Texture is not valid in the current context");
}
if (tempSurface && ctx)
ctx->doneCurrent();
} }
delete m_textures; // this does not actually own any GL resources delete m_textures; // this does not actually own any GL resources
@ -137,8 +117,6 @@ void QOpenGLCompositorBackingStore::updateTexture()
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_image.width(), m_image.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_image.width(), m_image.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
m_bsTextureWrapper = m_rhi->newTexture(QRhiTexture::RGBA8, m_image.size());
m_bsTextureWrapper->createFrom({m_bsTexture, 0});
} else { } else {
glBindTexture(GL_TEXTURE_2D, m_bsTexture); glBindTexture(GL_TEXTURE_2D, m_bsTexture);
} }
@ -185,6 +163,11 @@ void QOpenGLCompositorBackingStore::updateTexture()
m_dirty = QRegion(); m_dirty = QRegion();
} }
if (!m_bsTextureWrapper) {
m_bsTextureWrapper = m_rhi->newTexture(QRhiTexture::RGBA8, m_image.size());
m_bsTextureWrapper->createFrom({m_bsTexture, 0});
}
} }
void QOpenGLCompositorBackingStore::flush(QWindow *window, const QRegion &region, const QPoint &offset) void QOpenGLCompositorBackingStore::flush(QWindow *window, const QRegion &region, const QPoint &offset)
@ -194,15 +177,25 @@ void QOpenGLCompositorBackingStore::flush(QWindow *window, const QRegion &region
Q_UNUSED(region); Q_UNUSED(region);
Q_UNUSED(offset); Q_UNUSED(offset);
m_rhi = rhi();
if (!m_rhi) {
setRhiConfig(QPlatformBackingStoreRhiConfig(QPlatformBackingStoreRhiConfig::OpenGL));
m_rhi = rhi();
}
Q_ASSERT(m_rhi);
QOpenGLCompositor *compositor = QOpenGLCompositor::instance(); QOpenGLCompositor *compositor = QOpenGLCompositor::instance();
QOpenGLContext *dstCtx = compositor->context(); QOpenGLContext *dstCtx = compositor->context();
Q_ASSERT(dstCtx); if (!dstCtx)
return;
QWindow *dstWin = compositor->targetWindow(); QWindow *dstWin = compositor->targetWindow();
if (!dstWin) if (!dstWin)
return; return;
dstCtx->makeCurrent(dstWin); if (!dstCtx->makeCurrent(dstWin))
return;
updateTexture(); updateTexture();
m_textures->clear(); m_textures->clear();
m_textures->appendTexture(nullptr, m_bsTextureWrapper, window->geometry()); m_textures->appendTexture(nullptr, m_bsTextureWrapper, window->geometry());
@ -223,16 +216,23 @@ QPlatformBackingStore::FlushResult QOpenGLCompositorBackingStore::rhiFlush(QWind
Q_UNUSED(translucentBackground); Q_UNUSED(translucentBackground);
m_rhi = rhi(); m_rhi = rhi();
if (!m_rhi) {
setRhiConfig(QPlatformBackingStoreRhiConfig(QPlatformBackingStoreRhiConfig::OpenGL));
m_rhi = rhi();
}
Q_ASSERT(m_rhi);
QOpenGLCompositor *compositor = QOpenGLCompositor::instance(); QOpenGLCompositor *compositor = QOpenGLCompositor::instance();
QOpenGLContext *dstCtx = compositor->context(); QOpenGLContext *dstCtx = compositor->context();
Q_ASSERT(dstCtx); // setTarget() must have been called before, e.g. from QEGLFSWindow if (!dstCtx)
return FlushFailed;
QWindow *dstWin = compositor->targetWindow(); QWindow *dstWin = compositor->targetWindow();
if (!dstWin) if (!dstWin)
return FlushFailed; return FlushFailed;
dstCtx->makeCurrent(dstWin); if (!dstCtx->makeCurrent(dstWin))
return FlushFailed;
QWindowPrivate::get(window)->lastComposeTime.start(); QWindowPrivate::get(window)->lastComposeTime.start();

View File

@ -274,7 +274,7 @@ void QOpenGLVertexArrayObjectPrivate::destroy()
vao = 0; vao = 0;
} }
if (oldContext && oldContextSurface) { if (oldContext && oldContextSurface && oldContextSurface->surfaceHandle()) {
if (!oldContext->makeCurrent(oldContextSurface)) if (!oldContext->makeCurrent(oldContextSurface))
qWarning("QOpenGLVertexArrayObject::destroy() failed to restore current context"); qWarning("QOpenGLVertexArrayObject::destroy() failed to restore current context");
} }

View File

@ -201,7 +201,8 @@ QPixmap QEglFSScreen::grabWindow(WId wid, int x, int y, int width, int height) c
QImage img; QImage img;
if (static_cast<QEglFSWindow *>(windows.first()->sourceWindow()->handle())->isRaster()) { QEglFSWindow *primaryWin = static_cast<QEglFSWindow *>(windows.first()->sourceWindow()->handle());
if (primaryWin->isRaster() || primaryWin->backingStore()) {
// Request the compositor to render everything into an FBO and read it back. This // Request the compositor to render everything into an FBO and read it back. This
// is of course slow, but it's safe and reliable. It will not include the mouse // is of course slow, but it's safe and reliable. It will not include the mouse
// cursor, which is a plus. // cursor, which is a plus.

View File

@ -110,7 +110,7 @@ void QEglFSWindow::create()
#ifndef QT_NO_OPENGL #ifndef QT_NO_OPENGL
QOpenGLCompositor *compositor = QOpenGLCompositor::instance(); QOpenGLCompositor *compositor = QOpenGLCompositor::instance();
if (screen->primarySurface() != EGL_NO_SURFACE) { if (screen->primarySurface() != EGL_NO_SURFACE) {
if (Q_UNLIKELY(!isRaster() || !compositor->targetWindow())) { if (Q_UNLIKELY(isRaster() != (compositor->targetWindow() != nullptr))) {
# ifndef Q_OS_ANDROID # ifndef Q_OS_ANDROID
// We can have either a single OpenGL window or multiple raster windows. // We can have either a single OpenGL window or multiple raster windows.
// Other combinations cannot work. // Other combinations cannot work.
@ -137,21 +137,30 @@ void QEglFSWindow::create()
screen->setPrimarySurface(m_surface); screen->setPrimarySurface(m_surface);
#ifndef QT_NO_OPENGL #ifndef QT_NO_OPENGL
if (isRaster()) { compositor->setTargetWindow(window(), screen->rawGeometry());
compositor->setRotation(qEnvironmentVariableIntValue("QT_QPA_EGLFS_ROTATION"));
#endif
}
void QEglFSWindow::setBackingStore(QOpenGLCompositorBackingStore *backingStore)
{
#ifndef QT_NO_OPENGL
if (!m_rasterCompositingContext) {
m_rasterCompositingContext = new QOpenGLContext; m_rasterCompositingContext = new QOpenGLContext;
m_rasterCompositingContext->setShareContext(qt_gl_global_share_context()); m_rasterCompositingContext->setShareContext(qt_gl_global_share_context());
m_rasterCompositingContext->setFormat(m_format); m_rasterCompositingContext->setFormat(m_format);
m_rasterCompositingContext->setScreen(window()->screen()); m_rasterCompositingContext->setScreen(window()->screen());
if (Q_UNLIKELY(!m_rasterCompositingContext->create())) if (Q_UNLIKELY(!m_rasterCompositingContext->create()))
qFatal("EGLFS: Failed to create compositing context"); qFatal("EGLFS: Failed to create compositing context");
compositor->setTarget(m_rasterCompositingContext, window(), screen->rawGeometry());
compositor->setRotation(qEnvironmentVariableIntValue("QT_QPA_EGLFS_ROTATION"));
// If there is a "root" window into which raster and QOpenGLWidget content is // If there is a "root" window into which raster and QOpenGLWidget content is
// composited, all other contexts must share with its context. // composited, all other contexts must share with its context.
if (!qt_gl_global_share_context()) if (!qt_gl_global_share_context())
qt_gl_set_global_share_context(m_rasterCompositingContext); qt_gl_set_global_share_context(m_rasterCompositingContext);
} }
#endif // QT_NO_OPENGL QOpenGLCompositor *compositor = QOpenGLCompositor::instance();
compositor->setTargetContext(m_rasterCompositingContext);
#endif
m_backingStore = backingStore;
} }
void QEglFSWindow::destroy() void QEglFSWindow::destroy()
@ -352,7 +361,7 @@ WId QEglFSWindow::winId() const
void QEglFSWindow::setOpacity(qreal) void QEglFSWindow::setOpacity(qreal)
{ {
if (!isRaster()) if (!isRaster() && !backingStore())
qWarning("QEglFSWindow: Cannot set opacity for non-raster windows"); qWarning("QEglFSWindow: Cannot set opacity for non-raster windows");
// Nothing to do here. The opacity is stored in the QWindow. // Nothing to do here. The opacity is stored in the QWindow.

View File

@ -103,12 +103,11 @@ public:
void invalidateSurface() override; void invalidateSurface() override;
virtual void resetSurface(); virtual void resetSurface();
bool isRaster() const;
#ifndef QT_NO_OPENGL #ifndef QT_NO_OPENGL
QOpenGLCompositorBackingStore *backingStore() { return m_backingStore; } QOpenGLCompositorBackingStore *backingStore() { return m_backingStore; }
void setBackingStore(QOpenGLCompositorBackingStore *backingStore) { m_backingStore = backingStore; } void setBackingStore(QOpenGLCompositorBackingStore *backingStore);
#endif
bool isRaster() const;
#ifndef QT_NO_OPENGL
QWindow *sourceWindow() const override; QWindow *sourceWindow() const override;
const QPlatformTextureList *textures() const override; const QPlatformTextureList *textures() const override;
void endCompositing() override; void endCompositing() override;