From e20c3516945269a43d070809c08e9797c329306d Mon Sep 17 00:00:00 2001
From: Gunnar Sletta <gunnar.sletta@nokia.com>
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 <samuel.rodal@nokia.com>
---
 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 @@ public:
     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 @@ public:
 
     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;
-- 
GitLab