diff options
author | Laszlo Agocs <laszlo.agocs@theqtcompany.com> | 2015-11-03 11:41:01 +0100 |
---|---|---|
committer | Laszlo Agocs <laszlo.agocs@theqtcompany.com> | 2015-11-19 13:56:52 +0000 |
commit | 7c6625b105511191f739d07dc658094ff6f682ac (patch) | |
tree | 60f5cd8cefce4ac559d240988644b49c6259b009 /src/gui/painting/qplatformbackingstore.cpp | |
parent | e1fb3b0b3e38cbe23ed73722952ab90e0a128cfe (diff) |
Support mixing native child widgets with texture-based ones
Currently QOpenGLWidget and QQuickWidget do not support having native
child widgets inside the same top-level window. In some cases this is
inevitable, f.ex. multimedia may require native windows when used from
widget apps. winId() calls made for various (valid or invalid) reasons
are also problematic.
There are no blockers for supporting this setup, however. By storing
multiple texture lists (one for each subtree where the root is a
native widget), adding the missing markDirtyOnScreen calls, letting
each native widget access the correct texture list (i.e. the one
corresponding to its children) when they are (separately) flushed, and
fixing composeAndFlush() to take the update region and the (native
child) offset into account, it can all be made functional.
The change also fixes the issue of keeping GL-based compositing
enabled even after all render-to-texture widgets in the window become
hidden. Due to the changes of how such widgets are gathered,
composeAndFlush() is not invoked anymore when no such widgets are
discovered for a given native parent. This is great since having
compositing enabled infinitely is an issue for applications like Qt
Creator that implement certain views with QQuickWidgets but cannot
afford the cost of texture uploads in other places (e.g. for the text
editor) on slower machines.
The openglwidget manual test is greatly enhanced to test various
situations (MDI, scroll areas, tab widgets, QOpenGLWidget as native
child, QOpenGLWidget with non-tlw native parent, etc.)
Task-number: QTBUG-48130
Task-number: QTBUG-49172
Change-Id: Iad098359c8bcf749f01c050da0853415e1550eda
Reviewed-by: Paul Olav Tvete <paul.tvete@theqtcompany.com>
Reviewed-by: Morten Johan Sørvig <morten.sorvig@theqtcompany.com>
Diffstat (limited to 'src/gui/painting/qplatformbackingstore.cpp')
-rw-r--r-- | src/gui/painting/qplatformbackingstore.cpp | 42 |
1 files changed, 29 insertions, 13 deletions
diff --git a/src/gui/painting/qplatformbackingstore.cpp b/src/gui/painting/qplatformbackingstore.cpp index dd02e24676..5f873bfe7e 100644 --- a/src/gui/painting/qplatformbackingstore.cpp +++ b/src/gui/painting/qplatformbackingstore.cpp @@ -224,16 +224,16 @@ static inline QRect deviceRect(const QRect &rect, QWindow *window) return deviceRect; } -static QRegion deviceRegion(const QRegion ®ion, QWindow *window) +static QRegion deviceRegion(const QRegion ®ion, QWindow *window, const QPoint &offset) { - if (!(window->devicePixelRatio() > 1)) + if (offset.isNull() && window->devicePixelRatio() <= 1) return region; QVector<QRect> rects; const QVector<QRect> regionRects = region.rects(); rects.reserve(regionRects.count()); foreach (const QRect &rect, regionRects) - rects.append(deviceRect(rect, window)); + rects.append(deviceRect(rect.translated(offset), window)); QRegion deviceRegion; deviceRegion.setRects(rects.constData(), rects.count()); @@ -246,10 +246,12 @@ static inline QRect toBottomLeftRect(const QRect &topLeftRect, int windowHeight) topLeftRect.width(), topLeftRect.height()); } -static void blit(const QPlatformTextureList *textures, int idx, QWindow *window, const QRect &deviceWindowRect, - QOpenGLTextureBlitter *blitter) +static void blitTextureForWidget(const QPlatformTextureList *textures, int idx, QWindow *window, const QRect &deviceWindowRect, + QOpenGLTextureBlitter *blitter, const QPoint &offset) { - const QRect rectInWindow = textures->geometry(idx); + QRect rectInWindow = textures->geometry(idx); + // relative to the TLW, not necessarily our window (if the flush is for a native child widget), have to adjust + rectInWindow.translate(-offset); QRect clipRect = textures->clipRect(idx); if (clipRect.isEmpty()) clipRect = QRect(QPoint(0, 0), rectInWindow.size()); @@ -274,7 +276,9 @@ static void blit(const QPlatformTextureList *textures, int idx, QWindow *window, and composes using OpenGL. May be reimplemented in subclasses if there is a more efficient native way to do it. - Note that the \a offset parameter is currently unused. + \note \a region is relative to the window which may not be top-level in case + \a window corresponds to a native child widget. \a offset is the position of + the native child relative to the top-level window. */ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion ®ion, @@ -282,7 +286,8 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion ®i QPlatformTextureList *textures, QOpenGLContext *context, bool translucentBackground) { - Q_UNUSED(offset); + if (!qt_window_private(window)->receivedExpose) + return; if (!context->makeCurrent(window)) { qWarning("composeAndFlush: makeCurrent() failed"); @@ -306,7 +311,7 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion ®i // Textures for renderToTexture widgets. for (int i = 0; i < textures->count(); ++i) { if (!textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) - blit(textures, i, window, deviceWindowRect, d_ptr->blitter); + blitTextureForWidget(textures, i, window, deviceWindowRect, d_ptr->blitter, offset); } funcs->glEnable(GL_BLEND); @@ -348,17 +353,26 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion ®i textureId = d_ptr->textureId; } else { TextureFlags flags = 0; - textureId = toTexture(deviceRegion(region, window), &d_ptr->textureSize, &flags); + textureId = toTexture(deviceRegion(region, window, offset), &d_ptr->textureSize, &flags); d_ptr->needsSwizzle = (flags & TextureSwizzle) != 0; if (flags & TextureFlip) origin = QOpenGLTextureBlitter::OriginBottomLeft; } if (textureId) { - QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(QRect(QPoint(), d_ptr->textureSize), deviceWindowRect); if (d_ptr->needsSwizzle) d_ptr->blitter->setSwizzleRB(true); - d_ptr->blitter->blit(textureId, target, origin); + // offset is usually (0, 0) unless we have native child widgets. + if (offset.isNull()) { + d_ptr->blitter->blit(textureId, QMatrix4x4(), origin); + } else { + // The backingstore is for the entire tlw. offset tells the position of the native child in the tlw. + const QRect srcRect = toBottomLeftRect(deviceWindowRect.translated(offset), d_ptr->textureSize.height()); + const QMatrix3x3 source = QOpenGLTextureBlitter::sourceTransform(deviceRect(srcRect, window), + d_ptr->textureSize, + origin); + d_ptr->blitter->blit(textureId, QMatrix4x4(), source); + } if (d_ptr->needsSwizzle) d_ptr->blitter->setSwizzleRB(false); } @@ -366,7 +380,7 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion ®i // Textures for renderToTexture widgets that have WA_AlwaysStackOnTop set. for (int i = 0; i < textures->count(); ++i) { if (textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) - blit(textures, i, window, deviceWindowRect, d_ptr->blitter); + blitTextureForWidget(textures, i, window, deviceWindowRect, d_ptr->blitter, offset); } funcs->glDisable(GL_BLEND); @@ -413,6 +427,8 @@ QImage QPlatformBackingStore::toImage() const If the image has to be flipped (e.g. because the texture is attached to an FBO), \a flags will be set to include \c TextureFlip. + + \note \a dirtyRegion is relative to the backingstore so no adjustment is needed. */ GLuint QPlatformBackingStore::toTexture(const QRegion &dirtyRegion, QSize *textureSize, TextureFlags *flags) const { |