diff options
Diffstat (limited to 'src/widgets/kernel/qwidget.cpp')
-rw-r--r-- | src/widgets/kernel/qwidget.cpp | 118 |
1 files changed, 73 insertions, 45 deletions
diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index 365323933b5..46e0d2c76c7 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -1029,10 +1029,13 @@ void QWidgetPrivate::createRecursively() QRhi *QWidgetPrivate::rhi() const { - if (QWidgetRepaintManager *repaintManager = maybeRepaintManager()) - return repaintManager->rhi(); - else + Q_Q(const QWidget); + if (auto *backingStore = q->backingStore()) { + auto *window = windowHandle(WindowHandleMode::Closest); + return backingStore->handle()->rhi(window); + } else { return nullptr; + } } /*! @@ -1112,8 +1115,15 @@ static bool q_evaluateRhiConfigRecursive(const QWidget *w, QPlatformBackingStore } for (const QObject *child : w->children()) { if (const QWidget *childWidget = qobject_cast<const QWidget *>(child)) { - if (q_evaluateRhiConfigRecursive(childWidget, outConfig, outType)) + if (q_evaluateRhiConfigRecursive(childWidget, outConfig, outType)) { + static bool optOut = qEnvironmentVariableIsSet("QT_WIDGETS_NO_CHILD_RHI"); + // Native child widgets should not trigger RHI for its parent + // hierarchy, but will still flush the native child using RHI. + if (!optOut && childWidget->testAttribute(Qt::WA_NativeWindow)) + continue; + return true; + } } } return false; @@ -1356,19 +1366,19 @@ void QWidgetPrivate::create() QBackingStore *store = q->backingStore(); usesRhiFlush = false; - if (!store) { - if (q->windowType() != Qt::Desktop) { - if (q->isWindow()) { - q->setBackingStore(new QBackingStore(win)); - QPlatformBackingStoreRhiConfig rhiConfig; - usesRhiFlush = q_evaluateRhiConfig(q, &rhiConfig, nullptr); - topData()->backingStore->handle()->setRhiConfig(rhiConfig); - } - } else { - q->setAttribute(Qt::WA_PaintOnScreen, true); + if (q->windowType() == Qt::Desktop) { + q->setAttribute(Qt::WA_PaintOnScreen, true); + } else { + if (!store && q->isWindow()) + q->setBackingStore(new QBackingStore(win)); + + QPlatformBackingStoreRhiConfig rhiConfig; + usesRhiFlush = q_evaluateRhiConfig(q, &rhiConfig, nullptr); + if (usesRhiFlush && q->backingStore()) { + // Trigger creation of support infrastructure up front, + // now that we have a specific RHI configuration. + q->backingStore()->handle()->createRhi(win, rhiConfig); } - } else if (win->handle()) { - usesRhiFlush = q_evaluateRhiConfig(q, nullptr, nullptr); } setWindowModified_helper(); @@ -10673,6 +10683,7 @@ void QWidget::setParent(QWidget *parent, Qt::WindowFlags f) const bool wasCreated = testAttribute(Qt::WA_WState_Created); QWidget *oldtlw = window(); Q_ASSERT(oldtlw); + QWidget *oldParentWithWindow = d->closestParentWidgetWithWindowHandle(); if (f & Qt::Window) // Frame geometry likely changes, refresh. d->data.fstrut_dirty = true; @@ -10715,7 +10726,8 @@ void QWidget::setParent(QWidget *parent, Qt::WindowFlags f) // texture-based widgets need a pre-notification when their associated top-level window changes // This is not under the wasCreated/newParent conditions above in order to also play nice with QDockWidget. - if (oldtlw->d_func()->usesRhiFlush && ((!parent && parentWidget()) || (parent && parent->window() != oldtlw))) + const bool oldParentUsesRhiFlush = oldParentWithWindow ? oldParentWithWindow->d_func()->usesRhiFlush : false; + if (oldParentUsesRhiFlush && ((!parent && parentWidget()) || (parent && parent->window() != oldtlw))) qSendWindowChangeToTextureChildrenRecursively(this, QEvent::WindowAboutToChangeInternal); // If we get parented into another window, children will be folded @@ -10796,7 +10808,7 @@ void QWidget::setParent(QWidget *parent, Qt::WindowFlags f) // texture-based widgets need another event when their top-level window // changes (more precisely, has already changed at this point) - if (oldtlw->d_func()->usesRhiFlush && oldtlw != window()) + if (oldParentUsesRhiFlush && oldtlw != window()) qSendWindowChangeToTextureChildrenRecursively(this, QEvent::WindowChangeInternal); if (!wasCreated) { @@ -10824,33 +10836,47 @@ void QWidget::setParent(QWidget *parent, Qt::WindowFlags f) if (d->extra && d->extra->hasWindowContainer) QWindowContainer::parentWasChanged(this); - QWidget *newtlw = window(); - if (oldtlw != newtlw) { + QWidget *newParentWithWindow = d->closestParentWidgetWithWindowHandle(); + if (newParentWithWindow && newParentWithWindow != oldParentWithWindow) { + // Check if the native parent now needs to switch to RHI + qCDebug(lcWidgetPainting) << "Evaluating whether reparenting of" << this + << "into" << parent << "requires RHI enablement for" << newParentWithWindow; + + QPlatformBackingStoreRhiConfig rhiConfig; QSurface::SurfaceType surfaceType = QSurface::RasterSurface; - // Only evaluate the reparented subtree. While it might be tempting to - // do it on newtlw instead, the performance implications of that are + + // First evaluate whether the reparented widget uses RHI. + // We do this as a separate step because the performance + // implications of always checking the native parent are // problematic when it comes to large widget trees. - if (q_evaluateRhiConfig(this, nullptr, &surfaceType)) { - const bool wasUsingRhiFlush = newtlw->d_func()->usesRhiFlush; - newtlw->d_func()->usesRhiFlush = true; - bool recreate = false; - if (QWindow *w = newtlw->windowHandle()) { - if (w->surfaceType() != surfaceType || !wasUsingRhiFlush) - recreate = true; - } - // QTBUG-115652: Besides the toplevel the nativeParentWidget()'s QWindow must be checked as well. - if (QWindow *w = d->windowHandle(QWidgetPrivate::WindowHandleMode::Closest)) { - if (w->surfaceType() != surfaceType) - recreate = true; - } - if (recreate) { - const auto windowStateBeforeDestroy = newtlw->windowState(); - const auto visibilityBeforeDestroy = newtlw->isVisible(); - newtlw->destroy(); - newtlw->create(); - Q_ASSERT(newtlw->windowHandle()); - newtlw->windowHandle()->setWindowStates(windowStateBeforeDestroy); - QWidgetPrivate::get(newtlw)->setVisible(visibilityBeforeDestroy); + if (q_evaluateRhiConfig(this, &rhiConfig, &surfaceType)) { + // Then check whether the native parent requires RHI + // as a result. It may not, if this widget is a native + // window, and can handle its own RHI flushing. + if (q_evaluateRhiConfig(newParentWithWindow, nullptr, nullptr)) { + // Finally, check whether we need to recreate the + // native parent to enable RHI flushing. + auto *existingWindow = newParentWithWindow->windowHandle(); + auto existingSurfaceType = existingWindow->surfaceType(); + if (existingSurfaceType != surfaceType) { + qCDebug(lcWidgetPainting) + << "Recreating" << existingWindow + << "with current type" << existingSurfaceType + << "to support" << surfaceType; + const auto windowStateBeforeDestroy = newParentWithWindow->windowState(); + const auto visibilityBeforeDestroy = newParentWithWindow->isVisible(); + newParentWithWindow->destroy(); + newParentWithWindow->create(); + Q_ASSERT(newParentWithWindow->windowHandle()); + newParentWithWindow->windowHandle()->setWindowStates(windowStateBeforeDestroy); + QWidgetPrivate::get(newParentWithWindow)->setVisible(visibilityBeforeDestroy); + } else if (auto *backingStore = newParentWithWindow->backingStore()) { + // If we don't recreate we still need to make sure the native parent + // widget has a RHI config that the reparented widget can use. + backingStore->handle()->createRhi(existingWindow, rhiConfig); + // And that it knows it's now flushing with RHI + QWidgetPrivate::get(newParentWithWindow)->usesRhiFlush = true; + } } } } @@ -12308,8 +12334,10 @@ QBackingStore *QWidget::backingStore() const if (extra && extra->backingStore) return extra->backingStore; - QWidgetRepaintManager *repaintManager = d->maybeRepaintManager(); - return repaintManager ? repaintManager->backingStore() : nullptr; + if (!isWindow()) + return window()->backingStore(); + + return nullptr; } void QWidgetPrivate::getLayoutItemMargins(int *left, int *top, int *right, int *bottom) const |