Add a QSGCanvas incubation controller
authorAaron Kennedy <aaron.kennedy@nokia.com>
Fri, 30 Sep 2011 04:26:56 +0000 (14:26 +1000)
committerQt by Nokia <qt-info@nokia.com>
Fri, 30 Sep 2011 08:37:05 +0000 (10:37 +0200)
Change-Id: I0324c32240746b013eeefaae2dfaa390d6e777e5
Task-number: QTBUG-21151
Reviewed-on: http://codereview.qt-project.org/5828
Reviewed-by: Aaron Kennedy <aaron.kennedy@nokia.com>
src/declarative/items/qsgcanvas.cpp
src/declarative/items/qsgcanvas.h
src/declarative/items/qsgcanvas_p.h
src/declarative/items/qsgview.cpp

index cdef37f..2ced204 100644 (file)
@@ -60,6 +60,7 @@
 #include <QtGui/qmatrix4x4.h>
 #include <QtCore/qvarlengtharray.h>
 #include <QtCore/qabstractanimation.h>
+#include <QtDeclarative/qdeclarativeincubator.h>
 
 #include <private/qdeclarativedebugtrace_p.h>
 
@@ -78,6 +79,45 @@ void QSGCanvasPrivate::updateFocusItemTransform()
         qApp->inputPanel()->setInputItemTransform(QSGItemPrivate::get(focus)->itemToCanvasTransform());
 }
 
+class QSGCanvasIncubationController : public QObject, public QDeclarativeIncubationController
+{
+public:
+    QSGCanvasIncubationController(QSGCanvasPrivate *canvas) 
+    : m_canvas(canvas), m_eventSent(false) {}
+
+protected:
+    virtual bool event(QEvent *e)
+    {
+        if (e->type() == QEvent::User) {
+            Q_ASSERT(m_eventSent);
+
+            bool *amtp = m_canvas->thread->allowMainThreadProcessing();
+            while (incubatingObjectCount()) {
+                if (amtp)
+                    incubateWhile(amtp);
+                else
+                    incubateFor(5);
+                QCoreApplication::processEvents();
+            }
+
+            m_eventSent = false;
+        }
+        return QObject::event(e);
+    }
+
+    virtual void incubatingObjectCountChanged(int count)
+    {
+        if (count && !m_eventSent) {
+            m_eventSent = true;
+            QCoreApplication::postEvent(this, new QEvent(QEvent::User));
+        }
+    }
+
+private:
+    QSGCanvasPrivate *m_canvas;
+    bool m_eventSent;
+};
+
 class QSGCanvasPlainRenderLoop : public QObject, public QSGCanvasRenderLoop
 {
 public:
@@ -416,6 +456,7 @@ QSGCanvasPrivate::QSGCanvasPrivate()
     , thread(0)
     , animationDriver(0)
     , renderTarget(0)
+    , incubationController(0)
 {
 }
 
@@ -792,6 +833,8 @@ QSGCanvas::~QSGCanvas()
     QSGItemPrivate *rootItemPrivate = QSGItemPrivate::get(d->rootItem);
     rootItemPrivate->removeFromDirtyList();
 
+    delete d->incubationController; d->incubationController = 0;
+
     delete d->rootItem; d->rootItem = 0;
     d->cleanupNodes();
 }
@@ -1830,6 +1873,21 @@ QImage QSGCanvas::grabFrameBuffer()
     return d->thread ? d->thread->grab() : QImage();
 }
 
+/*!
+    Returns an incubation controller that splices incubation between frames 
+    for this canvas.  QSGView automatically installs this controller for you.
+
+    The controller is owned by the canvas and will be destroyed when the canvas
+    is deleted.
+*/
+QDeclarativeIncubationController *QSGCanvas::incubationController() const
+{
+    Q_D(const QSGCanvas);
+
+    if (!d->incubationController)
+        d->incubationController = new QSGCanvasIncubationController(const_cast<QSGCanvasPrivate *>(d));
+    return d->incubationController;
+}
 
 
 void QSGCanvasRenderLoop::createGLContext()
@@ -1878,6 +1936,7 @@ void QSGCanvasRenderThread::run()
 #ifdef THREAD_DEBUG
             printf("                RenderThread: aquired sync lock...\n");
 #endif
+            allowMainThreadProcessingFlag = false;
             QCoreApplication::postEvent(this, new QEvent(QEvent::User));
 #ifdef THREAD_DEBUG
             printf("                RenderThread: going to sleep...\n");
@@ -1895,6 +1954,7 @@ void QSGCanvasRenderThread::run()
         inSync = false;
 
         // Wake GUI after sync to let it continue animating and event processing.
+        allowMainThreadProcessingFlag = true;
         wake();
         unlock();
 #ifdef THREAD_DEBUG
index a2bb278..094fe40 100644 (file)
@@ -56,6 +56,7 @@ class QSGItem;
 class QSGEngine;
 class QSGCanvasPrivate;
 class QOpenGLFramebufferObject;
+class QDeclarativeIncubationController;
 
 class Q_DECLARATIVE_EXPORT QSGCanvas : public QWindow
 {
@@ -85,6 +86,8 @@ public:
     void setRenderTarget(QOpenGLFramebufferObject *fbo);
     QOpenGLFramebufferObject *renderTarget() const;
 
+    QDeclarativeIncubationController *incubationController() const;
+
 Q_SIGNALS:
     void frameSwapped();
     void sceneGraphInitialized();
index 6a8e0a0..4a53e6b 100644 (file)
@@ -84,6 +84,7 @@ class QSGCanvasPrivate;
 
 class QTouchEvent;
 class QSGCanvasRenderLoop;
+class QSGCanvasIncubationController;
 
 class QSGCanvasPrivate : public QWindowPrivate
 {
@@ -167,6 +168,8 @@ public:
     QOpenGLFramebufferObject *renderTarget;
 
     QHash<int, QSGItem *> itemForTouchPointId;
+
+    mutable QSGCanvasIncubationController *incubationController;
 };
 
 class QSGCanvasRenderLoop
@@ -196,6 +199,7 @@ public:
     virtual void animationStarted() = 0;
     virtual void animationStopped() = 0;
     virtual void moveContextToThread(QSGContext *) { }
+    virtual bool *allowMainThreadProcessing() { return 0; }
 
 protected:
     void initializeSceneGraph() { d->initializeSceneGraph(); }
@@ -226,6 +230,7 @@ class QSGCanvasRenderThread : public QThread, public QSGCanvasRenderLoop
 public:
     QSGCanvasRenderThread()
         : mutex(QMutex::NonRecursive)
+        , allowMainThreadProcessingFlag(true)
         , animationRunning(false)
         , isGuiBlocked(0)
         , isPaintCompleted(false)
@@ -258,6 +263,7 @@ public:
     void setWindowSize(const QSize &size) { windowSize = size; }
     void maybeUpdate();
     void moveContextToThread(QSGContext *c) { c->moveToThread(this); }
+    bool *allowMainThreadProcessing() { return &allowMainThreadProcessingFlag; }
 
     bool event(QEvent *);
 
@@ -271,6 +277,8 @@ public:
     QMutex mutex;
     QWaitCondition condition;
 
+    bool allowMainThreadProcessingFlag;
+
     QSize windowSize;
     QSize renderedSize;
 
index 236fd4e..7d9a451 100644 (file)
@@ -62,9 +62,13 @@ DEFINE_BOOL_CONFIG_OPTION(frameRateDebug, QML_SHOW_FRAMERATE)
 
 void QSGViewPrivate::init()
 {
+    Q_Q(QSGView);
+
     QDeclarativeEnginePrivate::get(&engine)->sgContext = QSGCanvasPrivate::context;
 
-    QDeclarativeInspectorService::instance()->addView(q_func());
+    engine.setIncubationController(q->incubationController());
+
+    QDeclarativeInspectorService::instance()->addView(q);
 }
 
 QSGViewPrivate::QSGViewPrivate()