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 68a4c5da9a

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;
}
void QOpenGLCompositor::setTarget(QOpenGLContext *context, QWindow *targetWindow,
const QRect &nativeTargetGeometry)
void QOpenGLCompositor::setTargetWindow(QWindow *targetWindow, const QRect &nativeTargetGeometry)
{
m_context = context;
m_targetWindow = targetWindow;
m_nativeTargetGeometry = nativeTargetGeometry;
}
void QOpenGLCompositor::setTargetContext(QOpenGLContext *context)
{
m_context = context;
}
void QOpenGLCompositor::setRotation(int degrees)
{
m_rotation = degrees;

View File

@ -83,7 +83,8 @@ public:
static QOpenGLCompositor *instance();
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);
QOpenGLContext *context() const { return m_context; }
QWindow *targetWindow() const { return m_targetWindow; }

View File

@ -40,7 +40,6 @@
#include <QtGui/QOpenGLContext>
#include <QtGui/QWindow>
#include <QtGui/QPainter>
#include <QtGui/QOffscreenSurface>
#include <qpa/qplatformbackingstore.h>
#include <private/qwindow_p.h>
#include <private/qrhi_p.h>
@ -90,31 +89,12 @@ QOpenGLCompositorBackingStore::QOpenGLCompositorBackingStore(QWindow *window)
QOpenGLCompositorBackingStore::~QOpenGLCompositorBackingStore()
{
if (m_bsTexture) {
QOpenGLContext *ctx = QOpenGLContext::currentContext();
// With render-to-texture-widgets QWidget makes sure the TLW's shareContext() is
// made current before destroying backingstores. That is however not the case for
// windows with regular widgets only.
QScopedPointer<QOffscreenSurface> tempSurface;
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();
if (m_bsTexture && m_rhi) {
delete m_bsTextureWrapper;
// Contexts are sharing resources, won't matter which one is
// current here, use the rhi's shortcut.
m_rhi->makeThreadLocalNativeContextCurrent();
glDeleteTextures(1, &m_bsTexture);
}
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_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);
m_bsTextureWrapper = m_rhi->newTexture(QRhiTexture::RGBA8, m_image.size());
m_bsTextureWrapper->createFrom({m_bsTexture, 0});
} else {
glBindTexture(GL_TEXTURE_2D, m_bsTexture);
}
@ -185,6 +163,11 @@ void QOpenGLCompositorBackingStore::updateTexture()
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)
@ -194,15 +177,25 @@ void QOpenGLCompositorBackingStore::flush(QWindow *window, const QRegion &region
Q_UNUSED(region);
Q_UNUSED(offset);
m_rhi = rhi();
if (!m_rhi) {
setRhiConfig(QPlatformBackingStoreRhiConfig(QPlatformBackingStoreRhiConfig::OpenGL));
m_rhi = rhi();
}
Q_ASSERT(m_rhi);
QOpenGLCompositor *compositor = QOpenGLCompositor::instance();
QOpenGLContext *dstCtx = compositor->context();
Q_ASSERT(dstCtx);
if (!dstCtx)
return;
QWindow *dstWin = compositor->targetWindow();
if (!dstWin)
return;
dstCtx->makeCurrent(dstWin);
if (!dstCtx->makeCurrent(dstWin))
return;
updateTexture();
m_textures->clear();
m_textures->appendTexture(nullptr, m_bsTextureWrapper, window->geometry());
@ -223,16 +216,23 @@ QPlatformBackingStore::FlushResult QOpenGLCompositorBackingStore::rhiFlush(QWind
Q_UNUSED(translucentBackground);
m_rhi = rhi();
if (!m_rhi) {
setRhiConfig(QPlatformBackingStoreRhiConfig(QPlatformBackingStoreRhiConfig::OpenGL));
m_rhi = rhi();
}
Q_ASSERT(m_rhi);
QOpenGLCompositor *compositor = QOpenGLCompositor::instance();
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();
if (!dstWin)
return FlushFailed;
dstCtx->makeCurrent(dstWin);
if (!dstCtx->makeCurrent(dstWin))
return FlushFailed;
QWindowPrivate::get(window)->lastComposeTime.start();

View File

@ -274,7 +274,7 @@ void QOpenGLVertexArrayObjectPrivate::destroy()
vao = 0;
}
if (oldContext && oldContextSurface) {
if (oldContext && oldContextSurface && oldContextSurface->surfaceHandle()) {
if (!oldContext->makeCurrent(oldContextSurface))
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;
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
// is of course slow, but it's safe and reliable. It will not include the mouse
// cursor, which is a plus.

View File

@ -110,7 +110,7 @@ void QEglFSWindow::create()
#ifndef QT_NO_OPENGL
QOpenGLCompositor *compositor = QOpenGLCompositor::instance();
if (screen->primarySurface() != EGL_NO_SURFACE) {
if (Q_UNLIKELY(!isRaster() || !compositor->targetWindow())) {
if (Q_UNLIKELY(isRaster() != (compositor->targetWindow() != nullptr))) {
# ifndef Q_OS_ANDROID
// We can have either a single OpenGL window or multiple raster windows.
// Other combinations cannot work.
@ -137,21 +137,30 @@ void QEglFSWindow::create()
screen->setPrimarySurface(m_surface);
#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->setShareContext(qt_gl_global_share_context());
m_rasterCompositingContext->setFormat(m_format);
m_rasterCompositingContext->setScreen(window()->screen());
if (Q_UNLIKELY(!m_rasterCompositingContext->create()))
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
// composited, all other contexts must share with its context.
if (!qt_gl_global_share_context())
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()
@ -352,7 +361,7 @@ WId QEglFSWindow::winId() const
void QEglFSWindow::setOpacity(qreal)
{
if (!isRaster())
if (!isRaster() && !backingStore())
qWarning("QEglFSWindow: Cannot set opacity for non-raster windows");
// Nothing to do here. The opacity is stored in the QWindow.

View File

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