From: Gunnar Sletta Date: Fri, 6 Jan 2012 09:57:12 +0000 (+0100) Subject: Fix tst_qdeclarativestates::anchorsRewindBug failure X-Git-Tag: qt-v5.0.0-alpha1~710 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=627bcb8a88f6c1be73b0bbd45f9488b37fd40e83;p=profile%2Fivi%2Fqtdeclarative.git Fix tst_qdeclarativestates::anchorsRewindBug failure maybeUpdate() has an optimization to void locking the Gui thread on every QQuickItem::update() call, which was faulty. When the render thread was done rendering the flag should have been reset which would have meant another locked sync between render and GUI. Solve it slightly differently by posting an event to ourselves in GUI and resetting the state once the event is processed. This batches all update calls made until the GUI thread returns to the event loop, aka all animation updates, all responds to one touch event, etc. The isExternalUpdatePending variable, written from maybeUpdate, was accumulated per canvas, but is used per render thread only, so this change simplifies the variable to be per render thread only. Task-number: QTBUG-23478 Change-Id: I067a9918383e3e05e2feebcc6dfa3163b032eb5b Reviewed-by: Samuel Rødal --- diff --git a/src/quick/items/qquickwindowmanager.cpp b/src/quick/items/qquickwindowmanager.cpp index 8388cc6..1154f13 100644 --- a/src/quick/items/qquickwindowmanager.cpp +++ b/src/quick/items/qquickwindowmanager.cpp @@ -58,6 +58,9 @@ QT_BEGIN_NAMESPACE +const QEvent::Type QEvent_Sync = QEvent::Type(QEvent::User); +const QEvent::Type QEvent_DeferredUpdate = QEvent::Type(QEvent::User + 1); + #define QQUICK_CANVAS_TIMING #ifdef QQUICK_CANVAS_TIMING @@ -154,11 +157,12 @@ public: , isPaintCompleted(false) , isPostingSyncEvent(false) , isRenderBlocked(false) + , isExternalUpdatePending(false) , syncAlreadyHappened(false) , inSync(false) , shouldExit(false) , hasExited(false) - , renderThreadAwakened(false) + , isDeferredUpdatePosted(false) , canvasToGrab(0) { sg->moveToThread(this); @@ -179,6 +183,7 @@ public: void paint(QQuickCanvas *canvas); QImage grab(QQuickCanvas *canvas); void resize(QQuickCanvas *canvas, const QSize &size); + void handleDeferredUpdate(); void maybeUpdate(QQuickCanvas *canvas); void startRendering(); @@ -232,8 +237,7 @@ private: uint inSync : 1; uint shouldExit : 1; uint hasExited : 1; - uint renderThreadAwakened : 1; - uint isGuiAboutToBeBlockedForSync : 1; + uint isDeferredUpdatePosted : 1; QQuickCanvas *canvasToGrab; QImage grabContent; @@ -244,7 +248,6 @@ private: QSize viewportSize; uint sizeWasChanged : 1; - uint isExternalUpdatePending : 1; }; QHash m_rendered_windows; @@ -371,10 +374,11 @@ void QQuickRenderThreadSingleContextWindowManager::handleAddedWindow(QQuickCanva #endif CanvasData *data = new CanvasData; - data->isExternalUpdatePending = true; data->sizeWasChanged = false; data->windowSize = canvas->size(); m_rendered_windows[canvas] = data; + + isExternalUpdatePending = true; } @@ -542,6 +546,7 @@ void QQuickRenderThreadSingleContextWindowManager::run() printf(" RenderThread: *** NEW FRAME ***\n"); #endif + isExternalUpdatePending = false; handleAddedWindows(); if (!isGuiLocked) { @@ -551,7 +556,7 @@ void QQuickRenderThreadSingleContextWindowManager::run() printf(" RenderThread: aquired sync lock...\n"); #endif allowMainThreadProcessingFlag = false; - QCoreApplication::postEvent(this, new QEvent(QEvent::User)); + QCoreApplication::postEvent(this, new QEvent(QEvent_Sync)); #ifdef THREAD_DEBUG printf(" RenderThread: going to sleep...\n"); @@ -595,7 +600,6 @@ void QQuickRenderThreadSingleContextWindowManager::run() glViewport(0, 0, canvasData->viewportSize.width(), canvasData->viewportSize.height()); } - canvasData->isExternalUpdatePending = false; canvasPrivate->syncSceneGraph(); } inSync = false; @@ -677,8 +681,6 @@ void QQuickRenderThreadSingleContextWindowManager::run() isPaintCompleted = true; - bool isExternalUpdatePending = false; - // Update sizes... for (QHash::const_iterator it = m_rendered_windows.constBegin(); it != m_rendered_windows.constEnd(); ++it) { @@ -687,7 +689,6 @@ void QQuickRenderThreadSingleContextWindowManager::run() canvasData->renderedSize = canvasData->viewportSize; canvasData->sizeWasChanged = false; } - isExternalUpdatePending |= canvasData->isExternalUpdatePending; } @@ -749,7 +750,7 @@ bool QQuickRenderThreadSingleContextWindowManager::event(QEvent *e) { Q_ASSERT(QThread::currentThread() == qApp->thread()); - if (e->type() == QEvent::User) { + if (e->type() == QEvent_Sync) { // If all canvases have been hidden, ignore the event if (!isRunning()) @@ -773,6 +774,8 @@ bool QQuickRenderThreadSingleContextWindowManager::event(QEvent *e) } return true; + } else if (e->type() == QEvent_DeferredUpdate) { + handleDeferredUpdate(); } else if (e->type() == QEvent::Timer) { #ifdef THREAD_DEBUG @@ -804,8 +807,6 @@ void QQuickRenderThreadSingleContextWindowManager::sync(bool guiAlreadyLocked) if (!guiAlreadyLocked) lockInGui(); - renderThreadAwakened = false; - for (QHash::const_iterator it = m_rendered_windows.constBegin(); it != m_rendered_windows.constEnd(); ++it) { QQuickCanvasPrivate::get(it.key())->polishItems(); @@ -962,7 +963,6 @@ void QQuickRenderThreadSingleContextWindowManager::startRendering() isGuiLocked = 0; isPostingSyncEvent = false; syncAlreadyHappened = false; - renderThreadAwakened = false; inSync = false; lockInGui(); @@ -1059,36 +1059,38 @@ QImage QQuickRenderThreadSingleContextWindowManager::grab(QQuickCanvas *canvas) } +void QQuickRenderThreadSingleContextWindowManager::handleDeferredUpdate() +{ +#ifdef THREAD_DEBUG + printf("GUI: handling update to ourselves...\n"); +#endif + + isDeferredUpdatePosted = false; -void QQuickRenderThreadSingleContextWindowManager::maybeUpdate(QQuickCanvas *canvas) + lockInGui(); + isExternalUpdatePending = true; + if (isRenderBlocked) + wake(); + unlockInGui(); +} + +void QQuickRenderThreadSingleContextWindowManager::maybeUpdate(QQuickCanvas *) { Q_ASSERT_X(QThread::currentThread() == QCoreApplication::instance()->thread() || inSync, "QQuickCanvas::update", "Function can only be called from GUI thread or during QQuickItem::updatePaintNode()"); if (inSync) { - CanvasData *canvasData = m_rendered_windows.value(canvas); - if (canvasData) - canvasData->isExternalUpdatePending = true; + isExternalUpdatePending = true; - } else if (!renderThreadAwakened) { + } else if (!isDeferredUpdatePosted) { #ifdef THREAD_DEBUG - printf("GUI: doing update...\n"); + printf("GUI: posting update to ourselves...\n"); #endif - renderThreadAwakened = true; - - // If we are getting here from the renderer's sync event, the renderer is about - // to go to sleep anyway. - if (!isGuiAboutToBeBlockedForSync) - lockInGui(); - CanvasData *canvasData = m_rendered_windows.value(canvas); - if (canvasData) - canvasData->isExternalUpdatePending = true; - if (isRenderBlocked) - wake(); - if (!isGuiAboutToBeBlockedForSync) - unlockInGui(); + isDeferredUpdatePosted = true; + QCoreApplication::postEvent(this, new QEvent(QEvent_DeferredUpdate)); } + } QQuickTrivialWindowManager::QQuickTrivialWindowManager() diff --git a/tests/auto/qtquick2/qdeclarativestates/tst_qdeclarativestates.cpp b/tests/auto/qtquick2/qdeclarativestates/tst_qdeclarativestates.cpp index df0c2f2..4d5df12 100644 --- a/tests/auto/qtquick2/qdeclarativestates/tst_qdeclarativestates.cpp +++ b/tests/auto/qtquick2/qdeclarativestates/tst_qdeclarativestates.cpp @@ -1001,9 +1001,6 @@ void tst_qdeclarativestates::anchorRewindBug() // and column's implicit resizing should still work QVERIFY(!QQuickItemPrivate::get(column)->heightValid); QVERIFY(!QQuickItemPrivate::get(column)->widthValid); -#ifdef Q_OS_MAC - QEXPECT_FAIL("", "QTBUG-23478", Abort); -#endif QTRY_COMPARE(column->height(), 200.0); delete view; diff --git a/tests/auto/qtquick2/qquickpositioners/tst_qquickpositioners.cpp b/tests/auto/qtquick2/qquickpositioners/tst_qquickpositioners.cpp index e39162d..441c343 100644 --- a/tests/auto/qtquick2/qquickpositioners/tst_qquickpositioners.cpp +++ b/tests/auto/qtquick2/qquickpositioners/tst_qquickpositioners.cpp @@ -1448,9 +1448,6 @@ void tst_qquickpositioners::test_attachedproperties_dynamic() QTRY_VERIFY(rect1->property("index").toInt() == 1); QTRY_VERIFY(rect1->property("firstItem").toBool() == false); -#ifdef Q_OS_MAC - QEXPECT_FAIL("", "QTBUG-23483", Abort); -#endif QTRY_VERIFY(rect1->property("lastItem").toBool() == true); delete canvas;