summaryrefslogtreecommitdiffstats
path: root/src/widgets/kernel/qwidgetrepaintmanager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/widgets/kernel/qwidgetrepaintmanager.cpp')
-rw-r--r--src/widgets/kernel/qwidgetrepaintmanager.cpp96
1 files changed, 54 insertions, 42 deletions
diff --git a/src/widgets/kernel/qwidgetrepaintmanager.cpp b/src/widgets/kernel/qwidgetrepaintmanager.cpp
index 69ab7de1af..0dee380a91 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;
@@ -1011,11 +1016,13 @@ void QWidgetRepaintManager::flush(QWidget *widget, const QRegion &region, QPlatf
if (tlw->testAttribute(Qt::WA_DontShowOnScreen) || widget->testAttribute(Qt::WA_DontShowOnScreen))
return;
+ QWindow *window = widget->windowHandle();
+ // We should only be flushing to native widgets
+ Q_ASSERT(window);
+
// Foreign Windows do not have backing store content and must not be flushed
- if (QWindow *widgetWindow = widget->windowHandle()) {
- if (widgetWindow->type() == Qt::ForeignWindow)
- return;
- }
+ if (window->type() == Qt::ForeignWindow)
+ return;
static bool fpsDebug = qEnvironmentVariableIntValue("QT_DEBUG_FPS");
if (fpsDebug) {
@@ -1032,37 +1039,51 @@ void QWidgetRepaintManager::flush(QWidget *widget, const QRegion &region, QPlatf
if (widget != tlw)
offset += widget->mapTo(tlw, QPoint());
- if (widget->d_func()->usesRhiFlush) {
- QRhi *rhi = store->handle()->rhi();
- qCDebug(lcWidgetPainting) << "Flushing" << region << "of" << widget
- << "with QRhi" << rhi
- << "to window" << widget->windowHandle();
+ // A widget uses RHI flush if itself, or one of its non-native children
+ // uses RHI for its drawing. If so, we composite the backing store raster
+ // data along with textures produced by the RHI widgets.
+ const bool flushWithRhi = widget->d_func()->usesRhiFlush;
+
+ qCDebug(lcWidgetPainting) << "Flushing" << region << "of" << widget
+ << "to" << window << (flushWithRhi ? "using RHI" : "");
+
+ // A widget uses RHI flush if itself, or one of its non-native children
+ // uses RHI for its drawing. If so, we composite the backing store raster
+ // data along with textures produced by the RHI widgets.
+ if (flushWithRhi) {
if (!widgetTextures)
widgetTextures = qt_dummy_platformTextureList;
- qt_window_private(tlw->windowHandle())->compositing = true;
- QWidgetPrivate *widgetWindowPrivate = widget->window()->d_func();
- widgetWindowPrivate->sendComposeStatus(widget->window(), false);
+ // We only need to let the widget sub-hierarchy that
+ // we are flushing know that we're compositing.
+ auto *widgetPrivate = QWidgetPrivate::get(widget);
+ widgetPrivate->sendComposeStatus(widget, false);
+
// A window may have alpha even when the app did not request
// WA_TranslucentBackground. Therefore the compositor needs to know whether the app intends
// to rely on translucency, in order to decide if it should clear to transparent or opaque.
const bool translucentBackground = widget->testAttribute(Qt::WA_TranslucentBackground);
QPlatformBackingStore::FlushResult flushResult;
- flushResult = store->handle()->rhiFlush(widget->windowHandle(),
+ flushResult = store->handle()->rhiFlush(window,
widget->devicePixelRatio(),
region,
offset,
widgetTextures,
translucentBackground);
- widgetWindowPrivate->sendComposeStatus(widget->window(), true);
+
+ widgetPrivate->sendComposeStatus(widget, true);
+
if (flushResult == QPlatformBackingStore::FlushFailedDueToLostDevice) {
- store->handle()->graphicsDeviceReportedLost();
+ qSendWindowChangeToTextureChildrenRecursively(widget->window(),
+ QEvent::WindowAboutToChangeInternal);
+ store->handle()->graphicsDeviceReportedLost(window);
+ qSendWindowChangeToTextureChildrenRecursively(widget->window(),
+ QEvent::WindowChangeInternal);
widget->update();
}
} else {
- qCInfo(lcWidgetPainting) << "Flushing" << region << "of" << widget;
- store->flush(region, widget->windowHandle(), offset);
+ store->flush(region, window, offset);
}
}
@@ -1107,11 +1128,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 +1150,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();
@@ -1275,11 +1292,6 @@ void QWidgetPrivate::invalidateBackingStore_resizeHelper(const QPoint &oldPos, c
}
}
-QRhi *QWidgetRepaintManager::rhi() const
-{
- return store->handle()->rhi();
-}
-
QT_END_NAMESPACE
#include "qwidgetrepaintmanager.moc"