aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGunnar Sletta <gunnar.sletta@jollamobile.com>2014-07-04 23:50:50 +0200
committerGunnar Sletta <gunnar.sletta@jollamobile.com>2014-07-29 19:13:39 +0200
commit15ce5d915b6bda4bf1d3c85cbdc79b2e11690bca (patch)
tree83668da1212904d81a73208211861c36a74261ee
parent9c67029ee5aca18ae02e740afbf6d0f883799ebd (diff)
Introducing QQuickWindow::scheduleRenderJob()
[ChangeLog][QtQuick][QQuickWindow] Added QQuickWindow::scheduleRenderJob(), a convenience alternative to the equivalent signals for one-shot tasks. Change-Id: I5e4f0d67d5223f7fd77bca394e2a85810fadd335 Reviewed-by: Laszlo Agocs <laszlo.agocs@digia.com>
-rw-r--r--src/quick/items/qquickwindow.cpp107
-rw-r--r--src/quick/items/qquickwindow.h12
-rw-r--r--src/quick/items/qquickwindow_p.h9
-rw-r--r--tests/auto/quick/qquickwindow/tst_qquickwindow.cpp55
4 files changed, 182 insertions, 1 deletions
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index 63e57615ba..0c71254169 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -66,6 +66,7 @@
#include <QtCore/qvarlengtharray.h>
#include <QtCore/qabstractanimation.h>
#include <QtCore/QLibraryInfo>
+#include <QtCore/QRunnable>
#include <QtQml/qqmlincubator.h>
#include <QtQuick/private/qquickpixmapcache_p.h>
@@ -331,6 +332,7 @@ void QQuickWindowPrivate::syncSceneGraph()
animationController->beforeNodeSync();
emit q->beforeSynchronizing();
+ runAndClearJobs(&beforeSynchronizingJobs);
if (!renderer) {
forceUpdate(contentItem);
@@ -354,6 +356,7 @@ void QQuickWindowPrivate::syncSceneGraph()
renderer->setCustomRenderMode(customRenderMode);
emit q->afterSynchronizing();
+ runAndClearJobs(&afterSynchronizingJobs);
context->endSync();
}
@@ -367,6 +370,7 @@ void QQuickWindowPrivate::renderSceneGraph(const QSize &size)
animationController->advance();
emit q->beforeRendering();
+ runAndClearJobs(&beforeRenderingJobs);
int fboId = 0;
const qreal devicePixelRatio = q->devicePixelRatio();
renderer->setDeviceRect(QRect(QPoint(0, 0), size * devicePixelRatio));
@@ -381,6 +385,7 @@ void QQuickWindowPrivate::renderSceneGraph(const QSize &size)
context->renderNextFrame(renderer, fboId);
emit q->afterRendering();
+ runAndClearJobs(&afterRenderingJobs);
}
QQuickWindowPrivate::QQuickWindowPrivate()
@@ -470,6 +475,8 @@ void QQuickWindowPrivate::init(QQuickWindow *c, QQuickRenderControl *control)
QObject::connect(q, SIGNAL(focusObjectChanged(QObject*)), q, SIGNAL(activeFocusItemChanged()));
QObject::connect(q, SIGNAL(screenChanged(QScreen*)), q, SLOT(forcePolish()));
+
+ QObject::connect(q, SIGNAL(frameSwapped()), q, SLOT(runJobsAfterSwap()), Qt::DirectConnection);
}
/*!
@@ -1101,6 +1108,19 @@ QQuickWindow::~QQuickWindow()
delete d->dragGrabber; d->dragGrabber = 0;
#endif
delete d->contentItem; d->contentItem = 0;
+
+ d->renderJobMutex.lock();
+ qDeleteAll(d->beforeSynchronizingJobs);
+ d->beforeSynchronizingJobs.clear();
+ qDeleteAll(d->afterSynchronizingJobs);
+ d->afterSynchronizingJobs.clear();
+ qDeleteAll(d->beforeRenderingJobs);
+ d->beforeRenderingJobs.clear();
+ qDeleteAll(d->afterRenderingJobs);
+ d->afterRenderingJobs.clear();
+ qDeleteAll(d->afterSwapJobs);
+ d->afterSwapJobs.clear();
+ d->renderJobMutex.unlock();
}
/*!
@@ -2815,8 +2835,13 @@ void QQuickWindow::cleanupSceneGraph()
delete d->renderer->rootNode();
delete d->renderer;
-
d->renderer = 0;
+
+ d->runAndClearJobs(&d->beforeSynchronizingJobs);
+ d->runAndClearJobs(&d->afterSynchronizingJobs);
+ d->runAndClearJobs(&d->beforeRenderingJobs);
+ d->runAndClearJobs(&d->afterRenderingJobs);
+ d->runAndClearJobs(&d->afterSwapJobs);
}
void QQuickWindow::setTransientParent_helper(QQuickWindow *window)
@@ -3834,6 +3859,86 @@ bool QQuickWindow::glslIsCoreProfile() const
flashing or bouncing the taskbar entry.
*/
+/*!
+ \enum QQuickWindow::RenderJobSchedule
+ \since 5.4
+
+ \value ScheduleBeforeSynchronizing Before synchronization.
+ \value ScheduleAfterSynchronizing After synchronization.
+ \value ScheduleBeforeRendering Before rendering.
+ \value ScheduleAfterRendering After rendering.
+ \value ScheduleAfterSwap After the frame is swapped.
+
+ \sa {Scene Graph and Rendering}
+ */
+
+/*!
+ \since 5.4
+
+ Schedule \a job to run when the rendering of this window reaches
+ the given \a stage.
+
+ This is a convenience to the equivalent signals in QQuickWindow for
+ "one shot" tasks.
+
+ The window takes ownership over \a job and will delete it when the
+ job is completed.
+
+ If rendering is shut down before \a job has a chance to run, the
+ job will be run and then deleted as part of the scene graph cleanup.
+ If the window is never shown and no rendering happens before the QQuickWindow
+ is destroyed, all pending jobs will be destroyed without their run()
+ method being called.
+
+ If the rendering is happening on a different thread, then the job
+ will happen on the rendering thread.
+
+ \note This function does not trigger rendering; the job
+ will be stored run until rendering is triggered elsewhere.
+ To force the job to run earlier, call QQuickWindow::update();
+
+ \sa beforeRendering(), afterRendering(), beforeSynchronizing(),
+ afterSynchronizing(), frameSwapped(), sceneGraphInvalidated()
+ */
+
+void QQuickWindow::scheduleRenderJob(QRunnable *job, RenderStage stage)
+{
+ Q_D(QQuickWindow);
+
+ d->renderJobMutex.lock();
+ if (stage == BeforeSynchronizingStage)
+ d->beforeSynchronizingJobs << job;
+ else if (stage == AfterSynchronizingStage)
+ d->afterSynchronizingJobs << job;
+ else if (stage == BeforeRenderingStage)
+ d->beforeRenderingJobs << job;
+ else if (stage == AfterRenderingStage)
+ d->afterRenderingJobs << job;
+ else if (stage == AfterSwapStage)
+ d->afterSwapJobs << job;
+ d->renderJobMutex.unlock();
+}
+
+void QQuickWindowPrivate::runAndClearJobs(QList<QRunnable *> *jobs)
+{
+ renderJobMutex.lock();
+ QList<QRunnable *> jobList = *jobs;
+ jobs->clear();
+ renderJobMutex.unlock();
+
+ foreach (QRunnable *r, jobList) {
+ r->run();
+ delete r;
+ }
+}
+
+void QQuickWindow::runJobsAfterSwap()
+{
+ Q_D(QQuickWindow);
+ d->runAndClearJobs(&d->afterSwapJobs);
+}
+
+
#include "moc_qquickwindow.cpp"
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickwindow.h b/src/quick/items/qquickwindow.h
index 4ed663ee6e..6353f6a30c 100644
--- a/src/quick/items/qquickwindow.h
+++ b/src/quick/items/qquickwindow.h
@@ -50,6 +50,7 @@
QT_BEGIN_NAMESPACE
+class QRunnable;
class QQuickItem;
class QSGTexture;
class QInputMethodEvent;
@@ -79,6 +80,14 @@ public:
TextureCanUseAtlas = 0x0008
};
+ enum RenderStage {
+ BeforeSynchronizingStage,
+ AfterSynchronizingStage,
+ BeforeRenderingStage,
+ AfterRenderingStage,
+ AfterSwapStage
+ };
+
Q_DECLARE_FLAGS(CreateTextureOptions, CreateTextureOption)
enum SceneGraphError {
@@ -145,6 +154,8 @@ public:
QString glslVersion() const;
bool glslIsCoreProfile() const;
+ void scheduleRenderJob(QRunnable *job, RenderStage schedule);
+
Q_SIGNALS:
void frameSwapped();
Q_REVISION(2) void openglContextCreated(QOpenGLContext *context);
@@ -196,6 +207,7 @@ private Q_SLOTS:
void cleanupSceneGraph();
void forcePolish();
void setTransientParent_helper(QQuickWindow *window);
+ void runJobsAfterSwap();
private:
friend class QQuickItem;
diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h
index 8faaf6489b..66202aec5c 100644
--- a/src/quick/items/qquickwindow_p.h
+++ b/src/quick/items/qquickwindow_p.h
@@ -256,6 +256,15 @@ public:
static bool defaultFormatInitialized;
static QSurfaceFormat defaultFormat;
+ QMutex renderJobMutex;
+ QList<QRunnable *> beforeSynchronizingJobs;
+ QList<QRunnable *> afterSynchronizingJobs;
+ QList<QRunnable *> beforeRenderingJobs;
+ QList<QRunnable *> afterRenderingJobs;
+ QList<QRunnable *> afterSwapJobs;
+
+ void runAndClearJobs(QList<QRunnable *> *jobs);
+
private:
static void cleanupNodesOnShutdown(QQuickItem *);
};
diff --git a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
index 17773fcfc4..6c1d46b191 100644
--- a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
+++ b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
@@ -55,6 +55,7 @@
#include <qpa/qwindowsysteminterface.h>
#include <private/qquickwindow_p.h>
#include <private/qguiapplication_p.h>
+#include <QRunnable>
struct TouchEventData {
QEvent::Type type;
@@ -367,6 +368,8 @@ private slots:
void defaultSurfaceFormat();
void glslVersion();
+ void testRenderJob();
+
private:
QTouchDevice *touchDevice;
QTouchDevice *touchDeviceWithVelocity;
@@ -1971,6 +1974,58 @@ void tst_qquickwindow::glslVersion()
}
}
+class RenderJob : public QRunnable
+{
+public:
+ RenderJob(QQuickWindow::RenderStage s, QList<QQuickWindow::RenderStage> *l) : stage(s), list(l) { }
+ ~RenderJob() { ++deleted; }
+ QQuickWindow::RenderStage stage;
+ QList<QQuickWindow::RenderStage> *list;
+ void run() {
+ list->append(stage);
+ }
+ static int deleted;
+};
+
+int RenderJob::deleted = 0;
+
+void tst_qquickwindow::testRenderJob()
+{
+ QList<QQuickWindow::RenderStage> completedJobs;
+
+ QQuickWindow window;
+
+ QQuickWindow::RenderStage stages[] = {
+ QQuickWindow::BeforeSynchronizingStage,
+ QQuickWindow::AfterSynchronizingStage,
+ QQuickWindow::BeforeRenderingStage,
+ QQuickWindow::AfterRenderingStage,
+ QQuickWindow::AfterSwapStage
+ };
+ // Schedule the jobs
+ for (int i=0; i<5; ++i)
+ window.scheduleRenderJob(new RenderJob(stages[i], &completedJobs), stages[i]);
+ window.show();
+
+ QTRY_COMPARE(completedJobs.size(), 5);
+
+ for (int i=0; i<5; ++i) {
+ QCOMPARE(completedJobs.at(i), stages[i]);
+ }
+
+ // Verify that jobs are deleted when window has not been rendered at all...
+ completedJobs.clear();
+ RenderJob::deleted = 0;
+ {
+ QQuickWindow window2;
+ for (int i=0; i<5; ++i) {
+ window2.scheduleRenderJob(new RenderJob(stages[i], &completedJobs), stages[i]);
+ }
+ }
+ QCOMPARE(completedJobs.size(), 0);
+ QCOMPARE(RenderJob::deleted, 5);
+}
+
QTEST_MAIN(tst_qquickwindow)
#include "tst_qquickwindow.moc"