From e20c3516945269a43d070809c08e9797c329306d Mon Sep 17 00:00:00 2001 From: Gunnar Sletta Date: Mon, 19 Mar 2012 20:23:02 +0100 Subject: [PATCH] Allow SG and GL resources to survive a releaseResources. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The presence of these functions required some documentation so I added some. Change-Id: Id66bb6704b3db788ed612ebd6497a5c16ee8b2ca Reviewed-by: Samuel Rødal --- src/quick/items/qquickcanvas.cpp | 123 +++++++++++++++++++++++++++++++ src/quick/items/qquickcanvas.h | 6 ++ src/quick/items/qquickcanvas_p.h | 5 ++ 3 files changed, 134 insertions(+) diff --git a/src/quick/items/qquickcanvas.cpp b/src/quick/items/qquickcanvas.cpp index a5d3250b41..7f512028fd 100644 --- a/src/quick/items/qquickcanvas.cpp +++ b/src/quick/items/qquickcanvas.cpp @@ -306,6 +306,8 @@ QQuickCanvasPrivate::QQuickCanvasPrivate() , windowManager(0) , clearColor(Qt::white) , clearBeforeRendering(true) + , persistentGLContext(false) + , persistentSceneGraph(false) , renderTarget(0) , renderTargetId(0) , incubationController(0) @@ -728,6 +730,55 @@ void QQuickCanvasPrivate::cleanup(QSGNode *n) reparent the items to the root item or to an existing item in the scene. For easily displaying a scene from a QML file, see \l{QQuickView}. + + + \section1 Scene Graph and Rendering + + The QQuickCanvas uses a scene graph on top of OpenGL to render. This scene graph is disconnected + from the QML scene and potentially lives in another thread, depending on the platform + implementation. Since the rendering scene graph lives independently from the QML scene, it can + also be completely released without affecting the state of the QML scene. + + The sceneGraphInitialized() signal is emitted on the rendering thread before the QML scene is + rendered to the screen for the first time. If the rendering scene graph has been released + the signal will be emitted again before the next frame is rendered. + + Rendering is done by first copying the QML scene's state into the rendering scene graph. This is + done by calling QQuickItem::updatePaintNode() functions on all items that have changed. This phase + is run on the rendering thread with the GUI thread blocked, when a separate rendering thread + is being used. The scene can then be rendered. + + Before the scene graph is rendered, the beforeRendering() signal is emitted. The OpenGL context + is bound at this point and the application is free to do its own rendering. Also + make sure to disable the clearing of the color buffer, using setClearBeforeRendering(). The + default clear color is white and can be changed with setClearColor(). After the scene has + been rendered, the afterRendering() signal is emitted. The application can use this to render + OpenGL on top of a QML application. Once the frame is fully done and has been swapped, + the frameSwapped() signal is emitted. + + While the scene graph is being rendered on the rendering thread, the GUI will process animations + for the next frame. This means that as long as users are not using scene graph API + directly, the added complexity of a rendering thread can be completely ignored. + + When a QQuickCanvas is programatically hidden with hide() or setVisible(false), it will + stop rendering and its scene graph and OpenGL context might be released. The + sceneGraphInvalidated() signal will be emitted when this happens. + + \warning It is crucial that OpenGL operations and interaction with the scene graph happens + exclusively on the rendering thread, primarily during the updatePaintNode() phase. + + \warning As signals related to rendering might be emitted from the rendering thread, + connections should be made using Qt::DirectConnection + + + \section1 Resource Management + + QML will typically try to cache images, scene graph nodes, etc to improve performance, but in + some low-memory scenarios it might be required to aggressively release these resources. The + releaseResources() can be used to force clean up of certain resources. Calling releaseResources() + may result in the entire scene graph and its OpenGL context being deleted. The + sceneGraphInvalidated() signal will be emitted when this happens. + */ QQuickCanvas::QQuickCanvas(QWindow *parent) : QWindow(*(new QQuickCanvasPrivate), parent) @@ -764,6 +815,15 @@ QQuickCanvas::~QQuickCanvas() /*! This function tries to release redundant resources currently held by the QML scene. + + Calling this function might result in the scene graph and the OpenGL context used + for rendering being released to release graphics memory. If this happens, the + sceneGraphInvalidated() signal will be called, allowing users to clean up their + own graphics resources. The setPersistentOpenGLContext() and setPersistentSceneGraph() + functions can be used to prevent this from happening, if handling the cleanup is + not feasible in the application, at the cost of higher memory usage. + + \sa sceneGraphInvalidated(), setPersistentOpenGLContext(), setPersistentSceneGraph(). */ void QQuickCanvas::releaseResources() @@ -775,6 +835,69 @@ void QQuickCanvas::releaseResources() +/*! + Controls whether the OpenGL context can be released as a part of a call to + releaseResources(). + + The OpenGL context might still be released when the user makes an explicit + call to hide(). + + \sa setPersistentSceneGraph() + */ + +void QQuickCanvas::setPersistentOpenGLContext(bool persistent) +{ + Q_D(QQuickCanvas); + d->persistentGLContext = persistent; +} + + +/*! + Returns whether the OpenGL context can be released as a part of a call to + releaseResources(). + */ + +bool QQuickCanvas::isPersistentOpenGLContext() const +{ + Q_D(const QQuickCanvas); + return d->persistentGLContext; +} + + + +/*! + Controls whether the scene graph nodes and resources can be released as a + part of a call to releaseResources(). + + The scene graph nodes and resources might still be released when the user + makes an explicit call to hide(). + + \sa setPersistentOpenGLContext() + */ + +void QQuickCanvas::setPersistentSceneGraph(bool persistent) +{ + Q_D(QQuickCanvas); + d->persistentSceneGraph = persistent; +} + + + +/*! + Returns whether the scene graph nodes and resources can be released as a part + of a call to releaseResources(). + */ + +bool QQuickCanvas::isPersistentSceneGraph() const +{ + Q_D(const QQuickCanvas); + return d->persistentSceneGraph; +} + + + + + /*! Returns the invisible root item of the scene. diff --git a/src/quick/items/qquickcanvas.h b/src/quick/items/qquickcanvas.h index 4ac9509896..787bb7e3c7 100644 --- a/src/quick/items/qquickcanvas.h +++ b/src/quick/items/qquickcanvas.h @@ -114,6 +114,12 @@ class Q_QUICK_EXPORT QQuickCanvas : public QWindow void setClearColor(const QColor &color); QColor clearColor() const; + void setPersistentOpenGLContext(bool persistent); + bool isPersistentOpenGLContext() const; + + void setPersistentSceneGraph(bool persistent); + bool isPersistentSceneGraph() const; + QOpenGLContext *openglContext() const; Q_SIGNALS: diff --git a/src/quick/items/qquickcanvas_p.h b/src/quick/items/qquickcanvas_p.h index 0ecdf1fa70..643d694400 100644 --- a/src/quick/items/qquickcanvas_p.h +++ b/src/quick/items/qquickcanvas_p.h @@ -184,6 +184,11 @@ class Q_QUICK_EXPORT QQuickCanvasPrivate : public QWindowPrivate uint clearBeforeRendering : 1; + // Currently unused in the default implementation, as we're not stopping + // rendering when obscured as we should... + uint persistentGLContext : 1; + uint persistentSceneGraph : 1; + QOpenGLFramebufferObject *renderTarget; uint renderTargetId; QSize renderTargetSize;