aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGunnar Sletta <gunnar.sletta@jollamobile.com>2014-02-10 15:51:16 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2014-02-25 17:08:02 +0100
commitaaea23708a46259094a8203f73ee0650c362d85f (patch)
tree2d6dda4f7542fd091bca8008f962bc8fcb6ffc41
parentb9f74e7467f31b63bd0ff2ae9d66bcd61a8b8b6f (diff)
Introduced a few more signals to QQuickWindow.
Also marked the new afterAnimation() signal as \since 5.3 and introduced proper revisioning on the new signals. [Changelog][QtQuick] Added QQuickWindow::afterSynchronizing(), openglContextCreated(), sceneGraphAboutToStop(). Useful for deeper integration with the rendering. Change-Id: I5532b310506c2432325595e55ef9307b8934abee Reviewed-by: Laszlo Agocs <laszlo.agocs@digia.com>
-rw-r--r--src/quick/items/qquickwindow.cpp67
-rw-r--r--src/quick/items/qquickwindow.h9
-rw-r--r--src/quick/items/qquickwindow_p.h2
-rw-r--r--src/quick/items/qquickwindowmodule.cpp1
-rw-r--r--src/quick/scenegraph/qsgrenderloop.cpp8
-rw-r--r--src/quick/scenegraph/qsgthreadedrenderloop.cpp3
-rw-r--r--src/quick/scenegraph/qsgwindowsrenderloop.cpp4
-rw-r--r--tests/auto/quick/qquickwindow/tst_qquickwindow.cpp41
8 files changed, 127 insertions, 8 deletions
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index 014fb51572..4eb41a27cd 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -353,6 +353,8 @@ void QQuickWindowPrivate::syncSceneGraph()
renderer->setClearMode(mode);
renderer->setCustomRenderMode(customRenderMode);
+
+ emit q->afterSynchronizing();
context->endSync();
}
@@ -3042,6 +3044,27 @@ QQmlIncubationController *QQuickWindow::incubationController() const
*/
/*!
+ \fn void QQuickWindow::afterSynchronizing()
+
+ This signal is emitted after the scene graph is synchronized with the QML state.
+
+ This signal can be used to do preparation required after calls to
+ QQuickItem::updatePaintNode(), while the GUI thread is still locked.
+
+ The GL context used for rendering the scene graph will be bound at this point.
+
+ \warning This signal is emitted from the scene graph rendering thread. If your
+ slot function needs to finish before execution continues, you must make sure that
+ the connection is direct (see Qt::ConnectionType).
+
+ \warning Make very sure that a signal handler for afterSynchronizing leaves the GL
+ context in the same state as it was when the signal handler was entered. Failing to
+ do so can result in the scene not rendering properly.
+
+ \since 5.3
+ */
+
+/*!
\fn void QQuickWindow::beforeRendering()
This signal is emitted before the scene starts rendering.
@@ -3089,6 +3112,50 @@ QQmlIncubationController *QQuickWindow::incubationController() const
Unlike the other similar signals, this one is emitted on the gui thread instead
of the render thread. It can be used to synchronize external animation systems
with the QML content.
+
+ \since 5.3
+ */
+
+/*!
+ \fn void QQuickWindow::openglContextCreated(QOpenGLContext *context)
+
+ This signal is emitted on the gui thread when the OpenGL \a context
+ for this window is created, before it is made current.
+
+ Some implementations will share the same OpenGL context between
+ multiple QQuickWindow instances. The openglContextCreated() signal
+ will in this case only be emitted for the first window, when the
+ OpenGL context is actually created.
+
+ QQuickWindow::openglContext() will still return 0 for this window
+ until after the QQuickWindow::sceneGraphInitialize() has been
+ emitted.
+
+ \since 5.3
+ */
+
+/*!
+ \fn void QQuickWindow::sceneGraphAboutToStop()
+
+ This signal is emitted on the render thread when the scene graph is
+ about to stop rendering. This happens usually because the window
+ has been hidden.
+
+ Applications may use this signal to release resources, but should be
+ prepared to reinstantiated them again fast. The scene graph and the
+ OpenGL context are not released at this time.
+
+ \warning This signal is emitted from the scene graph rendering thread. If your
+ slot function needs to finish before execution continues, you must make sure that
+ the connection is direct (see Qt::ConnectionType).
+
+ \warning Make very sure that a signal handler for afterRendering() leaves the GL
+ context in the same state as it was when the signal handler was entered. Failing to
+ do so can result in the scene not rendering properly.
+
+ \sa scenegraphInvalidated()
+
+ \since 5.3
*/
diff --git a/src/quick/items/qquickwindow.h b/src/quick/items/qquickwindow.h
index 8be6cc88b7..2572f31375 100644
--- a/src/quick/items/qquickwindow.h
+++ b/src/quick/items/qquickwindow.h
@@ -138,16 +138,21 @@ public:
Q_SIGNALS:
void frameSwapped();
+ Q_REVISION(2) void openglContextCreated(QOpenGLContext *context);
void sceneGraphInitialized();
void sceneGraphInvalidated();
void beforeSynchronizing();
+ Q_REVISION(2) void afterSynchronizing();
void beforeRendering();
void afterRendering();
- void afterAnimating();
+ Q_REVISION(2) void afterAnimating();
+ Q_REVISION(2) void sceneGraphAboutToStop();
+
Q_REVISION(1) void closing(QQuickCloseEvent *close);
void colorChanged(const QColor &);
Q_REVISION(1) void activeFocusItemChanged();
- void sceneGraphError(QQuickWindow::SceneGraphError error, const QString &message);
+ Q_REVISION(2) void sceneGraphError(QQuickWindow::SceneGraphError error, const QString &message);
+
public Q_SLOTS:
void update();
diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h
index 4fb3d0fa08..50f4a289f8 100644
--- a/src/quick/items/qquickwindow_p.h
+++ b/src/quick/items/qquickwindow_p.h
@@ -201,6 +201,8 @@ public:
void updateDirtyNode(QQuickItem *);
void fireFrameSwapped() { Q_EMIT q_func()->frameSwapped(); }
+ void fireOpenGLContextCreated(QOpenGLContext *context) { Q_EMIT q_func()->openglContextCreated(context); }
+ void fireAboutToStop() { Q_EMIT q_func()->sceneGraphAboutToStop(); }
QSGRenderContext *context;
QSGRenderer *renderer;
diff --git a/src/quick/items/qquickwindowmodule.cpp b/src/quick/items/qquickwindowmodule.cpp
index 44a4bf3db6..f6c32dcac3 100644
--- a/src/quick/items/qquickwindowmodule.cpp
+++ b/src/quick/items/qquickwindowmodule.cpp
@@ -149,6 +149,7 @@ void QQuickWindowModule::defineModule()
qmlRegisterType<QQuickWindow>(uri, 2, 0, "Window");
qmlRegisterRevision<QWindow,1>(uri, 2, 1);
qmlRegisterRevision<QQuickWindow,1>(uri, 2, 1);//Type moved to a subclass, but also has new members
+ qmlRegisterRevision<QQuickWindow,2>(uri, 2, 2);
qmlRegisterType<QQuickWindowQmlImpl>(uri, 2, 1, "Window");
qmlRegisterUncreatableType<QQuickScreen>(uri, 2, 0, "Screen", QStringLiteral("Screen can only be used via the attached property."));
}
diff --git a/src/quick/scenegraph/qsgrenderloop.cpp b/src/quick/scenegraph/qsgrenderloop.cpp
index 499abab76b..9ff34f92b8 100644
--- a/src/quick/scenegraph/qsgrenderloop.cpp
+++ b/src/quick/scenegraph/qsgrenderloop.cpp
@@ -241,6 +241,7 @@ void QSGGuiThreadRenderLoop::hide(QQuickWindow *window)
QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window);
if (gl)
gl->makeCurrent(window);
+ cd->fireAboutToStop();
cd->cleanupNodesOnShutdown();
if (m_windows.size() == 0) {
@@ -268,7 +269,8 @@ void QSGGuiThreadRenderLoop::windowDestroyed(QQuickWindow *window)
void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window)
{
- if (!QQuickWindowPrivate::get(window)->isRenderable() || !m_windows.contains(window))
+ QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window);
+ if (!cd->isRenderable() || !m_windows.contains(window))
return;
WindowData &data = const_cast<WindowData &>(m_windows[window]);
@@ -294,10 +296,11 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window)
if (!signalEmitted)
qFatal("%s", qPrintable(nonTranslatedMsg));
} else {
+ cd->fireOpenGLContextCreated(gl);
current = gl->makeCurrent(window);
}
if (current)
- QQuickWindowPrivate::get(window)->context->initialize(gl);
+ cd->context->initialize(gl);
} else {
current = gl->makeCurrent(window);
}
@@ -308,7 +311,6 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window)
if (!current)
return;
- QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window);
cd->polishItems();
emit window->afterAnimating();
diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
index 7b5f161174..5bc7be1d97 100644
--- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp
+++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
@@ -378,6 +378,7 @@ bool QSGRenderThread::event(QEvent *e)
mutex.lock();
if (window) {
+ QQuickWindowPrivate::get(window)->fireAboutToStop();
QSG_RT_DEBUG(" - removed window...");
window = 0;
}
@@ -928,6 +929,8 @@ void QSGThreadedRenderLoop::handleExposure(Window *w)
return;
}
+ QQuickWindowPrivate::get(w->window)->fireOpenGLContextCreated(w->thread->gl);
+
w->thread->gl->moveToThread(w->thread);
QSG_GUI_DEBUG(w->window, " - OpenGL context created...");
}
diff --git a/src/quick/scenegraph/qsgwindowsrenderloop.cpp b/src/quick/scenegraph/qsgwindowsrenderloop.cpp
index 8af0401478..b3def43514 100644
--- a/src/quick/scenegraph/qsgwindowsrenderloop.cpp
+++ b/src/quick/scenegraph/qsgwindowsrenderloop.cpp
@@ -214,6 +214,9 @@ void QSGWindowsRenderLoop::show(QQuickWindow *window)
qFatal("%s", qPrintable(nonTranslatedMsg));
return;
}
+
+ QQuickWindowPrivate::get(window)->fireOpenGLContextCreated(m_gl);
+
QSG_RENDER_TIMING_SAMPLE(time_created);
RLDEBUG(" - making current");
bool current = m_gl->makeCurrent(window);
@@ -269,6 +272,7 @@ void QSGWindowsRenderLoop::hide(QQuickWindow *window)
QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window);
m_gl->makeCurrent(window);
+ cd->fireAboutToStop();
cd->cleanupNodesOnShutdown();
// If this is the last tracked window, check for persistent SG and GL and
diff --git a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
index edde8d2134..73e45fa719 100644
--- a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
+++ b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
@@ -295,6 +295,8 @@ private slots:
QWindowSystemInterface::registerTouchDevice(touchDeviceWithVelocity);
}
+ void openglContextCreatedSignal();
+ void aboutToStopSignal();
void constantUpdates();
void constantUpdatesOnWindow_data();
@@ -358,7 +360,38 @@ private:
QTouchDevice *touchDeviceWithVelocity;
};
-//If the item calls update inside updatePaintNode, it should schedule another update
+Q_DECLARE_METATYPE(QOpenGLContext *);
+
+void tst_qquickwindow::openglContextCreatedSignal()
+{
+ qRegisterMetaType<QOpenGLContext *>();
+
+ QQuickWindow window;
+ QSignalSpy spy(&window, SIGNAL(openglContextCreated(QOpenGLContext *)));
+
+ window.show();
+ QTest::qWaitForWindowExposed(&window);
+
+ QVERIFY(spy.size() > 0);
+
+ QVariant ctx = spy.at(0).at(0);
+ QCOMPARE(qVariantValue<QOpenGLContext *>(ctx), window.openglContext());
+}
+
+void tst_qquickwindow::aboutToStopSignal()
+{
+ QQuickWindow window;
+ window.show();
+ QTest::qWaitForWindowExposed(&window);
+
+ QSignalSpy spy(&window, SIGNAL(sceneGraphAboutToStop()));
+
+ window.hide();
+
+ QVERIFY(spy.count() > 0);
+}
+
+//If the item calls update inside updatePaintNode, it should schedule another sync pass
void tst_qquickwindow::constantUpdates()
{
QQuickWindow window;
@@ -366,10 +399,12 @@ void tst_qquickwindow::constantUpdates()
ConstantUpdateItem item(window.contentItem());
window.show();
- QSignalSpy spy(&window, SIGNAL(beforeSynchronizing()));
+ QSignalSpy beforeSpy(&window, SIGNAL(beforeSynchronizing()));
+ QSignalSpy afterSpy(&window, SIGNAL(afterSynchronizing()));
QTRY_VERIFY(item.iterations > 10);
- QTRY_VERIFY(spy.count() > 10);
+ QTRY_VERIFY(beforeSpy.count() > 10);
+ QTRY_VERIFY(afterSpy.count() > 10);
}
void tst_qquickwindow::constantUpdatesOnWindow_data()