From 890648a91b266a889ac5c4d20acad2fe8ecb11e3 Mon Sep 17 00:00:00 2001
From: Gunnar Sletta <gunnar.sletta@nokia.com>
Date: Fri, 1 Jul 2011 08:19:52 +0200
Subject: [PATCH] Support setting an FBO as the render target for a canvas

Change-Id: I8049580f1d2b27d6ebc4d595712939338c01b711
Reviewed-on: http://codereview.qt.nokia.com/986
Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com>
Reviewed-by: Gunnar Sletta <gunnar.sletta@nokia.com>
---
 src/declarative/items/qsgcanvas.cpp       | 44 +++++++++++++++++++++--
 src/declarative/items/qsgcanvas.h         |  5 +++
 src/declarative/items/qsgcanvas_p.h       |  3 ++
 src/declarative/scenegraph/qsgcontext.cpp | 10 ++++--
 src/declarative/scenegraph/qsgcontext_p.h |  3 +-
 5 files changed, 60 insertions(+), 5 deletions(-)

diff --git a/src/declarative/items/qsgcanvas.cpp b/src/declarative/items/qsgcanvas.cpp
index 3abbec323d..343a7e1dd2 100644
--- a/src/declarative/items/qsgcanvas.cpp
+++ b/src/declarative/items/qsgcanvas.cpp
@@ -393,10 +393,10 @@ void QSGCanvasPrivate::syncSceneGraph()
 void QSGCanvasPrivate::renderSceneGraph(const QSize &size)
 {
     context->renderer()->setDeviceRect(QRect(QPoint(0, 0), size));
-    context->renderer()->setViewportRect(QRect(QPoint(0, 0), size));
+    context->renderer()->setViewportRect(QRect(QPoint(0, 0), renderTarget ? renderTarget->size() : size));
     context->renderer()->setProjectionMatrixToDeviceRect();
 
-    context->renderNextFrame();
+    context->renderNextFrame(renderTarget);
 
 #ifdef FRAME_TIMING
     sceneGraphRenderTime = frameTimer.elapsed();
@@ -432,6 +432,7 @@ QSGCanvasPrivate::QSGCanvasPrivate()
     , vsyncAnimations(false)
     , thread(0)
     , animationDriver(0)
+    , renderTarget(0)
 {
     threadedRendering = !qmlNoThreadedRenderer();
 }
@@ -1979,6 +1980,44 @@ QSGEngine *QSGCanvas::sceneGraphEngine() const
 }
 
 
+
+/*!
+    Sets the render target for this canvas to be \a fbo.
+
+    The specified fbo must be created in the context of the canvas
+    or one that shares with it.
+
+    \warning
+    This function can only be called from the thread doing
+    the rendering.
+ */
+
+void QSGCanvas::setRenderTarget(QGLFramebufferObject *fbo)
+{
+    Q_D(QSGCanvas);
+    if (d->context && d->context && QThread::currentThread() != d->context->thread()) {
+        qWarning("QSGCanvas::setRenderThread: Cannot set render target from outside the rendering thread");
+        return;
+    }
+
+    d->renderTarget = fbo;
+}
+
+
+
+/*!
+    Returns the render target for this canvas.
+
+    The default is to render to the surface of the canvas, in which
+    case the render target is 0.
+ */
+QGLFramebufferObject *QSGCanvas::renderTarget() const
+{
+    Q_D(const QSGCanvas);
+    return d->renderTarget;
+}
+
+
 /*!
     Grabs the contents of the framebuffer and returns it as an image.
 
@@ -2081,6 +2120,7 @@ void QSGCanvasRenderThread::run()
 #endif
 
         renderer->swapBuffers();
+
 #ifdef THREAD_DEBUG
         printf("                RenderThread: swap complete...\n");
 #endif
diff --git a/src/declarative/items/qsgcanvas.h b/src/declarative/items/qsgcanvas.h
index 8913e41b86..aa0cdc8138 100644
--- a/src/declarative/items/qsgcanvas.h
+++ b/src/declarative/items/qsgcanvas.h
@@ -55,6 +55,8 @@ QT_MODULE(Declarative)
 class QSGItem;
 class QSGEngine;
 class QSGCanvasPrivate;
+class QGLFramebufferObject;
+
 class Q_DECLARATIVE_EXPORT QSGCanvas : public QGLWidget
 {
 Q_OBJECT
@@ -80,6 +82,9 @@ public:
 
     QImage grabFrameBuffer();
 
+    void setRenderTarget(QGLFramebufferObject *fbo);
+    QGLFramebufferObject *renderTarget() const;
+
 Q_SIGNALS:
     void sceneGraphInitialized();
 
diff --git a/src/declarative/items/qsgcanvas_p.h b/src/declarative/items/qsgcanvas_p.h
index 7f7182ee52..c4c82b666c 100644
--- a/src/declarative/items/qsgcanvas_p.h
+++ b/src/declarative/items/qsgcanvas_p.h
@@ -65,6 +65,7 @@
 #include <QtCore/qwaitcondition.h>
 #include <private/qwidget_p.h>
 #include <private/qgl_p.h>
+#include <QtOpenGL/qglframebufferobject.h>
 
 QT_BEGIN_NAMESPACE
 
@@ -168,6 +169,8 @@ public:
 
     QAnimationDriver *animationDriver;
 
+    QGLFramebufferObject *renderTarget;
+
     QHash<int, QSGItem *> itemForTouchPointId;
 };
 
diff --git a/src/declarative/scenegraph/qsgcontext.cpp b/src/declarative/scenegraph/qsgcontext.cpp
index 682b514b9c..f5a082ba06 100644
--- a/src/declarative/scenegraph/qsgcontext.cpp
+++ b/src/declarative/scenegraph/qsgcontext.cpp
@@ -246,14 +246,20 @@ bool QSGContext::isReady() const
 }
 
 
-void QSGContext::renderNextFrame()
+void QSGContext::renderNextFrame(QGLFramebufferObject *fbo)
 {
     Q_D(QSGContext);
 
     emit d->engine.beforeRendering();
 
     cleanupTextures();
-    d->renderer->renderScene();
+
+    if (fbo) {
+        BindableFbo bindable(fbo);
+        d->renderer->renderScene(bindable);
+    } else {
+        d->renderer->renderScene();
+    }
 
     emit d->engine.afterRendering();
 
diff --git a/src/declarative/scenegraph/qsgcontext_p.h b/src/declarative/scenegraph/qsgcontext_p.h
index 1344ac705d..5ce2e9e80b 100644
--- a/src/declarative/scenegraph/qsgcontext_p.h
+++ b/src/declarative/scenegraph/qsgcontext_p.h
@@ -65,6 +65,7 @@ class QSGMaterialShader;
 class QSGEngine;
 
 class QGLContext;
+class QGLFramebufferObject;
 
 class Q_DECLARATIVE_EXPORT QSGContext : public QObject
 {
@@ -89,7 +90,7 @@ public:
 
     QSGMaterialShader *prepareMaterial(QSGMaterial *material);
 
-    virtual void renderNextFrame();
+    virtual void renderNextFrame(QGLFramebufferObject *fbo = 0);
 
     virtual QSGRectangleNode *createRectangleNode();
     virtual QSGImageNode *createImageNode();
-- 
GitLab