diff --git a/src/gui/painting/qplatformbackingstore.cpp b/src/gui/painting/qplatformbackingstore.cpp index e87f796888..76269f6e65 100644 --- a/src/gui/painting/qplatformbackingstore.cpp +++ b/src/gui/painting/qplatformbackingstore.cpp @@ -82,9 +82,10 @@ public: struct QBackingstoreTextureInfo { + QWidget *widget; // may be null GLuint textureId; QRect rect; - bool stacksOnTop; + QPlatformTextureList::Flags flags; }; Q_DECLARE_TYPEINFO(QBackingstoreTextureInfo, Q_MOVABLE_TYPE); @@ -122,10 +123,16 @@ GLuint QPlatformTextureList::textureId(int index) const return d->textures.at(index).textureId; } -bool QPlatformTextureList::stacksOnTop(int index) const +QWidget *QPlatformTextureList::widget(int index) { Q_D(const QPlatformTextureList); - return d->textures.at(index).stacksOnTop; + return d->textures.at(index).widget; +} + +QPlatformTextureList::Flags QPlatformTextureList::flags(int index) const +{ + Q_D(const QPlatformTextureList); + return d->textures.at(index).flags; } QRect QPlatformTextureList::geometry(int index) const @@ -149,13 +156,14 @@ bool QPlatformTextureList::isLocked() const return d->locked; } -void QPlatformTextureList::appendTexture(GLuint textureId, const QRect &geometry, bool stacksOnTop) +void QPlatformTextureList::appendTexture(QWidget *widget, GLuint textureId, const QRect &geometry, Flags flags) { Q_D(QPlatformTextureList); QBackingstoreTextureInfo bi; + bi.widget = widget; bi.textureId = textureId; bi.rect = geometry; - bi.stacksOnTop = stacksOnTop; + bi.flags = flags; d->textures.append(bi); } @@ -245,7 +253,7 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion ®i // Textures for renderToTexture widgets. for (int i = 0; i < textures->count(); ++i) { - if (!textures->stacksOnTop(i)) { + if (!textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) { QRect targetRect = deviceRect(textures->geometry(i), window); QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(targetRect, windowRect); d_ptr->blitter->blit(textures->textureId(i), target, QOpenGLTextureBlitter::OriginBottomLeft); @@ -272,7 +280,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->stacksOnTop(i)) { + if (textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) { QRect targetRect = deviceRect(textures->geometry(i), window); QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(targetRect, windowRect); d_ptr->blitter->blit(textures->textureId(i), target, QOpenGLTextureBlitter::OriginBottomLeft); diff --git a/src/gui/painting/qplatformbackingstore.h b/src/gui/painting/qplatformbackingstore.h index 52c263f05d..c69612ca44 100644 --- a/src/gui/painting/qplatformbackingstore.h +++ b/src/gui/painting/qplatformbackingstore.h @@ -69,6 +69,11 @@ class Q_GUI_EXPORT QPlatformTextureList : public QObject Q_OBJECT Q_DECLARE_PRIVATE(QPlatformTextureList) public: + enum Flag { + StacksOnTop = 0x01 + }; + Q_DECLARE_FLAGS(Flags, Flag) + explicit QPlatformTextureList(QObject *parent = 0); ~QPlatformTextureList(); @@ -76,16 +81,18 @@ public: bool isEmpty() const { return count() == 0; } GLuint textureId(int index) const; QRect geometry(int index) const; - bool stacksOnTop(int index) const; + QWidget *widget(int index); + Flags flags(int index) const; void lock(bool on); bool isLocked() const; - void appendTexture(GLuint textureId, const QRect &geometry, bool stacksOnTop = false); + void appendTexture(QWidget *widget, GLuint textureId, const QRect &geometry, Flags flags = 0); void clear(); Q_SIGNALS: void locked(bool); }; +Q_DECLARE_OPERATORS_FOR_FLAGS(QPlatformTextureList::Flags) #endif class Q_GUI_EXPORT QPlatformBackingStore diff --git a/src/platformsupport/eglconvenience/qeglcompositor.cpp b/src/platformsupport/eglconvenience/qeglcompositor.cpp index 5866edc48d..a46e5698de 100644 --- a/src/platformsupport/eglconvenience/qeglcompositor.cpp +++ b/src/platformsupport/eglconvenience/qeglcompositor.cpp @@ -151,7 +151,7 @@ void QEGLCompositor::render(QEGLPlatformWindow *window) const bool translucent = window->window()->requestedFormat().alphaBufferSize() > 0; blend.set(translucent); m_blitter->blit(textureId, target, QOpenGLTextureBlitter::OriginTopLeft); - } else if (!textures->stacksOnTop(i)) { + } else if (!textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) { // Texture from an FBO belonging to a QOpenGLWidget blend.set(false); m_blitter->blit(textureId, target, QOpenGLTextureBlitter::OriginBottomLeft); @@ -159,7 +159,7 @@ void QEGLCompositor::render(QEGLPlatformWindow *window) } for (int i = 0; i < textures->count(); ++i) { - if (textures->stacksOnTop(i)) { + if (textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) { QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(textures->geometry(i), targetWindowRect); blend.set(true); m_blitter->blit(textures->textureId(i), target, QOpenGLTextureBlitter::OriginBottomLeft); diff --git a/src/platformsupport/eglconvenience/qeglplatformbackingstore.cpp b/src/platformsupport/eglconvenience/qeglplatformbackingstore.cpp index 43c18573f2..d7d95ea97d 100644 --- a/src/platformsupport/eglconvenience/qeglplatformbackingstore.cpp +++ b/src/platformsupport/eglconvenience/qeglplatformbackingstore.cpp @@ -152,7 +152,7 @@ void QEGLPlatformBackingStore::flush(QWindow *window, const QRegion ®ion, con screen->compositingContext()->makeCurrent(dstWin->window()); updateTexture(); m_textures->clear(); - m_textures->appendTexture(m_bsTexture, window->geometry()); + m_textures->appendTexture(Q_NULLPTR, m_bsTexture, window->geometry()); composite(screen->compositingContext(), dstWin); } @@ -176,10 +176,10 @@ void QEGLPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion &r m_textures->clear(); for (int i = 0; i < textures->count(); ++i) - m_textures->appendTexture(textures->textureId(i), textures->geometry(i), textures->stacksOnTop(i)); + m_textures->appendTexture(textures->widget(i), textures->textureId(i), textures->geometry(i), textures->flags(i)); updateTexture(); - m_textures->appendTexture(m_bsTexture, window->geometry()); + m_textures->appendTexture(Q_NULLPTR, m_bsTexture, window->geometry()); textures->lock(true); m_lockedWidgetTextures = textures; diff --git a/src/widgets/kernel/qwidgetbackingstore.cpp b/src/widgets/kernel/qwidgetbackingstore.cpp index 9f014aa4fe..cd01869af2 100644 --- a/src/widgets/kernel/qwidgetbackingstore.cpp +++ b/src/widgets/kernel/qwidgetbackingstore.cpp @@ -963,9 +963,12 @@ void QWidgetBackingStore::sync(QWidget *exposedWidget, const QRegion &exposedReg static void findTextureWidgetsRecursively(QWidget *tlw, QWidget *widget, QPlatformTextureList *widgetTextures) { QWidgetPrivate *wd = QWidgetPrivate::get(widget); - if (wd->renderToTexture) - widgetTextures->appendTexture(wd->textureId(), QRect(widget->mapTo(tlw, QPoint()), widget->size()), - widget->testAttribute(Qt::WA_AlwaysStackOnTop)); + if (wd->renderToTexture) { + QPlatformTextureList::Flags flags = 0; + if (widget->testAttribute(Qt::WA_AlwaysStackOnTop)) + flags |= QPlatformTextureList::StacksOnTop; + widgetTextures->appendTexture(widget, wd->textureId(), QRect(widget->mapTo(tlw, QPoint()), widget->size()), flags); + } for (int i = 0; i < wd->children.size(); ++i) { QWidget *w = qobject_cast(wd->children.at(i)); @@ -1156,28 +1159,20 @@ void QWidgetBackingStore::doSync() } #ifndef QT_NO_OPENGL - // There is something other dirty than the renderToTexture widgets. - // Now it is time to include the renderToTexture ones among the others. if (widgetTextures && widgetTextures->count()) { for (int i = 0; i < widgetTextures->count(); ++i) { - const QRect rect = widgetTextures->geometry(i); // mapped to the tlw already - dirty += rect; - toClean += rect; + QWidget *w = widgetTextures->widget(i); + if (dirtyRenderToTextureWidgets.contains(w)) { + const QRect rect = widgetTextures->geometry(i); // mapped to the tlw already + dirty += rect; + toClean += rect; + } } } -#endif - - // The dirtyRenderToTextureWidgets list is useless here, so just reset. As - // unintuitive as it is, we need to send paint events to renderToTexture - // widgets always when something (any widget) needs to be updated, even if - // the renderToTexture widget itself is clean, i.e. there was no update() - // call for it. This is because changing any widget will cause a flush and - // so a potentially blocking buffer swap for the window, and skipping paints - // for the renderToTexture widgets would make it impossible to have smoothly - // animated content in them. for (int i = 0; i < dirtyRenderToTextureWidgets.count(); ++i) resetWidget(dirtyRenderToTextureWidgets.at(i)); dirtyRenderToTextureWidgets.clear(); +#endif #ifndef QT_NO_GRAPHICSVIEW if (tlw->d_func()->extra->proxyWidget) { diff --git a/tests/auto/widgets/widgets/qopenglwidget/tst_qopenglwidget.cpp b/tests/auto/widgets/widgets/qopenglwidget/tst_qopenglwidget.cpp index d309b0840e..2ac31bfe1b 100644 --- a/tests/auto/widgets/widgets/qopenglwidget/tst_qopenglwidget.cpp +++ b/tests/auto/widgets/widgets/qopenglwidget/tst_qopenglwidget.cpp @@ -34,6 +34,11 @@ #include #include #include +#include +#include +#include +#include +#include #include #include @@ -49,6 +54,7 @@ private slots: void painter(); void reparentToAlreadyCreated(); void reparentToNotYetCreated(); + void asViewport(); }; void tst_QOpenGLWidget::create() @@ -253,6 +259,52 @@ void tst_QOpenGLWidget::reparentToNotYetCreated() QVERIFY(image.pixel(20, 10) == qRgb(0, 0, 255)); } +class CountingGraphicsView : public QGraphicsView +{ +public: + CountingGraphicsView(): m_count(0) { } + int paintCount() const { return m_count; } + void resetPaintCount() { m_count = 0; } + +protected: + void drawForeground(QPainter *, const QRectF &) Q_DECL_OVERRIDE; + int m_count; +}; + +void CountingGraphicsView::drawForeground(QPainter *, const QRectF &) +{ + ++m_count; +} + +void tst_QOpenGLWidget::asViewport() +{ + // Have a QGraphicsView with a QOpenGLWidget as its viewport. + QGraphicsScene scene; + scene.addItem(new QGraphicsRectItem(10, 10, 100, 100)); + CountingGraphicsView *view = new CountingGraphicsView; + view->setScene(&scene); + view->setViewport(new QOpenGLWidget); + QWidget widget; + QVBoxLayout *layout = new QVBoxLayout; + layout->addWidget(view); + QPushButton *btn = new QPushButton("Test"); + layout->addWidget(btn); + widget.setLayout(layout); + widget.show(); + QTest::qWaitForWindowExposed(&widget); + + QVERIFY(view->paintCount() > 0); + view->resetPaintCount(); + + // And now trigger a repaint on the push button. We must not + // receive paint events for the graphics view. If we do, that's a + // side effect of QOpenGLWidget's special behavior and handling in + // the widget stack. + btn->update(); + qApp->processEvents(); + QVERIFY(view->paintCount() == 0); +} + QTEST_MAIN(tst_QOpenGLWidget) #include "tst_qopenglwidget.moc"