QtWidgets: Reduce paint events when resizing native widget

This patch reduces paint events by removing code which sets native
widgets dirty in QWidgetWindow::handleExposeEvent. Native widgets are
also marked dirty in QWidgetPrivate::drawWidget, so it is enough for
proper painting.

This restores Qt4 behavior when one resize means one repaint for native
widgets. Without this patch the native widget is marked as dirty on
every expose event, so one repaint is from syncBackingStore and second
(or more) is from marking the widget dirty explicitly.

This patch improves performance of native widgets and it also reduces
locks when paint event is v-synced, e.g. on OpenGL swap buffers or on
any other technology like VDPAU, VA-API, etc.

Added autotest for checking number of paint events for native widgets.

Task-number: QTBUG-50796
Change-Id: I4e1649069e2e73d15b038fd1834d0551915252ee
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
This commit is contained in:
Błażej Szczygieł 2016-02-01 11:49:02 +01:00
parent 640441882d
commit bc410cc706
2 changed files with 25 additions and 7 deletions

View File

@ -873,14 +873,8 @@ void QWidgetWindow::handleExposeEvent(QExposeEvent *event)
{ {
if (isExposed()) { if (isExposed()) {
m_widget->setAttribute(Qt::WA_Mapped); m_widget->setAttribute(Qt::WA_Mapped);
if (!event->region().isNull()) { if (!event->region().isNull())
// Exposed native widgets need to be marked dirty to get them repainted correctly.
if (m_widget->internalWinId() && !m_widget->isWindow() && m_widget->isVisible() && m_widget->updatesEnabled()) {
if (QWidgetBackingStore *bs = m_widget->d_func()->maybeBackingStore())
bs->markDirty(event->region(), m_widget);
}
m_widget->d_func()->syncBackingStore(event->region()); m_widget->d_func()->syncBackingStore(event->region());
}
} else { } else {
m_widget->setAttribute(Qt::WA_Mapped, false); m_widget->setAttribute(Qt::WA_Mapped, false);
} }

View File

@ -88,6 +88,7 @@ private slots:
void tst_showWithoutActivating(); void tst_showWithoutActivating();
void tst_paintEventOnSecondShow(); void tst_paintEventOnSecondShow();
void tst_paintEventOnResize_QTBUG50796();
#ifndef QT_NO_DRAGANDDROP #ifndef QT_NO_DRAGANDDROP
void tst_dnd(); void tst_dnd();
@ -369,6 +370,29 @@ void tst_QWidget_window::tst_paintEventOnSecondShow()
QTRY_VERIFY(w.paintEventCount > 0); QTRY_VERIFY(w.paintEventCount > 0);
} }
void tst_QWidget_window::tst_paintEventOnResize_QTBUG50796()
{
const QRect availableGeo = QGuiApplication::primaryScreen()->availableGeometry();
QWidget root;
root.setGeometry(availableGeo.width()/2 - 100, availableGeo.height()/2 - 100,
200, 200);
PaintTestWidget *native = new PaintTestWidget(&root);
native->winId(); // We're testing native widgets
native->setGeometry(10, 10, 50, 50);
root.show();
QVERIFY(QTest::qWaitForWindowExposed(&root));
QVERIFY(QTest::qWaitForWindowActive(&root));
QVERIFY(native->isVisible());
native->paintEventCount = 0;
native->resize(native->width() + 10, native->height() + 10);
QTest::qWait(50); // Wait for paint events
QTRY_COMPARE(native->paintEventCount, 1); // Only one paint event must occur
}
#ifndef QT_NO_DRAGANDDROP #ifndef QT_NO_DRAGANDDROP
/* DnD test for QWidgetWindow (handleDrag*Event() functions). /* DnD test for QWidgetWindow (handleDrag*Event() functions).