diff options
Diffstat (limited to 'src/widgets/kernel/qwidgetrepaintmanager.cpp')
-rw-r--r-- | src/widgets/kernel/qwidgetrepaintmanager.cpp | 77 |
1 files changed, 55 insertions, 22 deletions
diff --git a/src/widgets/kernel/qwidgetrepaintmanager.cpp b/src/widgets/kernel/qwidgetrepaintmanager.cpp index 69ab7de1af..607a767a20 100644 --- a/src/widgets/kernel/qwidgetrepaintmanager.cpp +++ b/src/widgets/kernel/qwidgetrepaintmanager.cpp @@ -1,7 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only - #include "qplatformdefs.h" #include "qwidgetrepaintmanager_p.h" @@ -49,7 +48,7 @@ public: } bool isLocked() const { - foreach (bool v, m_locked) { + for (const auto &[_, v] : m_locked.asKeyValueRange()) { if (v) return true; } @@ -126,7 +125,7 @@ void QWidgetPrivate::invalidateBackingStore(const T &r) return; QTLWExtra *tlwExtra = q->window()->d_func()->maybeTopData(); - if (!tlwExtra || !tlwExtra->backingStore) + if (!tlwExtra || !tlwExtra->backingStore || !tlwExtra->repaintManager) return; T clipped(r); @@ -302,7 +301,7 @@ void QWidgetRepaintManager::removeDirtyWidget(QWidget *w) needsFlushWidgets.removeAll(w); QWidgetPrivate *wd = w->d_func(); - const int n = wd->children.count(); + const int n = wd->children.size(); for (int i = 0; i < n; ++i) { if (QWidget *child = qobject_cast<QWidget*>(wd->children.at(i))) removeDirtyWidget(child); @@ -340,9 +339,9 @@ void QWidgetRepaintManager::sendUpdateRequest(QWidget *widget, UpdateTime update // compositing and waiting for vsync each and every time. Change to // UpdateLater, except for approx. once per frame to prevent starvation in // case the control does not get back to the event loop. - QWidget *w = widget->window(); - if (updateTime == UpdateNow && w && w->windowHandle() && QWindowPrivate::get(w->windowHandle())->compositing) { + if (updateTime == UpdateNow && QWidgetPrivate::get(widget)->textureChildSeen) { int refresh = 60; + QWidget *w = widget->window(); QScreen *ws = w->windowHandle()->screen(); if (ws) refresh = ws->refreshRate(); @@ -351,12 +350,16 @@ void QWidgetRepaintManager::sendUpdateRequest(QWidget *widget, UpdateTime update const qint64 elapsed = wd->lastComposeTime.elapsed(); if (elapsed <= qint64(1000.0f / refresh)) updateTime = UpdateLater; - } + } } switch (updateTime) { case UpdateLater: - updateRequestSent = true; + // Prevent redundant update request events, unless it's a + // paint on screen widget, as these don't go through the + // normal backingstore sync machinery. + if (!widget->d_func()->shouldPaintOnScreen()) + updateRequestSent = true; QCoreApplication::postEvent(widget, new QEvent(QEvent::UpdateRequest), Qt::LowEventPriority); break; case UpdateNow: { @@ -539,7 +542,8 @@ static void findTextureWidgetsRecursively(QWidget *tlw, QWidget *widget, if (wd->renderToTexture) { QPlatformTextureList::Flags flags = wd->textureListFlags(); const QRect rect(widget->mapTo(tlw, QPoint()), widget->size()); - widgetTextures->appendTexture(widget, wd->texture(), rect, wd->clipRect(), flags); + QWidgetPrivate::TextureData data = wd->texture(); + widgetTextures->appendTexture(widget, data.textureLeft, data.textureRight, rect, wd->clipRect(), flags); } for (int i = 0; i < wd->children.size(); ++i) { @@ -565,7 +569,7 @@ static void findAllTextureWidgetsRecursively(QWidget *tlw, QWidget *widget) if (!tl->isEmpty()) QWidgetPrivate::get(tlw)->topData()->widgetTextures.push_back(std::move(tl)); // Native child widgets, if there was any, get their own separate QPlatformTextureList. - for (QWidget *ncw : qAsConst(nativeChildren)) { + for (QWidget *ncw : std::as_const(nativeChildren)) { if (QWidgetPrivate::get(ncw)->textureChildSeen) findAllTextureWidgetsRecursively(tlw, ncw); } @@ -706,7 +710,9 @@ void QWidgetRepaintManager::paintAndFlush() const QRect tlwRect = tlw->data->crect; if (!updatesDisabled && store->size() != tlwRect.size()) { - if (hasStaticContents() && !store->size().isEmpty() ) { + QPlatformIntegration *integration = QGuiApplicationPrivate::platformIntegration(); + if (hasStaticContents() && !store->size().isEmpty() + && integration->hasCapability(QPlatformIntegration::BackingStoreStaticContents)) { // Repaint existing dirty area and newly visible area. const QRect clipRect(QPoint(0, 0), store->size()); const QRegion staticRegion(staticContents(nullptr, clipRect)); @@ -799,7 +805,6 @@ void QWidgetRepaintManager::paintAndFlush() QTLWExtra *tlwExtra = tlw->d_func()->topData(); tlwExtra->widgetTextures.clear(); findAllTextureWidgetsRecursively(tlw, tlw); - qt_window_private(tlw->windowHandle())->compositing = false; // will get updated in flush() if (toClean.isEmpty()) { // Nothing to repaint. However renderToTexture widgets are handled @@ -808,7 +813,7 @@ void QWidgetRepaintManager::paintAndFlush() // texture content changes. Check if we have such widgets in the special // dirty list. QVarLengthArray<QWidget *, 16> paintPending; - const int numPaintPending = dirtyRenderToTextureWidgets.count(); + const int numPaintPending = dirtyRenderToTextureWidgets.size(); paintPending.reserve(numPaintPending); for (int i = 0; i < numPaintPending; ++i) { QWidget *w = dirtyRenderToTextureWidgets.at(i); @@ -850,7 +855,7 @@ void QWidgetRepaintManager::paintAndFlush() } } } - for (int i = 0; i < dirtyRenderToTextureWidgets.count(); ++i) + for (int i = 0; i < dirtyRenderToTextureWidgets.size(); ++i) resetWidget(dirtyRenderToTextureWidgets.at(i)); dirtyRenderToTextureWidgets.clear(); @@ -988,7 +993,7 @@ void QWidgetRepaintManager::flush() if (!hasNeedsFlushWidgets) return; - for (QWidget *w : qExchange(needsFlushWidgets, {})) { + for (QWidget *w : std::exchange(needsFlushWidgets, {})) { QWidgetPrivate *wd = w->d_func(); Q_ASSERT(wd->needsFlush); QPlatformTextureList *widgetTexturesForNative = wd->textureChildSeen ? widgetTexturesFor(tlw, w) : nullptr; @@ -1032,7 +1037,36 @@ void QWidgetRepaintManager::flush(QWidget *widget, const QRegion ®ion, QPlatf if (widget != tlw) offset += widget->mapTo(tlw, QPoint()); - if (widget->d_func()->usesRhiFlush) { + // Use a condition that tries to keep both QTBUG-108344 and QTBUG-113557 + // happy, i.e. support both (A) "native rhi-based child in a rhi-based + // toplevel" and (B) "native raster child in a rhi-based toplevel". + // + // If the tlw and the backingstore are RHI-based, then there are two cases + // to consider: + // + // (1) widget is not a native child, i.e. the QWindow for widget and tlw are + // the same, + // + // (2) widget is a native child which we now attempt to flush with tlw's + // backingstore to widget's native window. This is the interesting one. + // + // Using the condition tlw->usesRhiFlush on its own is insufficient since + // it fails to capture the case of a raster-based native child widget + // within tlw. (which must hit the non-rhi flush path) + // + // Extending the condition with tlw->windowHandle() == widget->windowHandle() + // would be logical but wrong, when it comes to (A) since flushing a + // RHI-based native child with a given 3D API using a RHI-based + // tlw/backingstore with the same 3D API needs to be supported still. (this + // happens when e.g. someone calls winId() on a QOpenGLWidget) + // + // Different 3D APIs do not need to be supported since we do not allow to + // do things like having a QQuickWidget with Vulkan and a QOpenGLWidget in + // the same toplevel, regardless of the widgets being native children or + // not. Hence comparing the surfaceType() instead. This satisfies both (A) + // and (B) given that an RHI-based toplevel cannot be RasterSurface. + // + if (tlw->d_func()->usesRhiFlush && tlw->windowHandle()->surfaceType() == widget->windowHandle()->surfaceType()) { QRhi *rhi = store->handle()->rhi(); qCDebug(lcWidgetPainting) << "Flushing" << region << "of" << widget << "with QRhi" << rhi @@ -1040,7 +1074,6 @@ void QWidgetRepaintManager::flush(QWidget *widget, const QRegion ®ion, QPlatf if (!widgetTextures) widgetTextures = qt_dummy_platformTextureList; - qt_window_private(tlw->windowHandle())->compositing = true; QWidgetPrivate *widgetWindowPrivate = widget->window()->d_func(); widgetWindowPrivate->sendComposeStatus(widget->window(), false); // A window may have alpha even when the app did not request @@ -1057,7 +1090,11 @@ void QWidgetRepaintManager::flush(QWidget *widget, const QRegion ®ion, QPlatf translucentBackground); widgetWindowPrivate->sendComposeStatus(widget->window(), true); if (flushResult == QPlatformBackingStore::FlushFailedDueToLostDevice) { + qSendWindowChangeToTextureChildrenRecursively(widget->window(), + QEvent::WindowAboutToChangeInternal); store->handle()->graphicsDeviceReportedLost(); + qSendWindowChangeToTextureChildrenRecursively(widget->window(), + QEvent::WindowChangeInternal); widget->update(); } } else { @@ -1107,11 +1144,7 @@ void QWidgetRepaintManager::removeStaticWidget(QWidget *widget) bool QWidgetRepaintManager::hasStaticContents() const { -#if defined(Q_OS_WIN) return !staticWidgets.isEmpty(); -#else - return !staticWidgets.isEmpty() && false; -#endif } /*! @@ -1133,7 +1166,7 @@ QRegion QWidgetRepaintManager::staticContents(QWidget *parent, const QRect &with return region; const bool clipToRect = !withinClipRect.isEmpty(); - const int count = staticWidgets.count(); + const int count = staticWidgets.size(); for (int i = 0; i < count; ++i) { QWidget *w = staticWidgets.at(i); QWidgetPrivate *wd = w->d_func(); |